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 <alekratz@gmail.com>
This commit is contained in:
2024-05-30 11:38:33 -07:00
parent 1def2fa7bf
commit ad014b4ea4
4 changed files with 111 additions and 43 deletions

View File

@@ -8,13 +8,13 @@ import textwrap
from .colorizer import PaletteColorizer from .colorizer import PaletteColorizer
from .matricizer import Matricizer, NibbleMatricizer, RandomartMatricizer from .matricizer import Matricizer, NibbleMatricizer, RandomartMatricizer
from .palettes import Palette, DEFAULT_PALETTES, PALETTES 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 - WASM compile for embedding directly in HTML
# TODO - option to add a caption based on the filename # TODO - option to add a caption based on the filename
# TODO - load palettes from a file # TODO - load palettes from a file
# TODO - ANSI 24-bit color output
def cli_main() -> None: def cli_main() -> None:
"Main function entrypoint." "Main function entrypoint."
@@ -49,7 +49,14 @@ def cli_main() -> None:
INPUT_TYPE_HELP = "INPUT TYPE (-x, --input-type)\n" + "\n".join( INPUT_TYPE_HELP = "INPUT TYPE (-x, --input-type)\n" + "\n".join(
[f" {choice} - {desc}" for choice, desc in INPUT_TYPE_CHOICES.items()] [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] progname: str = sys.argv[0]
if progname.endswith("__main__.py"): if progname.endswith("__main__.py"):
@@ -102,12 +109,11 @@ def cli_main() -> None:
help="Choose the hash algorithm. default: sha512", help="Choose the hash algorithm. default: sha512",
) )
ap.add_argument( ap.add_argument(
"-z", "--svg-square-size",
"--square-size",
metavar="PX", metavar="PX",
type=int, type=int,
default=32, 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( ap.add_argument(
"-x", "-x",
@@ -116,6 +122,13 @@ def cli_main() -> None:
choices=INPUT_TYPE_CHOICES.keys(), choices=INPUT_TYPE_CHOICES.keys(),
help="Determines how the input should be treated. default: path", 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() args = ap.parse_args()
############################################################################ ############################################################################
@@ -182,9 +195,19 @@ def cli_main() -> None:
# Print SVG # Print SVG
matrix = matricizer.matricize(hashdata) matrix = matricizer.matricize(hashdata)
colors = colorizer.colorize(matrix) colors = colorizer.colorize(matrix)
svg = gensvg(colors, args.square_size)
if str(args.out) == "-": # Choose the output writer
sys.stdout.write(svg) writer: Writer
else: match args.output_type:
args.out.write_text(svg) 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)

View File

@@ -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'<svg width="{w * square_size}" height="{h * square_size}" xmlns="http://www.w3.org/2000/svg">\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' <rect x="{x}" y="{y}" width="{square_size}" height="{square_size}" fill="{color.to_html_color()}" />\n'
# Close SVG string
svg += "</svg>"
return svg

71
colorhash/writer.py Normal file
View File

@@ -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'<svg width="{w * self.square_size}" height="{h * self.square_size}" xmlns="http://www.w3.org/2000/svg">\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' <rect x="{x}" y="{y}" width="{self.square_size}" height="{self.square_size}" fill="{color.to_html_color()}" />\n'
# Close SVG string
svg += "</svg>"
return svg

View File

@@ -11,9 +11,12 @@ find "examples" -type f -name '*.in' | \
while read infile; do while read infile; do
for hash in "${hashes[@]}"; do for hash in "${hashes[@]}"; do
for matrix in "${matrices[@]}"; do for matrix in "${matrices[@]}"; do
outfile="examples/$(basename -s .in "$infile")-$hash-$matrix.svg" svgfile="examples/$(basename -s .in "$infile")-$hash-$matrix.svg"
echo "Generating $outfile" pngfile="examples/$(basename -s .in "$infile")-$hash-$matrix.png"
python3 -m colorhash "$infile" --out "$outfile" --hash "$hash" --matrix "$matrix" 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 done
done done