love2d教程23--金庸群侠资源格式解析2
接上篇,今天又折腾了半天,终于可以解析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顺序。最终调试完成,可是发现有些图片显示会出现黑点,暂时不知什么原因。
注意运行时要在工程目录使用"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
作者:半山
出处:http://www.cnblogs.com/xdao/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。