-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtobmp.py
142 lines (127 loc) · 4.51 KB
/
tobmp.py
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
#Some key imports.
#Struct is used to create the actual bytes.
#It is super handy for this type of thing.
import struct, random, sys, getopt
class Usage(Exception):
def __init__(self, msg):
self.msg = msg
#Function to write a bmp file. It takes a dictionary (d) of
#header values and the pixel data (bytes) and writes them
#to a file. This function is called at the bottom of the code.
def bmp_write(d,the_bytes):
mn1 = struct.pack('<B',d['mn1'])
mn2 = struct.pack('<B',d['mn2'])
filesize = struct.pack('<L',d['filesize'])
undef1 = struct.pack('<H',d['undef1'])
undef2 = struct.pack('<H',d['undef2'])
offset = struct.pack('<L',d['offset'])
headerlength = struct.pack('<L',d['headerlength'])
width = struct.pack('<L',d['width'])
height = struct.pack('<L',d['height'])
colorplanes = struct.pack('<H',d['colorplanes'])
colordepth = struct.pack('<H',d['colordepth'])
compression = struct.pack('<L',d['compression'])
imagesize = struct.pack('<L',d['imagesize'])
res_hor = struct.pack('<L',d['res_hor'])
res_vert = struct.pack('<L',d['res_vert'])
palette = struct.pack('<L',d['palette'])
importantcolors = struct.pack('<L',d['importantcolors'])
#create the outfile
outfile = open(d['filename'],'wb')
#write the header + the_bytes
outfile.write(mn1+mn2+filesize+undef1+undef2+offset+headerlength+width+height+\
colorplanes+colordepth+compression+imagesize+res_hor+res_vert+\
palette+importantcolors+the_bytes)
outfile.close()
###################################
def main(argv=None):
if argv is None:
argv = sys.argv
try:
try:
opts, args = getopt.getopt(argv[1:], "h", ["help"])
except getopt.GetoptError, msg:
raise Usage(msg)
for o, a in opts:
if o in ["-h", "--help"]:
print(" Usage: %s [OPTIONS] LX LY FILE_NAME_IN BMP_FILE_OUT" % argv[0])
print(" Options:")
print(" -h, --help\t\t: This help message")
print
return 2
else:
print(" %s: ignoring unhandled option" % o)
if len(args) != 4:
raise Usage(" Usage: %s [OPTIONS] LX LY FILE_NAME_IN BMP_FILE_OUT" % argv[0])
except Usage, err:
print(err.msg)
print(" for help use --help")
return 2
Lx = int(args[0])
Ly = int(args[1])
datfile = args[2]
bmpfile = args[3]
#Here is a minimal dictionary with header values.
#Of importance is the offset, headerlength, width,
#height and colordepth.
#Edit the width and height to your liking.
#These header values are described in the bmp format spec.
#You can find it on the internet. This is for a Windows
#Version 3 DIB header.
d = {
'mn1':66,
'mn2':77,
'filesize':0,
'undef1':0,
'undef2':0,
'offset':54,
'headerlength':40,
'width':Lx,
'height':Ly,
'colorplanes':1,
'colordepth':24,
'compression':0,
'imagesize':0,
'res_hor':0,
'res_vert':0,
'palette':0,
'importantcolors':0,
'filename': bmpfile,
}
fp = open(datfile, "rb")
buf = fp.read()
fmt = "".join(["f"]*Lx*Ly)
buf = struct.unpack(fmt, buf)
#Build the byte array. This code takes the height
#and width values from the dictionary above and
#generates the pixels row by row. The row_mod and padding
#stuff is necessary to ensure that the byte count for each
#row is divisible by 4. This is part of the specification.
the_bytes = ''
max_val = max(buf)
width = d['width']
colordepth = d['colordepth']
for row in range(d['height']-1,-1,-1):# (BMPs are L to R from the bottom L row)
row_buf = []
for column in range(d['width']):
b = 0
g = 0
r = int(255*buf[column + row*width]/max_val)
row_buf += [b,g,r]
the_bytes += struct.pack('<' + ''.join(['BBB']*width), *row_buf)
row_mod = (width*colordepth/8) % 4
if row_mod == 0:
padding = 0
else:
padding = (4 - row_mod)
padbytes = ''
for i in range(padding):
x = struct.pack('<B',0)
padbytes = padbytes + x
the_bytes = the_bytes + padbytes
#call the bmp_write function with the
#dictionary of header values and the
#bytes created above.
bmp_write(d,the_bytes)
if __name__ == '__main__':
main()