This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
bobster71's profile picture

Load Bitmap image

Started by bobster71, 05 December 2012 - 03:20 PM
bobster71 #1
Posted 05 December 2012 - 04:20 PM
Hi

I've been trying to find a way of loading a bitmap file or any image file and reading the rgb for each x,y. I'm not famuliar with the file structure and am getting stuck. Could anyone write me a small routine to load a bitmap please.

thanks
Bobster

ps - if I can get this working, I can show you something cool. Otheriwise it wont be as cool, but check computercraft on minecraft forum for pic and vid later.

This is my code I've been trying to use.
Spoilerfunction error(err)

println(err);
end

– Helper function: Parse a 16-bit WORD from the binary string
function ReadWORD(str, offset)
local loByte = str:byte(offset);
local hiByte = str:byte(offset+1);
return hiByte*256 + loByte;
end

– Helper function: Parse a 32-bit DWORD from the binary string
function ReadDWORD(str, offset)
local loWord = ReadWORD(str, offset);
local hiWord = ReadWORD(str, offset+2);
return hiWord*65536 + loWord;
end

– Process a bitmap file in a string, and call DrawPoint for each pixel
function DrawBitmap(bytecode)
————————-
– Parse BITMAPFILEHEADER
————————-
local offset = 1;
local bfType = ReadWORD(bytecode, offset);
if(bfType ~= 0x4D42) then
error("Not a bitmap file (Invalid BMP magic value)");
return;
end
local bfOffBits = ReadWORD(bytecode, offset+10);

————————-
– Parse BITMAPINFOHEADER
————————-
offset = 15; – BITMAPFILEHEADER is 14 bytes long
local biWidth = ReadDWORD(bytecode, offset+4);
local biHeight = ReadDWORD(bytecode, offset+8);
local biBitCount = ReadWORD(bytecode, offset+14);
local biCompression = ReadDWORD(bytecode, offset+16);
if(biBitCount ~= 24) then
error("Only 24-bit bitmaps supported (Is " .. biBitCount .. "bpp)");
return;
end
if(biCompression ~= 0) then
error("Only uncompressed bitmaps supported (Compression type is " .. biCompression .. ")");
return;
end

———————
– Parse bitmap image
———————
for y = biHeight-1, 0, -1 do
offset = bfOffBits + (biWidth*biBitCount/8)*y + 1;
for x = 0, biWidth-1 do
local b = bytecode:byte(offset);
local g = bytecode:byte(offset+1);
local r = bytecode:byte(offset+2);
offset = offset + 3;

print(x, biHeight-y-1, r, g, B)/>; – to see result only
end
end
end


function testBmp(args)
local f = assert(io.open(args, "rb"));
local bmp = f:read("*a");
f:close();

DrawBitmap(bmp);
end
Lyqyd #2
Posted 05 December 2012 - 04:38 PM
I believe this is what you're looking for.
faubiguy #3
Posted 05 December 2012 - 04:47 PM
A while ago I was creating a program for exporting a color tags image to a BMP file, but it wasn't working so I gave up on it after a few hours. I don't know if any of the code would be useful for you, but if you want you can use any of it.

Spoiler
local args = {...}
if #args ~= 2 then
print("Usage: ExportBMP <filepath-to-export> <new-filepath>")
return
end
local filepath = args[1]
local newpath = args[2]

if not fs.exists(filepath) then
print("Error: File not found")
return
end

if fs.isDir(filepath) then
print(filepath, " is a directory")
return
end

if fs.exists(newpath) then
print(newpath, " already exists")
return
end

print("Exporting to BMP...")

local lines = {}

local file = fs.open(filepath, "r")
while true do
local line = file.readLine()
if not line then break end
table.insert(lines, line)
end
file.close()

pixels = {}
for _=1,#lines do table.insert(pixels, {}) end

for i=1,#lines do
pixels[i] = {}
for hex in string.gmatch(lines[i], "&amp;([0-9a-f])") do
  table.insert(pixels[i], tonumber(hex, 16))
end
end

local height = #pixels
local width = #pixels[1]

if width == 0 or height == 0 then
print("Corrupt file")
return
end

for i=2,#pixels do
if #pixels[i] ~= width then
  print("Corrupt file")
  return
end
end

local colorList = { -- RGB values of pixel colors:
240, 240, 240, -- White
235, 136, 68, -- Orange
195, 84, 205, -- Magenta
102, 137, 211, -- Light Blue
222, 207, 42, -- Yellow
65, 205, 52, -- Lime
216, 128, 152, -- Pink
67, 67, 67, -- Gray
153, 153, 153, -- Light Gray
40, 118, 151, -- Cyan
123, 47, 190, -- Purple
37, 49, 146, -- Blue
81, 48, 26, -- Brown
59, 81, 26, -- Green
179, 49, 44, -- Red
0, 0, 0 -- Black
}

bytes = {66, 77} -- BM is file code for Bitmap

bytes[11] = 75 -- Pixel data offset = 14 byte file header + 12 byte DIB header + 48 byte color table

bytes[15] = 12 -- Size of BITMAPCOREHEADER

tempWidth = width
for i=18,19 do -- Set width in header to image width
bytes[i] = tempWidth%256
tempWidth = (tempWidth-bytes[i])/256
end

local tempHeight = height
for i=20,21 do
bytes[i] = tempHeight%256
tempHeight = (tempHeight-bytes[i])/256
end

bytes[22] = 1 -- 1 color plane

bytes[24] = 4 -- 4 colors per pixel

for i=1, 48 do -- Create color table
bytes[i+26] = colorList[i]
end

local offset = 75
local first = true
local byte = 0
for row=height,1,-1 do
for column=1,width do
  if first then
   byte = pixels[row][column]*16
   first = false
  else
   byte = byte + pixels[row][column]
   bytes[offset] = byte
   offset = offset + 1
   first = true
   byte = 0
  end
end
end

if byte ~= 0 then bytes[offset] = byte offset=offset+1 end

