2014-05-22 1:57 GMT+04:00 Roberto E. Vargas Caballero <k...@shike2.com>: >> Read this: http://www.4p8.com/eric.brasseur/gamma.html >> >> We need to generally re-think the algorithm used here. I hate the idea >> of being conformant to this or that terminal emulator and instead >> prefer an implementation according to how it's defined (!). > > I like this idea, but I don't know how it could be implemented.
The obvious idea is to convert a colour to HSV/HSL, increase brightness, and convert it back (One cannot help but notice that such a calculation is a matter of initialization, since appropriate bright colours may be calculated for all built-in colours in advance. Therefore, one possible solution may be to modify dc.col (also xloadcols and xsetcolorname) to have structures, containing normal and bold variants for a colour.) After this point, dragons lie. In HSV model, there are notions of Value, which is equal to maximum among colors, and Saturation, which is 1 - Max/Min. Thus, Max = V, Min = V (1 - S). Then, R = r * Max + (1 - r) * Min = V * (r + (1 - r) * (1 - S)), G = g * Max + (1 - g) * Min = ..., and so on, and r, g, b depend only on Hue. It is then trivial to see that a change in Brightness is a trivial rescale: R_{new} = V_{new} * R_{old}/V_{old}. (In linear space, not gamma space.) It's a simple calculation indeed, but, as XTerm cube contains a lot of colours close to pure, it may not look appropriate. In HSL model, there are notions of Saturation and Lightness. Saturation is calculated as (Max - Min)/(1 - |1 - (Max + Min)|), and Lightness as (Max + Min)/2. Thus, reverse calculations of Max and Min are a little more involved, but the general truth remains the same: all colour components are convex combinations between Max and Min, whose coefficients depend only on Hue. Thus, for R coordinate for example, R_{new} = (R_{old} - Min_{old}) / (Max_{old} - Min_{old}) * (Max_{new} - Min_{new}) + Min_{new}. It's the same rescaling but with two points instead of one. (I cannot emphanise enough that we DO NOT need luminance or perceived brightness here. These define the brightness of all colours to come common reference point, whereas lightness/value define brightness relative to a reference color of the same hue. Which is exactly what we need. Default colors are of different brightnesses, and this is not our concern.) Let us now estimate how precise should we be in our tables of sRGB <-> linear conversion. Let's say that, for the simplicity, we use the evenly-spaced table and linear interpolation. (Dreadful.) The error is estimated thus by h^2 * 1/8 max(f''(x)). for sRGB->linear, the constant is 3.429/8 = 0.428. Let's say we want the precision of 2e-16, which is totally reasonable considering that we use 16-bit color model. And I might say, is ain't so bad! We merely need ~170 data points. Let's go big and make it 257. (Then, the index for a 16-bit integer is just number>>8.) As for the reverse transofrmation, there we experience a big uprise around zero. In fact, the second derivative peaks at ~-2300, which is indeed true: the function curves a lot there, and interpolating it is the world of trouble, requiring ~4300 points, which is distressingly only slightly more than 4096. Makes things even worse. Fortunately, we happen to know the reverse function for this one, which is not only pretty smooth - but we also have a table for it! So the task results in binary search in aforementioned table (of size 257, I might remind you, so it's more or less instant) and doing a linear interpolation afterwards. Slower, but saves us a lot of trouble! Thus, the proposal requires addition of: - the table of 16-bit integers of size 257; - the function of interpolating y given x1, x2, y1, y2 and x; - the function of increasing a given color's brightness; - possibly changes to dc.col, depending on how costly it will be to do such calculations on the fly vs in the initialization. -- Best regards, Alexander Sedov.