上篇,今天又折腾了半天,终于可以解析grp文件了。 “金”的图片编码方式为rle8(行程编码),

一个grp文件里存放一系列的图片, 图片编码的格式为:

起始8个字节 

xxxx   xxxx   xxxx   xxxx       --xxxx表示两位二进制数,也是大端格式

宽       高      x偏移  y偏移

剩下的表示颜色数据,按行编码,每一行的第一个字节表示当前行所占的字节数, 第二个字节表示

透明点的个数,接着的字节表示颜色点的个数,然后是颜色点的 颜色值,如此反复。

ssss                 xxxx         yyyy       zz.......zz   ssss    xxxx   yyyy   zz......zz ......

本行所占字节  透明点字节   颜色点字节   像素值     如此反复  

 

于是我便开始尝试解析第一幅图片,可是居然费了很久也没成功,关键是想的复杂了, 后来看了一下

游泳的鱼前辈“金”sdl复刻版里的解析代码,才写来了出来,在这里向 前辈致谢。可是第一幅图片显示

时,颜色却是灰的,我又仔细排错,并没有找到逻辑 里的问题,于是把颜色的bgr,改成了rgb,居然

正常了,看来颜色是rgb顺序。最终调试完成,可是发现有些图片显示会出现黑点,暂时不知什么原因。

 love2d教程23--金庸群侠资源格式解析2  

注意运行时要在工程目录使用"love ." ,否则有可能提示错误。  

由于解析时涉及了十六进制,采用了dialectronics 的BinDecHex库,并做了一点修改。

代码如下,点击下载

 main.lua

require('grp')
--创建一个grp
hdgrp=grp:new()
function love.load()
    image=hdgrp:getImg(1,"hdgrp") --读取第一张图片
end

function love.draw()
    love.graphics.draw(image,100,100)
end

grp.lua

local bit=require('BinDecHex')
require('mmapcol')
grp={idx={},filename="",imgs={}}
function grp:new(o)
    o = o or {} --如果参数中没有提供table,则创建一个空的。
     --将新对象实例的metatable指向表(类)
     setmetatable(o,self)
     self.__index = self
     --最后返回构造后的对象实例
     return o
end
--filename文件名不需要后缀,从idx文件创建idx表
function grp:createIdx(filename)
    local file=assert(io.open(filename..".idx","rb"))
    local current = file:seek()  --保存当前文件首地址
    local size = file:seek("end")   -- 得到文件长度
    file:seek("set", current)       -- 恢复
    
    
    table.insert(self.idx,0) --第一个图像的地址实际是0
    local block=4 --设置文件偏移
    local num=size/block --一共多少个图像
    local tmp="" --存放临时4字节数据
    local data="" --存放tmp逆序后的数据
    
    for i=1,num do
        local bytes=file:read(block)
        --把每个byte都转完16进制数
        for b in string.gfind(bytes,".") do
            tmp=tmp ..string.format("%02x", string.byte(b))
        end
        
        --大端转小端
        data= string.sub(tmp,7,8) ..string.sub(tmp,5,6)..string.sub(tmp,3,4)..    string.sub(tmp,1,2) 
        --16进制数转10进制数存入self.idx
        table.insert(self.idx,bit.H2D(data))
        tmp="" --清空
        
        file:seek("set",block*i) --移动文件位置
    
    end
    
    file:close()
end
--从grp文件创建图像 index索引,filename文件名不要后缀
--返回Image类型,图片的偏移ox,oy
function grp:getImg(index,filename)

    local file=assert(io.open(filename..".grp","rb"))
    self:createIdx(filename)
    self.filename=filename
    local addr=self.idx[index] --获取图像地址
    if not addr then
        print("index is bigger")
    end
    local block=self.idx[index+1]-addr --获取图像占用字节数
    --移动文件地址
    file:seek("set",addr)
    local imgInfo=file:read(8) --读取前8个字节的图像信息
    local infostr=""
    for b in string.gfind(imgInfo,".") do
        infostr=infostr..string.format("%02x", string.byte(b))
    end
    local w,h=0,0 --图像的宽和高
    w=bit.H2D(string.sub(infostr,3,4)..string.sub(infostr,1,2))
    h=bit.H2D(string.sub(infostr,7,8)..string.sub(infostr,5,6))
    
    --用infostr="00000000f2ff2d00"测试通过
    local ox,oy=0,0 --图像的偏移
    --这里有的偏移是负数要判断
    if string.find(infostr,"ff",11,12) then
        local hex=string.sub(infostr,11,12)..string.sub(infostr,9,10)
        ox=-(bit.H2D(bit.BNot(hex))+1) --补码原理
    else
        ox=bit.H2D(string.sub(infostr,9,10))
    end
    if string.find(infostr,"ff",15,16) then
    local hex=string.sub(infostr,15,16)..string.sub(infostr,13,14)
        oy=-(bit.H2D(bit.BNot(hex))+1) --补码原理
    else
        oy=bit.H2D(string.sub(infostr,13,14))
    end
    

--先初始化为透明的图片
    imgdata=love.image.newImageData(w,h)
    for y=0,h-1 do
        for x=0,w-1 do --48,112,112,0
        imgdata:setPixel(x,y,0,0,0,0) --todo ,0还是255
        end
    end
    
    --读取索引为index的图像
    local data={}
    file:seek("set",addr)
    local bytes=file:read(block)
    local tmpstr=""
    --读取第一个图片
    for b in string.gfind(bytes,".") do
        table.insert(data,tonumber(string.format("%03d", string.byte(b))))
    end

    file:close()

    local row=0 --保存每行的字节数
    local p=9 --指向data里的数据里的颜色起始点
    local ks=0 --空白点个数
    local solidnum=0 --颜色点个数
    local nilc=0 --保存空白点个数
    local start=0
    for i=0,h do
        row=data[p] --i行的数据个数
        start=p
        p=p+1 --移动到下一点
        if row> 0 then --i行的数据都是颜色点,如果是透明点则为0
             ks=0
             while(1) do
                ks=ks+data[p] --当前行空白点的个数
                nilc=ks
                if ks>=w-1 then -- i行宽度到头,结束
                break
                end
            
                p=p+1 --移动到下一点 ,颜色点
                solidnum=data[p]  -- 不透明点个数
            
                p=p+1 --现在指向不透明点的颜色
                for j=0,solidnum-1 do
            
                imgdata:setPixel(j+nilc,i,mmapcol[data[p]][1],mmapcol[data[p]][2],mmapcol[data[p]][3],255)
                --移动到下一点
                ks=ks+1 --颜色点结束,便是透明点
                p=p+1
                end
            
                   if(ks>=w) then
                        break -- i行宽度到头,结束
                   end
                   --todo
                    if(p-start>=row) then
                        break    --i行没有数据,结束
                    end
            end
            if p>=#data then
            break
            end
        end
    
    end
    
    return love.graphics.newImage(imgdata),ox,oy    
end

 

    

相关文章: