事情是这样的我想从一个游戏客户端的bin文件里面提取出该游戏的图片。我已知此bin文件的图像数据存放规则(有固定的数据块)。但是我读取出指定数据块的数据后,我不懂该怎么把它转换成我们可以在屏幕上看见的图像。比如下面的这段数据,便是我从bin这个二进制文件中读取出来的二进制数据。用for循环,循环已知图像数据大小的次数,用byte类型接收,一个字节一个字节接收出来。再inttohex转换成16进制字符。得到的数据如下1F02A77FD03C06A7A79EA77F7FD039087FA7A77FA77EA7A7D037067F9E9E7F5E7F84A7D0340EA7A77F9E5E9E7FA77FA7A7BB7FBBD0311010A7A77F5E7F9E5E7FA7A7BB7FA7A77FBBD02F839E08A77FBDA77EA77FA7839E047F7F7EBBD02C84A70D5E7FA77FA7A7BDA77F5E9E9E5E837F029E9ED029089E7E7EA77FA77FA7837E0DBDA6A79E705EA7A77F5E9E9E7FD027101A9E9EA77E7EA77FA77FA75D7E5D7DBB7CBC5C7E7DA7BDA77FA77FD0240B7C9EBC9E7F9EA77FA77FA7837E0B5D7EBC7DBD7D7CBDA7BCBD83A7027F7FD02110207F9E7CBC9EA69E7FA77F5E9EA77E5D7EBD53BDA77E7CA6A75D7E7EA77FA77EA7D01F04A7A77BBC84A6101ABBBDA77F5E7FA7A77E7EA77FA77E7EBCA77FA76FA77FA77EA77ED01C83A704BD7EBD6E83A61013BC7FA77F5E7FA7BDA7A77FA76FA7BDBC7D9E7F83A7067EA77EBDBBA7D01910127F9EA79EA77DBABA5BBB7CA67F7F9E9E5E7F837E10139E7F7D7E7E5DA67E5EA77E7DBD7E537BBBA77FD01783BC1014BBBDBC7EA67B5BBBBBA67FBD5E5E7FBDBC7D5C7E83A710109EBD5CBDA77FA77E7EBDBD7CBCA7BBA7D014019E83BC07A6BC7D7E7BBBA683BB10209EA7BDA77EA7BD537DBCBDA77F9E9E7DA6BD7EA77EA7A76F9E9EA7BB7FBD7C7FD011839E102A5DBCBC9EBB7EBB7FBCA6BC9EA6A77E7EA77F7EBD7D537EA7BC9EBC9EA77EA76FA7A6BBBBA69EBC9E9EA7839ECF0EA7A7BCBC7F9EBCBC7EBBBDBBBB9E83A60CBD7E7EBDA77F5E9E9EA7A69E83A710129EA79EA79EBBA7BB9EA77EA7A77F9EBC9EA6CC1020A6BB5BBBBBA7A7BDA7BBBBBD7E5A7D5BBD7D5A5C7D53A6A65CBCA79EBBBBBDBB83A783BD10105D7D7BBDA6A77EA79E9E5E9EA6A7BBA7C908BCBCA6BBA6BBA7A7837E1024BB7B7BA6A77F9EA7BC5C7D7E7E7D7DBD9EBC9EBB7EA79E7F9EA77EBDBD537D7E9EA7A7BD839E06A7BB7EBD7FA6C7103A7FBBA67CA6BBA77E7EA7A77EA77FBBBBA7A77F9E7D7D5D7D7E537E7E9E5E9EA7A7BD5E7F5E7FA7BD53BDBD7FBB7F6E7DBC7E7FA7BDA7BB9EA77EC40D9EBBA7BBBC9EBB5BBCA69EA77E83A7102B7FA77EA7BBBD5D7EA77F7F9E9EBCBC7DBBA77F9E7F5E9E7F7F9E9EA79E9EA77A3BA67D7EA77FA77FA7A6BB83A7101500BBA67F7F9E9EBBA7A79C7FA6A7A63D7D7F5E7F5E839E047FA77F5E839E06BCBCBDBD9E5E839E1015BDA75E7FBBA7BBBDBB7EA6A6535D7FA77FA79E7F7F84A71011009EA77F5EA77EA7A77FBCBCA7A6BCBBA6849E102A5E9E7EA7A77FA7A6A69E9EA77E7F9E5F9E9EBD9E7FBBA77EBDA6A75BBB7F7EA77EBB7EA77F5E7FA77FA7C4101AA77F7FA7A77FBC9EBCA6BB5A59A66D7FA7BD9E9E7E7EA7A7BDBB83BC101D9EA7A75E9EA7A7BD7FBBBDBBA75B7FBC9C9EBC7E5B5BBBBD7F5E7F9EA7C705A7A77F9E7F839E0FBBBA59B95CA65CA6A7A76FBD5AA6A683BC10179CBC9EA77FA77F7E9E7FA7BDA7BB7FA6BCBB9E9EBC9E9E83A7047F5E9E9EC9029E5E839E1016BCA65BA6B9B9A6A65C7E9EA77DBCA65BBB7BA6BCA6A6839E0C7EA7A77F5E7FA7A7BB5BBCA684BC849E047F5E7F7FCC059E9E5E9EBC83BB0F7B7DBC3DBDBD7E7D7D53BDBA7BBB5D849E0D5E7F7E7F5E9E7FA7A7BBBBA6A684BC069E9E5F9E5E9ECF1014A7A6BCBBBB5B5BA75E7EA65D7EA77EBDA7A7BCBB839E05A6BC5E709E83A7049E5E9E9E83BB0A5BA69CBC9E5E9E709E7FD011102EA69E5BBB7C7EA5BD7DBD7E7EA77EA77FBD7DBB9EA6A7BBBCBC9EBC9E7F9E9E709EBCBCA6BBBBBABBA69E9E5F9E9ED0141024A69EBCA6BC7EA7A79E7F9E5E7F9EBDB96E6EA7BDBBA69CBCBC9E5E9E9E5EBC9E7C7CA6BB83BC03A65E9ED01705BC9E7FBA9E83A710205EBD7FA77DBA3B7CB97DA7A6A6BCBC5DBCBC9E5F9E9E7FBBBB5BA6A6BCBC9E9ED01910117FA7BDA77F5E7F9EA7A7BDA5A77B7D7C5D839E08A6A6BCBC9E9EA7BD83A704A6A69EA6839ED01C0F7DBDBD9E9E5E9EA79EBD7FA77F7EA6839E83BD0D5B7BA7A79EA77F9E7F9E9EA79ED01F101B7EBD9E9E70A7A6BBA77CA77F9EA79E5F9E5E9E7F9EBB7E7F9E9E5F859ED021101E7F9E5EA77FBBBBA77FA79E5EBD9E9E709E9EBB9EA7BD5E705F9E5E705E9ED024101A7EBBBBA77F9E9E5E7F7FA77E5E9E5EBCA79EA77EA75E9E709E9ED02783BB1015A69E9E7F5EA7A77FBDA7BC7E5ABDA6A7BD5E9E5F9ED02910167BBBBB9E705E7FA77FA77FA7BDBD5BBDBCBCBB7EA7BBD02C0EBC9E9E5E7F7FA77FA7BD7E7EBBB983A601BBD02F10109E9E709E5E7FA7A77E7E7F7CBBA67C7BD0310B7F5E9E709E9EA7A79E7F7D83A6D0340ABC5E5F9E7F9E9EBC9CBCD037839E055E5EBC9EBCD03906BC5E709EA79ED03C029E7FD01F52440110400000002F000000A0060000D0
以上二进制数据应该是一副完整的图像了。这个游戏客户端图像数据压缩用的是自定义的RLE算法。算法的具体已经有人发文章了,我转过来,如下:++++++++++++++++++++++++++++++++++
这是JSS自定的一种Run-Length算法,用于StoneAge和CrossGate,下面是说明:首字节(00) 01 02 03 说明 
0n String     长度为n的字符串 
1n m String   长度为n*0x100+m的字符串 
2x y z String 长度为x*0x10000+y*0x100+z的字符串 
8n X     填充n个X 
9n X m   填充n*0x100+m个X 
Ax X y z 填充x*0x10000+y*0x100+z个X 
Cn       填充n个背景色 
Dn m     填充n*0x100+m个背景色 
Ex y z   填充x*0x10000+y*0x100+z个背景色 
比如,C9表示填充9个背景色,D1 10表示填充0x110个背景色,12 50表示后面跟着一个长度为0x250的字符串,91 02 30则表示将0x02重复0x130遍。 
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的点+++++++++++++++++++++++++++++++++这个是RLE算法的解释,可是我看不太懂……。我不知道这个算法是不是说要我自己写一个解压算法,将我上面提取出来的二进制数据解码?郁闷……,谁能告诉我怎么解码?要不就告诉我怎么理解上面那个RLE算法,它那个说明0N,1N的我无法理解另外,图像要完整显示,还跟调色板有关系。游戏客户端有调色板文件。但是我同样因为没有做过这方面的程序,不理解调色板是做什么用的?我只知道,如果没有应用调色板,图像的色彩会失真,有时候会错乱,但是图像的轮廓还是存在的。希望高手可以告诉我一下,首先就是如何将我上面提取的二进制数据还原成一个图像。
然后就是调色板的应用是怎么一回事~~!谢谢谢谢~,分不多,只有一百,……多多包涵~,在下实在是被它困扰多日,寝食难安……