while (#bytes-74)%4~=0 do
bytes[offset] = 0
offset = offset+1
end

maxIndex = 0 -- Getting number of bytes
for index in pairs(bytes) do
maxIndex = index > maxIndex and index or maxIndex
end

for i=1,maxIndex do -- Filling in blanks
bytes[i] = bytes[i] or 0
end

local size = maxIndex -- Filling in size in header
for i=3,6 do
bytes[i] = size%256
size = (size-bytes[i])/256
end

local file = fs.open(newpath, "wb")
if not file then
print("Error: failed to open ",newpath)
return
end
for _,byte in pairs(bytes) do
file.write(byte)
end
file.close()
print("Succesfully exported to BMP!")
bobster71 #4
Posted 05 December 2012 - 04:48 PM
I believe this is what you're looking for.

yeah I found that too, but I'm not that good a programmer. I have worked out some,but not all. Added my code to my post too.
I have saved bmp useing paint and photoshop they all come up with NOT A BMP file.
I'm doing something wrong but not sure what.
kazagistar #5
Posted 05 December 2012 - 04:48 PM
Could anyone write me a small routine to load a bitmap please.
No. I am pretty sure no one could, because loading a bitmap is an non-trivial process. So you could make a long and complicated routine to do it, in theory.
bobster71 #6
Posted 05 December 2012 - 04:50 PM
A while ago I was creating a program for exporting a color tags image to a BMP file, but it wasn't working so I gave up on it after a few hours. I don't know if any of the code would be useful for you, but if you want you can use any of it.

Spoiler
local args = {...}
if #args ~= 2 then
print("Usage: ExportBMP <filepath-to-export> <new-filepath>")
return
end
local filepath = args[1]
local newpath = args[2]

if not fs.exists(filepath) then
print("Error: File not found")
return
end

if fs.isDir(filepath) then
print(filepath, " is a directory")
return
end

if fs.exists(newpath) then
print(newpath, " already exists")
return
end

print("Exporting to BMP...")

local lines = {}

local file = fs.open(filepath, "r")
while true do
local line = file.readLine()
if not line then break end
table.insert(lines, line)
end
file.close()

pixels = {}
for _=1,#lines do table.insert(pixels, {}) end

for i=1,#lines do
pixels[i] = {}
for hex in string.gmatch(lines[i], "&amp;([0-9a-f])") do
  table.insert(pixels[i], tonumber(hex, 16))
end
end

local height = #pixels
local width = #pixels[1]

if width == 0 or height == 0 then
print("Corrupt file")
return
end

for i=2,#pixels do
if #pixels[i] ~= width then
  print("Corrupt file")
  return
end
end

local colorList = { -- RGB values of pixel colors:
240, 240, 240, -- White
235, 136, 68, -- Orange
195, 84, 205, -- Magenta
102, 137, 211, -- Light Blue
222, 207, 42, -- Yellow
65, 205, 52, -- Lime
216, 128, 152, -- Pink
67, 67, 67, -- Gray
153, 153, 153, -- Light Gray
40, 118, 151, -- Cyan
123, 47, 190, -- Purple
37, 49, 146, -- Blue
81, 48, 26, -- Brown
59, 81, 26, -- Green
179, 49, 44, -- Red
0, 0, 0 -- Black
}

bytes = {66, 77} -- BM is file code for Bitmap

bytes[11] = 75 -- Pixel data offset = 14 byte file header + 12 byte DIB header + 48 byte color table

bytes[15] = 12 -- Size of BITMAPCOREHEADER

tempWidth = width
for i=18,19 do -- Set width in header to image width
bytes[i] = tempWidth%256
tempWidth = (tempWidth-bytes[i])/256
end

local tempHeight = height
for i=20,21 do
bytes[i] = tempHeight%256
tempHeight = (tempHeight-bytes[i])/256
end

bytes[22] = 1 -- 1 color plane

bytes[24] = 4 -- 4 colors per pixel

for i=1, 48 do -- Create color table
bytes[i+26] = colorList[i]
end

local offset = 75
local first = true
local byte = 0
for row=height,1,-1 do
for column=1,width do
  if first then
   byte = pixels[row][column]*16
   first = false
  else
   byte = byte + pixels[row][column]
   bytes[offset] = byte
   offset = offset + 1
   first = true
   byte = 0
  end
end
end

if byte ~= 0 then bytes[offset] = byte offset=offset+1 end

while (#bytes-74)%4~=0 do
bytes[offset] = 0
offset = offset+1
end

maxIndex = 0 -- Getting number of bytes
for index in pairs(bytes) do
maxIndex = index > maxIndex and index or maxIndex
end

for i=1,maxIndex do -- Filling in blanks
bytes[i] = bytes[i] or 0
end

local size = maxIndex -- Filling in size in header
for i=3,6 do
bytes[i] = size%256
size = (size-bytes[i])/256
end

local file = fs.open(newpath, "wb")
if not file then
print("Error: failed to open ",newpath)
return
end
for _,byte in pairs(bytes) do
file.write(byte)
end
file.close()
print("Succesfully exported to BMP!")

Thanks it might be what I need.

UPDATE: I tried it, I can't get it to work either. Its a clever idea, I had the same idea but never got around to doing anything about it.
faubiguy #7
Posted 06 December 2012 - 03:19 AM
Even if I did get it to work, and reversed it so it read instead of wrote, it would only work for reading one type of BMP. When I coded it I didn't intend to release it. It might be easier just to write something up without using that code.
bobster71 #8
Posted 06 December 2012 - 09:59 AM
Hey

I didn't end up getting it to load a bitmap or any pic, but I'll work on it. Maybe gif or another format might be simpler, I'll look into it and let you lot know. Anyway here's a vid of what's I've done so far. It doesn't show any pics only a red gradient but you get the idea of what I"m trying to do.

[media]http://www.youtube.com/watch?v=e6nfSW4xmtk[/media]

What do you think? I tried doing a laser display when CC first came out, but this is full rgb.
I've also seen a better laser display, with 16 (I think) colors but they had the same prob I did, the lasers were buggy.