-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbmp_to_bits.lua
executable file
·193 lines (160 loc) · 5.14 KB
/
bmp_to_bits.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#!/usr/bin/env lua-5.4
if #arg < 1 then
print("usage: " .. arg[0] .. " <file.bmp>")
os.exit(1)
end
function BitAND(a,b)--Bitwise and
local p,c=1,0
while a>0 and b>0 do
local ra,rb=a%2,b%2
if ra+rb>1 then c=c+p end
a,b,p=(a-ra)/2,(b-rb)/2,p*2
end
return c
end
-- Offset (hex) Offset (dec) Size (bytes) Windows BITMAPINFOHEADER[1]
-- 0A 10 4 location of the pixel data
-- 0E 14 4 the size of this header (40 bytes)
-- 12 18 4 the bitmap width in pixels (signed integer)
-- 16 22 4 the bitmap height in pixels (signed integer)
-- 1A 26 2 the number of color planes (must be 1)
-- 1C 28 2 the number of bits per pixel, which is the color depth of the image. Typical values are 1, 4, 8, 16, 24 and 32.
-- 1E 30 4 the compression method being used. See the next table for a list of possible values
-- 22 34 4 the image size. This is the size of the raw bitmap data; a dummy 0 can be given for BI_RGB bitmaps.
-- 26 38 4 the horizontal resolution of the image. (pixel per metre, signed integer)
-- 2A 42 4 the vertical resolution of the image. (pixel per metre, signed integer)
-- 2E 46 4 the number of colors in the color palette, or 0 to default to 2n
-- 32 50 4 the number of important colors used, or 0 when every color is important; generally ignored
-- See https://en.wikipedia.org/wiki/BMP_file_format#References for more info
-- Color table starts at 0x36 - 4 bpp = 16 colors * 4 bytes each
function read_bitmap(file)
local f = assert(io.open(file, "rb"))
local magic = string.format("%02X", string.unpack(">I2", f:read(2)))
if magic ~= "424D" then
print("magic: ", magic)
print(file .. ": is not a bitmap file.")
os.exit(1)
end
local pixeldata = {}
-- 0x0A contains the offset to the pixel data
f:seek("set", 0x0A)
offset = string.unpack("<I4", f:read(4))
f:seek("set", 0x12)
width = string.unpack("I4", f:read(4))
f:seek("set", 0x16)
height = string.unpack("I4", f:read(4))
f:seek("set", 0x1c)
bpp = string.unpack("I2", f:read(2))
f:seek("set", 0x1e)
compression = string.unpack("I4", f:read(4))
if compression ~= 0x0 then
print("compressed images are not supported.")
os.exit(1)
end
print("offset: " .. string.format("0x%02X", offset))
print("height: " .. height)
print("width: " .. width)
print("bpp: " .. bpp)
rowsize = math.floor(bpp/8 * width)
while rowsize % 4 ~= 0 do
rowsize = rowsize +1
--padding = padding +1
end
print("padded row size: " .. rowsize .. " bytes")
if bpp > 24 then
print(bpp .. " bpp images are not supported. Please convert to a lower color depth.")
os.exit(1)
end
print("pixel data bytes: " .. rowsize*height)
-- Seek to pixel data location
f:seek("set", offset)
-- read pixel data into a nested table
for i=1,height do
r = {}
if bpp == 4 then
for j = 1, rowsize, 1 do
p = string.byte(f:read(1));
HiNIBBLE = math.floor(p / 0x10); -- High bits contain the color data. Divide by 16 to produce an index number.
LoNIBBLE = BitAND(p, 0x0F); -- Low bits contain the pixel value. ASC AND &HF ASCII value AND 15
table.insert(r, HiNIBBLE)
table.insert(r, LoNIBBLE)
end
else
for j = 1, rowsize, 1 do
-- bpp/8 gives bytes per pixel
n = math.floor(bpp/8)
fmt = "I" .. n
pxl = string.unpack(fmt, f:read(n))
table.insert(r, pxl)
end
end
table.insert(pixeldata, r)
end
f:close()
return pixeldata
end
-- ANSI color codes
-- foreground
-- black = 30,
-- red = 31,
-- green = 32,
-- yellow = 33,
-- blue = 34,
-- magenta = 35,
-- cyan = 36,
-- white = 37,
-- background
-- onblack = 40,
-- onred = 41,
-- ongreen = 42,
-- onyellow = 43,
-- onblue = 44,
-- onmagenta = 45,
-- oncyan = 46,
-- onwhite = 47,
colors = {
[0] = 30,
[1] = 31,
[2] = 32,
[3] = 33,
[4] = 30,
[5] = 35,
[6] = 36,
[7] = 37,
[8] = 30,
[9] = 32,
[0x0A] = 31,
[0x0B] = 37,
[0x0C] = 32,
[0x0D] = 32,
[0x0E] = 32,
[0x0F] = 32,
[0x10] = 35,
[0x77] = 33,
[0xFC] = 34,
[0xF9] = 31,
[0xFF] = 30,
}
img = read_bitmap(arg[1])
io.write("Uint16 pixels[" .. height .. "*" .. width .. "] = {\n")
-- Read pixel data from the table and print out the hex values
-- Image data is read from the "bottom" up
for i = #img, 1, -1 do
io.write("\t");
rowdata = img[i]
for n, v in ipairs(rowdata) do
-- Lua 5.1 doesn't support bit shifts. Dividing by 2^shift equals the same result.
-- This produces an index number of 1 - 16 for color codes
if bpp == 4 then
q = v
else
q = math.floor(v / (2^(bpp-4)))
--q = v
--io.write("v: ", v, " ")
--io.write("q: ", q, " ")
end
io.write('\27[' .. colors[q] .. 'm' .. string.format("%02X", v) .. '\27[0m')
end
io.write("\n");
end
io.write("};\n");