-
Notifications
You must be signed in to change notification settings - Fork 73
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
256 color and 24-bit true color support #60
Comments
Note of, https://www.w3.org/TR/REC-CSS1/#color-units The three-digit RGB notation (#rgb) is converted into six-digit form (#rrggbb) by replicating digits, not by adding zeros. For example, #FB0 expands to #FFBB00. |
I started working on this. Changes pushed to the color branch. So far I have dictionaries mapping 8, 16, 88, and 256 color indexes to RGB values. There's also a dictionary mapping x11 color names to RGB values and a color translator, which supports caching and finds the color closest to the given RGB values in the supported range. In Terminal I added truecolor detection based on what I could find. It's likely to be accurate when detecting true color support, but will miss some. The nice part is, the workaround is just to set an environment variable. Where I hit a wall was in implementing the methods/properties in Terminal. With truecolor support, |
Sorry to be late in responding, I didn't want to respond until I had time to look, I'll be doing that today, I do aim to get this full color support in soon, and this looks very good so far, I'll branch along! Thanks again! |
Will drop support for 88-colorspace, to reduce tests and such. This was unique to "rxvt", which is generally abandoned, and no significant forks exists (RIP, my first unicode terminal urxvt, and first programmable tabbed terminal mrxvt). urxvt is moderately active, but jumping on the truecolor bandwagon too. Interesting that some of these "support" true color, but map to the 256 color space like we will also be doing, for those without COLORTERM defined |
Will drop support for superscript and subscript, though documented as a VT100 code, is unimplemented by almost all common emulators, searches find only discussions that generally come down to 4:3 and monospace fonts being incompatible with the idea, and as unicode support was added became proffered, there are online converters ..
|
On caching, I would prefer the context wrapper functools.lru_cache, but for this library, i prefer not to cache unless necessary, there were caching experiments in the past, fear of costs of dipping into curses, etc., and after writing a few downstream utils, I think its best for downstream to do a 'string builder' pattern -- gather up all the before a display/refresh, and any of those string "parts" can be cached or re-used. |
I think memoization is necessary here because finding the closest color can be expensive. You're basically doing a three dimension distance calculation and comparing the results 256 times every time you convert from truecolor to 256 color. Chances are the end user will use a limited palette but use the same colors multiple times. |
I understand, I won't fight it hard, I'll be working on demo apps and try functools.lru_cache, and backport it if it seems to help enough, but the potential for memoizing up to 16,777,216 results is too great for a sort of shim library, needs to have a maxsize or be backported. I wouldn't expect libraries like blessed have the kind of memory allocation potential, lru cache provides a limit. And as a downstream user doing demoscene art stuff, calculating say more than a few dozen different colors per refresh, I would cache those strings anyway as a part of a buildup. From experience with "x/84 bbs" on gen 1 raspberry pi's, we would cache any repeatidly called string, because even a basic |
Yeah, that's a good point. I could see someone running through all the colors. It definitely needs a limit. I think we could limit it to 100 and that would max out around 24KB or so depending on the way lru_cache is implemented. Looks like backports.functools-lru-cache has been around a while and is being maintained. I do the same thing caching lookups, but I've seen a lot of examples where people are doing formatting lookups over and over again, sometimes within the same string. Sometimes you need to protect people from themselves. |
I've added a setter to |
indigo and hotpink are two examples of colors that don't map to what I think people would expect by RGB distance rather than a weighted HSV. Right now: |
Work looks great! The number_of_colors setter could flush the cache. Do you think we should look at HSV? There's more math there. We could try weighted RGB as described here. |
I spent a lot of time today looking into color conversion. I implemented a weighted rgb which is better and CIE94 which is much better. CIEDE2000 is supposed to be even better, but my implementation isn't, so I must have something messed up in it. It might be worth allowing the algorithm to be changed because we may improve our algorithms in the future and there are trade-offs between resources and accuracy. I was mainly focused on matching 24-bit colors to 256 color using the x11 colors as a sample. I think 8 and 16 color conversions may need to be statically mapped from the 256 color pallet because the numbers are small and the algorithms in small sets like that can have unexpected results. So if we have decent dynamic mapping from 24-bit to 256 color and then statically map to 8 and 16 color, it should result in mostly expected results. I'll try to push what I have soon. |
looks like python colorsys module goes back to python 2.6, https://docs.python.org/2.6/library/colorsys.html so that's available to us, i know what you mean about 8 and 16-color translations being a bit overkill? I'm sure what you have will be fine. |
sorry i touched a bit of the formatters.py, you'll probably find a conflict. run bin/plasma.py and press tab to cycle colorspaces, the 256 colorspace is very slow compared to all others, the 4/8/16 search is perfectly fast. |
That's pretty slick! NIce job! |
Pushed what I have so far. Added a script, colorchart.py, which we can improve or drop later. Output is below with three different algorithms for calculating distance between two colors. These are the X11 colors. first block is the 24-color, second is down-converted to 256 color, then 16 color, and finally 8 color. The 16 and 8 are off by a lot, but I'm going to deal with that later. Just looking at the first two blocks right now. You can see there are slight differences. Still would like to get CIE2000 working, as it's considered the most accurate, but I'll have to take another look at it. |
sounds good, i jotted down two demo utils i wanted earlier in the week, and you pretty much knocked out 1 of 2 -- an "x11 colorpicker", so we're on the same page. thanks! I don't mind alternate algorithms in the tree that we can select the default for, the fastest I guess, and that downstream folks can derive and modify, selecting others in the tree if they like. That's how I'll try to make the API. |
That same script has another function that lists the color names next to colors. Some colors are duplicates like grey# and gray#, so it lists all the names next to the color. If you uncomment the call in I'd also like to sort the colors better, but sorting is even harder than matching. So right now they are sorted alphabetically with some additional natural sort logic so light/dark/medium color number are sorted with the same color. I think that logic could be improved, maybe with color aliases, like snow and ivory for white. Another idea I had was to group by name, again snow/ivory/white, then do an rgb or hsv sort on each group. |
Oh, and as far as an x11 picker. Once Blessed has hyperlink support, we could make the colors clickable and have them target each color like https://www.colorhexa.com/fff8dc or https://www.google.com/search?q=%23FFF8DC |
pushed the api i'm thinking of, and bin/x11_colorpicker.py. also pushed comments into rgb_downconvert:
anyway, its good enough for a release, I'm ready to merge it if you are. I hope that future blessed release doesn't need any color distance algorithms or selections, none of these solutions are particularly fast, as much as I appreciate this effort, I'd much rather find a way to remove all this code and complexity and be sure not to document or test or maintain it. |
I'm going to start merging into master, we won't release to pypi for a few days yet so don't sweat lack of docs, I'd like to do the 2.0 breaking API changes, like move(y, x) -> move(x, y) and so on with this 24-bit color support, I don't wish to juggle branches ! |
Ok, sounds good! I have code for CIE2000 working, but it needs some cleanup. I can wait until you merge into master to push it. We also need to add some caching for rgb_downconvert. I think plasma illustrates the need for that well. Even with the simplest algorithm I get 1 fps with 256 color vs 30 fps in 24-color. The color picker is awesome! I noticed plasma always shows "paused" unless it's showing "please wait". If you're going for 2.0, then #94 should be done at the same time too. I'm not sure what effect it will have on existing code, so best to knock it out when breaking things anyway. |
I decided to go with |
I did some investigation into caching. The only place I could find where caching provided a significant speedup for all use cases was with a 256 item lru cache for rgb_to_lab(). It helps here because the CEI algorithms convert RGB to CEI-Lab for both colors given. One of those colors is the source color, the other is one of the colors in the 256 color palette. The 256 color palette is looked up for every color and the source color is looked up 256 times in a row. Since 0 and 16 are both (0,0,0), that makes 256 the perfect size to hold the 256 color palette and the current source color. While caching in other places could have benefit for some use cases, most of those use cases could also be addressed by saving the result to a variable downstream like you suggested. |
did you ever notice the open pull request for approximate_rgb()? This uses a very fast method, that is equivalent to saying, |
I hadn't seen that. We could add it in and see how it compares. I'm not sure I understand it enough to document it. These seems to assume the 256 color pallette is a summary of a larger color space, but I'm not sure that's true. We also haven't implemented weighted HSV like you suggested. Doing simple HSV is easy, but I'm not sure what the weighting would need to be. It might be worth pulling the conversion algorithms out into their own package. They probably have more utility independently and will get eyes on them from color people rather than just terminal application people. There are some packages that already do this, colour-science, colorio, and colormath, but they tend to do a lot more and have heavy requirements like numpy, scipy, and/or matplotlib. |
This backports upstream issue erikrose#67
Some background: https://gist.github.com/XVilka/8346728
See also erikrose#30 (comment)
In brief: if
number_of_colors
is 256, we can pretty safely assume to support emitting 256 colors, and this is currently possible withterm.color(196)
or some such. However, as a "formatting name" it is deplorable. It would require using a reference guide to map colors-by-number. I actually spent some time trying to find a mapping and came up pretty short, I guess you would run a script that emits all 256, pick the one you like, and note it down.As an API, supporting
{t.bold_color196}
is very much against the "easy to write, easy to read" philosophy that Blessings encourages. What follows is my draft proposal.rgb method
This would be exactly like the existing
color(n)
, except if givenrgb(255, 50, 100)
on a terminal wherenumber_of_colors
is 16, this would be "coerced" (or downsampled) as though you calledrgb(255, 85, 85)
which is exactly the expected color in the CGA palette, emitting the exact same sequence ofterm.bright_red
orcolor(12)
.true_colorspace context manager
This is necessary as a context manager: we cannot determine whether the given terminal emulator supports true colors: There is no
xterm-16777216color
terminal name, or anything like it. There is no situation that I know of where the terminal capability database fornumber_of_colors
could return 16,777,216. A terminal emulator that supports it provides no method to query whether or not it supports it. For those who know their intended audience/emulator, they may rightly go ahead and use them, or provide configuration to enable it through the use of such context manager.Compound Formatters as X11 color names
Use the official X11 color names, http://en.wikipedia.org/wiki/X11_color_names as compound formatters. These are mapped by their hexidecimal values to rgb() to emit the appropriate sequence. This allows one to use "deep_pink", which is (255, 20, 147), but on a 16-color terminal it would be mapped to the same sequence as term.bright_red.
The text was updated successfully, but these errors were encountered: