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
|
#!/usr/bin/python
"""Convert ppm-format files to XO-1 native 565 format."""
from __future__ import division, with_statement
import sys
def eat_comment(inf): # just read #, read until next EOL
while True:
c = inf.read(1)
if c == '\n' or c == '\r': break # read to EOL
return c
def read_token(inf):
# eat up leading whitespace
while True:
c = inf.read(1)
if c == '#': eat_comment(inf)
elif not c.isspace(): break
# now read in non-whitespace.
s = c
while True:
c = inf.read(1)
if c == '#': c = eat_comment(inf)
if c.isspace(): break
s += c
# done!
return s
def main(inf, outf, compress=False):
import struct
# read ppm from input
magic = inf.read(2)
assert magic == 'P6'
width = int(read_token(inf))
height = int(read_token(inf))
maxval = int(read_token(inf))
unpackstr = '!3B' if maxval < 256 else '!3H'
unpacklen = struct.calcsize(unpackstr)
# write header
outf.write(struct.pack('@III', width, height, 1 if compress else 0))
if compress:
from zlib import compressobj
off0 = outf.tell()
# we'll come back and fill in the next field later w/ the right size.
outf.write(struct.pack('@I', 0))
off1 = outf.tell()
comp = compressobj(9)
encode_me = lambda bytes: comp.compress(bytes)
else:
encode_me = lambda bytes: bytes
# read pixel data, convert, and write it to output
def scale(x, y): return int((y*x/maxval)+0.5)
for y in xrange(0, height):
for x in xrange(0, width):
red, green, blue = struct.unpack(unpackstr, inf.read(unpacklen))
encoded = (scale(red, 0x1f) << 11) + \
(scale(green, 0x3f) << 5) + \
(scale(blue, 0x1f))
outf.write(encode_me(struct.pack('@H', encoded)))
if compress:
outf.write(comp.flush())
# go back and write the proper file size.
off2 = outf.tell()
outf.seek(off0)
outf.write(struct.pack('@I', off2-off1))
if __name__ == '__main__':
from optparse import OptionParser
import sys
parser = OptionParser()
parser.add_option('-o','--output',default=None,dest='output',
metavar='FILE', help='output file name.')
parser.add_option('-z','--compress',action='store_true',dest='compress',
help='use compressed image format')
(options, args) = parser.parse_args()
if options.compress and options.output is None:
parser.error('Output file name required when writing '+
'compressed format.')
infile = open(args[0]) if args else sys.stdin
outfile = open(options.output, 'w') if options.output else sys.stdout
main(infile, outfile, options.compress)
|