有一些未知图像,我想将其解码为RRGGBBAA格式。这确实是一项艰苦的工作,但是目前我可以理解,二进制文件的哪一部分负责什么。但是我被束之高阁,我不知道如何继续下去。这是我发现的:

我知道第一张图片的大小是9 * 3。

开头有某种表格文件的编号:

0x08 0x08 0x10
0x08 0x08 0x08
0x00 0x00 0x00
0x10 0x10 0x18
0x18 0x18 0x20
0x10 0x14 0x18
0x08 0x08 0x10


这是图像数据:

0x09 0x00 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00
0x0c 0x00 0x00 0x00 0x00 0x01 0x03 0x09 0x01 0x01 0x02 0x11 0x01 0x01 0x02 0x02
0x01 0x0f 0x0f 0x03 0x0a 0x03 0x08 0x05 0x08 0x04 0x08 0x03 0x09 0x00 0x09 0x00
0x0c 0x00 0x02


元素数该表可以一分为三,所以我认为它是某种RRGGBB调色板。

但是我不知道如何解码图像数据。它的大小不是9 * 3,因此可能已压缩。这是一个非常小的图像,我认为这就是压缩使二进制文件比以前更大的原因。

编辑:

我已经在此处上传了此文件:下载文件

我已经对它进行了着色,以更好地了解其结构。

文件的第一部分:




红色部分只是某种文件签名。
棕色部分是文件长度(以字节为单位)。 (1107)
绿色表示文件中已存储多少图像(当前为一张)
蓝色部分表示表的起始位置(0x60 =第96个字节)
灰色部分显示了表格中的内容有多长时间。当前为7,因此该表具有7 * 3 = 21字节,其他值为CD

该表已标记为紫色

文件的第二部分:




蓝色部分是图像的标题。
黄色部分显示图像的长度(51字节)
红色是图像宽度,棕色是高度(3 * 9)
每个文件中的8个零字节(用绿色选择)相同。


我又上传了两个文件。


类似的小文件:下载

,更大的文件:下载


较大的文件的分辨率为800 * 600,我怀疑是这个文件(截图):



开头(从3C0开始),每个4字节组中仅设置了前两个字节或前三个字节。从0xD28开始,我无法识别任何模式。


Edit2:

Spektre的代码适用于大多数文件。但是有些透明的小图标看起来会变形。例如,此图标:下载

这是棕色背景下的外观:



在这种情况下,扫描线不是固定宽度的。而且每条扫描线开头的未知252标志和每32字节之后的254标志也有所不同。

我可以识别二进制文件中的模式和对称性,但是我还没有弄清楚如何

我给图标的图像数据的扫描线上色,以得到更好的概览:



其中许多开始于,并且全部以0x02结尾


Edit3:

我上传了一些图像,并附带了屏幕截图:


雪山:下载

三个图标:下载


我上传了另外两个图像,但发现它们变形了。第一个是图标,几乎是完美的。第二个是一条龙,几乎无法辨认。不幸的是,我无法提供这两个屏幕截图:下载

我在JS中实现了核心算法(来自Spektre的答案)。可以在此处找到并进行在线编辑:JSFiddle链接


Edit4:

我在山和龙上取得了一些进步。

我认为,标志字节的前7位显示了该行在x坐标处开始的位置(´xstart = flag >> 1;´)。最低有效位是一个开关,它指示该行是否具有此偏移量。您可以在此处尝试/编辑当前代码:JSFiddle链接

结果是这样的:



预期的结果将与此类似(不远):



山是阴影/透明度,但是我仍然找不到关于带有alpha值的块的开始和结束位置的任何标记/标志。


Edit5:

我认为,我已经在山峰图像中找到了图案。在标志字节之后,下一个字节可能显示(flag2>>1),该行的开头有多少个(Color, Alpha)块。

现在山的左侧看起来稍微好一点:



不幸的是,此更改破坏了其他图像

评论

我认为您不知道图像实际上是什么样的?没有标题字节字符串,这将很难破解。

这是文件中的所有数据吗?您还有更多样品吗? (最好可供下载。)

我用更多信息和可下载的示例更新了问题

@Spektre我一到家就会详细查看

@Spektre 0x388-0x38B处的整数随处都指向0x3C0。显示0x38C-0x38F的整数,图像数据在此结束。 0x3C0和0x3C2的16位整数又是宽度和高度。从0x3C4-0x3C7开始的字节始终为零。如我所见,几乎每个图像中只有0x37C-0x383部分(仍然未知)是不同的。

