Every Bitmap file MUST BE:
* 24-Bit
* Uncompressed
Code:
Spoiler
local localFunctions = {}
localFunctions.colorRGB = {
{r = 240, g = 240, b = 240, code = colors.white},
{r = 235, g = 236, b = 68, code = colors.orange},
{r = 195, g = 84, b = 205, code = colors.magenta},
{r = 102, g = 137, b = 211, code = colors.lightBlue},
{r = 222, g = 222, b = 108, code = colors.yellow},
{r = 65, g = 205, b = 52, code = colors.lime},
{r = 216, g = 129, b = 152, code = colors.pink},
{r = 67, g = 67, b = 67, code = colors.gray},
{r = 153, g = 153, b = 153, code = colors.lightGray},
{r = 40, g = 118, b = 151, code = colors.cyan},
{r = 123, g = 47, b = 190, code = colors.purple},
{r = 37, g = 49, b = 146, code = colors.blue},
{r = 81, g = 48, b = 26, code = colors.brown},
{r = 59, g = 81, b = 26, code = colors.green},
{r = 179, g = 49, b = 44, code = colors.red},
{r = 0, g = 0, b = 0, code = colors.black}
}
localFunctions.PaintPx = {
{code = colors.white,pCode = "0"},
{code = colors.orange,pCode = "1"},
{code = colors.magenta,pCode = "2"},
{code = colors.lightBlue,pCode = "3"},
{code = colors.yellow,pCode = "4"},
{code = colors.lime,pCode = "5"},
{code = colors.pink,pCode = "6"},
{code = colors.gray,pCode = "7"},
{code = colors.lightGray,pCode = "8"},
{code = colors.cyan,pCode = "9"},
{code = colors.purple,pCode = "a"},
{code = colors.blue,pCode = "b"},
{code = colors.brown,pCode = "c"},
{code = colors.green,pCode = "d"},
{code = colors.red,pCode = "e"},
{code = colors.black,pCode = "f"}
}
function localFunctions:readBMP(file)
local f = assert(fs.open(file, "rb"))
local bytecode = ""
local byte = f:read()
while byte ~= nil do
bytecode = bytecode .. string.char(byte)
byte = f:read()
end
f:close()
return bytecode
end
function localFunctions:readWORD(str, offset)
local loByte = str:byte(offset)
local hiByte = str:byte(offset + 1)
return hiByte * 256 + loByte
end
function localFunctions:readDWORD(str, offset)
local loWord = localFunctions:readWORD(str, offset)
local hiWord = localFunctions:readWORD(str, offset + 2)
return hiWord * 65536 + loWord
end
function localFunctions:toWORD(num)
local loByte = 0
local hiByte = 0
if num / 256 < 1 then
loByte = num
else
hiByte = math.modf(num/256)
loByte = num - hiByte * 256
end
return string.char(loByte)..string.char(hiByte)
end
function localFunctions:toDWORD(num)
local loByte = 0
local hiByte = 0
local loByte2 = 0
local hiByte2 = 0
local r = 0
local r2 = 0
if num / 16777216 >= 1 then --4 bytes
hiByte2 = math.modf(num/16777216)
r2 = num - hiByte2 * 16777216
loByte2 = math.modf(r2/65536)
r = r2 - loByte2 * 65536
hiByte = math.modf(r/256)
loByte = r - hiByte * 256
elseif num / 65536 >= 1 then --3 bytes
loByte2 = math.modf(num/65536)
r = num - loByte2 * 65536
hiByte = math.modf(r/256)
loByte = r - hiByte * 256
elseif num / 256 >= 1 then --2 bytes
hiByte = math.modf(num/256)
loByte = num - hiByte * 256
else
loByte = num
end
return string.char(loByte)..string.char(hiByte)..string.char(loByte2)..string.char(hiByte2)
end
function localFunctions:get4BitColor(r, g, B)/>/>/>/>/>
for k, v in ipairs(localFunctions.colorRGB) do
--print(tostring(v.r).." "..tostring(v.g).." "..tostring(v.B)/>/>/>/>/>.." "..tostring(v.code)
local lookVel = 10
if r > v.r - lookVel and r < v.r + lookVel and g > v.g - lookVel and g < v.g + lookVel and b > v.b - lookVel and b < v.b + lookVel then
return v.code
end
end
return colors.white
end
function localFunctions:getRGB(color)
for k, v in ipairs(localFunctions.colorRGB) do
if v.code == color then
return v.r,v.g,v.b
end
end
return 221,221,221
end
function localFunctions:isBMP(binary)
if localFunctions:readWORD(binary, 1) ~= 0x4D42 then
return "Not a readable BMP File: Invalid Header"
elseif localFunctions:readWORD(binary, 29) ~= 24 then
return "Not a readable BMP File: 24-bit BMP ONLY"
elseif localFunctions:readWORD(binary, 31) ~= 0 then
return "Not a readable BMP File: File must be uncompressed"
else
return -1
end
end
function localFunctions:readHeader(binary)
properities = {}
res = localFunctions:isBMP(binary)
if res ~= -1 then
error(res,3)
end
properities.bytesize = localFunctions:readDWORD(binary, 3)
properities.width = localFunctions:readDWORD(binary, 19)
properities.height = localFunctions:readDWORD(binary, 23)
properities.bitCount = localFunctions:readDWORD(binary, 29)
return properities
end
function localFunctions:readBodyToTable(binary)
local offBits = localFunctions:readWORD(binary, 11)
local prop = localFunctions:readHeader(binary)
pixelTable = {}
rem = math.modf((prop.width)/4)
repToDWORD = (prop.width)-rem*4
for y = prop.height - 1, 0, -1 do
offset = offBits +(repToDWORD*y) + (prop.width * prop.bitCount / 8) * y + 1
for x = 1, prop.width do
if type(pixelTable[x]) ~= "table" then
pixelTable[x] = {}
end
local b = binary:byte(offset)
local g = binary:byte(offset + 1)
local r = binary:byte(offset + 2)
offset = offset + 3
--deb(offset.." "..b.." "..g.." "..r)
cl = localFunctions:get4BitColor(r,g,B)/>/>/>/>/>
pixelTable[x][prop.height - y] = cl
end
end
return pixelTable
end
function localFunctions:emptyBMP(width,height)
local px = {}
for y = 1,height do
for x = 1,width do
if type(px[x]) ~= "table" then
px[x] = {}
end
px[x][y] = colors.white
end
end
return px
end
function localFunctions:toPaintPixel(px)
for i,v in ipairs(localFunctions.PaintPx) do
if v.code == px then
return v.pCode
end
end
return "0"
end
function localFunctions:toColorPixel(ppx)
for i,v in ipairs(localFunctions.PaintPx) do
if v.pCode == ppx then
return v.code
end
end
return colors.white
end
function localFunctions:generateBMPString(obj)
--File Header
local magicNum = localFunctions:toWORD(0x4D42)
local size = "" --unknown yet
local reserverd = localFunctions:toDWORD(0)
local OffBits = localFunctions:toDWORD(54)
--File Settings
local headerSize = localFunctions:toDWORD(40)
local width = localFunctions:toDWORD(obj.width)
local height = localFunctions:toDWORD(obj.height)
local planes = localFunctions:toWORD(1)
local bitCount = localFunctions:toWORD(24)
local compression = localFunctions:toDWORD(0)
local sizeImg = "" --unknown yet
local PelsPerMX = localFunctions:toDWORD(0)
local PelsPerMY = localFunctions:toDWORD(0)
local ClrUsed = localFunctions:toDWORD(0)
local ClrUsedImp = localFunctions:toDWORD(0)
--File Body
local rgbStr = ""
local rem = 0
local repToDWORD = 0
local remStr = ""
for y = obj.height, 1, -1 do
for x = 1, obj.width do
local r,g,b = localFunctions:getRGB(obj.pixels[x][y])
rgbStr = rgbStr..string.char(B)/>/>/>/>/>..string.char(g)..string.char(r)
end
rem = math.modf((obj.width)/4)
repToDWORD = (obj.width)-rem*4
if repToDWORD ~= 0 then
for i = 1,repToDWORD do
rgbStr = rgbStr..string.char(0)
end
end
end
sizeImg = localFunctions:toDWORD(#rgbStr)
size = localFunctions:toDWORD(#rgbStr + 54)
local fHeader = magicNum..size..reserverd..OffBits
local fSettings = headerSize..width..height..planes..bitCount..compression..sizeImg..PelsPerMX..PelsPerMY..ClrUsed..ClrUsedImp
return fHeader..fSettings..rgbStr
end
BMP = {}
BMP.__index = BMP
function BMP:new(width, height)
local bmpObj = {}
setmetatable(bmpObj, BMP)
bmpObj.width = width
bmpObj.height = height
bmpObj.pixels = localFunctions:emptyBMP(width, height)
return bmpObj
end
function BMP:fromFile(filename)
local f = localFunctions:readBMP(filename)
local prop = localFunctions:readHeader(f)
local subObj = BMP:new(prop.width,prop.height)
subObj.pixels = localFunctions:readBodyToTable(f)
return subObj
end
function BMP:fromURL(URL)
if http then
local hStream = http.get(URL)
local tmpF = fs.open("_tmp_","w")
tmpF.write(hStream.readAll())
hStream.close()
tmpF.close()
local httpBMP = BMP:fromFile("_tmp_")
fs.delete("_tmp_")
return httpBMP
else
error("HTTP api not active!",2)
end
end
function BMP:fromPaintFile(filename)
local pF = fs.open(filename, "r")
local rl = pF:readLine()
local height = 0
local width = 0
local pixels = {}
while(rl ~= nil)do
height = height + 1
if width == 0 then
width = #rl
end
for sPos = 1,width do
ssPos = string.sub(rl,sPos,sPos)
if type(pixels[sPos]) ~= "table" then
pixels[sPos] = {}
end
pixels[sPos][height] = localFunctions:toColorPixel(ssPos)
end
rl = pF:readLine()
end
local subObj = BMP:new(width, height)
subObj.pixels = pixels
pF:close()
return subObj
end
function BMP:toPaintFile(filename)
local pF = fs.open(filename, "w")
for y = 1, self.height do
for x = 1, self.width do
pF.write(localFunctions:toPaintPixel(self.pixels[x][y]))
end
pF.write("\n")
end
pF:close()
end
function BMP:toFile(filename)
local strHeader = localFunctions:generateBMPString(self)
local hFile = fs.open(filename,"wb")
for i = 1,#strHeader+1 do
hFile.write(strHeader:byte(i))
end
hFile:close()
end
function BMP:setPixel(x,y,color)
self.pixels[x][y] = color
end
function BMP:getPixel(x,y)
return self.pixels[x][y]
end
Documentry:
Spoiler
First you need to load the api! I suggest to use "BMPDll", what I used, but you can use every name you want ;)/>So in my case: os.loadAPI("BMPDll")
h = BMPDll.BMP:new(width, height)
Creates a new Bitmap-Api-Object .
h = BMPDll.BMP:fromFile(filename)
Creates a new Bitmap-Api-Object from an exsisting Bitmap-File.
h = BMPDll.BMP:fromURL(URL)
Creates a new Bitmap-Api-Object from an Bitmap-File located on a webserver.
h = BMPDll.BMP:fromPaintFile(filename)
Creates a new Bitmap-Api-Object from an exsisting Computercraft-Paint-File.
h:toFile(filename)
Saves the Bitmap-Api-Object to a Bitmap-File.
h:toPaintFile(filename)
Saves the Bitmap-Api-Object to a Computercraft-Paint-File.
h:setPixel(x,y,color)
Set the pixel x,y to a Computercraft-Color (e.g. colors.green).
h:getPixel(x,y)
Get the color of a pixel x,y.
Simple Example:
Spoiler
h = BMPDll.BMP:new(10,10)
for i=1,10 do
h:setPixel(i,i,colors.red)
end
h:toFile("sample.bmp")
pastebin get 2DavwMVN BMPDll
I hope you enjoy this API guys! I am happy with every feedback I get!
EDIT: Dammit…. wanted to post it in APIs and Utilities