|
@@ -0,0 +1,133 @@
|
|
|
+#!/usr/bin/env python
|
|
|
+#
|
|
|
+# ppmrotate.py: Rotate PPM images
|
|
|
+#
|
|
|
+# AUTHOR: Glynn Clements (Python version)
|
|
|
+# Vaclav Petras (separate script)
|
|
|
+# Earlier Bourne script version by Hamish Bowman,
|
|
|
+# http://grasswiki.osgeo.org/wiki/Talk:Color_tables
|
|
|
+#
|
|
|
+# (C) 2009-2017 by the GRASS Development Team
|
|
|
+# This program is free software under the GNU General Public
|
|
|
+# License (>=v2). Read the file COPYING that comes with GRASS
|
|
|
+# for details.
|
|
|
+#
|
|
|
+
|
|
|
+import sys
|
|
|
+import os
|
|
|
+import atexit
|
|
|
+import array
|
|
|
+import grass.script as grass
|
|
|
+
|
|
|
+tmp_img = None
|
|
|
+
|
|
|
+height = None
|
|
|
+width = None
|
|
|
+
|
|
|
+
|
|
|
+def cleanup():
|
|
|
+ if tmp_img:
|
|
|
+ grass.try_remove(tmp_img)
|
|
|
+
|
|
|
+# def rotate(src, dst):
|
|
|
+# grass.call(["convert", "-rotate", "90", src, dst])
|
|
|
+
|
|
|
+
|
|
|
+def read_ppm(src):
|
|
|
+ global width, height
|
|
|
+
|
|
|
+ fh = open(src, "rb")
|
|
|
+ text = fh.read()
|
|
|
+ fh.close()
|
|
|
+ i = 0
|
|
|
+ j = text.find('\n', i)
|
|
|
+ if text[i:j] != 'P6':
|
|
|
+ raise IOError(text[i:j] + " != P6. Is the file PPM?")
|
|
|
+ i = j + 1
|
|
|
+ j = text.find('\n', i)
|
|
|
+ w, h = text[i:j].split()
|
|
|
+ width = int(w)
|
|
|
+ height = int(h)
|
|
|
+ i = j + 1
|
|
|
+ j = text.find('\n', i)
|
|
|
+ maxval = text[i:j]
|
|
|
+ if int(maxval) != 255:
|
|
|
+ raise IOError("Max value in image != 255")
|
|
|
+ i = j + 1
|
|
|
+ return array.array('B', text[i:])
|
|
|
+
|
|
|
+
|
|
|
+def write_ppm(dst, data):
|
|
|
+ w = height
|
|
|
+ h = width
|
|
|
+ fh = open(dst, "wb")
|
|
|
+ fh.write("P6\n%d %d\n%d\n" % (w, h, 255))
|
|
|
+ data.tofile(fh)
|
|
|
+ fh.close()
|
|
|
+
|
|
|
+
|
|
|
+def rotate_ppm(srcd):
|
|
|
+ dstd = array.array('B', len(srcd) * '\0')
|
|
|
+ for y in xrange(height):
|
|
|
+ for x in xrange(width):
|
|
|
+ for c in xrange(3):
|
|
|
+ old_pos = (y * width + x) * 3 + c
|
|
|
+ new_pos = (x * height + (height - 1 - y)) * 3 + c
|
|
|
+ dstd[new_pos] = srcd[old_pos]
|
|
|
+ return dstd
|
|
|
+
|
|
|
+
|
|
|
+def flip_ppm(srcd):
|
|
|
+ dstd = array.array('B', len(srcd) * '\0')
|
|
|
+ stride = width * 3
|
|
|
+ for y in xrange(height):
|
|
|
+ dy = (height - 1 - y)
|
|
|
+ dstd[dy * stride:(dy + 1) * stride] = srcd[y * stride:(y + 1) * stride]
|
|
|
+ return dstd
|
|
|
+
|
|
|
+
|
|
|
+def ppmtopng(dst, src):
|
|
|
+ if grass.find_program("g.ppmtopng", '--help'):
|
|
|
+ grass.run_command('g.ppmtopng', input=src, output=dst, quiet=True)
|
|
|
+ elif grass.find_program("pnmtopng"):
|
|
|
+ fh = open(dst, 'wb')
|
|
|
+ grass.call(["pnmtopng", src], stdout=fh)
|
|
|
+ fh.close()
|
|
|
+ elif grass.find_program("convert"):
|
|
|
+ grass.call(["convert", src, dst])
|
|
|
+ else:
|
|
|
+ grass.fatal(_("Cannot find g.ppmtopng, pnmtopng or convert"))
|
|
|
+
|
|
|
+
|
|
|
+def convert_and_rotate(src, dst, flip=False):
|
|
|
+ global tmp_img
|
|
|
+
|
|
|
+ ppm = read_ppm(src)
|
|
|
+ if flip:
|
|
|
+ ppm = flip_ppm(ppm)
|
|
|
+ ppm = rotate_ppm(ppm)
|
|
|
+ to_png = False
|
|
|
+ if dst.lower().endswith('.png'):
|
|
|
+ to_png = True
|
|
|
+ if to_png:
|
|
|
+ tmp_img = grass.tempfile() + ".ppm"
|
|
|
+ # TODO: clean up the file
|
|
|
+ else:
|
|
|
+ tmp_img = dst
|
|
|
+ write_ppm(tmp_img, ppm)
|
|
|
+ if to_png:
|
|
|
+ ppmtopng(dst, tmp_img)
|
|
|
+
|
|
|
+
|
|
|
+def main():
|
|
|
+ os.environ['GRASS_OVERWRITE'] = '1'
|
|
|
+
|
|
|
+ infile = sys.argv[1]
|
|
|
+ outfile = sys.argv[2]
|
|
|
+
|
|
|
+ convert_and_rotate(infile, outfile, flip=False)
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ atexit.register(cleanup)
|
|
|
+ main()
|