You need to enable JavaScript to run this app. Lua生成BMP用于曼德博集合渲染时非1:1宽高比伪影问题
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.27 00:15:03