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
|
#!/usr/bin/env python
from __future__ import print_function
import argparse
import struct
import sys
import png
def write_pnm(file, rows, meta):
"""Write a Netpbm PNM/PAM file.
"""
meta = dict(meta)
meta['maxval'] = 2**meta['bitdepth'] - 1
meta['width'], meta['height'] = meta['size']
# Number of planes determines both image formats:
# 1 : L to PGM
# 2 : LA to PAM
# 3 : RGB to PPM
# 4 : RGBA to PAM
planes = meta['planes']
# Assume inputs are from a PNG file.
assert planes in (1, 2, 3, 4)
if planes in (1, 3):
if 1 == planes:
# PGM
# Even if maxval is 1 we use PGM instead of PBM,
# to avoid conerting data.
magic = 'P5'
else:
# PPM
magic = 'P6'
header = "{magic} {width:d} {height:d} {maxval:d}\n".format(
magic=magic, **meta)
if planes in (2, 4):
# PAM
# See http://netpbm.sourceforge.net/doc/pam.html
if 2 == planes:
tupltype = 'GRAYSCALE_ALPHA'
else:
tupltype = 'RGB_ALPHA'
header = ('P7\nWIDTH {width:d}\nHEIGHT {height:d}\n'
'DEPTH {planes:d}\nMAXVAL {maxval:d}\n'
'TUPLTYPE {tupltype}\nENDHDR\n'.format(
tupltype=tupltype, **meta))
file.write(header.encode('ascii'))
# Values per row
vpr = planes * meta['width']
# format for struct.pack
fmt = '>%d' % vpr
if meta['maxval'] > 0xFF:
fmt = fmt + 'H'
else:
fmt = fmt + 'B'
for row in rows:
file.write(struct.pack(fmt, *row))
file.flush()
def cli_open(path):
if path == "-":
return binary_stdin()
return open(path, 'rb')
def binary_stdin():
"""
A sys.stdin that returns bytes.
"""
try:
return sys.stdin.buffer
except AttributeError:
# Probably Python 2, where bytes are strings.
pass
return sys.stdin
def binary_stdout():
"""
A sys.stdout that accepts bytes.
"""
# First there is a Python3 issue.
try:
stdout = sys.stdout.buffer
except AttributeError:
# Probably Python 2, where bytes are strings.
stdout = sys.stdout
# On Windows the C runtime file orientation needs changing.
if sys.platform == "win32":
import msvcrt
import os
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
return stdout
def main(argv=None):
parser = argparse.ArgumentParser(description='Convert PNG to PAM')
parser.add_argument('png', nargs='?', default='-')
args = parser.parse_args()
inp = cli_open(args.png)
# Encode PNG to PPM
image = png.Reader(file=inp)
_, _, rows, info = image.asDirect()
write_pnm(binary_stdout(), rows, info)
if __name__ == '__main__':
sys.exit(main())
|