Skip to content

Commit 6bcd092

Browse files
committed
UOL class cast exception ( #2 )
- Added support for canvas properties using the _outlink and _inlink property (although not fully working?)
1 parent 9b74b48 commit 6bcd092

File tree

3 files changed

+139
-20
lines changed

3 files changed

+139
-20
lines changed

MapleLib/WzLib/WzProperties/WzCanvasProperty.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,35 @@ public void ClearProperties()
252252

253253
public override Bitmap GetBitmap()
254254
{
255+
if (this["_inlink"] is WzStringProperty inlink) {
256+
WzObject currentWzObj = this; // first object to work with
257+
while ((currentWzObj = currentWzObj.Parent) != null) {
258+
if (!(currentWzObj is WzImage)) // keep looping if its not a WzImage
259+
continue;
260+
261+
WzImage wzImageParent = (WzImage)currentWzObj;
262+
WzImageProperty foundProperty = wzImageParent.GetFromPath(inlink.Value);
263+
if (foundProperty != null && foundProperty is WzImageProperty) {
264+
return ((WzImageProperty)foundProperty).GetBitmap();
265+
}
266+
}
267+
} else if (this["_outlink"] is WzStringProperty outlink) {
268+
WzObject wzObject = WzFileParent.GetObjectFromPath(outlink.Value);
269+
if (wzObject is WzImageProperty imgProperty) {
270+
return imgProperty.GetBitmap();
271+
}
272+
//WzObject currentWzObj = this; // first object to work with
273+
//while ((currentWzObj = currentWzObj.Parent) != null) {
274+
// if (!(currentWzObj is WzDirectory)) // keep looping if its not a WzImage
275+
// continue;
276+
277+
// WzFile wzFileParent = ((WzDirectory)currentWzObj).wzFile;
278+
// WzObject foundProperty = wzFileParent.GetObjectFromPath(outlink.Value);
279+
// if (foundProperty != null && foundProperty is WzImageProperty) {
280+
// return ((WzImageProperty)foundProperty).GetBitmap();
281+
// }
282+
//}
283+
}
255284
return imageProp.GetPNG(false);
256285
}
257286
#endregion

MapleLib/WzLib/WzProperties/WzPngProperty.cs

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,25 @@ internal void ParsePng()
299299
Marshal.Copy(decBuf, 0, bmpData.Scan0, decBuf.Length);
300300
bmp.UnlockBits(bmpData);
301301
break;
302-
case 513:
302+
case 3: {
303+
// New format 黑白缩略图
304+
// thank you Elem8100, http://forum.ragezone.com/f702/wz-png-format-decode-code-1114978/
305+
// you'll be remembered forever <3
306+
bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
307+
bmpData = bmp.LockBits(new Rectangle(Point.Empty, bmp.Size), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
308+
309+
uncompressedSize = width * height * 4;
310+
decBuf = new byte[uncompressedSize];
311+
zlib.Read(decBuf, 0, uncompressedSize);
312+
zlib.Close();
313+
314+
byte[] decoded = GetPixelDataDXT3(decBuf, width, height);
315+
316+
Marshal.Copy(decoded, 0, bmpData.Scan0, width * height);
317+
bmp.UnlockBits(bmpData);
318+
break;
319+
}
320+
case 513:
303321
bmp = new Bitmap(width, height, PixelFormat.Format16bppRgb565);
304322
bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format16bppRgb565);
305323
uncompressedSize = width * height * 2;
@@ -340,7 +358,20 @@ internal void ParsePng()
340358
Marshal.Copy(decBuf, 0, bmpData.Scan0, decBuf.Length);
341359
bmp.UnlockBits(bmpData);
342360
break;
361+
case 2050: // new
362+
bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
363+
bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
364+
365+
uncompressedSize = width * height;
366+
decBuf = new byte[uncompressedSize];
367+
zlib.Read(decBuf, 0, uncompressedSize);
368+
zlib.Close();
369+
370+
decBuf = GetPixelDataDXT5(decBuf, Width, Height);
343371

372+
Marshal.Copy(decBuf, 0, bmpData.Scan0, decBuf.Length);
373+
bmp.UnlockBits(bmpData);
374+
break;
344375
default:
345376
Helpers.ErrorLogger.Log(Helpers.ErrorLevel.MissingFeature, string.Format("Unknown PNG format {0} {1}", format, format2));
346377
break;
@@ -430,6 +461,66 @@ private static byte[] GetPixelDataDXT3(byte[] rawData, int width, int height)
430461
return pixel;
431462
}
432463

