#!/venv/bin/python3 # http://www.python.org/doc/2.4.4/lib/module-itertools.html import itertools import sys import png Description = """Join PNG images in a row left-to-right.""" class FormatError(Exception): """ Some problem with the image format. """ def join_row(out, l): """ Concatenate the list of images. All input images must be same height and have the same number of channels. They are concatenated left-to-right. `out` is the (open file) destination for the output image. `l` should be a list of open files (the input image files). """ l = [png.Reader(file=f) for f in l] # Ewgh, side effects. for r in l: r.preamble() # The reference height; from the first image. height = l[0].height # The total target width width = 0 for i,r in enumerate(l): if r.height != height: raise FormatError('Image %d, height %d, does not match %d.' % (i, r.height, height)) width += r.width # Various bugs here because different numbers of channels and depths go wrong. pixel, info = zip(*[r.asDirect()[2:4] for r in l]) tinfo = dict(info[0]) del tinfo['size'] w = png.Writer(width, height, **tinfo) def iter_all_rows(): for row in zip(*pixel): # `row` is a sequence that has one row from each input image. # list() is required here to hasten the lazy row building; # not sure if that's a bug in PyPNG or not. yield list(itertools.chain(*row)) w.write(out, iter_all_rows()) def main(argv): import argparse parser = argparse.ArgumentParser(description=Description) parser.add_argument( "input", nargs="*", default="-", type=png.cli_open, metavar="PNG" ) args = parser.parse_args() return join_row(png.binary_stdout(), args.input) if __name__ == '__main__': main(sys.argv)