从Lua中的ICO文件读取和掩盖16x16图像

时间:2015-12-31 16:10:03

标签: image lua icons bmp ico

我正在创建一个将解析和ICO / CUR并将数据转换为普通像素(特定于我的API)的函数,然后将其输入到将创建最终图像的dxCreateTexture函数。当ICO文件中的图像为8bpp或更低时,我正在研究这种情况。以下是目前的工作方式:

  1. 我读了调色板并将每种颜色存储在一个数组中。
  2. 我继续阅读XOR蒙版,其中包含每个像素颜色的索引,并将每个像素存储在另一个表格中。
  3. 然后我读了AND mask,我理解的是1bpp。
  4. 我将在下面发布的代码完美适用于1bpp,4bpp和8bpp图像,大小为32x32,XOR& AND掩码正确解释,但对于8x8,16x16或48x48大小的图像(我怀疑还有其他大小)只有正确解释XOR掩码。读取AND掩码将导致错误放置的透明像素。请注意,我还没有翻转图片,因此此代码会导致图像颠倒。

    local IcoSignature = string.char(0,0,1,0);
    local PngSignature = string.char(137,80,78,71,13,10,26,10);
    
    local AlphaByte = string.char(255);
    local TransparentPixel = string.char(0,0,0,0);
    
    function ParseCur(FilePath)
        if (fileExists(FilePath) == true) then
            local File = fileOpen(FilePath);
            if (File ~= false) and (fileRead(File,4) == IcoSignature) then
                local Icons = {}
                for i = 1,fileReadInteger(File,2) do -- number of icons in file
                    local SizeX = fileReadInteger(File,1); -- icon width
                    if (SizeX == 0) then
                        SizeX = 256;
                    end
                    local SizeY = fileReadInteger(File,1); -- icon height
                    if (SizeY == 0) then
                        SizeY = 256;
                    end
    
                    fileRead(File,2); -- skip ColorCount and Reserved
    
                    local PlanesNumber = fileReadInteger(File,2);
                    local BitsPerPixel = fileReadInteger(File,2);
    
                    local Size = fileReadInteger(File); -- bytes occupied by icon
                    local Offset = fileReadInteger(File); -- icon data offset
    
                    Icons[i] = {
                        PlanesNumber = PlanesNumber,
                        BitsPerPixel = BitsPerPixel,
    
                        SizeX = SizeX,
                        SizeY = SizeY,
    
                        Texture = true
                    }
    
                    local PreviousPosition = fileGetPos(File);
    
                    fileSetPos(File,Offset);
                    if (fileRead(File,8) == PngSignature) then -- check data format (png or bmp)
                        fileSetPos(File,Offset);
    
                        -- to do
                    else
                        fileSetPos(File,Offset+4); -- skip BITMAPINFOHEADER Size
    
                        local SizeX = fileReadInteger(File);
                        local SizeY = fileReadInteger(File)/2;
    
                        local PlanesNumber = fileReadInteger(File,2);
                        local BitsPerPixel = fileReadInteger(File,2);
    
                        fileRead(File,24); -- skip rest of BITMAPINFOHEADER
    
                        local Pixels = {}
                        if (BitsPerPixel == 1) or (BitsPerPixel == 4) or (BitsPerPixel == 8) then
                            local Colors = {}
                            for j = 1,2^(PlanesNumber*BitsPerPixel) do
                                Colors[j] = fileRead(File,3)..AlphaByte;
                                fileRead(File,1);
                            end
    
                            local PixelsPerByte = 8/BitsPerPixel;
                            local CurrentByte;
    
                            for y = 1,SizeY do -- XOR mask
                                Pixels[y] = {}
    
                                local CurrentRow = Pixels[y];
                                for x = 0,SizeX-1 do
                                    local CurrentBit = x%PixelsPerByte;
                                    if (CurrentBit == 0) then
                                        CurrentByte = fileReadInteger(File,1);
                                    end
    
                                    CurrentRow[x+1] = Colors[bitExtract(
                                        CurrentByte,
                                        (PixelsPerByte-1-CurrentBit)*BitsPerPixel,BitsPerPixel
                                    )+1];
                                end
                            end
    
                            for y = 1,SizeY do -- AND mask
                                local CurrentRow = Pixels[y];
                                for x = 0,SizeX-1 do
                                    local CurrentBit = x%8;
                                    if (CurrentBit == 0) then
                                        CurrentByte = fileReadInteger(File,1);
                                    end
    
                                    if (bitExtract(CurrentByte,7-CurrentBit,1) == 1) then
                                        CurrentRow[x+1] = TransparentPixel;
                                    end
                                end
                            end
    
                            for y = 1,SizeY do -- concatenate rows into strings
                                Pixels[y] = table.concat(Pixels[y]);
                            end
    
    
                            Icons[i].Texture = dxCreateTexture(
                                table.concat(Pixels)..string.char(
                                    bitExtract(SizeX,0,8),bitExtract(SizeX,8,8),
                                    bitExtract(SizeY,0,8),bitExtract(SizeY,8,8)
                                ), -- plain pixels
                                nil,
                                false
                            );
                        elseif (BitsPerPixel == 16) or (BitsPerPixel == 24) or (BitsPerPixel == 32) then
                            -- to do
                        end
                    end
    
                    fileSetPos(File,PreviousPosition); -- continue reading next ICO header
                end
                fileClose(File);
    
                return Icons;
            end
        end
    end
    

    我认为fileExists,fileOpen,fileClose,fileGetPos和fileSetPos是不言自明的功能。其余的功能'参数如下:

    • fileRead(文件文件,编号字节) - 从文件中读取 bytes 字节并将其作为串
    • fileReadInteger(文件文件,[number bytes = 4],[bool order = true]) - 读取一个大小的整数来自
    • bitExtract(数字,数字已归档,数字宽度
    • dxCreateTexture(字符串像素,[字符串格式 =" argb"],[bool mipmaps = true])

    以下是函数当前状态的一些输出:http://i.imgur.com/dRlaoan.png 第一个图像是16x16,AND掩码代码注释掉,第二个是32x32,AND掩码代码注释掉,第三个是带有AND掩码代码的16x16,第四个带有AND掩码代码的32x32。带有AND掩码的8x8和48x48图像与演示中的第三张图像相同。

    ICO用于演示:http://lua-users.org/files/wiki_insecure/lua-std.ico

1 个答案:

答案 0 :(得分:1)

谢谢,@ EgorSkriptunoff!

  

这个掩码也是一个用零填充其每一行的主题。

这确实是个问题。每个循环中的三行代码解决了它。

XOR面具:

if ((SizeX/PixelsPerByte)%4 ~= 0) then
    fileRead(File,4-SizeX/PixelsPerByte%4);
end

AND mask:

if ((SizeX/8)%4 ~= 0) then
    fileRead(File,4-SizeX/8%4);
end