464+
public static byte[] GetPixelDataDXT5(byte[] rawData, int width, int height) {
465+
byte[] pixel = new byte[width * height * 4];
466+
467+
Color[] colorTable = new Color[4];
468+
int[] colorIdxTable = new int[16];
469+
byte[] alphaTable = new byte[8];
470+
int[] alphaIdxTable = new int[16];
471+
for (int y = 0; y < height; y += 4) {
472+
for (int x = 0; x < width; x += 4) {
473+
int off = x * 4 + y * width;
474+
ExpandAlphaTableDXT5(alphaTable, rawData[off + 0], rawData[off + 1]);
475+
ExpandAlphaIndexTableDXT5(alphaIdxTable, rawData, off + 2);
476+
ushort u0 = BitConverter.ToUInt16(rawData, off + 8);
477+
ushort u1 = BitConverter.ToUInt16(rawData, off + 10);
478+
ExpandColorTable(colorTable, u0, u1);
479+
ExpandColorIndexTable(colorIdxTable, rawData, off + 12);
480+
481+
for (int j = 0; j < 4; j++) {
482+
for (int i = 0; i < 4; i++) {
483+
SetPixel(pixel,
484+
x + i,
485+
y + j,
486+
width,
487+
colorTable[colorIdxTable[j * 4 + i]],
488+
alphaTable[alphaIdxTable[j * 4 + i]]);
489+
}
490+
}
491+
}
492+
}
493+
return pixel;
494+
}
495+
496+
private static void ExpandAlphaTableDXT5(byte[] alpha, byte a0, byte a1) {
497+
alpha[0] = a0;
498+
alpha[1] = a1;
499+
if (a0 > a1) {
500+
for (int i = 2; i < 8; i++) {
501+
alpha[i] = (byte)(((8 - i) * a0 + (i - 1) * a1 + 3) / 7);
502+
}
503+
} else {
504+
for (int i = 2; i < 6; i++) {
505+
alpha[i] = (byte)(((6 - i) * a0 + (i - 1) * a1 + 2) / 5);
506+
}
507+
alpha[6] = 0;
508+
alpha[7] = 255;
509+
}
510+
}
511+
512+
private static void ExpandAlphaIndexTableDXT5(int[] alphaIndex, byte[] rawData, int offset) {
513+
for (int i = 0; i < 16; i += 8, offset += 3) {
514+
int flags = rawData[offset]
515+
| (rawData[offset + 1] << 8)
516+
| (rawData[offset + 2] << 16);
517+
for (int j = 0; j < 8; j++) {
518+
int mask = 0x07 << (3 * j);
519+
alphaIndex[i + j] = (flags & mask) >> (3 * j);
520+
}
521+
}
522+
}
523+
433524
private static void SetPixel(byte[] pixelData, int x, int y, int width, Color color, byte alpha)
434525
{
435526
int offset = (y * width + x) * 4;

WzVisualizer/GUI/Form1.cs

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ private void AddEventHandlers(TabPage page) {
5656
foreach (var c in page.Controls) {
5757
switch (c) {
5858
case DataViewer view: {
59-
Debug.WriteLine($"Added event handler for view: {view.Name}");
6059
view.GridView.CellDoubleClick += Grid_CellDoubleClick;
6160
view.GridView.CellStateChanged += Grid_RowStateChanged;
6261
break;
@@ -100,7 +99,7 @@ private void AddGridRow(DataGridView grid, object wzObject) {
10099
int id;
101100
string properties = BuildProperties(wzObject);
102101
string name = null;
103-
WzCanvasProperty icon = null;
102+
WzImageProperty icon = null;
104103

105104
if (wzObject is WzImage image) {
106105
image.ParseImage();
@@ -116,32 +115,27 @@ private void AddGridRow(DataGridView grid, object wzObject) {
116115
}
117116

118117
if (image.WzFileParent.Name.StartsWith("Npc")) { // icon path like: '{ID}/stand/0'
119-
// and also sometimes contains a link STRING property instead of using UOL
120118
name = StringUtility.GetNPC(id);
121-
} else if (image.WzFileParent.Name.StartsWith("Mob")) {
122-
// icon path like: '{ID}/(move|stand|fly)/0'
119+
} else if (image.WzFileParent.Name.StartsWith("Mob")) { // icon path like: '{ID}/(move|stand|fly)/0'
123120
name = StringUtility.GetMob(id);
124-
// attempt to get image of the monster
125-
entityIcon = image.GetFromPath("fly/0") ?? image.GetFromPath("move/0");
121+
entityIcon = image.GetFromPath("fly/0") ?? image.GetFromPath("move/0"); // attempt to get image of the monster
126122
} else if (image.WzFileParent.Name.StartsWith("Reactor")) {
127123
name = image.GetFromPath("action")?.WzValue.ToString();
128124
entityIcon = image.GetFromPath("0/0");
129125
} else { // for breadcrumb like: '{ID}.img/info/icon'
130126
if (ItemConstants.IsEquip(id)) name = StringUtility.GetEqp(id);
131127
else if (ItemConstants.IsPet(id)) name = StringUtility.GetPet(id);
132-
icon = (WzCanvasProperty)image.GetFromPath("info/icon");
128+
icon = image.GetFromPath("info/icon");
133129
}
134130

135131
if (icon == null) {
136-
if (entityIcon is WzUOLProperty uol) icon = (WzCanvasProperty)uol.LinkValue;
137-
else icon = (WzCanvasProperty)entityIcon;
132+
icon = (WzImageProperty)(entityIcon is WzUOLProperty link ? link.LinkValue : entityIcon);
138133
}
139134
} else if (wzObject is WzSubProperty subProperty) {
140135
if (subProperty.WzFileParent.Name.StartsWith("Skill")) {
141136
id = int.Parse(subProperty.Name);
142137
name = StringUtility.GetSkill(subProperty.Name);
143-
144-
icon = (WzCanvasProperty)subProperty.GetFromPath("icon");
138+
icon = subProperty.GetFromPath("icon");
145139
} else { // for breadcrumb like: 'category.img/{ID}/info/icon' (etc.wz)
146140
string imgName = subProperty.Name;
147141
id = int.Parse(imgName);
@@ -150,15 +144,19 @@ private void AddGridRow(DataGridView grid, object wzObject) {
150144
else if (ItemConstants.IsChair(id)) name = StringUtility.GetChair(id);
151145
else if (ItemConstants.IsConsume(id)) name = StringUtility.GetConsume(id);
152146

153-
WzImageProperty imgIcon = subProperty.GetFromPath("info/icon");
154-
if (imgIcon is WzUOLProperty ufo) imgIcon = (WzCanvasProperty)ufo.LinkValue;
155-
else if (imgIcon is WzCanvasProperty canvas) imgIcon = canvas;
156-
if (imgIcon != null) icon = (WzCanvasProperty)imgIcon;
147+
icon = subProperty.GetFromPath("info/icon");
157148
}
158149
} else
159150
return;
151+
152+
if (icon is WzUOLProperty uol && uol.LinkValue is WzCanvasProperty) {
153+
icon = (WzCanvasProperty)uol.LinkValue;
154+
}
155+
160156
Bitmap bitmap = null;
161-
try { bitmap = icon?.GetBitmap(); } catch (Exception) { }
157+
try {
158+
bitmap = icon is WzCanvasProperty canvas ? canvas.GetBitmap() : null;
159+
} catch (Exception) { }
162160
grid.Rows.Add(id, bitmap, name, properties);
163161
}
164162
#endregion
@@ -197,11 +195,11 @@ private string ExtractProperties(WzImageProperty p, string prefix) {
197195
private void LoadWzData(WzMapleVersion mapleVersion, string mapleDirectory) {
198196
int selectedRoot = TabControlMain.SelectedIndex;
199197
switch (TabControlMain.SelectedTab.Controls[0]) {
200-
case DataViewer view: {
198+
case DataViewer view: { // contains just the grid table
201199
view.GridView.Rows.Clear();
202200
break;
203201
}
204-
case TabControl ctrl: {
202+
case TabControl ctrl: { // contains sub-categories
205203
if (ctrl.SelectedTab.Controls[0] is DataViewer view) view.GridView.Rows.Clear();
206204
break;
207205
}
@@ -214,6 +212,7 @@ private void LoadWzData(WzMapleVersion mapleVersion, string mapleDirectory) {
214212
case 0: // Equips
215213
{
216214
if (!LoadWzFileIfAbsent(ref characterWz, mapleDirectory + "/Character", mapleVersion)) return;
215+
217216
List<WzImage> children = characterWz.WzDirectory.GetChildImages();
218217
children.Sort((a, b) => a.Name.CompareTo(b.Name));
219218
for (int i = 0; i < characterWz.WzDirectory.CountImages(); i++) {

0 commit comments

Comments
 (0)