这两种游戏使用的是同一种压缩方式,都是RLE压缩方式,具体的压缩编码如下: 0a xx xx xx a 个单独的颜色点
1a bb xx xx xx abb 个单独的颜色点
Da bb abb 个透明色
Ca a 个透明色
8a xx a 个颜色是XX的点
9a xx bb abb 个颜色为xx的点
Aa xx bb cc abbcc 个颜色为xx的点
其他情况,没有压缩
基本上超过3个点一样就用8a xx 了
然后,以魔力宝贝为例,graphics_10.bin是图像压缩数据文件,一幅图像的结构如下:
typedef struct { WORD fmtflag; //全部为"RD" WORD unknow; //不知道什么用 DWORD width; DWORD height; DWORD size; // 整个结构大小,就是头+压缩数据 unsigned char * pdata; // 大小为(size - 16) }st_RDHeader;
另外还有一个GraphicInfo_10.bin的文件,里面是图片信息的数据,具体结构如下:
typedef struct { int idx; //索引号,基本上是按照顺序排列的 DWORD fileptr; //在数据文件中的偏移量 DWORD size; //大小,整个图像结构的大小,同上一个结构的SIZE int ofs_x; //x偏移量 int ofs_y; //y偏移量,就是对齐点离坐上角的y 轴距离 DWORD width; DWORD height; DWORD colorkey; //随便猜得,不一定正确 DWORD unuse1; DWORD unuse2; }st_GrpInfo; // 40 bytes
有了这3样资料,就可以从他们的数据文件里面解出我们需要的图片了。
一般来说,他们的图片都是256色的,调色板存储在相应的目录下,只要读出来就能够把颜色调整好。
但是魔力宝贝3。0增加了16位色的新资源,其实,压缩方法还是按照字节的方式来得。只不过,输出的缓存不再是高度* 宽度,而是高度* 宽度的2倍。 而且是两个字节描述一个点的16位色位图。具体是555,还是565模式的,我没有试验。
下面是我的8位解压函数,不过一些情况没有处理,比如说没有压缩的数据。而且写得很烂。。。。。-_-b
如果需要改成16位,需要送进的out_len 是 w * h *2。
int _core_uncompress_rle8( char * instream, int in_len, char * outstream, int out_len ) { char rle_code; int ptr_instream = 0, ptr_outstream = 0; int i = 0,loopcnt = 0;;
if( instream == NULL || in_len == 0 || outstream == NULL || out_len == 0 || in_len > out_len ) return 0;
while( ptr_instream < in_len ) { rle_code = instream[ptr_instream]; ptr_instream ++; switch( rle_code & 0xf0 ) { case 0x00: loopcnt = rle_code; for( i = 0;i < loopcnt;i ++ ) { outstream[ptr_outstream] = instream[ptr_instream]; ptr_instream ++; ptr_outstream ++; } break;
case 0x10: loopcnt = (rle_code & 0xf) * 0x100 + instream[ptr_instream]; ptr_instream ++; for( i = 0;i < loopcnt;i ++ ) { outstream[ptr_outstream] = instream[ptr_instream]; ptr_instream ++; ptr_outstream ++; } break;
case 0x80: loopcnt = rle_code & 0xf; rle_code = instream[ptr_instream]; ptr_instream ++; for( i = 0;i < loopcnt;i ++ ) { outstream[ptr_outstream] = rle_code; ptr_outstream ++; } break;
case 0x90: loopcnt = (rle_code & 0xf) * 0x100 + instream[ptr_instream + 1]; rle_code = instream[ptr_instream]; ptr_instream += 2; for( i = 0;i < loopcnt;i++) { outstream[ptr_outstream] = rle_code; ptr_outstream ++; } break;
case 0xa0: loopcnt = (rle_code & 0xf) * 0x10000 + instream[ptr_instream + 1] * 0x100 + instream[ptr_instream + 2]; rle_code = instream[ptr_instream]; ptr_instream += 3; for( i = 0;i < loopcnt;i ++ ) { outstream[ptr_outstream] = rle_code; ptr_outstream ++; } break;
case 0xc0: loopcnt = rle_code & 0xf; for( i = 0;i < loopcnt;i ++) { outstream[ptr_outstream] = (char)0xff; ptr_outstream ++; } break;
case 0xd0: loopcnt = (rle_code & 0xf) * 0x100 + instream[ptr_instream]; ptr_instream ++; for( i = 0;i < loopcnt;i ++ ) { outstream[ptr_outstream] = (char)0xff; ptr_outstream ++; } break; } ptr_instream ++; }
return 1; }
终于写完了,希望能对别人有用。。。
《魔力宝贝》 《石器时代》 图片破解 补遗
上次分析得不够完善,一些情况没有分析出来,抱歉。下面是补充。
RLE压缩的地方多了几个:
0a xx xx xx a 个单独的颜色点
1a bb xx xx xx abb 个单独的颜色点 (添加) 2a bb cc xx xx xx abbcc个单独的点
Ca a 个透明色
Da bb abb 个透明色 (添加) Ea bb cc abbcc个透明色
8a xx a 个颜色是XX的点
9a xx bb abb 个颜色为xx的点
Aa xx bb cc abbcc 个颜色为xx的点
所有的a ,b ,c 都是表示单个十六进制数字
关于3。0的魔力宝贝添加的图片其实还是8位色的图片。按照8位色的图片解出来就是了,她不过是用了16位色的显示模式(其实是任何显示模式都可以)。
还有,《石器时代》的INFO的结构和魔力宝贝一样,不过,需要在后面添加一个40字节的数组,什么用都没有。只是结构增大为80字节。
另外,他们的调色板把前面的16个位置丢掉了,就是说实际上调色板是存储了后236个颜色的数值。所使用的时候要注意。
暂时就补充这些了。如果需要软件或者原码,请请联系我 johndragon@sohu.com。 |