-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RGB -> XTerm256 approximation? #473
Comments
I think this already exists. See https://github.com/KristofferC/Crayons.jl |
Crayons.jl has the conversion feature, but I don't think there is a public API just for the conversion. At least, Crayons.jl does not provide an interface to the types defined in ColorTypes.jl. |
Note that I have considered this issue before, and I realized that finding an approximate color is not so easy. |
Micah gave me permission to make public the ported code. You can find it in this gist, though it will probably need a lot of clean-up (see original gist for more detail and notes in comments). I also contacted Kristoffer, who wrote Crayons.jl. This is what he wrote. This is very reminiscent of this comment in the original gist. Perhaps someone that knows more about colours can shed some light on which method might be better. Let me know what you think @kimikage. |
At least, as I mentioned above, the current implementations of Crayons.jl and ImageInTerminal.jl assume so-called web-safe colors, not so-called terminal colors. Therefore, the gist version is better WRT the palette. The problem is how to find the closest color. On the other hand, converting from a terminal color (index) to RGB is easy. using Colors, FixedPointNumbers
_to_term_tone256(v::Integer) = v * 0x28 + (v === zero(v) ? 0x00 : 0x37)
function from_term256(i::Integer)
i8 = i % UInt8
if i8 < 0x10
term16 = RGB.(reinterpret.(RGB24, (0x000000, 0x800000, 0x008000, 0x808000,
0x000080, 0x800080, 0x008080, 0xc0c0c0,
0x808080, 0xff0000, 0x00ff00, 0xffff00,
0x0000ff, 0xff00ff, 0x00ffff, 0xffffff)))
return @inbounds term16[i8 + 1]
elseif i8 < 0xe8
c = i8 - 0x10
r = _to_term_tone256(c ÷ 0x24) % UInt8
g = _to_term_tone256((c ÷ 0x6) % 0x6) % UInt8
b = _to_term_tone256(c % 0x6) % UInt8
return RGB(reinterpret.(N0f8, (r, g, b))...)
else
c = i8 - 0xe8
return RGB(reinterpret(N0f8, c * 0xa + 0x8))
end
end |
I'm not happy with it's performance, but the following just works. _to_term_tone6(v::UInt8) = (((max(v, 0x4a) + 0x0005) * 0x00cd) >> 0xd) - 0x1
to_term256(@nospecialize(c::Color)) = to_term256(RGB24(c))
function to_term256(c::C) where C <: AbstractRGB
rgb = RGB24(c)
r0 = reinterpret(red(rgb))
g0 = reinterpret(green(rgb))
b0 = reinterpret(blue(rgb))
rt = _to_term_tone6(r0)
gt = _to_term_tone6(g0)
bt = _to_term_tone6(b0)
d = max(r0, g0, b0) - min(r0, g0, b0)
if (rt === gt === bt) || d < 0x15
gr16 = 0x003d * r0 + 0x0079 * g0 + 0x0017 * b0
ths = (0x04, 0x5c, 0x61, 0x84, 0x89, 0xac, 0xb1, 0xd4, 0xd9, 0xf7) .* 0x00cd
if mapreduce(th -> gr16 < th, ⊻, ths; init=false)
return Int(min((gr16 - 0x0334) >> 0xb, 0x17)) + 232
end
end
return Int(rt * 0x24 + gt * 0x6 + bt) + 16
end |
The left shows the nearest neighbor colors based on There are several possible approaches to improve the conversion, but there are the following problems.
|
As long as round-trip compatibility is ensured for 240 colors, there is no need to maintain compatibility for the rest. So, I think improvements can be left as a future task. The other thing we need to decide is the API design. |
I know very little about this. My understanding is that you're going to add this into Colors.jl. Just curious to ask, is there any reason that we can't add/extend this functionality inside Crayons?
Both |
Crayons.jl is not dependent on ColorTypes.jl. That's both an advantage and a disadvantage. I am not in a position to decide its dependency. |
This is off-topic, but is there a package for color quantization or color reduction in the JuliaImages ecosystem? |
I think I've supported this feature in JuliaImages/ImageInTerminal.jl#62... Maybe I should just port the codes to Colors? |
Hi there! A few months back, I wrote a port of this gist to convert RGB to XTerm256 colours (or their nearest approximation).
I don't know much about colours. This might have been done in this Colors.jl package, but obfuscated by the technical names of the colour spaces. However, if this hasn't been done, I can add this code to here in a PR. If I found it useful, maybe someone else will.
Is this the best place for such a function?
P.S., in the process of getting permission from Micah Elliott (the original author of the code) to publish the port. Will credit them at the top of the script.
The text was updated successfully, but these errors were encountered: