Generating good terminal colors
The popular software pywal is a great way to quickly set your wallpaper and have your terminal reflect the wallpapers colors in its appearance. However it has a quite serious flaw: The generated colors do not match the semantic ones. In other words if your wallpaper is mostl blue, then the color the would be red in your color scheme most likely will appear blue, simply because it is the first color assigned a value. This can lead to certain terminal output or TUIs not being displayed correctly. Or rather: being viewed and understood correctly.
So I set out for a mission to generate some actually good colors for the terminal, given an arbitrary image as an input. This article will only just touch upon the basic ideas I have so far.
Abstraction
To start off, let's abstract the objective: The goal is to get the most prominent colors of an arbitrary image sorted by the ANSI terminal color which they are most closely related to.
To achieve this, we might want to first get the top n colors of an image. From there we would need to determine where in that color-space our the ideal ANSI terminal colors, s.v. anchors are, and which colors are closest to them. With higher n we would have better precision, yet higher computation time.
Throwing together a working example
For now, I will be using a library to do all the work. For performance or feature-oriented reasons this might change, but for now this will do:
# NOTE: The arguments to this function were stolen from the library's internal code.
=
=
# This just normalizes the colors from the colorz library so I can work with them better.
=
=
=
=
Notice that I have a dictionary called terminal_colors
. It contains each anchor and it's corresponding hue value in degrees in the https://en.wikipedia.org/wiki/HSL_and_HSV[HSL] color space.
// image:/assets/blog/hsl_cylinder.png[width=200px]
# (color, key, hue_offset, distane) of color with minimal distance yet
=
=
,
=
# set terminal_colors[key] to a better color
At the very end, I just forumalte a proper list of colors. This is just the ANSI colors in the previously used order. I add my own shades of gray though.
=
# my favorite constant black
# my favorite constant white
To get the distance, I use the following function. Notice that this is just a weird way to calculate the norm of a delta vector of the RGB color space. This should also be optimized (and possible rethought) later.
I personally would like to use the HSL color space, since it should make calculations easier. And the conversion from RGB to HSL and vice versa introduces a distortion.
=
= .
=
=
=
=
return ,
On the other hand, get_distance
ist basically just Pythagoras' Theorem.
# TODO: Use hsl / hsv instead of rgb
return
Results
The results are somewhat underwhelming, I must admit. But this is most likely due to:
- There is nothing to make sure the colors actually work together.
- Approxmiation to ideal, yet unnatural colors
- Maybe color space conversion?
Once those are fixed, I believe to have quite an ineresting software on my hands. But for now this will do. Until then, this work is to be procrastinated! Unless I need it again...