Lua bmp纵横比问题

Lua bmp纵横比问题,lua,bmp,Lua,Bmp,我一直在尝试了解bmp文件是如何工作的,这样我就可以渲染一些Mandelbrot set图片并将它们作为bmp文件输出,因为这似乎是最简单的方法之一,但出于某种原因,当我使用的纵横比不是1:1时,即使它的倍数是4(因此不需要填充)我得到了像这样奇怪的伪影,我正试图把一个像素阵列,偶数为白色,奇数为黑色,变成一个bmp,这就是长宽比为1:1时的样子。 我试着通读维基百科的文章,看看我是否能找出我做错了什么,但我仍然不明白我遗漏了什么 这是迄今为止我用Lua编写的脚本: ResolutionX=10

我一直在尝试了解bmp文件是如何工作的,这样我就可以渲染一些Mandelbrot set图片并将它们作为bmp文件输出,因为这似乎是最简单的方法之一,但出于某种原因,当我使用的纵横比不是1:1时,即使它的倍数是4(因此不需要填充)我得到了像这样奇怪的伪影,我正试图把一个像素阵列,偶数为白色,奇数为黑色,变成一个bmp,这就是长宽比为1:1时的样子。 我试着通读维基百科的文章,看看我是否能找出我做错了什么,但我仍然不明白我遗漏了什么

这是迄今为止我用Lua编写的脚本:

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