80 lines
3.5 KiB
Python
80 lines
3.5 KiB
Python
"""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())
|