#1 楼

我能够解码图像。 Spektre在检测文件结构方面做得很好,调试视图在此过程中确实很有帮助。我在JS中实现了该算法,并且源代码在这里:https://github.com/K-Adam/DrekDecoder

摘要

每行以标志字节。它告诉解码器要写入多少像素以及使用哪种模式。有三种可能的写入模式:


不透明
透明
跳过

在不透明模式下,每个像素由一个字节表示,引用调色板中的RGB颜色。在透明模式下,像素是成对的字节:[Alpha,ColorIndex]

每个序列之后都有一个控制字节。它的结构与标志字节不同,并且在每种写入模式下也不同。该控制字节将告诉您要写入多少像素以及接下来要使用哪种模式,或者是否到达行尾。

详细信息

标志字节

如果(flag == 0x0)的标志为零,则该行为空。

如果将LSB设置为(flag & 0b1),则该行的开头有一个偏移量,并且解码器将以“跳过”开始模式。其余的位将代表偏移的长度(flag >> 1) + 1

如果设置了第二个位,则为透明,否则将使用不透明模式:

mode = (flag & 0b10) ? Transparent : Opaque


像素数可在5个MSB (flag >> 3) + 1中找到

跳过模式

解码器将简单地将n空像素写入输出。下一个字节将是控制字节。

如果设置了LSB,则解码器将切换到瞬态模式。其他7位表示透明像素的数量。

如果三个LSB为0b100,则解码器将继续在“跳过”模式下运行,否则将变为“不透明”模式。其他位表示像素数(vv >> 3) + 1不透明模式

每个数据字节均引用调色板中的RGB颜色。

如果设置了LSB,则解码器将针对(v1 >> 1) + 1像素切换到透明模式。否则,控制字节的三个LSB是标志:


0b000行尾
0b110在不透明模式下继续
0b100切换到跳过模式

其余为像素数(v1 >> 3) + 1

透明模式

透明块由成对的序列表示:[Alpha,Color]。 Alpha字节的5 MSB是透明度(0-32)。颜色字节引用调色板中的RGB颜色。

控制字节的两个LSB是一个标志:


0b10行的结尾
0b11切换到不透明模式
0b01切换到跳过模式
0b00在透明模式下继续

其余位数是像素数(v1 >> 2) + 1,透明模式除外,其中它是(v1 >> 3) + 1

解码过程

由于颜色是由索引引用的,因此需要两个字节来表示一个透明像素。通过查看山的左下角部分,从这些交替的模式中可以清楚地看到那里必须是透明的。圆形图标周围的颜色也不正确,因此我怀疑外部像素也是半透明的。

在大图像中,每32个字节出现0xFE。它不引用调色板中的颜色,因此它必须是某种控制字节。

然后我开始用二进制形式记下字节,其中颜色似乎不合适。我将这些值按它们出现的位置分组,然后发现透明和不透明区域边界上的最低有效位相似。

经过进一步分析,当我能够解码时,用手较小的图标,我实现了算法,并针对较大的图标进行了测试。从那里开始,很容易消除结果中的剩余异常。

#2 楼

[Complete ReEdit3]进一步改进并缩短了文本以适合30KB的限制。

首先,我是如何进入这里的(对于将来的读者,尝试对不同格式进行相同的操作)。

比较提供的背景图像与其原始图像大小xs*ys显示直接相关性,这意味着没有压缩或始终具有相同的像素数据比率。我假设没有压缩。


图像数据对齐。

第一个数字是DWORD,其填充为零。仔细观察,它始终是DWORD[ys],因此每条ScanLine都包含一些信息。数字以恒定的步长递增。对于800x600图像,带有步骤826表示这是包含相对偏移的ScanLine目录。测试证实了这一点:



小图像太小而看不到任何细节,因此我将其完全忽略。

从包含某些信息的ScanLine的第一个26 BYTES开始,xsBYTE不一致。经过更多的讲授和像素测量后,这些33 BYTES可能会出现每个257,其中可能包含一些标志信息(例如:拼贴高光,透明度或效果蒙版)。如果跳过,则结果更接近:




颜色

我只是拿了您的ScreenShot,然后将第一个解码像素与其进行比较。在调色板中找到与每个图像的颜色相匹配的颜色索引,并发现差异是简单的增量。因此,我首先在解码时增加了颜色索引,结果还是不错的。经过一些研究,我发现调色板数据最初具有256颜色,而不是假定的0xFC,因此我更改了调色板偏移量以进行补偿(不再需要更改颜色索引)意味着第一个颜色条目(通过偏移量更改跳过)是某种特殊颜色(请参阅项目符号1)。我后来推断它根本不是颜色,不属于调色板数据,而属于标题数据。现在的结果是:



