Working Python version for Commodore.

This commit is contained in:
The Dust Council 2026-06-14 17:43:12 -07:00
commit 2a48f52979
51 changed files with 3095 additions and 0 deletions

80
c64view/cli.py Normal file
View file

@ -0,0 +1,80 @@
"""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())