125 lines
3.5 KiB
Python
Executable file
125 lines
3.5 KiB
Python
Executable file
#!/usr/bin/env nix-shell
|
|
#! nix-shell -i python3 --pure
|
|
#! nix-shell -p python3 python3Packages.colorspacious python3Packages.numpy
|
|
# vim: filetype=python
|
|
|
|
import argparse
|
|
import json
|
|
|
|
import colorspacious
|
|
import numpy as np
|
|
import numpy.typing as npt
|
|
|
|
# Original values for the Solarized color scheme,
|
|
# created by Ethan Schoonover (https://ethanschoonover.com/solarized/)
|
|
SOLARIZED_LAB = np.array(
|
|
[
|
|
[15, -12, -12],
|
|
[20, -12, -12],
|
|
[45, -7, -7],
|
|
[50, -7, -7],
|
|
[60, -6, -3],
|
|
[65, -5, -2],
|
|
[92, -0, 10],
|
|
[97, 0, 10],
|
|
[50, 65, 45],
|
|
[50, 50, 55],
|
|
[60, 10, 65],
|
|
[60, -20, 65],
|
|
[60, -35, -5],
|
|
[55, -10, -45],
|
|
[50, 15, -45],
|
|
[50, 65, -5],
|
|
]
|
|
)
|
|
|
|
# I couldn't get a perfect translation of Solarized L*a*b values into sRGB,
|
|
# so here is upstream's translation for reference
|
|
SOLARIZED_RGB = np.array(
|
|
[
|
|
[0, 43, 54],
|
|
[7, 54, 66],
|
|
[88, 110, 117],
|
|
[101, 123, 131],
|
|
[131, 148, 150],
|
|
[147, 161, 161],
|
|
[238, 232, 213],
|
|
[253, 246, 227],
|
|
[220, 50, 47],
|
|
[203, 75, 22],
|
|
[181, 137, 0],
|
|
[133, 153, 0],
|
|
[42, 161, 152],
|
|
[38, 139, 210],
|
|
[108, 113, 196],
|
|
[211, 54, 130],
|
|
]
|
|
)
|
|
|
|
# Parse arguments
|
|
parser = argparse.ArgumentParser(
|
|
description="Generate a base16-theme based derived from Solarized"
|
|
)
|
|
_ = parser.add_argument("--source", choices=["lab", "rgb"], default="lab")
|
|
_ = parser.add_argument("--lightness_factor", type=float, default=1.0)
|
|
_ = parser.add_argument("--chroma-factor", type=float, default=1.0)
|
|
_ = parser.add_argument("--hue_shift", type=float, default=-75.0)
|
|
_ = parser.add_argument(
|
|
"--polarity", choices=["dark", "light"], default="dark"
|
|
)
|
|
_ = parser.add_argument(
|
|
"--output", choices=["json", "truecolor"], default="truecolor"
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
|
|
def cspace_convert(
|
|
array: npt.NDArray[np.float64], src: str, dst: str
|
|
) -> npt.NDArray[np.float64]:
|
|
return colorspacious.cspace_convert(array, src, dst)
|
|
|
|
|
|
# Convert source to JCh color space
|
|
if args.source == "lab":
|
|
solarized_jch = cspace_convert(SOLARIZED_LAB, "CIELab", "JCh")
|
|
else: # rgb
|
|
solarized_jch = cspace_convert(SOLARIZED_RGB, "sRGB255", "JCh")
|
|
|
|
|
|
# Build frogarized theme
|
|
jch_factor: list[float] = [args.lightness_factor, args.chroma_factor, 1]
|
|
jch_shift: list[float] = [0, 0, args.hue_shift]
|
|
frogarized_jch = np.vstack(
|
|
[solarized_jch[:8] * jch_factor + jch_shift, solarized_jch[8:]]
|
|
)
|
|
|
|
# Convert frogarized to RGB
|
|
frogarized_srgb = cspace_convert(frogarized_jch, "JCh", "sRGB255")
|
|
frogarized_rgb = np.asarray(
|
|
np.rint(np.clip(frogarized_srgb, 0, 255)), dtype=np.uint8
|
|
)
|
|
|
|
if args.polarity == "light":
|
|
frogarized_rgb = np.vstack([frogarized_rgb[7::-1], frogarized_rgb[8:]])
|
|
|
|
# Output
|
|
palette: dict[str, str] = {}
|
|
for i in range(16):
|
|
rgb = frogarized_rgb[i]
|
|
r, g, b = rgb
|
|
hexa = f"#{r:02x}{g:02x}{b:02x}"
|
|
palette[f"base{i:02X}"] = hexa
|
|
if args.output == "truecolor":
|
|
print(f"\033[48;2;{r};{g};{b}m{hexa}\033[0m") # ]]
|
|
# treesitter is silly and will consider brackets in strings
|
|
# as indentation, hence the comment above
|
|
if args.output == "json":
|
|
scheme = palette.copy()
|
|
scheme.update(
|
|
{
|
|
"slug": f"frogarized-{args.polarity}",
|
|
"scheme": f"Frogarized {args.polarity.title()}",
|
|
"author": "Geoffrey Frogeye (with work from Ethan Schoonover)",
|
|
}
|
|
)
|
|
print(json.dumps(scheme, indent=4))
|