From f019823505582182d254c0d5882e207903618073 Mon Sep 17 00:00:00 2001 From: kris Date: Thu, 2 Feb 2023 23:35:28 +0000 Subject: [PATCH] Clean up hgr conversion optionns --- convert.py | 98 +++++++++++++++++++++++------------------------ convert_dhr.py | 1 + convert_hgr.py | 17 ++------ dither_pattern.py | 14 ++----- 4 files changed, 56 insertions(+), 74 deletions(-) diff --git a/convert.py b/convert.py index fd7bc8a..f8069fe 100644 --- a/convert.py +++ b/convert.py @@ -44,70 +44,67 @@ def add_common_args(parser): ) +def add_dhr_hgr_args(parser): + parser.add_argument( + '--dither', type=str, choices=list(dither_pattern.PATTERNS.keys()), + default=dither_pattern.DEFAULT_PATTERN, + help="Error distribution pattern to apply when dithering (default: " + + dither_pattern.DEFAULT_PATTERN + ")") + parser.add_argument( + '--palette', type=str, choices=list(set(palette_py.PALETTES.keys())), + default=palette_py.DEFAULT_PALETTE, + help='RGB colour palette to dither to. "ntsc" blends colours over 8 ' + 'pixels and gives better image quality on targets that ' + 'use/emulate NTSC, but can be substantially slower. Other ' + 'palettes determine colours based on 4 pixel sequences ' + '(default: ' + palette_py.DEFAULT_PALETTE + ")") + parser.add_argument( + '--show-palette', type=str, choices=list(palette_py.PALETTES.keys()), + help="RGB colour palette to use when --show_output (default: " + "value of --palette)") + + +def validate_lookahead(arg: int) -> int: + try: + int_arg = int(arg) + except Exception: + raise argparse.ArgumentTypeError("--lookahead must be an integer") + if int_arg < 1: + raise argparse.ArgumentTypeError("--lookahead must be at least 1") + return int_arg + + def main(): parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(required=True) + # Hi-res hgr_parser = subparsers.add_parser("hgr") add_common_args(hgr_parser) + add_dhr_hgr_args(hgr_parser) hgr_parser.add_argument( - '--dither', type=str, choices=list(dither_pattern.PATTERNS.keys()), - default=dither_pattern.DEFAULT_PATTERN, - help="Error distribution pattern to apply when dithering (default: " - + dither_pattern.DEFAULT_PATTERN + ")") - hgr_parser.add_argument( - '--palette', type=str, choices=list(set(palette_py.PALETTES.keys())), - default=palette_py.DEFAULT_PALETTE, - help='RGB colour palette to dither to. "ntsc" blends colours over 8 ' - 'pixels and gives better image quality on targets that ' - 'use/emulate NTSC, but can be substantially slower. Other ' - 'palettes determine colours based on 4 pixel sequences ' - '(default: ' + palette_py.DEFAULT_PALETTE + ")") - hgr_parser.add_argument( - '--show-palette', type=str, choices=list(palette_py.PALETTES.keys()), - help="RGB colour palette to use when --show_output (default: " - "value of --palette)") + '--error_fraction', type=float, default = 0.7, + help="Fraction of quantization error to distribute to neighbouring " + "pixels according to dither pattern" + ) hgr_parser.set_defaults(func=convert_hgr) + # Double Hi-res dhr_parser = subparsers.add_parser("dhr") add_common_args(dhr_parser) - - def validate_lookahead(arg: int) -> int: - try: - int_arg = int(arg) - except Exception: - raise argparse.ArgumentTypeError("--lookahead must be an integer") - if int_arg < 1: - raise argparse.ArgumentTypeError("--lookahead must be at least 1") - return int_arg - + add_dhr_hgr_args(dhr_parser) dhr_parser.add_argument( "--lookahead", type=validate_lookahead, default=8, help=("How many pixels to look ahead to compensate for NTSC colour " "artifacts (default: 8)")) - dhr_parser.add_argument( - '--dither', type=str, choices=list(dither_pattern.PATTERNS.keys()), - default=dither_pattern.DEFAULT_PATTERN, - help="Error distribution pattern to apply when dithering (default: " - + dither_pattern.DEFAULT_PATTERN + ")") - dhr_parser.add_argument( - '--palette', type=str, choices=list(set(palette_py.PALETTES.keys())), - default=palette_py.DEFAULT_PALETTE, - help='RGB colour palette to dither to. "ntsc" blends colours over 8 ' - 'pixels and gives better image quality on targets that ' - 'use/emulate NTSC, but can be substantially slower. Other ' - 'palettes determine colours based on 4 pixel sequences ' - '(default: ' + palette_py.DEFAULT_PALETTE + ")") - dhr_parser.add_argument( - '--show-palette', type=str, choices=list(palette_py.PALETTES.keys()), - help="RGB colour palette to use when --show_output (default: " - "value of --palette)") dhr_parser.set_defaults(func=convert_dhr) + # Double Hi-Res mono dhr_mono_parser = subparsers.add_parser("dhr_mono") add_common_args(dhr_mono_parser) dhr_mono_parser.set_defaults(func=convert_dhr_mono) + # Super Hi-Res 320x200 shr_parser = subparsers.add_parser("shr") add_common_args(shr_parser) shr_parser.add_argument( @@ -141,13 +138,6 @@ def prepare_image(image_filename: str, show_input: bool, screen, gamma=gamma_correct) -def convert_dhr(args): - palette = palette_py.PALETTES[args.palette]() - screen = screen_py.DHGRNTSCScreen(palette) - image = prepare_image(args.input, args.show_input, screen, - args.gamma_correct) - convert_dhr_py.convert(screen, image, args) - def convert_hgr(args): palette = palette_py.PALETTES[args.palette]() screen = screen_py.HGRScreen(palette) @@ -156,6 +146,14 @@ def convert_hgr(args): convert_hgr_py.convert(screen, image, args) +def convert_dhr(args): + palette = palette_py.PALETTES[args.palette]() + screen = screen_py.DHGRNTSCScreen(palette) + image = prepare_image(args.input, args.show_input, screen, + args.gamma_correct) + convert_dhr_py.convert(screen, image, args) + + def convert_dhr_mono(args): screen = screen_py.DHGRScreen() image = prepare_image(args.input, args.show_input, screen, diff --git a/convert_dhr.py b/convert_dhr.py index 6318237..ec83c9d 100644 --- a/convert_dhr.py +++ b/convert_dhr.py @@ -28,6 +28,7 @@ def _write(screen: screen_py.DHGRScreen, bitmap: np.ndarray, args): f.write(bytes(screen.main)) +# TODO: unify with convert_hgr.convert() def convert(screen: screen_py.DHGRNTSCScreen, image: Image, args): rgb = np.array(image).astype(np.float32) / 255 diff --git a/convert_hgr.py b/convert_hgr.py index 7f48eb5..88a14e9 100644 --- a/convert_hgr.py +++ b/convert_hgr.py @@ -15,7 +15,7 @@ def _output(out_image: Image, args): out_image.show() if args.save_preview: - # Save Double hi-res image + # Save Hi-res image outfile = os.path.join( os.path.splitext(args.output)[0] + "-preview.png") out_image.save(outfile, "PNG") @@ -27,6 +27,7 @@ def _write(screen: screen_py.HGRScreen, linear_bytemap: np.ndarray, args): f.write(bytes(screen.main)) +# TODO: unify with convert_dhr.convert() def convert(screen: screen_py.HGRScreen, image: Image, args): rgb = np.array(image).astype(np.float32) / 255 @@ -36,7 +37,8 @@ def convert(screen: screen_py.HGRScreen, image: Image, args): rgb24_to_cam16ucs = np.load( os.path.join(base_dir, "data/rgb24_to_cam16ucs.npy")) - dither = dither_pattern.PATTERNS[args.dither]() + dither = dither_pattern.PATTERNS[args.dither]( + error_fraction = args.error_fraction) bitmap, linear_bytemap = dither_dhr_pyx.dither_image( screen, rgb, dither, 8, args.verbose, rgb24_to_cam16ucs) @@ -55,14 +57,3 @@ def convert(screen: screen_py.HGRScreen, image: Image, args): _output(out_image, args) _write(screen, linear_bytemap, args) - - -def convert_mono(screen: screen_py.DHGRScreen, image: Image, args): - image = image.convert("1") - - out_image = Image.fromarray((np.array(image) * 255).astype(np.uint8)) - out_image = image_py.resize( - out_image, screen.X_RES, screen.Y_RES * 2, srgb_output=True) - - _output(out_image, args) - _write(screen, np.array(image).astype(bool), args) diff --git a/dither_pattern.py b/dither_pattern.py index 2ae73cb..3e309f4 100644 --- a/dither_pattern.py +++ b/dither_pattern.py @@ -7,6 +7,9 @@ class DitherPattern: PATTERN = None ORIGIN = None + def __init__(self, error_fraction=1.0): + self.PATTERN *= error_fraction + class NoDither(DitherPattern): """No dithering.""" @@ -76,15 +79,6 @@ class JarvisModifiedDither(DitherPattern): PATTERN /= np.sum(PATTERN) ORIGIN = (0, 2) -class KrisDither(DitherPattern): - """Default dither from bmp2dhr.""" - - # 0 * 7 - # 3 5 1 - PATTERN = np.array(((0, 0, 7), (3, 5, 1)), - dtype=np.float32).reshape(2, 3) / np.float32(24) - ORIGIN = (0, 1) - PATTERNS = { 'floyd': FloydSteinbergDither, @@ -94,8 +88,6 @@ PATTERNS = { 'jarvis': JarvisDither, 'jarvis-mod': JarvisModifiedDither, 'none': NoDither, - 'kris': KrisDither, - } DEFAULT_PATTERN = 'floyd'