8bitlenser/lenser/atari/convert/gr8.py
2026-07-03 19:35:35 -07:00

40 lines
1.5 KiB
Python

"""Atari GR.8 (ANTIC mode F): 320x192 hi-res, two tones of one hue.
Highest spatial resolution; carries tone by dithering between background and a
foreground luminance. ``base_color`` picks the hue (None = greyscale).
"""
from __future__ import annotations
import numpy as np
from ...convert.base import Conversion, perceptual_error
from .. import palette as apal
from . import _common
WIDTH, HEIGHT = 320, 192
PIXEL_ASPECT = 1.0
def convert(img_rgb, palette_name="ntsc", dither_mode="floyd",
intensive=False, base_color=None):
hue = 0 if base_color is None else (int(base_color) & 0x0F)
bg_reg = (hue << 4) | 0x00 # darkest of the hue
fg_reg = (hue << 4) | 0x0E # brightest of the hue
plab = apal.palette_lab(palette_name)
prgb = apal.get_palette(palette_name).astype(np.uint8)
img_mono, plab_mono = _common.luminance_lab(img_rgb, plab)
idx = _common.quantize_global(img_mono, plab_mono, [bg_reg, fg_reg], dither_mode)
val = (idx == fg_reg).astype(np.uint8)
data = _common.split_screen(_common.pack_1bpp(val)) + bytes([bg_reg, fg_reg])
preview = prgb[idx] # already 320 wide
return Conversion(
mode="gr8", width=WIDTH, height=HEIGHT, pixel_aspect=PIXEL_ASPECT,
index_image=idx.astype(np.uint16), data=data, data_addr=_common.DATA_ADDR,
viewer="gr8", preview_rgb=preview,
error=perceptual_error(idx, img_mono, plab_mono),
meta={"palette": palette_name, "dither": dither_mode, "hue": hue},
)