解决方案 »

  1.   

    先Canvas一下看看能画出来不?
      

  2.   

    郁闷~~~谁能用一段代码将我帖子中的数据还原成图像吗?标志位,长度,内容,效验位,结束位这些得出来是不是还要跟象素点配合一点一点画出来?我看过别人的程序,数据量大的时候有20万多字节,这样的大数据他的程序也是一下子就显示出图像来。我估计不是这样运算的,肯定有什么办法。但是我联系不到程序作者,只好自己琢磨,在这里求助了。canvas画出来的画依据什么呢?
      

  3.   

    建议楼主先去学习下位图编码原则,这个问题就很容易解决了
    至于RLE算法应该是一个压缩算法,需要另外找个解压缩算法就行了
      

  4.   

    jpeg就是图象的一种压缩算法,相邻的像素颜色变化越大,那么jpg文件就越大,但是如果20万个字节才显示1张图片,那么还用压缩做什么,即使用bmp,像素就非常大了,估计20万个字节显示的不仅仅是1张图片,可能是动态图象如同mpeg,或者是1组图象资源,因此如果要显示出其中一张,那么只要找到这张图片的标志位,然后通过解压缩算法,很快可以显示出来。
      

  5.   

    另外不知道楼主有没有发现你的bin中有很多重复相同的格式,如 A77……,祝你好运吧
      

  6.   

    …………老实说我还是一头雾水。如SonicX(SonicX) 这位兄台所说的,却根本又不指明如何解决我这个问题的关键。我总不能为了这个问题而专门将位图的结构以及基础分析之类的看起来…………所谓位图编码原则是指什么呢?是不是指这些十六进制数据可以转换成位图的规则?这种说法我真的是不理解~~既然你说这个问题很容易解决,那么能否深入一点告诉我具体应该怎么解决呢?RLE算法根据我上面发的,应该是游戏开发者自己定义的算法规则。感谢IDWB() 兄台,你不说我还真没发现……数据中果然有很多A7,不知道是不是RLE算法的标志符。被问题弄蒙了,都没注意到。能否跟我说一下,比如我要是还原出这堆压缩数据,我应该怎么样让这堆数据变成屏幕上可以看见的图片?在我的理解范围里面,实在是搞不懂,数据跟图片之间的关系。比如给你们这样一堆数据你们该怎么编写代码将其保存为电脑里一个图片文件??希望各位指点指点
      

  7.   

    是否应该结合图像的高度和宽度?用image控件的canvas.pixels属性来一点一点的显示?逐行显示?然后根据调色板找出相应数值对应的色值?
      

  8.   

    还真是自定义的RLE算法......  
    不知道是你的数据有问题,还是你表诉的算法有问题,或着是我理解有问题.反正我理解下来,无法解码1F02A77FD0 3C06A7A79EA7...
    按你的表诉, 由1a bb xx xx xx 表示为: abb 个单独的颜色点
    则 有连续的 0xF02 个颜色为A77FD0的颜色点
    但是,接下来3C06A7A79EA7...   3c 无法解码了.晕死....况且,这个东西解码出来,没有图形,比如 高,宽等信息,你还是无法画..
    至于调色板,可能只有8a 9a Aa 下用, 
    如果你所有信息的得到 且数据解码了, 创建一个位图,就可以画出来了(这种画图代码,网上随便抓一把都是.).
      

  9.   

    呵呵,多谢各位的解答,感觉有点眉目了TO:IDWB() ,确实是有数据块的起始位置和大小的数据,我就是根据起始位置和数据块的大小读取出来的。但我用的比较笨的办法,一个一个字节循环读取。不知道你所说的分块读取是否是指用数据流来?我只能用byte类型来接收。如果不用数据流的话,分块读取该用什么类型来接收读取到的数据呢?我想不到……TO:jiju(UNCC)感谢你的回答,我现在才知道原来要把这堆数据还原成图像,还跟高度宽度有关。图像的高度和宽度数据我也都有的,原先以为没什么用(郁闷……当时不了解),便没有发上来。关于这个自定义RLE算法的问题,我看了很多数据块,发现有一个共同点,绝大部分的数据块开头都是1F02,数据一般是从第三个字节开始不同的。而结尾数据也绝大部分是为0000D0。这样是否可以解码?
      

  10.   

    另外……jiju(UNCC)兄台,你说的『则 有连续的 0xF02 个颜色为A77FD0的颜色点』这个我有点不好理解啊,A77FDO这个是三个字节,如果合起来表示一个颜色点的话,这个数值不是会很大?颜色的值的范围我知道,应该是256以内的,因为调色板的颜色点就是256色(以内)。而这样怎么能将后面三个字节全部归为颜色点呢?
      

  11.   

    不好意思,是我看错了
    0a xx xx xx 
    xx xx xx我理解为颜色, 看来只是每一个xx 代表一个颜色信息而已.
    表示为有a 个 颜色点的数据字节
      

  12.   

    1F02
    是说后面有F02个象素值(非压缩), A7 7F D0 3C 06 A7 ... 就是了。
    不过楼主给出的这一段数据连F02都不够啊,而且宽度、高度都不知道,没法还原。
      

  13.   

    今天依然无解……………………旺仔说的DFM却是什么东西??
      

  14.   

    jiju(UNCC) ~~~~你是怎么解出来的!!这个图形是一个斜放的四方形~~如果要说三角形的话也可以,就是两个三角形拼成一四方形
      

  15.   

    这段代码也许对你有用!
    只要把二进制读入入数组中就可以了,其余用流就可以,你试试吧!
    我最近也在做这方面的东西,交流一下!
    以下是代码:
    var
      S: TStream;
      B: TMemoryStream;
      T:TSTREAM;
      I: Integer;
      C:ARRAY[0..8000] OF Byte;
     begin
      B := TMemoryStream.Create;
      B.LoadFromFile('D:\lfg\手机照片\Image00001.bmp');
      B.Position := 0;
      S := TMemoryStream.Create;
      S.Position :=0;
      for I := 0 to B.Size-1 do
      begin
       B.Read(C[I], 1);
       S.Write(C[I],SIZEOF(C[I])) ;
      end;
      S.Position :=0;
      image1.Picture.Bitmap.LoadFromStream(S);
      B.Free;
      S.Free;
     end;
      

  16.   

    呵呵~谢谢。有个问题问一下你用的byte数组是固定长度的,能否用动态数组?我先前用动态数组接收读取到的数据竟然不行……
      

  17.   

    …………郁闷了~~静态数组可能是可以的,我没有试。现在的主要问题是,我不懂怎么将这段压缩过的数据还原出来~~RLE算法的。只有哪位能够指点一下这个数据的解码算法,我才能继续下一步…………神啊!!让高手都现身吧~~~
      

  18.   

    这么多天了,你好歹也要自己动手试试啊,
    看了你后面说的高度,和宽度,还有图形形状,我找了半天哪天写的代码,知道为什么是一个斜放的四方形(菱形吧),
    你给的数据有问题,前面应该还有一个D0,也就是说D01F02A77FD03C06...  这样正好解码出来是
    3008个数据,解码到52440110400000002F000000A0060000D0停止. 画出来就是一个菱形,
    加D0是我自己猜的,至于解码方式就按前面的提示来做.省得你再问,在说一点,解码出数据后用CreateBitmap 来创建位图,而不是用Bitmap.LoadFromStream(S)来读取,之后做的事情,自己去查帮助.
      

  19.   

    jiju(UNCC)谢谢你的提醒………………我这几天因为课程的原因,所以除了在这边寻求帮助外,我确实不敢花太多时间去搜索资料……我曾搜索过,但是我除了知道这个是RLE算法之外,我便没办法进一步了解如何写一个解码算法。这个帖子我现在主要就是被这个压缩算法卡住了。我看不懂那个算法的解释说明……我郁闷~~读取文件的程序我一直在写测试代码,但是我因为不知道如何解码,所以写不出个所以然……而且你说的没错,确实前面应该有一个DO,是我读取时候少算了一位可能。呵呵希望你能更详细点告诉我如何解码的,谢谢谢谢~~(本来想说万分感谢……可想一想这个词突然不敢用,哈哈,还请兄台帮帮我)
      

  20.   

    jiju(UNCC)兄,能否将你的代码复制出来我学习学习呢?就是RLE解码算法的代码,以及用解码后位图创建位图的代码~~!!渴求已久……5~~
      

  21.   

    procedure uncompress_rle8(instream:PChar;in_len:Integer;outstream:PChar;out_len:Integer);
    var
        rle_code:Word;
        ptr_instream:Word;
        ptr_outstream:Word;
        i,loopcnt:Word;
        c:Char;
    begin
        if( instream = nil) or (in_len = 0) or (outstream = nil) or (out_len = 0) or (in_len > out_len ) then exit ;
        ptr_instream:=0;
        ptr_outstream:=0;
        i:=0;
        loopcnt:=0;
        while ptr_instream < in_len do
        begin
            //c:=instream[ptr_instream];
            rle_code := Word(instream[ptr_instream]);
            //rle_code:=Integer(c);
            Inc(ptr_instream);
            case rle_code and $f0 of
                $00:
                    begin
                        loopcnt := rle_code;
                        for i := 0 to loopcnt - 1 do
                        begin
                            outstream[ptr_outstream] := instream[ptr_instream];
                            Inc(ptr_instream);
                            Inc(ptr_outstream);
                        end;
                    end;
                $10:
                begin
                    loopcnt:= (rle_code and $0f)*$100+Word(instream[ptr_instream]);
                    Inc(ptr_instream);
                    for i := 0 to loopcnt - 1 do
                    begin
                        outstream[ptr_outstream] := instream[ptr_instream];
                        Inc(ptr_instream);
                        Inc(ptr_outstream);
                    end;
                end;
                $20:
                begin
                    loopcnt := (rle_code and $0f) * $10000 + Word(instream[ptr_instream]) * $100 + Word(instream[ptr_instream+1]);
                    Inc(ptr_instream,2);
                    for i := 0 to loopcnt - 1 do
                    begin
                        outstream[ptr_outstream] := instream[ptr_instream];
                        Inc(ptr_instream);
                        Inc(ptr_outstream);
                    end;
                end;
                $80:
                begin
                    loopcnt := rle_code and $0f;
                    rle_code := Word(instream[ptr_instream]);
                    Inc(ptr_instream);
                    for i := 0 to loopcnt - 1 do
                    begin
                        outstream[ptr_outstream] := Char(rle_code);
                        Inc(ptr_outstream);
                    end;
                end;
                $90:
                begin
                    loopcnt := (rle_code and $0f) * $100 + Word(instream[ptr_instream + 1]);
                    rle_code := Word(instream[ptr_instream]);
                    Inc(ptr_instream,2);
                    for i := 0 to loopcnt - 1 do
                    begin
                        outstream[ptr_outstream] := Char(rle_code);
                        Inc(ptr_outstream);
                    end;
                end; //end $90
                $a0:
                begin
                    loopcnt := (rle_code and $0f) * $10000 + Word(instream[ptr_instream + 1]) * $100 + Word(instream[ptr_instream + 2]);
                    rle_code := Word(instream[ptr_instream]);
                    Inc(ptr_instream,3);
                    for i := 0 to loopcnt - 1 do
                    begin
                        outstream[ptr_outstream] := Char(rle_code);
                        Inc(ptr_outstream);
                    end;
                end;    //end $a0
                $c0:
                begin
                    loopcnt := rle_code and $0f;
                    for i := 0 to loopcnt - 1 do
                        begin
                        outstream[ptr_outstream] := #$ff;
                        Inc(ptr_outstream);
                    end;
                end;
                $d0:
                begin
                    loopcnt := (rle_code and $0f) * $100 + Word(instream[ptr_instream]);
                    Inc(ptr_instream);
                    for i := 0 to loopcnt - 1 do
                    begin
                        outstream[ptr_outstream] := #$ff;
                        Inc(ptr_outstream);
                    end;
                end;
                $e0:
                begin
                    loopcnt := (rle_code and $0f) * $10000 + Word(instream[ptr_instream]) * $100 + Word(instream[ptr_instream+1]);
                    Inc(ptr_instream,2);
                    for i := 0 to loopcnt - 1 do
                        begin
                        outstream[ptr_outstream] := #$ff;
                        Inc(ptr_outstream);
                    end;
                end;        end;    //end case
            Inc(ptr_instream);    
        end; //end whileend;找到这一份代码其中有些不理解的地方希望各位高手能够帮忙解答解答。其中这一句rle_code := Word(instream[ptr_instream]);word()表示什么意思?强制转换成word类型?