~shiny/gbcap

3032ac7fcb561d7cdc9cdb77145db7a82f0a8d83 — Thomas Spurden 3 years ago 4c0d999
decomp_stream improvements

- Add support for raw and hex encoded input
- Add support for outputting animated gifs using imageio
- Make non-verbose by default
- Support reading from a file or stdin
1 files changed, 60 insertions(+), 6 deletions(-)

M decomp_stream.py
M decomp_stream.py => decomp_stream.py +60 -6
@@ 1,27 1,81 @@
#!/usr/bin/env python3
import os
import contextlib
import compress_ref

def bytes_from_stream(stream):
def bytes_from_hex_stream(stream):
    for bstr in stream:
        n = int(bstr, 16)
        yield n

def bytes_from_binary(f):
    while True:
        b = f.read(1)
        if not b:
            break
        yield b[0]

def add_gif_frame(gif, frame):
    gif.append_data(numpy.array([[85*(3 - p) for p in compress_ref.lines_to_pixels([l], 160)] for l in frame], dtype='uint8'))

def ensure_dir(path):
    dp = os.path.dirname(path)
    if dp:
        os.makedirs(dp, exist_ok=True)

if __name__ == '__main__':
    import argparse
    import sys

    parser = argparse.ArgumentParser()
    parser.add_argument('--output', '-o', help='Output pgms with this base name')
    parser.add_argument('--output-pgm', '-o', help='Output pgms with this base name')
    parser.add_argument('--output-gif', '-g',
        help='''Output a gif animation to file. Requires imageio python library.
        The output GIF will be large and unoptimised, try gifsicle to create a
        smaller GIF, or convert to webp with gif2webp.''')
    parser.add_argument('--text', '-t', help='Data is newline-separated hex strings rather than raw binary')
    parser.add_argument('--verbose', '-v', action='store_true', help='Verbose decompression')
    parser.add_argument('file', nargs='?', help='File to read data from')
    args = parser.parse_args()

    codec = compress_ref.CODEC(160, 144, 4)
    frame_buf = []
    frame_count = 0
    for line in codec.decompress(bytes_from_stream(sys.stdin), verbose=True):
        if args.output:
    with contextlib.ExitStack() as stack:
        if args.file:
            f = stack.enter_context(open(args.file, 'r' if args.text else 'rb'))
        else:
            f = sys.stdin if args.text else sys.stdin.buffer

        if args.text:
            stream = bytes_from_hex_stream(f)
        else:
            stream = bytes_from_binary(f)

        if args.output_gif:
            import imageio
            import numpy
            ensure_dir(args.output_gif)
            gif = stack.enter_context(imageio.get_writer(args.output_gif, mode='I', fps=60, palettesize=4))

        if args.output_pgm:
            ensure_dir(args.output_pgm)

        for line in codec.decompress(stream, verbose=args.verbose):
            frame_buf.append(line)
            if len(frame_buf) == 144:
                compress_ref.dump_pgm('{}{:03d}.pgm'.format(args.output, frame_count), frame_buf)
                if args.output_pgm:
                    compress_ref.dump_pgm('{}{:05d}.pgm'.format(args.output_pgm, frame_count), frame_buf)
                if args.output_gif:
                    add_gif_frame(gif, frame_buf)

                if not args.verbose:
                    sys.stdout.write('\r{: 9d}'.format(frame_count))
                    sys.stdout.flush()
                frame_count += 1
                frame_buf = []
        print('{:080x}'.format(line))
            if args.verbose:
                print('{:080x}'.format(line))

        if not args.verbose:
            print()