First public commit.
This commit is contained in:
parent
2a48f52979
commit
4bac9d83ed
288 changed files with 18417 additions and 1076 deletions
83
lenser/vic20/convert/mono.py
Normal file
83
lenser/vic20/convert/mono.py
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
"""Commodore VIC-20 monochrome / tinted-mono mode.
|
||||
|
||||
176x184 hi-res matched by luminance: a single global background (black) and one
|
||||
foreground colour (white, or a tinted base) used by every cell, so the picture is
|
||||
carried entirely by the custom character shapes + dithering -- a clean two-tone
|
||||
image with no per-cell colour budget to spend. Reuses the hires char clustering,
|
||||
data layout and viewer.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import numpy as np
|
||||
|
||||
from ... import palette as c64pal
|
||||
from ...convert import base
|
||||
from .. import palette as vpal
|
||||
from . import hires
|
||||
|
||||
WIDTH, HEIGHT, PIXEL_ASPECT = hires.WIDTH, hires.HEIGHT, hires.PIXEL_ASPECT
|
||||
|
||||
|
||||
def convert(img_rgb, palette_name="vic", dither_mode="floyd",
|
||||
intensive=False, base_color=None):
|
||||
plab = vpal.palette_lab()
|
||||
prgb = vpal.get_palette().astype(np.uint8)
|
||||
|
||||
bg = 0 # black background
|
||||
fg = base_color if base_color in range(1, 8) else 1 # white (or tinted)
|
||||
ramp = sorted([bg, fg], key=lambda i: plab[i, 0])
|
||||
|
||||
idx, sets, rows, cols, err = base.mono_render(
|
||||
img_rgb, plab, ramp, hires.WIDTH, hires.HEIGHT,
|
||||
hires.CELL_W, hires.CELL_H, dither_mode, n_free=2)
|
||||
|
||||
# cell bitmaps (1 = foreground) reduced to the 256-char dictionary by a
|
||||
# frequency codebook -- keeps the dithered detail (k-means centroids would
|
||||
# invent near-solid 'average' chars -> block artefacts).
|
||||
bitmaps = np.zeros((hires.N_CELLS, 64), np.uint8)
|
||||
for cr in range(rows):
|
||||
for cc in range(cols):
|
||||
ci = cr * cols + cc
|
||||
block = idx[cr * 8:cr * 8 + 8, cc * 8:cc * 8 + 8]
|
||||
bitmaps[ci] = (block == fg).astype(np.uint8).reshape(-1)
|
||||
chars, labels = base.mono_codebook(bitmaps, hires.N_CHARS)
|
||||
|
||||
img_mono = np.zeros((hires.HEIGHT, hires.WIDTH, 3))
|
||||
img_mono[..., 0] = c64pal.srgb_to_lab(img_rgb)[..., 0]
|
||||
plab_mono = np.zeros_like(plab)
|
||||
plab_mono[:, 0] = plab[:, 0]
|
||||
|
||||
prev_idx = np.empty((hires.HEIGHT, hires.WIDTH), np.uint8)
|
||||
screen = np.zeros(hires.N_CELLS, np.uint8)
|
||||
color = np.zeros(hires.N_CELLS, np.uint8)
|
||||
for ci in range(hires.N_CELLS):
|
||||
cr, cc = divmod(ci, cols)
|
||||
ch = chars[labels[ci]].reshape(8, 8)
|
||||
prev_idx[cr * 8:cr * 8 + 8, cc * 8:cc * 8 + 8] = np.where(ch == 1, fg, bg)
|
||||
screen[ci] = labels[ci] & 0xFF
|
||||
color[ci] = fg & 0x07
|
||||
chardata = np.zeros(hires.N_CHARS * 8, np.uint8)
|
||||
for t in range(hires.N_CHARS):
|
||||
rb = chars[t].reshape(8, 8)
|
||||
for r in range(8):
|
||||
byte = 0
|
||||
for x in range(8):
|
||||
byte = (byte << 1) | int(rb[r, x])
|
||||
chardata[t * 8 + r] = byte
|
||||
|
||||
data = {"chardata": chardata, "screen": screen, "color": color,
|
||||
"bg": int(bg), "border": 0, "aux": 0}
|
||||
|
||||
preview = prgb[prev_idx]
|
||||
disp_w = int(round(hires.WIDTH * hires.PIXEL_ASPECT))
|
||||
xs = (np.arange(disp_w) * hires.WIDTH) // disp_w
|
||||
preview = preview[:, xs]
|
||||
|
||||
return base.Conversion(
|
||||
mode="mono", width=hires.WIDTH, height=hires.HEIGHT,
|
||||
pixel_aspect=hires.PIXEL_ASPECT, index_image=prev_idx.astype(np.uint16),
|
||||
data=data, data_addr=0, viewer="hires", preview_rgb=preview,
|
||||
error=base.perceptual_error(prev_idx, img_mono, plab_mono),
|
||||
meta={"palette": "vic", "dither": dither_mode, "base_color": base_color},
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue