Prevent internal errors when terminal width or height are very small
[elinks.git] / doc / color-model.txt
bloba874c6fe6a78db36b1f708b210297606c9f319a8
1                                 Color Models
3 The purpose of this document is to collect thoughts and ideas on how to mix and
4 adjust fore- and background colors to improve readability of pages.
6 Motivation
7 ----------
9 ELinks already provides a mean to configure and adjust color combinations to
10 maximize readability. We would like to extend this capability to also include
11 the newly added 256 color mode.
13 For 16 colors, the adjustment is done by doing a few lookups in a hard coded
14 color table. This is fine when there are only 16 * 8 fore- and background
15 combinations but would probably be too painful for 256 * 256 combinations. Also,
16 the hard-coded table - although doing a good job - does not leave much up for the
17 users preferences. So the second goal is to also make the adjustment more
18 configurable so people with color deficiencies can tune the rendering to their
19 needs.
21 Ideas
22 -----
24 Partial sight, aging and congenital color deficits all produce changes in
25 perception that reduce the visual effectiveness of certain color combinations.
26 Two colors that contrast sharply to someone with normal vision may be far less
27 distinguishable to someone with a visual disorder. It is important to appreciate
28 that it is the contrast of colors one against another that makes them more or
29 less discernible rather than the individual colors themselves.
31 I.e., the current allow/forbid dark on black colors will be really simple and far
32 more universal.  Zas is currently researching about rules to preserve page
33 readability by eliminating bad colors combinations (like dark red on dark red
34 or even primary red / primary blue, yellow on white, green on grey, ...). One
35 cool side effect is that we can adapt a color model to take in account some
36 user's visual deficiencies (e.g., rule like "do not use red colors at all", "forbid
37 orange on red", ...) Another color model may take in account screen environment:
38 "ensure very high lightness contrast".
40 Algorithms for determining bad color combinations
41 -------------------------------------------------
43 Zas has some ideas about that: there's no "algorithm" to determine bad color
44 combos, but many experiences, so we'll use common sense (i.e., low lightness
45 contrast, similar colors, white/bright yellow, and more...).
47 Algorithms for finding the nearest good color combination
48 ---------------------------------------------------------
50 This all comes down to applying what ever constraints the user desires:
52 1. given a back- and foreground color pair of RGB colors,
53 2. check if it satisfies all the constraints; if not, make a new couple obtained
54    by successive constraint satisfaction.
56 In some cases, one or more constraints can't be satisfied. For solving that, we
57 just need notions like "hard" / "strong" and "soft" / "weak" constraints.
59 Example
60 -------
62 hard constraint 1 = "no red"
63 hard constraint 2 = "lightness contrast > 50%"
64 hard constraint 3 = "saturation < 90%"
66 soft constraint 1 = "different hues for fg and bg"
67 soft constraint 2 = "foreground darker than background"
68 soft constraint 3 = "no green foreground on blue background"
70 Starting with (bg, fg) = (H=red L=70% S=100%; H=blue L=40% S=95%)
71 hc1 is not satisfied because fg is red, so we just need to move fg away from
72 red.
74 1. hc2 is satisfied.
75 2. hc3 is not satisfied: red and blue are fully saturated.
76 3. sc1 is satisfied.
77 4. sc2 is not satisfied: fg is lighter than bg; so move fg away
78    from lightness, and move bg away from darkness.
79 5. sc3 is satisfied
81 So we have 2 constraints to satisfy, but while doing this we should not make
82 other unsatisfied.
83 Let's try:
84 Sort constraints related to hue, lightness and saturation:
85 hue: hc1, sc1, sc3
86 lightness: hc2, sc2
87 saturation: hc3
89 - Hue constraints satisfaction:
90 A) Nearest not red hue from fg is either green or blue (simpler for now), let
91    choose randomly one: green.
92    Now hc1 is satisfied, sc1 too, and sc3 is not.
94 B) Move fg away from green and red: fg is now blue.
95    Now hc1 is satisfied, sc1 is not, and sc3 is.
97 C) Since we can't satisfy all constraints, reiterate,
98    going back to A). Let move initial fg from red to blue instead of green.
99    Now hc1 is satisfied, sc1 is not, and sc3 too.
101 D) We cannot satisfy hc1 and sc1. Since sc1 is a soft constraint,
102    just ignore it and continue.
104 Finally we have (fg, bg) = (H=blue L=70% S=100%; H=blue L=40% S=95%)
106 - Lightness constraints satisfaction:
107 E) hc2 can be satisfied by either increasing lightness of fg or darkness of bg.
108    We choose to change fg (randomly):
109    (fg, bg) = (H=blue L=90% S=100%; H=blue L=40% S=95%)
111 F) sc2 can be satisfied by swapping fg an bg lightness:
112    (fg, bg) = (H=blue L=40% S=100%; H=blue L=90% S=95%)
114 - Saturation constraints:
115 G) hc3 can be satisfied by decreasing fg and bg saturation values:
116    (fg, bg) = (H=blue L=40% S=89%; H=blue L=90% S=89%)
118 This last couple satisfies all constraints, so we are done ;)
121 How to cache the result and integrate it with the current color system
122 ----------------------------------------------------------------------
124 In the previous example, we supposed we were using a true color palette, but in
125 the most cases, we have a limited number of usable colors.
126 We need to convert (fg, bg) to the nearest available color _before_ constraints
127 satisfaction and at each step of it.
128 When a valid transformation has been found we cache the initial (fg, bg) and the
129 result, and because we can't cache all combos we need to limit cache size to a
130 reasonable value and, sometimes, recalculate.
132 Maybe if the calculations will be really heavy, we can save/restore the combinations
133 to file (~/.elinks/colorhist ;) from session to session.
135 How to make the configuration easy but still powerful
136 -----------------------------------------------------
138 User should be able to describe what he wants or not, so let's try to have our
139 own color-constraint interpreter:
141 One constraint is either hard or soft; it applies to fg, bg or both, and affects
142 either hue, lightness or saturation.
143 Hue unit is either a name (e.g., red) or an angle interval (e.g., for red, [0,30])
144 Lightness and saturation units are a percentage, 0-100%.
145 We'll use only integers values on the user side because it's simpler to handle.
147 Operators are either ! or no, < or lt, > or gt, = or eq, <= or lte, >= or
148 gte, != or ne, >< or hue differences (human sense).
149 Referring to hue, lighness and saturation is done by using these names or H, L,
151 Referring to fg or bg is possible by using fg or ^, bg or _.
152 Delta is expressed by / or delta
153 Conditional is ':'
155 hard constraint 1 = "no red" => "hue no red" == "H![0,30]"
156 hard constraint 2 = "lightness contrast > 50%" => "L delta gt 50"
157 hard constraint 3 = "saturation < 90%" => "saturation < 90"
159 soft constraint 1 = "different hues for fg and bg" => "hue fg >< bg"
160 soft constraint 2 = "foreground darker than background" => "L fg < bg"
161 soft constraint 3 = "no green foreground on blue background" =>
162                     "H bg eq blue: fg ne green"
164 Hmmm, not perfect at all, but it's a start.
166 Maybe the option system can be made to handle it even though it might not be optimal.
168         [-]- Color model
169          |    +-- Enable
170          |    +-- Cache size
171          |   [-]- Hard/Strong
172          |    |   [-]- Hue constraints
173          |    |    |    +- Red (0 or 1 whether to allow this color)
174          |    |    |    : (the basic colors of the color wheel)
175          |    |   [-]- Lightness constraints
176          |    |    |    +- Minimum contrast
177          |    |    |    +- Maximum contrast
178          |    |   [-]- Saturation constraints
179          |    |         +- Minimum saturation
180          |    |         +- Maximum saturation
181          |   [+]- Soft/Weak
183 Rather hostile but quite usable for testing.
185 Including text attributes in the color model
186 --------------------------------------------
188 Hmmm, since we use colors to render text attributes, I (zas) think we need to
189 integrate them in the process.
190 E.g., italics are rendered by color, so let the user tells which color to use.
192 A (bg, fg, type) triplet can be used for that. In constraint definition, we'll
193 have H, S, L and type (T) variables.
194 Type is (link|normal) and/or italic and/or bold and/or underline and/or
195 (subscript|supscript) etc...
196 Note link is not a text attribute (in the terminal sense of it); that's all the
197 magic.
198 Also note that the attribute enhancement should be fully optional.
200 In the solution we'll have (bg, fg, attributes), where bg and fg are colors.
201 Attributes are the ones supported by displaying device (i.e. normal bold underline
202 for now).
204 So constraints will take the form of:
205 link hue != blue : link hue = blue, link attr = bold
206 link hue >< italic hue
207 fg hue in !red
208 fg lightness > bg lightness
209 !(fg hue == yellow && bg hue == white)
210 fg hue >< bg hue
211 fg saturation < 90%
212 bg saturation < 90%
214 Hey, this language is better than the one before ;)
216 More about hues, or "what is red?":
218 Defining hues is not as easy it seems; the main problem here is to know what
219 we talk about when using the red name.
221 Where is the start and the end of red? Applying the KISS principle, let's say that in the HLS
222 system, S < H < E, where S is the starting hue and E the ending one.
223 For each hue we want to express let use a similar non-overlapping interval.
224 Take a circle and divide it in 3 parts for the primary hues, RGB:
225 Make R starts at 0 (hmm, in HLS it's not exactly the case, but NM).
226 Red is [0, 1*360/3[  (no, not a typo, 120 is not red)
227 Green is [1*360/3, 2*360/3[
228 Blue is [2*360/3, 0[
230 It will be convenient to have intermediate hues between red and green ;)
231 So just let divide by a value greater than 3, and name each part.
232 Using 12 subdivisions seems to be sufficient since we want to keep it simple.
233 Each subdivision should be equal but it may not reflect reality of human color
234 perception; using "uniform" color models instead of HLS may help here.
236 Implementation
237 --------------
239 There is some sample code for RGB <-> HSL conversion posted to the elinks-dev
240 mailing list. It is expected to be merged to CVS when the color model itself
241 implementation draws nearer.
243 Availability
244 ------------
246 The color model idea sounds great. However, its usability is probably rather
247 limited and most users could live fine without it (that is not to dispute that
248 it can prove to be unique and invaluable for others). Thus, it should be fully
249 optional both at compile time and runtime.
251 It should still be possible to use only the original 16 colors fg_color xlat
252 table (which is so trivial that its inclusion probably need not be configurable
253 at compile time) because its value is indisputably greater by orders of
254 magnitude for the whole (or most of the) scale of users - the approximation to
255 16 colors is so imprecise that the result is too often far from what the page
256 author intended. Pasky believes that the 256 colors already provide much
257 preciser transformation of the RGB triplet and thus it is quite unlikely the
258 color combinations shown would differ dramatically from the intended look.
260 Jonas: I agree that the color adjustment should be optional like the current
261 one. Especially since the development of this will probably require quite a lot
262 of tuning before being really usable. In the future, with some kind of CSS
263 implementation, the user will have a further possibility to override any unreadable
264 styling. Whether this kind of fix-up will still be necessary only time will show.
265 Anyway since even 256 colors are pretty limited
267 Of course some people want to always force readability over the Web page's
268 author color choice (there is some really sick stuff color-wise around the Web,
269 and of course there are the "secret" black-on-black or white-on-white texts ;-),
270 and people with all sorts of color disabilities (which are quite frequent in the
271 population, AFAIK). This would be a killer feature for them and that is the
272 reason why Pasky thinks that the compile-time option for including of the color
273 models implementation should be by default enabled. Pasky is still not sure
274 whether the color models should be by default enabled or disabled at
275 runtime; pros and cons welcomed.
277 Further reading
278 ---------------
280 Below are listed links to documents that have inspired this work.
282 http://citeseer.nj.nec.com/macintyre91constraintbased.html
284         Selecting harmonious colors for traditional window systems can be a
285         difficult and frustrating endeavor....
287 http://130.113.54.154/~monger/hsl-rgb.html
289         Conversion algorithms for these color spaces are originally from the
290         book Fundamentals of Interactive Computer Graphics by Foley and van Dam
291         (c 1982, Addison-Wesley).
293 http://www.lighthouse.org/color_contrast.htm
295         Basic introduction to usage of HSL colors.
299 vim: textwidth=80