Working Python version for Commodore.
This commit is contained in:
commit
2a48f52979
51 changed files with 3095 additions and 0 deletions
77
c64view/convert/mono.py
Normal file
77
c64view/convert/mono.py
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
"""Monochrome / grayscale mode -- the highest-resolution path.
|
||||
|
||||
Renders at hires (320x200) but matches the image by *luminance* to a small ramp
|
||||
of palette colours, so detail is carried entirely by spatial dithering. With the
|
||||
grayscale ramp (black -> dark grey -> grey -> light grey -> white) this gives a
|
||||
proper greyscale photo; pick any base colour and the ramp becomes that hue's
|
||||
shades (e.g. black -> blue -> light blue -> white) for a tinted monochrome.
|
||||
|
||||
Output is ordinary hires-format data, so it reuses the hires viewer.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .. import dither, palette as pal
|
||||
from . import base, hires
|
||||
|
||||
WIDTH, HEIGHT = 320, 200
|
||||
CELL_W, CELL_H = 8, 8
|
||||
PIXEL_ASPECT = 1.0
|
||||
DATA_LOAD = 0x2000
|
||||
|
||||
# Luminance-ordered grey ramp: black, dark grey, grey, light grey, white.
|
||||
GRAY_RAMP = [0, 11, 12, 15, 1]
|
||||
# A few palette colours have a lighter sibling, giving a richer tinted ramp.
|
||||
SIBLINGS = {2: 10, 10: 2, 5: 13, 13: 5, 6: 14, 14: 6, 8: 9, 9: 8}
|
||||
|
||||
|
||||
def build_ramp(base_color, plab):
|
||||
"""Return palette indices (luminance-sorted) used to render the image."""
|
||||
if base_color is None or base_color in (0, 1, 11, 12, 15):
|
||||
ramp = list(GRAY_RAMP)
|
||||
else:
|
||||
ramp = {0, 1, base_color}
|
||||
if base_color in SIBLINGS:
|
||||
ramp.add(SIBLINGS[base_color])
|
||||
ramp = list(ramp)
|
||||
ramp.sort(key=lambda i: plab[i, 0]) # by Lab lightness
|
||||
return ramp
|
||||
|
||||
|
||||
def convert(img_rgb, palette_name="colodore", dither_mode="floyd",
|
||||
intensive=False, base_color=None):
|
||||
plab = pal.palette_lab(palette_name)
|
||||
|
||||
# Work purely in luminance: collapse image and palette to (L, 0, 0).
|
||||
L_pix = pal.srgb_to_lab(img_rgb)[..., 0]
|
||||
img_mono = np.zeros((HEIGHT, WIDTH, 3))
|
||||
img_mono[..., 0] = L_pix
|
||||
plab_mono = np.zeros((16, 3))
|
||||
plab_mono[:, 0] = plab[:, 0]
|
||||
|
||||
ramp = build_ramp(base_color, plab)
|
||||
n_free = min(2, len(ramp))
|
||||
|
||||
cells, rows, cols = base.cells_lab(img_mono, CELL_W, CELL_H)
|
||||
dist = base.cell_distance(cells, plab_mono)
|
||||
sets, _ = base.select_cell_sets(dist, ramp, n_free=n_free)
|
||||
if n_free == 1: # pad to 2 colours per cell for hires
|
||||
sets = np.concatenate([sets, sets], axis=1)
|
||||
|
||||
allowed = base.per_pixel_allowed(sets, rows, cols, CELL_W, CELL_H, HEIGHT, WIDTH)
|
||||
index_image = dither.quantize(img_mono, allowed, plab_mono, dither_mode).astype(np.uint8)
|
||||
|
||||
bitmap, screen = hires._encode(index_image, sets, rows, cols)
|
||||
payload = bytes(bitmap) + bytes(screen)
|
||||
|
||||
conv = base.Conversion(
|
||||
mode="mono", width=WIDTH, height=HEIGHT, pixel_aspect=PIXEL_ASPECT,
|
||||
index_image=index_image, data=payload, data_addr=DATA_LOAD, viewer="hires",
|
||||
error=base.mean_error(index_image, img_mono, plab_mono),
|
||||
meta={"palette": palette_name, "dither": dither_mode,
|
||||
"base_color": base_color, "ramp": ramp},
|
||||
)
|
||||
conv.extra_files = [("picture.art", base.prg(0x2000, payload + b"\x00"))]
|
||||
return conv
|
||||
Loading…
Add table
Add a link
Reference in a new issue