st-minimumcontrast-20241029-0.9.2.diff - sites - public wiki contents of suckle… | |
git clone git://git.suckless.org/sites | |
Log | |
Files | |
Refs | |
--- | |
st-minimumcontrast-20241029-0.9.2.diff (5744B) | |
--- | |
1 From b0601465dc4d654485db7c3bcb28e019b21e78ca Mon Sep 17 00:00:00 2001 | |
2 From: Nick Lott <[email protected]> | |
3 Date: Sun, 13 Oct 2024 11:14:38 +1300 | |
4 Subject: [PATCH] Add minimum contrast ratio feature | |
5 | |
6 --- | |
7 Makefile | 2 +- | |
8 config.def.h | 6 +++ | |
9 contrast.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++ | |
10 contrast.h | 11 ++++ | |
11 x.c | 12 +++++ | |
12 5 files changed, 176 insertions(+), 1 deletion(-) | |
13 create mode 100644 contrast.c | |
14 create mode 100644 contrast.h | |
15 | |
16 diff --git a/Makefile b/Makefile | |
17 index 15db421..893c71b 100644 | |
18 --- a/Makefile | |
19 +++ b/Makefile | |
20 @@ -4,7 +4,7 @@ | |
21 | |
22 include config.mk | |
23 | |
24 -SRC = st.c x.c | |
25 +SRC = st.c x.c contrast.c | |
26 OBJ = $(SRC:.c=.o) | |
27 | |
28 all: st | |
29 diff --git a/config.def.h b/config.def.h | |
30 index 2cd740a..03eed3a 100644 | |
31 --- a/config.def.h | |
32 +++ b/config.def.h | |
33 @@ -134,6 +134,12 @@ unsigned int defaultbg = 259; | |
34 unsigned int defaultcs = 256; | |
35 static unsigned int defaultrcs = 257; | |
36 | |
37 + | |
38 +/* | |
39 +* Minimum contrast ratio (1-21) | |
40 +*/ | |
41 +const float min_contrast_ratio = 2.2f; | |
42 + | |
43 /* | |
44 * Default shape of cursor | |
45 * 2: Block ("█") | |
46 diff --git a/contrast.c b/contrast.c | |
47 new file mode 100644 | |
48 index 0000000..d956bd6 | |
49 --- /dev/null | |
50 +++ b/contrast.c | |
51 @@ -0,0 +1,146 @@ | |
52 +#include <math.h> | |
53 + | |
54 +#include "contrast.h" | |
55 + | |
56 + | |
57 +/* Linear RGB floating point color space for use in calculations */ | |
58 +typedef struct { | |
59 + float r; | |
60 + float g; | |
61 + float b; | |
62 + float l; | |
63 +} RGBf; | |
64 + | |
65 + | |
66 + | |
67 +static float | |
68 +sRGB_to_lin(const unsigned short c) | |
69 +{ | |
70 + /* Convert to normalized float. */ | |
71 + const float f = c / 65535.0f; | |
72 + | |
73 + /* Convert from sRGB to linear space. */ | |
74 + return (f <= 0.03928f) ? f / 12.92f : pow((f + 0.055f) / 1.055f… | |
75 +} | |
76 + | |
77 + | |
78 + | |
79 +static unsigned short | |
80 +lin_to_sRGB(const float c) | |
81 +{ | |
82 + /* Convert to sRGB space. */ | |
83 + const float f = (c <= 0.0031308f) ? | |
84 + 12.92f * c : 1.055f * pow(c, 1.0f / 2.4f)… | |
85 + | |
86 + /* Clamp and convert back to 16-bit values. */ | |
87 + return (unsigned short)(fminf(fmaxf(f * 65535.0f, 0.0f),… | |
88 +} | |
89 + | |
90 + | |
91 + | |
92 +static RGBf | |
93 +XftColor_to_RGBf( XftColor const * const c ) | |
94 +{ | |
95 + const float r = sRGB_to_lin(c->color.red); | |
96 + const float g = sRGB_to_lin(c->color.green); | |
97 + const float b = sRGB_to_lin(c->color.blue); | |
98 + | |
99 + /* Calculate luminance. */ | |
100 + const float l = 0.2126f * r + 0.7152f * g + 0.0722f * b; | |
101 + | |
102 + return (RGBf) {r, g, b, l}; | |
103 +} | |
104 + | |
105 + | |
106 + | |
107 +static void | |
108 +RGBf_to_XftColor( const RGBf rgb, XftColor * const c) | |
109 +{ | |
110 + c->color.red = lin_to_sRGB(rgb.r); | |
111 + c->color.green = lin_to_sRGB(rgb.g); | |
112 + c->color.blue = lin_to_sRGB(rgb.b); | |
113 +} | |
114 + | |
115 + | |
116 + | |
117 +static float | |
118 +get_luminance(XftColor const * const c) | |
119 +{ | |
120 + const RGBf rgb = XftColor_to_RGBf(c); | |
121 + return rgb.l; | |
122 +} | |
123 + | |
124 + | |
125 + | |
126 +static float | |
127 +get_contrast_ratio(const float fg_lum, const float bg_lum) | |
128 +{ | |
129 + if (fg_lum > bg_lum) { | |
130 + return (fg_lum + 0.05f) / (bg_lum + 0.05f); | |
131 + } else { | |
132 + return (bg_lum + 0.05f) / (fg_lum + 0.05f); | |
133 + } | |
134 +} | |
135 + | |
136 + | |
137 + | |
138 +static void | |
139 +adjust_luminance(XftColor * const c, const float adjustment) | |
140 +{ | |
141 + /* Convert sRGB to linear space and calculate luminance. */ | |
142 + RGBf rgb = XftColor_to_RGBf(c); | |
143 + | |
144 + /* Adjust luminance, clamping to 0-100% */ | |
145 + const float factor = fminf(fmaxf(rgb.l + adjustment, 0.0f), 1.0… | |
146 + rgb.r *= factor; | |
147 + rgb.g *= factor; | |
148 + rgb.b *= factor; | |
149 + | |
150 + /* Convert back to sRGB space. */ | |
151 + RGBf_to_XftColor(rgb, c); | |
152 +} | |
153 + | |
154 + | |
155 +static float | |
156 +get_luminance_adjustment( float fl, float bl, float contrast ) | |
157 +{ | |
158 + /* Increase existing any luminance difference to get contrast. … | |
159 + float adjustment = (bl > fl)? | |
160 + ((((bl + 0.05f) / min_contrast_ratio) - 0.05f) - fl) : | |
161 + (((min_contrast_ratio * (bl + 0.05f)) - 0.05f) - fl); | |
162 + | |
163 + const float new_lum = fl + adjustment; | |
164 + | |
165 + /* Use the opposite direction if we exceed valid luminance rang… | |
166 + if (new_lum < 0.0 || new_lum > 1.0) { | |
167 + adjustment = (bl <= fl)? | |
168 + ((((bl + 0.05f) / min_contrast_ratio) - 0.05f) - fl… | |
169 + (((min_contrast_ratio * (bl + 0.05f)) - 0.05f) - fl… | |
170 + } | |
171 + | |
172 + return adjustment; | |
173 +} | |
174 + | |
175 + | |
176 +void | |
177 +adjust_color_for_contrast(XftColor * const fg, XftColor * const bg) | |
178 +{ | |
179 + float fl = get_luminance(fg); | |
180 + const float bl = get_luminance(bg); | |
181 + const float contrast = get_contrast_ratio(fl, bl); | |
182 + | |
183 + if (contrast < min_contrast_ratio) { | |
184 + /* Change black to dark grey so the luminance calculati… | |
185 + if (fl < 0.00001) { | |
186 + fg->color.red = 0x1fff; | |
187 + fg->color.green = 0x1fff; | |
188 + fg->color.blue = 0x1fff; | |
189 + fl = get_luminance(fg); | |
190 + } | |
191 + | |
192 + const float adjustment = get_luminance_adjustment( | |
193 + fl, bl, min_contrast_ratio… | |
194 + | |
195 + adjust_luminance(fg, adjustment); | |
196 + } | |
197 +} | |
198 diff --git a/contrast.h b/contrast.h | |
199 new file mode 100644 | |
200 index 0000000..2aa6dd3 | |
201 --- /dev/null | |
202 +++ b/contrast.h | |
203 @@ -0,0 +1,11 @@ | |
204 +#ifndef __ST_CONTRAST_H_ | |
205 +#define __ST_CONTRAST_H_ | |
206 + | |
207 +#include <X11/Xft/Xft.h> | |
208 + | |
209 +void adjust_color_for_contrast(XftColor * const , XftColor * const ); | |
210 + | |
211 +/* config.h globals */ | |
212 +extern const float min_contrast_ratio; | |
213 + | |
214 +#endif | |
215 diff --git a/x.c b/x.c | |
216 index bd23686..4c79e52 100644 | |
217 --- a/x.c | |
218 +++ b/x.c | |
219 @@ -19,6 +19,7 @@ char *argv0; | |
220 #include "arg.h" | |
221 #include "st.h" | |
222 #include "win.h" | |
223 +#include "contrast.h" | |
224 | |
225 /* types used in config.h */ | |
226 typedef struct { | |
227 @@ -1478,6 +1479,17 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs… | |
228 if (winy + win.ch >= borderpx + win.th) | |
229 xclear(winx, winy + win.ch, winx + width, win.h); | |
230 | |
231 + | |
232 + /* | |
233 + * Adjust colours to enforce a minimum contrast. Using the loca… | |
234 + * here to ensure we don't alter the dc.cols table permanently. | |
235 + */ | |
236 + fg = memcpy( &truefg, fg, sizeof(Color)); | |
237 + bg = memcpy( &truebg, bg, sizeof(Color)); | |
238 + | |
239 + adjust_color_for_contrast( fg, bg); | |
240 + | |
241 + | |
242 /* Clean up the region we want to draw to. */ | |
243 XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); | |
244 | |
245 -- | |
246 2.34.1 | |
247 |