从 Lua 中的 ICO 文件中读取 16x16 图像的 AND 掩码
Reading AND mask of 16x16 images from ICO file in Lua
我正在创建一个函数,它将解析和 ICO/CUR 并将数据转换为纯像素(特定于我的 API),然后将其馈送到 dxCreateTexture 函数,该函数将创建最终的图片。我目前正在处理 ICO 文件中的图像为 8bpp 或更少的情况。这是目前的做法:
- 我读取了调色板并将每种颜色存储在一个数组中。
- 我继续读取包含每个像素颜色索引的 XOR 掩码并将每个像素存储在另一个 table。
- 然后我阅读了 AND 掩码,我知道它是 1bpp。
我将在下面 post 使用的代码非常适用于大小为 32x32 的 1bpp、4bpp 和 8bpp 图像,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(file file, number bytes) - 从 [=读取 bytes 字节24=]file 和 returns 它们作为字符串
- fileReadInteger(文件文件, [数字字节 = 4], [布尔顺序 = true]) - 从 file in order 中读取大小为 bytes 字节的整数(小-edian = true, big-edian = false)
- bitExtract(number value, number filed, number width)
- dxCreateTexture(字符串像素, [字符串格式 = "argb"], [bool mipmaps = 真])
以下是函数在当前状态下的一些输出:http://i.imgur.com/dRlaoan.png
第一个图像是 16x16,AND 掩码代码被注释掉,第二个是 32x32,AND 掩码代码被注释掉,第三个是 16x16,AND 掩码代码被注释掉,第四个是 32x32,AND 掩码代码被注释掉。带有 AND 掩码代码的 8x8 和 48x48 图像看起来与演示中的第三个图像相同。
用于演示的ICO:http://lua-users.org/files/wiki_insecure/lua-std.ico
谢谢@EgorSkriptunoff!
This mask is also a subject to right-padding its every line with zeroes.
确实是这个问题。每个循环中的三行代码解决了它。
异或掩码:
if ((SizeX/PixelsPerByte)%4 ~= 0) then
fileRead(File,4-SizeX/PixelsPerByte%4);
end
和掩码:
if ((SizeX/8)%4 ~= 0) then
fileRead(File,4-SizeX/8%4);
end
我正在创建一个函数,它将解析和 ICO/CUR 并将数据转换为纯像素(特定于我的 API),然后将其馈送到 dxCreateTexture 函数,该函数将创建最终的图片。我目前正在处理 ICO 文件中的图像为 8bpp 或更少的情况。这是目前的做法:
- 我读取了调色板并将每种颜色存储在一个数组中。
- 我继续读取包含每个像素颜色索引的 XOR 掩码并将每个像素存储在另一个 table。
- 然后我阅读了 AND 掩码,我知道它是 1bpp。
我将在下面 post 使用的代码非常适用于大小为 32x32 的 1bpp、4bpp 和 8bpp 图像,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(file file, number bytes) - 从 [=读取 bytes 字节24=]file 和 returns 它们作为字符串
- fileReadInteger(文件文件, [数字字节 = 4], [布尔顺序 = true]) - 从 file in order 中读取大小为 bytes 字节的整数(小-edian = true, big-edian = false)
- bitExtract(number value, number filed, number width)
- dxCreateTexture(字符串像素, [字符串格式 = "argb"], [bool mipmaps = 真])
以下是函数在当前状态下的一些输出:http://i.imgur.com/dRlaoan.png 第一个图像是 16x16,AND 掩码代码被注释掉,第二个是 32x32,AND 掩码代码被注释掉,第三个是 16x16,AND 掩码代码被注释掉,第四个是 32x32,AND 掩码代码被注释掉。带有 AND 掩码代码的 8x8 和 48x48 图像看起来与演示中的第三个图像相同。
用于演示的ICO:http://lua-users.org/files/wiki_insecure/lua-std.ico
谢谢@EgorSkriptunoff!
This mask is also a subject to right-padding its every line with zeroes.
确实是这个问题。每个循环中的三行代码解决了它。
异或掩码:
if ((SizeX/PixelsPerByte)%4 ~= 0) then
fileRead(File,4-SizeX/PixelsPerByte%4);
end
和掩码:
if ((SizeX/8)%4 ~= 0) then
fileRead(File,4-SizeX/8%4);
end