"""Headless entry point: convert an image, write a disk image and/or a preview PNG.""" from __future__ import annotations import argparse import sys from PIL import Image from . import imageprep from .convert import MODES, convert_image, render_preview from .palette import COLOR_NAMES def build_parser() -> argparse.ArgumentParser: p = argparse.ArgumentParser(prog="c64view", description=__doc__) p.add_argument("image", help="source image (png/jpg/gif/bmp/webp)") p.add_argument("-o", "--output", help="disk image path (.d64/.d71/.d81)") p.add_argument("-m", "--mode", default="auto", choices=["auto", *MODES], help="C64 display mode") p.add_argument("-f", "--format", default=None, choices=["d64", "d71", "d81"], help="disk format (default: from -o extension, else d64)") p.add_argument("-p", "--palette", default="colodore", choices=["colodore", "pepto"]) p.add_argument("-d", "--dither", default="bayer", choices=["bayer", "floyd", "atkinson", "stucki", "jarvis", "none"]) p.add_argument("--mono-base", default="grayscale", choices=["grayscale", *COLOR_NAMES], help="base colour for 'mono' mode (default greyscale)") p.add_argument("-a", "--aspect", default="fit", choices=["fit", "fill", "stretch"]) p.add_argument("--video", default="pal", choices=["pal", "ntsc"], help="target video standard (affects the FLI viewer timing)") p.add_argument("--intensive", action="store_true", help="exhaustive background search + slower, higher-quality passes") p.add_argument("--brightness", type=float, default=1.0) p.add_argument("--contrast", type=float, default=1.0) p.add_argument("--saturation", type=float, default=1.0) p.add_argument("--gamma", type=float, default=1.0) p.add_argument("--preview", help="also write a PNG preview to this path") p.add_argument("--disk-name", default=None, help="disk + viewer name (PETSCII)") return p def main(argv=None) -> int: args = build_parser().parse_args(argv) prep = imageprep.PrepOptions( aspect=args.aspect, brightness=args.brightness, contrast=args.contrast, saturation=args.saturation, gamma=args.gamma, ) base_color = (None if args.mono_base == "grayscale" else COLOR_NAMES.index(args.mono_base)) conv = convert_image(args.image, mode=args.mode, palette_name=args.palette, dither_mode=args.dither, intensive=args.intensive, prep_opt=prep, base_color=base_color) print(f"mode={conv.mode} mean dE={conv.error:.2f} " f"data={len(conv.data)}B extra={[f[0] for f in conv.extra_files]}") if args.preview: rgb = render_preview(conv, args.palette, scale=2) Image.fromarray(rgb, "RGB").save(args.preview) print(f"wrote preview {args.preview}") if args.output: from .exporter import export_disk fmt = args.format path = export_disk(conv, args.output, disk_format=fmt, disk_name=args.disk_name, source_path=args.image, video=args.video) print(f"wrote disk image {path}") if not args.output and not args.preview: print("nothing to do: pass -o DISK and/or --preview PNG", file=sys.stderr) return 1 return 0 if __name__ == "__main__": raise SystemExit(main())