| #!/usr/bin/env python |
| |
| # https://docs.python.org/3.5/library/itertools.html |
| import itertools |
| import sys |
| |
| import png |
| |
| Description = """Join PNG images in a column top-to-bottom.""" |
| |
| |
| class FormatError(Exception): |
| """ |
| Some problem with the image format. |
| """ |
| |
| |
| def join_col(out, l): |
| """ |
| Join the list of images. |
| All input images must be same width and |
| have the same number of channels. |
| They are joined top-to-bottom. |
| `out` is the (open file) destination for the output image. |
| `l` should be a list of open files (the input image files). |
| """ |
| |
| image = 0 |
| stream = 0 |
| |
| # When the first image is read, this will be the reference width, |
| # which must be the same for all images. |
| width = None |
| # Total height (accumulated as images are read). |
| height = 0 |
| # Accumulated rows. |
| rows = [] |
| |
| for f in l: |
| stream += 1 |
| while True: |
| im = png.Reader(file=f) |
| try: |
| im.preamble() |
| except EOFError: |
| break |
| image += 1 |
| |
| if not width: |
| width = im.width |
| elif width != im.width: |
| raise FormatError('Image %d in stream %d has width %d; does not match %d.' % |
| (image, stream, im.width, width)) |
| |
| height += im.height |
| # Various bugs here because different numbers of channels and depths go wrong. |
| w, h, p, info = im.asDirect() |
| rows.extend(p) |
| |
| # Alarmingly re-use the last info object. |
| tinfo = dict(info) |
| del tinfo['size'] |
| w = png.Writer(width, height, **tinfo) |
| |
| w.write(out, 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_col(png.binary_stdout(), args.input) |
| |
| if __name__ == '__main__': |
| main(sys.argv) |