如果我不发现颜色依赖性,那么我将对已解码和屏幕截图的图像进行直方图分析,然后分析对大多数出现的颜色索引的依赖性找出一些图案。


比较

我的像素与您的ScreenShot匹配了解码的图像,但是图像不匹配。可能对其应用了一些后期处理或照明,或者在解码中有一些错误。由于我无权访问原始应用和/或其内部运作知识,因此很难做出决定。您应该检查更多图像以查看是否有一些伪像。小图像无法使用,因为您不知道内容,而且尺寸很小,无法显示任何重要细节...


透明图像

Iter Ator发现某些文件未正确解码,并推断出它与透明度有关(因为图像是图标,后来又是精灵)。因此,进行了更多的深入分析以取得一些进展。

经过一番思考和循环后,我创建了特殊的调试视图,以便可以通过一些便捷的方式查看编码的图像数据,参考屏幕截图以及相应的调色板颜色,以发现图案或相关性。结果是这样的:



我只需将数据的每个像素/字节渲染为正方形,并使用与调色板条目对应的颜色,然后在其中渲染十六进制代码。我在下面渲染编码的ScanLine和屏幕快照ScanLine(在内部打印了调色板中的交叉匹配的颜色代码。然后痛苦地交叉引用了Paint中的两个ScanLines,并且在比较了所有图标之后我才开始推断出编码格式。这些间隙意味着某种标记或前缀,序列或特殊命令。将这些规则实施到解码器中后,图像突然看起来好多了。

我进入的状态是我得到的所有图标都是像素完美的,但是在获得更多图像之后在(精灵)中,很明显有些代码可能是可变的,并且需要对文件中的块进行更深入的分析才能搜索某些代码表或字典。

为了帮助进行分析,我重写了解码器调试视图以分离类,并具有识别完美色彩匹配(正方形)和紧密色彩匹配(圆形)的能力,从而可以更好地首先评估非透明像素上的代码。



我从这样的规则开始:

来自我推断出了这一点(不能完全确定,请参见实际状态代码):

前2个字节是标志
03 unknonw标志/命令跳过标志可以跟随!


也结束序列23(标志和像素跟随为01)
02结束扫描线
01标志和像素跟随,序列结束(如果不是前5个像素)
序列开始:13,17,23,27,2B
像素跟随:0D,0F,12,15,16,18,1A,1C,1D,1E
标志或像素跟随:06, 07,0C,0E?,10
序列不能作为第一个像素开始,否则为像素
序列可以在完成5个像素后停止,否则01/03只是像素

后来,我直接在解码器中对其进行了进一步改进。


ScanLine偏移量

当我发现ScanLine的第一个BYTE是否用作透明图像的偏移量时,某些图像看起来要好得多。 Ite Ator发现这是偏移量,而LSB位是此功能的开关。我发现,如果第一个ScanLine的第一个BYTE是mode 0/1,则它不是透明图像,并且解码在第一个项目符号中进行了描述。我引入了offset=(flag>>1)+1变量以在解码器中识别这一点。并且偏移仅在模式1(透明)下有效。我还发现0x0360从编码效率的角度更有意义(测试确认这是正确的假设)。


文件块

缺少代码表或字典,我开始剖析文件格式(每个尚未使用的BYTE)。经过一些编码和分析后,我向解码器添加了另一个调试输出,该调试输出以对齐的形式为每个文件/帧创建文本,因此我可以轻松地比较所得到的所有图像,因为在两个或更多十六进制视图中进行比较不是很方便。 />
标头数据:

file                          K  E  R  D              file_size        frames image_ofs                                                                                                                                                                                                   palette_ofs used_colors
dragon              00000000: 4B 45 52 44 C8 00 00 00 A1 BF 01 00 01 00 0B 00 60 03 00 00 01 00 00 00 54 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 2E 00 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60 00 00 00 00 01 00 00 18 CD CD CD 
mountain            00000000: 4B 45 52 44 C8 00 00 00 58 8C 01 00 01 00 02 00 60 03 00 00 01 00 00 00 54 00 00 00 00 00 00 00 56 8A 01 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60 00 00 00 00 01 00 00 18 CD CD CD 
icon0               00000000: 4B 45 52 44 C8 00 00 00 4F 05 00 00 01 00 01 00 60 03 00 00 01 00 00 00 54 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60 00 00 00 5A 00 00 00 18 CD CD CD 
icon1               00000000: 4B 45 52 44 C8 00 00 00 4F 05 00 00 01 00 01 00 60 03 00 00 01 00 00 00 54 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60 00 00 00 59 00 00 00 18 CD CD CD 
icon2               00000000: 4B 45 52 44 C8 00 00 00 4D 05 00 00 01 00 01 00 60 03 00 00 01 00 00 00 54 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60 00 00 00 50 00 00 00 18 CD CD CD 
icon3               00000000: 4B 45 52 44 C8 00 00 00 46 0B 00 00 01 00 01 00 60 03 00 00 01 00 00 00 54 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60 00 00 00 00 01 00 00 18 CD CD CD 
back                00000000: 4B 45 52 44 C8 00 00 00 78 9D 07 00 01 00 01 00 60 03 00 00 01 00 00 00 54 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60 00 00 00 00 01 00 00 18 CD CD CD 


这里的ImageData:

file                                                                    frame sz          xs          ys                                                                                                                                                                                                                      xs    ys                
dragon              00000360: 00 00 00 00 00 00 00 00 00 00 00 00 08 CD 01 00 04 25 00 00 B2 00 00 00 5B 00 00 00 E5 FF FF FF B3 FF FF FF 00 00 00 00 C0 03 00 00 C4 28 00 00 00 00 00 00 00 CD CD CD 00 00 00 00 04 CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD B2 00 5B 00 00 00 00 00 
                    000028C4: 00 00 00 00 00 00 00 00 00 00 00 00 08 00 02 00 A1 26 00 00 B6 00 00 00 5B 00 00 00 DD FF FF FF B4 FF FF FF 00 00 00 00 24 29 00 00 C5 4F 00 00 60 03 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B6 00 5B 00 00 00 00 00 
                    00004FC5: 00 00 00 00 00 00 00 00 00 00 00 00 08 00 03 00 57 27 00 00 C4 00 00 00 5E 00 00 00 D6 FF FF FF B1 FF FF FF 00 00 00 00 25 50 00 00 7C 77 00 00 C4 28 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C4 00 5E 00 00 00 00 00 
                    0000777C: 00 00 00 00 00 00 00 00 00 00 00 00 08 00 04 00 26 28 00 00 BF 00 00 00 64 00 00 00 D3 FF FF FF AA FF FF FF 00 00 00 00 DC 77 00 00 02 A0 00 00 C5 4F 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BF 00 64 00 00 00 00 00 
                    0000A002: 00 00 00 00 00 00 00 00 00 00 00 00 08 00 05 00 70 29 00 00 C3 00 00 00 67 00 00 00 D0 FF FF FF A6 FF FF FF 00 00 00 00 62 A0 00 00 D2 C9 00 00 7C 77 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C3 00 67 00 00 00 00 00 
                    0000C9D2: 00 00 00 00 00 00 00 00 00 00 00 00 08 00 06 00 DA 29 00 00 C6 00 00 00 6C 00 00 00 CF FF FF FF A2 FF FF FF 00 00 00 00 32 CA 00 00 0C F4 00 00 02 A0 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C6 00 6C 00 00 00 00 00 
                    0000F40C: 00 00 00 00 00 00 00 00 00 00 00 00 08 00 07 00 33 2A 00 00 C5 00 00 00 6F 00 00 00 D1 FF FF FF 9F FF FF FF 00 00 00 00 6C F4 00 00 9F 1E 01 00 D2 C9 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C5 00 6F 00 00 00 00 00 
                    00011E9F: 00 00 00 00 00 00 00 00 00 00 00 00 08 00 08 00 1A 2B 00 00 C0 00 00 00 6C 00 00 00 D4 FF FF FF A2 FF FF FF 00 00 00 00 FF 1E 01 00 19 4A 01 00 0C F4 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0 00 6C 00 00 00 00 00 
                    00014A19: 00 00 00 00 00 00 00 00 00 00 00 00 08 00 09 00 59 29 00 00 BE 00 00 00 68 00 00 00 DA FF FF FF A7 FF FF FF 00 00 00 00 79 4A 01 00 D2 73 01 00 9F 1E 01 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BE 00 68 00 00 00 00 00 
                    000173D2: 00 00 00 00 00 00 00 00 00 00 00 00 08 00 0A 00 E5 26 00 00 B5 00 00 00 62 00 00 00 E1 FF FF FF AB FF FF FF 00 00 00 00 32 74 01 00 17 9B 01 00 19 4A 01 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B5 00 62 00 00 00 00 00 
                    00019B17: 00 00 00 00 00 00 00 00 00 00 00 00 08 00 0B 00 CA 23 00 00 AB 00 00 00 5A 00 00 00 EA FF FF FF B3 FF FF FF 00 00 00 00 77 9B 01 00 41 BF 01 00 D2 73 01 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 AB 00 5A 00 00 00 00 00 
mountain            00000360: 00 00 00 00 00 00 00 00 00 00 00 00 08 CD 01 00 A7 BA 00 00 37 01 00 00 D3 00 00 00 00 00 00 00 C9 FF FF FF 00 00 00 00 C0 03 00 00 67 BE 00 00 00 00 00 00 00 CD CD CD 00 00 00 00 04 CD CD CD 00 00 00 00 CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 37 01 D3 00 00 00 00 00 
                    0000BE67: 00 00 00 00 00 00 00 00 00 00 00 00 08 00 02 00 2B C7 00 00 3C 01 00 00 DD 00 00 00 FC FF FF FF C4 FF FF FF 00 00 00 00 C7 BE 00 00 F2 85 01 00 60 03 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3C 01 DD 00 00 00 00 00 
icon0               00000360: 00 00 00 00 00 00 00 00 00 00 00 00 08 CD 01 00 2F 01 00 00 0D 00 00 00 0D 00 00 00 11 00 00 00 F9 FF FF FF 00 00 00 00 C0 03 00 00 EF 04 00 00 00 00 00 00 00 CD CD CD 00 00 00 00 04 CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 0D 00 0D 00 00 00 00 00 
icon1               00000360: 00 00 00 00 00 00 00 00 00 00 00 00 08 CD 01 00 2F 01 00 00 0D 00 00 00 0D 00 00 00 11 00 00 00 F9 FF FF FF 00 00 00 00 C0 03 00 00 EF 04 00 00 00 00 00 00 00 CD CD CD 00 00 00 00 04 CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 0D 00 0D 00 00 00 00 00 
icon2               00000360: 00 00 00 00 00 00 00 00 00 00 00 00 08 CD 01 00 2D 01 00 00 0D 00 00 00 0D 00 00 00 11 00 00 00 F9 FF FF FF 00 00 00 00 C0 03 00 00 ED 04 00 00 00 00 00 00 00 CD CD CD 00 00 00 00 04 CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 0D 00 0D 00 00 00 00 00 
icon3               00000360: 00 00 00 00 00 00 00 00 00 00 00 00 08 CD 01 00 26 07 00 00 26 00 00 00 26 00 00 00 05 00 00 00 ED FF FF FF 00 00 00 00 C0 03 00 00 E6 0A 00 00 00 00 00 00 00 CD CD CD 00 00 00 00 04 CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 26 00 26 00 00 00 00 00 
back                00000360: 00 00 00 00 00 00 00 00 00 00 00 00 08 CD 01 00 58 99 07 00 20 03 00 00 58 02 00 00 08 00 00 00 B4 FD FF FF 00 00 00 00 C0 03 00 00 18 9D 07 00 00 00 00 00 00 CD CD CD 00 00 00 00 04 CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 20 03 58 02 00 00 00 00 


更好地揭示结构。我从中发现了一些东西,例如帧索引,并且ImageData align是0x0370而不是我之前假设的0xCDTBitmap模式也仅出现在第一帧,而不是在所有位置。文件格式如下:

Offset              DataType                Meaning
--------------------------------------------------------
Header (0x0000):
0x0000              char[4]                 `DREK` Signature
0x0008              DWORD                   whole file size
0x000E              WORD                    number of frames
0x0010              DWORD                   ImageData offset from start of file 0x0360
0x0054              DWORD                   Palette offset from start of file 0x0060
0x0058              DWORD                   used_colors from Palette (rest are set to (CD,CD,CD))
--------------------------------------------------------
Palette: (0x060)
+0x0000             BYTE[768]               RGB palette
--------------------------------------------------------
ImageData (0x0360)
+0x000E             WORD                    frame 1,2,3,4,...
+0x0010             DWORD                   sz (ImageData size - 0x60)
+0x0014             DWORD                   xs
+0x0018             DWORD                   ys
+0x0060             WORD                    xs
+0x0064             WORD                    ys
+0x0068             DWORD[ys]               ScanLine offsets relative to end of this table (0x0068 + ys*4)
+0x0068+(ys*4)      BYTE[sz-68-(ys*4)]      ScanLineData
+0x0060+sz                                  Next frame ImageData if frame<frames



现在终于解码器了

代码是用Borlands BDS2006 C ++编写的,使用VCL AnsiStringimg因此,您需要将其重写为您的gfx访问类型以及编程环境支持的字符串。如果需要有关gfx代码含义的帮助,请参见:


C ++中的gfx渲染

此外,文件访问函数的名称可能有所不同。我评论了一下代码,但无论如何应该是显而易见的。至少对于已经做过这样的事情的人。

定义仅在调试和常规解码之间切换。如果不存在,则根本不需要调试映像类_debug_draw。为了保持简单并限制在30KB之内,我删除了调试绘图类的代码(需要/需要的人会在编辑历史记录中看到它们)。这意味着忽略所有0x02定义...

现在图标定义的像素已正确解码。但是我做了很多假设,可能无法在所有图像上使用。我将需要ScreenShots的更多示例来使其更强大。这些代码本身应该编码alpha通道,也可以是位置/偏移。我还添加了一些我发现的特殊情况。模式1的x偏移也存在。

在代码查找行中:

// image data (decoded)


这就是主解码所在的位置。解码变量为:



ScanLine-下一个_pixel是像素

BYTE-跟随像素序列(以_sequence0x01结尾,然后是渲染了5个像素) br />在注释中,某些代码标记为0x03,这些代码没有冲突且简单明了。其余注释表示要遵循的代码:



_stop表示像素0x02



seq表示代码// OK


pXX表示不确定像素或代码是

0xXX表示最有可能是像素cXX



透明扫描线数据在第一个BYTE之后开始所以不要只跳过2个BYTE !!!!

这里有一些预览:



和Dragon帧:



解码器的C ++源代码:

#ifdef _debug_save
AnsiString dbg_hdr="file                          K  E  R  D              file_size        frames image_ofs                                                                                                                                                                                                   palette_ofs used_colors\r\n";
AnsiString dbg_img="                                                                        frame sz          xs          ys                                                                                                                                                                                                                      xs    ys                \r\n";
#endif
void load_drk(Graphics::TBitmap *bmp,AnsiString name)
    {
    AnsiString s,fnam;
    fnam=name.SubString(1,name.Length()-4);

    // variables
    BYTE *dat;
    int hnd,adr,adr0,siz;
    int i,x,y,xs,ys,sz,mode,frame,frames;
    DWORD *p,*dir,pal[256],r,g,b,a;
    // allow direct pixel access
    bmp->HandleType=bmDIB;
    bmp->PixelFormat=pf32bit;
    // read file into memory
    hnd=FileOpen(name,fmOpenRead);
    if (hnd<0) return;
    siz=FileSeek(hnd,0,2);
        FileSeek(hnd,0,0);
    dat=new BYTE[siz];
    if (dat==NULL) { FileClose(hnd); return; }
    FileRead(hnd,dat,siz);
    FileClose(hnd);
    // decode
    for (;;)
        {
        #ifdef _debug_save
        // save frames to bmp
        s=fnam+"                    ";
        s=s.SubString(1,20);
        dbg_hdr+=s;
        dbg_img+=s;
        dbg_hdr+="00000000: "; for (i=0;i<0x60;i++) { s=s.sprintf("%X ",dat[i]); while (s.Length()<3) s="0"+s; dbg_hdr+=s; }
        dbg_hdr+="\r\n";
        #endif

        // signature
        if (siz<0x3C8) break;
        if (((DWORD*)(dat))[ 0]!='DREK') break;
        if (((DWORD*)(dat))[ 2]!=   siz) break;
        // palette
        for (adr=0x060,i=0;i<256;i++)
            {
            b=dat[adr]; adr++;
            g=dat[adr]; adr++;
            r=dat[adr]; adr++;
            pal[i]=(r<<16)|(g<<8)|(b);
            }
        // frames
        frames=((WORD*)(dat+0x0E))[0];
        adr0  =((DWORD*)(dat))[4];
        for (frame=0;frame<frames;adr0+=sz+0x60,frame++)
            {
            adr=adr0;
            // resolution
            if (adr0+0x60>siz) break;
            sz=((DWORD*)(dat+adr))[4];
            xs=((DWORD*)(dat+adr))[5];
            ys=((DWORD*)(dat+adr))[6];
            if (adr0+0x60+sz>siz) break;
            bmp->SetSize(xs,ys);

            #ifdef _debug_save
            // save frames to bmp
            if (frame) dbg_img+="                    ";
            s=s.sprintf("%X: ",adr0); while (s.Length()<10) s="0"+s; dbg_img+=s;
            for (i=adr0;i<adr0+0x68;i++) { s=s.sprintf("%X ",dat[i]); while (s.Length()<3) s="0"+s; dbg_img+=s; }
            dbg_img+="\r\n";
            #endif

            // scanline table
            dir=new DWORD[ys+1];
            if (dir==NULL) break;
            adr+=0x68;
            for (y=0;y<ys;y++)
             dir[y]=adr+(ys<<2)+((DWORD*)(dat+adr))[y];
            dir[ys]=adr0+sz+0x68;

            #ifdef _debug_draw
            // set size and palette of debug image
            img.resize(xs,ys);
            for (i=0;i<256;i++) img.rgb_pal[i]=pal[i];
            // copy reference data to debug image
            for (y=0;y<ys;y++) img.p[y].ref="";
            if ((png->Height)&&(png->Width))
                {
                Graphics::TBitmap *qqq=new Graphics::TBitmap;
                qqq->Assign(png);
                qqq->HandleType=bmDIB;
                qqq->PixelFormat=pf32bit;
                for (y=0;(y<qqq->Height)&&(y<ys);y++)
                    {
                    img.p[y].ref="";
                    img.p[y].cmp="";
                    p=(DWORD*)qqq->ScanLine[y];
                    for (x=0;(x<qqq->Width)&&(x<xs);x++)
                        {
                        for (a=0,b=256,g=768;a<256;a++)
                            {
                            r=rgb_absdistance(p[x],pal[a]);
                            if (g>r) { g=r; b=a; }
                            } a=b;
                        if (g) g='1'; else g='0';
                        img.p[y].ref+=char(BYTE(a));
                        img.p[y].cmp+=char(BYTE(g));
                        }
                    }
                delete qqq;
                }
            // copy encoded data to debug image
            for (y=0;y<ys;y++)
                {
                adr=dir[y];
                img.p[y].adr=adr;
                img.p[y].enc="";
                img.p[y].dec="";
                img.p[y].spc="";
                for (;adr<dir[y+1];adr++)
                 img.p[y].enc+=char(BYTE(dat[adr]));
                }
            #endif

            // image data (decoded)
            a=dat[dir[0]];
            mode=0; if (a!=0xFC) mode=1;
            for (y=0;y<ys;y++)
                {
                adr=dir[y];                     // get actual ScanLine offset in file
                p=(DWORD*)bmp->ScanLine[y];     // get actual ScanLine pointer in bmp
                int _sequence=0;
                int _pixel=0;
                int _stop=0;
                int seq=0;
                for (x=0;x<xs;x++) p[x]=0; x=0;

                if (mode==1)
                    {
                    // 1st ScanLine BYTE (x-offset)
                    a=dat[adr]; adr++;
                    if (BYTE(a&1)==1)
                        {
                        x=(a>>1)+1;
                        #ifdef _debug_draw
                        for (i=0;i<x;i++) img.p[y].spc+='q4312078q';
                        #endif
                        }
                    // 2nd ScanLine BYTE special cases
                    a=dat[adr];
                    if (a==0x0D) adr++; 
                    }
                for (a=0;adr<dir[y+1];)
                    {
                    if (mode==0)
                        {
                        a=dat[adr]; adr++;              // color index
                        if (int(x&31)==0)
                            {
                            r=a;                        // flag
                            a=dat[adr]; adr++;          // color index
                            }
                        }
                    if (mode==1) for (;;)
                        {
                        a=dat[adr]; adr++;              // color index
                        if (_pixel) { _pixel=false; break; }
                        if (_sequence) { seq++; if (seq<6) break; }
                        // commands
                        if (a==0x01)
                            {
                            a=dat[adr]; adr++;
                            _pixel=true; _sequence=false;
                            //if (a==0x07) { adr++; _pixel=false; }
                            continue;
                            }
                        if (a==0x03)
                            {
                            if (!_sequence)
                                {
                                if (dat[adr]==0x18) _pixel=1;
                                continue;
                                }
                            if (_sequence==0x2B) break;
                            a=dat[adr]; adr++;
                            _pixel=true; _sequence=false;
                            //if (a==0x07) { adr++; _pixel=false; }
                            continue;
                            }
                        if (_sequence) break;
                        // unused: 0A,14,1F,20,21,22,24,25,26,28,29,2A,2C+
                        // flag/color prefix
    //                  if((a==0x02)&&(adr>dir[y]+3)) { _stop=true; break; }    // end of ScanLine
                        if (a==0x04) { _pixel=1; continue; }    // ?? ?p18 p47 ?p47
                        if (a==0x05) { _pixel=1; continue; }    // ?? ?18 ?09
                        if (a==0x06) { _pixel=1; continue; }    // ?? ?p18 ?p47
                        if (a==0x07) { _pixel=1; continue; }    // ?? ?18 ?46 ?47
                        if (a==0x08) { _pixel=1; continue; }    // ?? ?09
                        if (a==0x09) { _pixel=0; continue; }    // ?? ?p02 !!!!!!!!!!!
                        if (a==0x0B) { _pixel=1; continue; }    // ?? ?p02
                        if (a==0x0C) { _pixel=1; continue; }    // OK p1D
                        if (a==0x0D)                            // ?? c04 p23 ?c06 p05 p12
                            {
                            _pixel=0;
                            if (dat[adr]==0x02) _pixel=1;
                            if (dat[adr]==0x05) _pixel=1;   // p47 c0D p05 | c0D c05 p09
                            if (dat[adr]==0x12) _pixel=1;
                            if (dat[adr]==0x23) _pixel=1;
                            continue;
                            }
                        if (a==0x0E) { _pixel=1; continue; }    // OK p24 p26 p16
                        if (a==0x0F) { _pixel=1; continue; }    // OK p0F
                        if (a==0x10) { _pixel=1; continue; }    // OK p04
                        if (a==0x11) { _pixel=1; continue; }    // ?? ?p02
                        if (a==0x12) { _pixel=1; continue; }    // OK p27
                        if (a==0x15) { _pixel=1; continue; }    // OK p16
                        if (a==0x16) { _pixel=1; continue; }    // OK p16
                        if (a==0x18) { _pixel=1; continue; }    // OK p00 p02
                        if (a==0x19)                            // ?? p1B
                            {
                            _pixel=1;
                            if (dat[adr]==0x01) _pixel=0;
                            continue;
                            }
                        if (a==0x1A) { _pixel=1; continue; }    // OK p05 p04
                        if (a==0x1B) { _pixel=1; continue; }    // OK p1F
                        if (a==0x1C) { _pixel=1; continue; }    // OK p10
                        if (a==0x1D) { _pixel=1; continue; }    // OK p33 p1E p14
                        if (a==0x1E) { _pixel=1; continue; }    // OK p34 p50 p13

                        // test from dragon and mountain
                        if (a==0x49) { _pixel=1; continue; }    // ?? ?p02
                        if (a==0xE3) { _pixel=1; continue; }    // ?? p18
                        if (a==0xD7) { _pixel=1; continue; }    // ?? pBC
                        if (a==0xDA) { _pixel=1; continue; }    // ?? ?p02

                        // sequence start
                        if (a==0x13) { seq=0; _sequence=a; } // 03
                        if (a==0x17) { seq=0; _sequence=a; } // 01
                        if (a==0x23) { seq=0; _sequence=a; } // 01 03
                        if (a==0x27) { seq=0; _sequence=a; } // 01
                        if (a==0x2B) { seq=0; _sequence=a; } // 01 !03 03
                        if (_sequence)
                            {
                            if (adr==dir[y]+3) { _sequence=false; break; }
                            continue;
                            }
                        break;
                        }
                    if (_stop) break;
                    if (x>xs) break;
                    if ((mode==1)&&((a==0xFE)||(a==0xFF))) { a=dat[adr]; adr++; }   // shadows?

                    if ((x>=0)&&(x<xs)) p[x]=pal[a]; x++;
                    #ifdef _debug_draw
                    // copy decoded data to debug image
                    img.p[y].dec+=char(BYTE(a));
                    #endif
                    }
                }
            delete[] dir; dir=NULL;
            #ifdef _debug_save
            // save frames to bmp
            s=frame;
            while (s.Length()<3) s="0"+s;
            png->Assign(bmp);
            png->SaveToFile("decoded_"+fnam+"_"+s+".png");
            #endif
            }
        img.compute();
        break;
        }
    delete[] dat;
    }


评论


评论已移至聊天室;请不要在扩展讨论中使用评论。

–伊戈尔·斯科钦斯基♦
16年8月24日在8:33