Lua生成BMP用于曼德博集合渲染时非1:1宽高比伪影问题
BMP生成伪影问题修正方案
错误点定位
- 像素存储顺序颠倒:24位BMP像素数据按行连续存储,即第0行所有列像素存完后再存下一行。当前代码外层循环遍历列X、内层遍历行Y,实际按列存储像素。1:1分辨率下棋盘格图案对称,颠倒后无视觉差异;非1:1分辨率下像素排列完全错乱,直接产生伪影。
- 行填充规则理解错误:24位BMP仅要求单行星节数为4的整数倍,和宽高是否为4的幂无关。行字节数计算公式为
(宽度 * 3 + 3) // 4 * 4,如果宽度*3不是4的倍数,每行末尾需要补对应数量的0字节。当前测试用例宽度乘3后刚好是4的倍数,暂未触发填充错位,后续更换宽度后必然出现问题。 - 通道顺序不符合规范(暂未触发):24位BMP像素通道顺序为BGR(蓝、绿、红),而非RGB。当前测试用黑白像素,通道顺序不影响效果,生成彩色图像时会出现颜色错误。
修正后代码
ResolutionX = 200 ResolutionY = 100 local floor = math.floor local insert, concat = table.insert, table.concat local sub, char, rep = string.sub, string.char, string.rep io.output("Test.bmp") 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 rowBytes = (ResolutionX * 3 + 3) // 4 * 4 local pixelDataSize = rowBytes * ResolutionY FileSize = Basen(pixelDataSize + 54, 2) FileSize4 = tonumber(sub(FileSize, 1, 8), 2) or 0 FileSize3 = tonumber(sub(FileSize, 9, 16), 2) or 0 FileSize2 = tonumber(sub(FileSize, 17, 24), 2) or 0 FileSize1 = tonumber(sub(FileSize, 25, 32), 2) or 0 Width = Basen(ResolutionX, 2) Width4 = tonumber(sub(Width, 1, 8), 2) or 0 Width3 = tonumber(sub(Width, 9, 16), 2) or 0 Width2 = tonumber(sub(Width, 17, 24), 2) or 0 Width1 = tonumber(sub(Width, 25, 32), 2) or 0 Height = Basen(ResolutionY, 2) Height4 = tonumber(sub(Height, 1, 8), 2) or 0 Height3 = tonumber(sub(Height, 9, 16), 2) or 0 Height2 = tonumber(sub(Height, 17, 24), 2) or 0 Height1 = tonumber(sub(Height, 25, 32), 2) or 0 BMPSize = Basen(pixelDataSize, 2) BMPSize4 = tonumber(sub(BMPSize, 1, 8), 2) or 0 BMPSize3 = tonumber(sub(BMPSize, 9, 16), 2) or 0 BMPSize2 = tonumber(sub(BMPSize, 17, 24), 2) or 0 BMPSize1 = tonumber(sub(BMPSize, 25, 32), 2) or 0 Result = {"BM" .. char( FileSize1, FileSize2, FileSize3, FileSize4, 0, 0, 0, 0, 54, 0, 0, 0, 40, 0, 0, 0, Width1, Width2, Width3, Width4, Height1, Height2, Height3, Height4, 1, 0, 24, 0, 0, 0, 0, 0, BMPSize1, BMPSize2, BMPSize3, BMPSize4, Width1, Width2, Width3, Width4, Height1, Height2, Height3, Height4, 0, 0, 0, 0, 0, 0, 0, 0 )} -- 循环顺序修正:外层遍历行Y,内层遍历列X for Y = 0, ResolutionY - 1 do for X = 0, ResolutionX - 1 do local brightness = 255 * ((X + 1) % 2) * ((Y + 1) % 2) insert(Result, rep(char(brightness), 3)) end -- 补充行填充空字节 insert(Result, rep(char(0), rowBytes - ResolutionX * 3)) end io.write(table.concat(Result))
内容的提问来源于stack exchange,提问作者HAX
相关产品推荐
相关产品推荐

