Add some comments and docstrings
This commit is contained in:
parent
a7d734f2b0
commit
2bbd65a079
12
convert.py
12
convert.py
|
@ -1,3 +1,5 @@
|
|||
"""Image converter to Apple II Double Hi-Res format."""
|
||||
|
||||
import argparse
|
||||
import os.path
|
||||
import time
|
||||
|
@ -13,11 +15,8 @@ import screen as screen_py
|
|||
|
||||
|
||||
# TODO:
|
||||
# - support alternate palettes properly
|
||||
# - compare to bmp2dhr and a2bestpix
|
||||
# - support LR/DLR
|
||||
# - support HGR
|
||||
# - README
|
||||
|
||||
|
||||
def main():
|
||||
|
@ -62,6 +61,7 @@ def main():
|
|||
screen = screen_py.DHGR140Screen(palette)
|
||||
lookahead = 0
|
||||
|
||||
# Open and resize source image
|
||||
image = image_py.open(args.input)
|
||||
resized = np.array(
|
||||
image_py.resize(image, screen.X_RES, screen.Y_RES)).astype(np.float32)
|
||||
|
@ -70,10 +70,10 @@ def main():
|
|||
|
||||
dither = dither_pattern.PATTERNS[args.dither]()
|
||||
|
||||
start = time.time()
|
||||
# start = time.time()
|
||||
output_4bit, output_rgb = dither_pyx.dither_image(
|
||||
screen, resized, dither, lookahead)
|
||||
print(time.time() - start)
|
||||
# print(time.time() - start)
|
||||
|
||||
if args.resolution == 140:
|
||||
# Show un-fringed 140px output image
|
||||
|
@ -92,9 +92,9 @@ def main():
|
|||
if args.show_output:
|
||||
out_image.show()
|
||||
|
||||
# Save Double hi-res image
|
||||
outfile = os.path.join(os.path.splitext(args.output)[0] + "-preview.png")
|
||||
out_image.save(outfile, "PNG")
|
||||
|
||||
with open(args.output, "wb") as f:
|
||||
f.write(bytes(screen.main))
|
||||
f.write(bytes(screen.aux))
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
"""Error diffusion dither patterns."""
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
|
|
3
image.py
3
image.py
|
@ -1,3 +1,5 @@
|
|||
"""Image transformation functions."""
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
|
@ -34,7 +36,6 @@ def resize(image: Image, x_res, y_res, srgb_output: bool = False) -> Image:
|
|||
# Convert to linear RGB before rescaling so that colour interpolation is
|
||||
# in linear space
|
||||
linear = srgb_to_linear(np.asarray(image)).astype(np.uint8)
|
||||
# linear = np.asarray(image).astype(np.uint8)
|
||||
res = Image.fromarray(linear).resize((x_res, y_res), Image.LANCZOS)
|
||||
if srgb_output:
|
||||
return Image.fromarray(
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
"""RGB colour palettes to target for Apple II image conversions."""
|
||||
|
||||
import numpy as np
|
||||
import image
|
||||
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
"""Precompute CIE2000 perceptual colour distance matrices.
|
||||
|
||||
The matrix of delta-E values is computed for all pairs of 24-bit RGB values,
|
||||
and 4-bit Apple II target palette. This is a 256MB file that is mmapped at
|
||||
runtime for efficient access.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import image
|
||||
import palette as palette_py
|
||||
|
|
19
screen.py
19
screen.py
|
@ -1,3 +1,5 @@
|
|||
"""Representation of Apple II screen memory."""
|
||||
|
||||
import numpy as np
|
||||
import palette as palette_py
|
||||
|
||||
|
@ -23,9 +25,15 @@ class Screen:
|
|||
return 1024 * c + 128 * b + 40 * a
|
||||
|
||||
def _image_to_bitmap(self, image: np.ndarray) -> np.ndarray:
|
||||
"""Converts 4-bit image to 2-bit image bitmap.
|
||||
|
||||
Each 4-bit colour value maps to a sliding window of 4 successive pixels,
|
||||
via x%4.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def pack(self, image: np.ndarray):
|
||||
"""Packs an image into memory format (8k AUX + 8K MAIN)."""
|
||||
bitmap = self._image_to_bitmap(image)
|
||||
# The DHGR display encodes 7 pixels across interleaved 4-byte sequences
|
||||
# of AUX and MAIN memory, as follows:
|
||||
|
@ -53,6 +61,12 @@ class Screen:
|
|||
return bitmap
|
||||
|
||||
def bitmap_to_image_rgb(self, bitmap: np.ndarray) -> np.ndarray:
|
||||
"""Convert our 2-bit bitmap image into a RGB image.
|
||||
|
||||
Colour at every pixel is determined by the value of a 4-bit sliding
|
||||
window indexed by x % 4, which gives the index into our 16-colour RGB
|
||||
palette.
|
||||
"""
|
||||
image_rgb = np.empty((192, 560, 3), dtype=np.uint8)
|
||||
for y in range(self.Y_RES):
|
||||
pixel = [False, False, False, False]
|
||||
|
@ -63,6 +77,7 @@ class Screen:
|
|||
return image_rgb
|
||||
|
||||
def pixel_palette_options(self, last_pixel_4bit, x: int):
|
||||
"""Returns available colours for given x pos and 4-bit colour of x-1"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
|
@ -85,6 +100,7 @@ class DHGR140Screen(Screen):
|
|||
return bitmap
|
||||
|
||||
def pixel_palette_options(self, last_pixel_4bit, x: int):
|
||||
# All 16 colour choices are available at every x position.
|
||||
return (
|
||||
np.array(list(self.palette.RGB.keys()), dtype=np.uint8),
|
||||
np.array(list(self.palette.RGB.values()), dtype=np.uint8))
|
||||
|
@ -107,6 +123,9 @@ class DHGR560Screen(Screen):
|
|||
return bitmap
|
||||
|
||||
def pixel_palette_options(self, last_pixel_4bit, x: int):
|
||||
# The two available colours for position x are given by the 4-bit
|
||||
# value of position x-1, and the 4-bit value produced by toggling the
|
||||
# value of the x % 4 bit (the current value of NTSC phase)
|
||||
last_dots = self.palette.DOTS[last_pixel_4bit]
|
||||
other_dots = list(last_dots)
|
||||
other_dots[x % 4] = not other_dots[x % 4]
|
||||
|
|
Loading…
Reference in New Issue