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

View file

@ -0,0 +1,81 @@
"""Conversion dispatch + preview rendering."""
from __future__ import annotations
import numpy as np
from .. import imageprep, palette as pal
from . import base, hires, mono, multicolor
# mode name -> module
_MODULES = {
"hires": hires,
"multicolor": multicolor,
"mono": mono,
}
# Registered lazily so FLI/IFLI can be added without import cycles.
try:
from . import fli # noqa: E402
_MODULES["fli"] = fli
except Exception:
pass
try:
from . import ifli # noqa: E402
_MODULES["interlace"] = ifli
except Exception:
pass
MODES = list(_MODULES.keys())
def convert_image(path_or_img, mode="multicolor", palette_name="colodore",
dither_mode="bayer", intensive=False,
prep_opt: imageprep.PrepOptions | None = None,
base_color=None) -> base.Conversion:
"""Prepare an image for ``mode`` and convert it. ``mode='auto'`` tries every
standard mode and returns the lowest-error result. ``base_color`` (palette
index, or None for grayscale) only applies to the ``mono`` mode."""
prep_opt = prep_opt or imageprep.PrepOptions()
if mode == "auto":
best = None
for m in ("multicolor", "hires"):
c = convert_image(path_or_img, m, palette_name, dither_mode, intensive, prep_opt)
if best is None or c.error < best.error:
best = c
return best
module = _MODULES[mode]
border_rgb = pal.get_palette(palette_name)[prep_opt.border_index]
img_rgb = imageprep.prepare(
path_or_img, module.WIDTH, module.HEIGHT, module.PIXEL_ASPECT,
prep_opt, border_rgb=border_rgb,
)
if mode == "mono":
return module.convert(img_rgb, palette_name, dither_mode, intensive,
base_color=base_color)
return module.convert(img_rgb, palette_name, dither_mode, intensive)
def render_preview(conv: base.Conversion, palette_name="colodore",
scale: int = 2) -> np.ndarray:
"""Render the conversion's index image to a displayed-resolution RGB array.
Logical pixels are widened by the mode's pixel aspect (so multicolor pixels
are twice as wide), giving a uniform 320x200 base which is then integer-scaled.
"""
if conv.preview_rgb is not None:
rgb = conv.preview_rgb
if scale > 1:
rgb = np.repeat(np.repeat(rgb, scale, axis=0), scale, axis=1)
return rgb
prgb = pal.get_palette(palette_name).astype(np.uint8)
rgb = prgb[conv.index_image] # (H, W, 3)
xrep = int(round(conv.pixel_aspect))
if xrep > 1:
rgb = np.repeat(rgb, xrep, axis=1)
if scale > 1:
rgb = np.repeat(np.repeat(rgb, scale, axis=0), scale, axis=1)
return rgb