Skip to content

Commit 25acdbf

Browse files
committed
simplify rgb to hsv conversion
By inlining some values, the starting hue calculation can be reduced from using three subtractions and two divisions to using one subtraction and one division. "fmod(n+1,1)" can be replaced with "n - floor(n)" due to the second parameter being 1. The saturation calculation can be done without floating point values. The "CLIP8"s are unnecessary because the values are already in the correct range.
1 parent f614580 commit 25acdbf

File tree

1 file changed

+32
-25
lines changed

1 file changed

+32
-25
lines changed

src/libImaging/Convert.c

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -310,40 +310,46 @@ rgb2bgr24(UINT8 *out, const UINT8 *in, int xsize) {
310310
}
311311

312312
static void
313-
rgb2hsv_row(UINT8 *out, const UINT8 *in) { // following colorsys.py
314-
float h, s, rc, gc, bc, cr;
315-
UINT8 maxc, minc;
316-
UINT8 r, g, b;
317-
UINT8 uh, us, uv;
318-
319-
r = in[0];
320-
g = in[1];
321-
b = in[2];
322-
maxc = MAX(r, MAX(g, b));
323-
minc = MIN(r, MIN(g, b));
324-
uv = maxc;
313+
rgb2hsv_row(UINT8 *out, const UINT8 *in) {
314+
// based on Python's colorsys module
315+
316+
const UINT8 r = in[0];
317+
const UINT8 g = in[1];
318+
const UINT8 b = in[2];
319+
320+
const UINT8 maxc = MAX(r, MAX(g, b));
321+
const UINT8 minc = MIN(r, MIN(g, b));
322+
323+
UINT8 uh, us;
324+
const UINT8 uv = maxc;
325+
325326
if (minc == maxc) {
326327
uh = 0;
327328
us = 0;
328329
} else {
329-
cr = (float)(maxc - minc);
330-
s = cr / (float)maxc;
331-
rc = ((float)(maxc - r)) / cr;
332-
gc = ((float)(maxc - g)) / cr;
333-
bc = ((float)(maxc - b)) / cr;
330+
const UINT8 color_range = maxc - minc;
331+
double h;
332+
333+
const double cr = (double)color_range;
334334
if (r == maxc) {
335-
h = bc - gc;
335+
h = (g - b) / cr;
336336
} else if (g == maxc) {
337-
h = 2.0 + rc - bc;
337+
h = 2.0 + (b - r) / cr;
338338
} else {
339-
h = 4.0 + gc - rc;
339+
h = 4.0 + (r - g) / cr;
340340
}
341-
// incorrect hue happens if h/6 is negative.
342-
h = fmod((h / 6.0 + 1.0), 1.0);
343341

344-
uh = (UINT8)CLIP8((int)(h * 255.0));
345-
us = (UINT8)CLIP8((int)(s * 255.0));
342+
// the modulus operator in Python does not exactly match
343+
// the modulus operator or the fmod function in C
344+
// https://stackoverflow.com/a/3883019/3878168
345+
// "h = (h/6.0) % 1.0" in Python can be computed as:
346+
h = h / 6.0;
347+
h = h - floor(h);
348+
349+
uh = (UINT8)(255.0 * h);
350+
us = 255 * color_range / maxc;
346351
}
352+
347353
out[0] = uh;
348354
out[1] = us;
349355
out[2] = uv;
@@ -359,7 +365,8 @@ rgb2hsv(UINT8 *out, const UINT8 *in, int xsize) {
359365
}
360366

361367
static void
362-
hsv2rgb(UINT8 *out, const UINT8 *in, int xsize) { // following colorsys.py
368+
hsv2rgb(UINT8 *out, const UINT8 *in, int xsize) {
369+
// based on Python's colorsys module
363370

364371
int p, q, t;
365372
UINT8 up, uq, ut;

0 commit comments

Comments
 (0)