From ad014b4ea4aefc5bb928a49bdeb62f1625ad92cb Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Thu, 30 May 2024 11:38:33 -0700 Subject: [PATCH] Add ANSI color output, set that as the default ANSI-based color output is available and now the default. Add a -y / --output-type argument to select SVG or ANSI output. Also update tools/genexamples.sh to use the SVG output type. Signed-off-by: Alek Ratzloff --- colorhash/cli.py | 45 +++++++++++++++++++++------- colorhash/svg.py | 29 ------------------ colorhash/writer.py | 71 ++++++++++++++++++++++++++++++++++++++++++++ tools/genexamples.sh | 9 ++++-- 4 files changed, 111 insertions(+), 43 deletions(-) delete mode 100644 colorhash/svg.py create mode 100644 colorhash/writer.py diff --git a/colorhash/cli.py b/colorhash/cli.py index 6c7efc6..398f16f 100644 --- a/colorhash/cli.py +++ b/colorhash/cli.py @@ -8,13 +8,13 @@ import textwrap from .colorizer import PaletteColorizer from .matricizer import Matricizer, NibbleMatricizer, RandomartMatricizer from .palettes import Palette, DEFAULT_PALETTES, PALETTES -from .svg import gensvg +from .writer import ANSIWriter, SVGWriter # TODO - WASM compile for embedding directly in HTML # TODO - option to add a caption based on the filename # TODO - load palettes from a file -# TODO - ANSI 24-bit color output + def cli_main() -> None: "Main function entrypoint." @@ -49,7 +49,14 @@ def cli_main() -> None: INPUT_TYPE_HELP = "INPUT TYPE (-x, --input-type)\n" + "\n".join( [f" {choice} - {desc}" for choice, desc in INPUT_TYPE_CHOICES.items()] ) - EPILOGUE = "\n\n".join([MATRIX_HELP, PALETTE_HELP, INPUT_TYPE_HELP]) + OUTPUT_TYPE_CHOICES = { + "ansi": "the output should be colored for ANSI terminals using 24 bit true color", + "svg": "the output should be an SVG format", + } + OUTPUT_TYPE_HELP = "OUTPUT TYPE (-y, --output-type)\n" + "\n".join( + [f" {choice} - {desc}" for choice, desc in OUTPUT_TYPE_CHOICES.items()] + ) + EPILOGUE = "\n\n".join([MATRIX_HELP, PALETTE_HELP, INPUT_TYPE_HELP, OUTPUT_TYPE_HELP]) progname: str = sys.argv[0] if progname.endswith("__main__.py"): @@ -102,12 +109,11 @@ def cli_main() -> None: help="Choose the hash algorithm. default: sha512", ) ap.add_argument( - "-z", - "--square-size", + "--svg-square-size", metavar="PX", type=int, default=32, - help="Decide how big the output squares are, in pixels. default: 32", + help="For SVG outputs, decide how big the output squares are, in pixels. default: 32", ) ap.add_argument( "-x", @@ -116,6 +122,13 @@ def cli_main() -> None: choices=INPUT_TYPE_CHOICES.keys(), help="Determines how the input should be treated. default: path", ) + ap.add_argument( + "-y", + "--output-type", + default="ansi", + choices=OUTPUT_TYPE_CHOICES.keys(), + help="Determines how the output should be generated. default: ansi", + ) args = ap.parse_args() ############################################################################ @@ -182,9 +195,19 @@ def cli_main() -> None: # Print SVG matrix = matricizer.matricize(hashdata) colors = colorizer.colorize(matrix) - svg = gensvg(colors, args.square_size) - if str(args.out) == "-": - sys.stdout.write(svg) - else: - args.out.write_text(svg) + + # Choose the output writer + writer: Writer + match args.output_type: + case "ansi": + writer = ANSIWriter() + case "svg": + writer = SVGWriter(args.svg_square_size) + + output = writer.write(colors) + + if str(args.out) == "-": + sys.stdout.write(output) + else: + args.out.write_text(output) diff --git a/colorhash/svg.py b/colorhash/svg.py deleted file mode 100644 index 1e168ae..0000000 --- a/colorhash/svg.py +++ /dev/null @@ -1,29 +0,0 @@ -"SVG-related functions." -from .colorizer import ColorMatrix - - -def gensvg(matrix: ColorMatrix, square_size: int) -> str: - """ - Generate an SVG based on a given matrix. - - :param matrix: the color matrix to generate the SVG for. - :param square_size: the size of the squares generated, in pixels. - :returns: the full generated SVG as a string. - """ - h = len(matrix) - w = len(matrix[0]) - - # Start SVG string - svg = f'\n' - - # Generate grid - for r in range(h): - for c in range(w): - x = c * square_size - y = r * square_size - color = matrix[r][c] - svg += f' \n' - - # Close SVG string - svg += "" - return svg diff --git a/colorhash/writer.py b/colorhash/writer.py new file mode 100644 index 0000000..a6f83eb --- /dev/null +++ b/colorhash/writer.py @@ -0,0 +1,71 @@ +import abc + +from .color import Color +from .colorizer import ColorMatrix + + +class Writer(metaclass=abc.ABCMeta): + """ + Base writer class. + + This is used to write an input colorized matrix to a string, which is then forwarded to the + appropriate output. + """ + + @abc.abstractmethod + def write(self, matrix: ColorMatrix) -> str: + "Write the color matrix to a string." + + +class ANSIWriter(Writer): + def write(self, matrix: ColorMatrix) -> str: + ESC = '\x1b' + RESET = f"{ESC}[0m" + C = "██" + def ansi_color(c: Color) -> str: + c = c.to_rgb() + return f"{ESC}[38;2;{round(c.r)};{round(c.g)};{round(c.b)}m" + out = '' + for row in matrix: + for col in row: + out += ansi_color(col) + out += C + out += "\n" + out += RESET + return out + + +class SVGWriter(Writer): + def __init__(self, square_size: int) -> None: + """ + Create a new SVG writer that uses the given square size. + + :param square_size: the size of the squares generated, in pixels. + """ + self.square_size = square_size + + def write(self, matrix: ColorMatrix) -> str: + """ + Generate an SVG based on a given matrix. + + :param matrix: the color matrix to generate the SVG for. + :returns: the full generated SVG as a string. + """ + h = len(matrix) + w = len(matrix[0]) + + # Start SVG string + svg = f'\n' + + # Generate grid + for r in range(h): + for c in range(w): + x = c * self.square_size + y = r * self.square_size + color = matrix[r][c] + svg += f' \n' + + # Close SVG string + svg += "" + return svg + diff --git a/tools/genexamples.sh b/tools/genexamples.sh index 1d611fb..9e51436 100755 --- a/tools/genexamples.sh +++ b/tools/genexamples.sh @@ -11,9 +11,12 @@ find "examples" -type f -name '*.in' | \ while read infile; do for hash in "${hashes[@]}"; do for matrix in "${matrices[@]}"; do - outfile="examples/$(basename -s .in "$infile")-$hash-$matrix.svg" - echo "Generating $outfile" - python3 -m colorhash "$infile" --out "$outfile" --hash "$hash" --matrix "$matrix" + svgfile="examples/$(basename -s .in "$infile")-$hash-$matrix.svg" + pngfile="examples/$(basename -s .in "$infile")-$hash-$matrix.png" + echo "Generating $svgfile" + python3 -m colorhash "$infile" --output-type svg --out "$svgfile" --hash "$hash" --matrix "$matrix" + echo "Generating $pngfile" + convert "$svgfile" "$pngfile" done done done