Lua bmp纵横比问题
我一直在尝试了解bmp文件是如何工作的,这样我就可以渲染一些Mandelbrot set图片并将它们作为bmp文件输出,因为这似乎是最简单的方法之一,但出于某种原因,当我使用的纵横比不是1:1时,即使它的倍数是4(因此不需要填充)我得到了像这样奇怪的伪影,我正试图把一个像素阵列,偶数为白色,奇数为黑色,变成一个bmp,这就是长宽比为1:1时的样子。 我试着通读维基百科的文章,看看我是否能找出我做错了什么,但我仍然不明白我遗漏了什么 这是迄今为止我用Lua编写的脚本:Lua bmp纵横比问题,lua,bmp,Lua,Bmp,我一直在尝试了解bmp文件是如何工作的,这样我就可以渲染一些Mandelbrot set图片并将它们作为bmp文件输出,因为这似乎是最简单的方法之一,但出于某种原因,当我使用的纵横比不是1:1时,即使它的倍数是4(因此不需要填充)我得到了像这样奇怪的伪影,我正试图把一个像素阵列,偶数为白色,奇数为黑色,变成一个bmp,这就是长宽比为1:1时的样子。 我试着通读维基百科的文章,看看我是否能找出我做错了什么,但我仍然不明白我遗漏了什么 这是迄今为止我用Lua编写的脚本: ResolutionX=10
ResolutionX=100
分辨率=100
本地cos,atan,sin,atan2,sqrt,floor=math.cos,math.atan,math.sin,math.atan2,math.sqrt,math.floor
本地插入,concat=table.insert,table.concat
local sub,char,rep=string.sub,string.char,string.rep
io.output(“Test.bmp”)
函数基n(n,b)
n=楼层(n)
如果不是b或b==10,则返回字符串(n)结束
本地数字=“0123456789abcdefghijklmnopqrstuvxyz”
局部t={}
重复
本地数据=(n%b)+1
n=楼层(n/b)
插入(t,1,数字:sub(d,d))
直到n==0
返回代表(“0”,32-#t)…concat(t,”)
结束
FileSize=Basen(分辨率*ResolutionX*3+54,2)
FileSize4=tonumber(sub(FileSize,1,8)、2)或0
FileSize3=tonumber(sub(FileSize,9,16)、2)或0
FileSize2=tonumber(sub(FileSize,17,24)、2)或0
FileSize1=tonumber(sub(FileSize,25,32)、2)或0
宽度=基准(分辨率X,2)
打印(“宽度:”,宽度)
宽度4=色调(子(宽度1,8)、2)或0
宽度3=色调(子(宽度9,16)、2)或0
宽度2=色调(子(宽度,17,24),2)或0
宽度1=色调(子(宽度,25,32),2)或0
高度=基准(分辨率,2)
打印(“高度:”,高度)
高度4=t编号(sub(高度,1,8)、2)或0
高度3=t编号(sub(高度,9,16)、2)或0
高度2=t编号(sub(高度,17,24)、2)或0
高度1=t编号(sub(高度,25,32)、2)或0
BMPSize=Basen(分辨率*分辨率X*3,2)
BMPSize4=tonumber(sub(BMPSize,1,8)、2)或0
BMPSize3=tonumber(sub(BMPSize,9,16),2)或0
BMPSize2=tonumber(sub(BMPSize,17,24),2)或0
BMPSize1=tonumber(sub(BMPSize,25,32),2)或0
打印(“总大小:”,文件大小1,文件大小2,文件大小3,文件大小4,“\n宽度:”,宽度1,宽度2,宽度3,宽度4,“\n高度:”,高度1,高度2,高度3,高度4,“\n图像数据:”,BMPSize1,BMPSize2,BMPSize3,BMPSize4)
结果={“BM”。.char(--文件类型
FileSize1、FileSize2、FileSize3、FileSize4,--文件大小
0,0,0,0,--保留
54,0,0,0,--像素数据开始的位置
40,0,0,0,--DIB总管
宽度1,宽度2,宽度3,宽度4,--宽度
高度1,高度2,高度3,高度4,--高度
1,0,--彩色平面
24,00,--位深度
0,0,0,0,--压缩
BMPSize1、BMPSize2、BMPSize3、BMPSize4,--像素数据将消耗的字节数
宽度1,宽度2,宽度3,宽度4,
高度1,高度2,高度3,高度4,
0,0,0,0,--腭部的颜色数
0,0,0,0
)}
对于X=0,分辨率X-1 do
对于Y=0,分辨率为-1
插入(结果,重复(字符(255*((X+1)%2)*((Y+1)%2)),3))
结束
结束
io.write(表concat(结果))
欢迎使用堆栈交换:)
我建议看一下PPM
文件,它们很简单。可以使用其他工具将其转换为png或bmp
以下是PPM解决方案:
ResolutionX = 48
ResolutionY = 100
local cos, atan, sin, atan2, sqrt, floor = math.cos, math.atan, math.sin, math.atan2, math.sqrt, math.floor
local insert, concat = table.insert, table.concat
local sub, char, rep = string.sub, string.char, string.rep
local file = io.open("Test.ppm","w")
-- PPM File headers
local Output = { }
Output[1] = "P3"
Output[2] = tostring(ResolutionX) .. " " .. tostring(ResolutionY)
Output[3] = "255"
-- Image body
for Y = 0, ResolutionY - 1 do
for X = 0, ResolutionX - 1 do
local value = 255 * ((X + 1) % 2) * ((Y + 1) % 2)
Output[#Output+1] = rep(tostring(floor(value)),3," ")
end
end
-- Join lines together
local Result = table.concat(Output,"\n")
file:write(Result)
注意:我无法将您的代码写入文件(请参阅我对
文件的用法)。如果写入顺序是英文阅读顺序(从左到右向下向上),则内部循环必须是X(列),外部循环必须是Y(行)。好的,这是BMP版本。我把东西放在一个模块中,这样可能更容易使用
local writeBMP = {}
local floor = math.floor
local insert, concat = table.insert, table.concat
local sub, char, rep = string.sub, string.char, string.rep
local function Basen(n,b)
n = floor(n)
if not b or b == 10 then return tostring(n) end
local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
local t = {}
repeat
local d = (n % b) + 1
n = floor(n / b)
insert(t, 1, digits:sub(d,d))
until n == 0
return rep("0",32-#t)..concat(t,"")
end
local function nextMul4(x)
if ( x % 4 == 0 ) then
return x
else
return x+4-(x%4)
end
end
local function clamp(x)
local y = x
if ( x > 255 ) then
y = 255
elseif ( x < 0 ) then
y = 0
end
return floor(y)
end
-- Accepts array of type pixelsXYC[X][Y][C] of numbers 0-255
-- C=1,2,3 are the red, green and blue channels respectively
-- X increases left to right, and Y increases top to bottom
function writeBMP.data(pixelsXYC, resolutionX, resolutionY)
local Pixels = pixelsXYC
local ResolutionX = resolutionX
local ResolutionY = resolutionY
assert(#Pixels == ResolutionX, "Table size and X resolution mismatch")
assert(#Pixels[1] == ResolutionY, "Table size and Y resolution mismatch")
local FileSize = Basen(ResolutionY*nextMul4(3*ResolutionX) + 54,2)
local FileSize4 = tonumber(sub(FileSize,1,8),2) or 0
local FileSize3 = tonumber(sub(FileSize,9,16),2) or 0
local FileSize2 = tonumber(sub(FileSize,17,24),2) or 0
local FileSize1 = tonumber(sub(FileSize,25,32),2) or 0
local Width = Basen(ResolutionX,2)
local Width4 = tonumber(sub(Width,1,8),2) or 0
local Width3 = tonumber(sub(Width,9,16),2) or 0
local Width2 = tonumber(sub(Width,17,24),2) or 0
local Width1 = tonumber(sub(Width,25,32),2) or 0
local Height = Basen(ResolutionY,2)
local Height4 = tonumber(sub(Height,1,8),2) or 0
local Height3 = tonumber(sub(Height,9,16),2) or 0
local Height2 = tonumber(sub(Height,17,24),2) or 0
local Height1 = tonumber(sub(Height,25,32),2) or 0
local BMPSize = Basen(ResolutionY*nextMul4(3*ResolutionX),2)
local BMPSize4 = tonumber(sub(BMPSize,1,8),2) or 0
local BMPSize3 = tonumber(sub(BMPSize,9,16),2) or 0
local BMPSize2 = tonumber(sub(BMPSize,17,24),2) or 0
local BMPSize1 = tonumber(sub(BMPSize,25,32),2) or 0
local Result = {}
Result[1] = "BM" .. char( --File type
FileSize1,FileSize2,FileSize3,FileSize4,--File size
0,0, --Reserved
0,0, --Reserved
54,0,0,0, --Where the pixel data starts
40,0,0,0, --DIB header
Width1,Width2,Width3,Width4, --Width
Height1,Height2,Height3,Height4, --Height
1,0, --Color planes
24,0, --Bit depth
0,0,0,0, --Compression
BMPSize1,BMPSize2,BMPSize3,BMPSize4, --The amount of bytes pixel data will consume
37,22,0,0, --Pixels per meter horizontal
37,22,0,0, --Pixels per meter vertical
0,0,0,0, --Number of colors in palatte
0,0,0,0
)
local Y = ResolutionY
while( Y >= 1 ) do
for X = 1, ResolutionX do
local r = clamp( Pixels[X][Y][1] )
local g = clamp( Pixels[X][Y][2] )
local b = clamp( Pixels[X][Y][3] )
Result[#Result+1] = char(b)
Result[#Result+1] = char(g)
Result[#Result+1] = char(r)
end
-- byte alignment
if ( ( (3*ResolutionX) % 4 ) ~= 0 ) then
local Padding = 4 - ((3*ResolutionX) % 4)
Result[#Result+1] = rep(char(0),Padding)
end
Y = Y - 1
end
return table.concat(Result)
end
function writeBMP.write(pixelsXYC, resolutionX, resolutionY, filename)
local file = io.open(filename,"wb")
local data = writeBMP.data(pixelsXYC, resolutionX, resolutionY)
file:write(data)
end
return writeBMP
注意:在BMP中,Y轴从底部开始。在计算机图形学中,我更习惯于Y轴自上而下(所以我就是这样写的)
感谢HAX的代码。对于X=0,ResolutionX-1 do必须是内部循环。注意Y轴在BMP中从底部开始(可以反向计数),而不是英语阅读顺序。我想我应该更加注意循环,它现在可以工作了,谢谢@EgorSkriptunoff@HAX您也缺少字节对齐,每行上的字节数应为4的倍数。在这种情况下,如果宽度不是4的倍数,则可能会出现问题。我稍后会发布一个更完整的答案。@Real我已经解决了这个问题,在我让循环正常工作后,我只是简单地添加了Padding=0如果(ResolutionX*3)%4>0,然后Padding=4-(ResolutionX*3)%4在循环之前结束
,并添加了Output[#Output+1]=rep(char(0),Padding)
在X循环之后。浏览器似乎不支持ppm。虽然这有很大帮助,但bmp的传播范围更广,渲染图像并不是我想学习如何处理bmp文件的唯一原因,我可以像你说的那样使用其他程序将ppm转换为bmp/png,但是基于bmp的解决方案会有很大帮助,因为我主要是为了学习bmp文件。谢谢你的帮助:)
-- writeBMP example
local writeBMP = require "writeBMP"
local resolutionX = 100
local resolutionY = 100
-- Pixel data
local pixels = {}
for x=1,resolutionX do
pixels[x] = {}
for y=1, resolutionY do
pixels[x][y] = {}
local red = 255*(resolutionX-x+resolutionY-y)/(resolutionX+resolutionY)
local green = 255*y/resolutionY
local blue = 255*x/resolutionX
pixels[x][y][1] = red
pixels[x][y][2] = green
pixels[x][y][3] = blue
end
end
writeBMP.write(pixels,resolutionX,resolutionY,"testwritebmp.bmp")
return