From 27d6fc7bc52c08e9909a6a9ce3c02a48603d7968 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 2 Aug 2019 21:35:17 +1000 Subject: [PATCH 1/2] Improved HSV conversion --- Tests/test_image_convert.py | 1 + src/libImaging/Convert.c | 180 ++++++++++++++++++++++++++++-------- 2 files changed, 145 insertions(+), 36 deletions(-) diff --git a/Tests/test_image_convert.py b/Tests/test_image_convert.py index 96ecf8996c9..abbd2a45f1d 100644 --- a/Tests/test_image_convert.py +++ b/Tests/test_image_convert.py @@ -23,6 +23,7 @@ def convert(im, mode): "RGBX", "CMYK", "YCbCr", + "HSV", ) for mode in modes: diff --git a/src/libImaging/Convert.c b/src/libImaging/Convert.c index 5df48fb23fe..b31eb1ecc2e 100644 --- a/src/libImaging/Convert.c +++ b/src/libImaging/Convert.c @@ -101,6 +101,19 @@ bit2ycbcr(UINT8* out, const UINT8* in, int xsize) } } +static void +bit2hsv(UINT8* out, const UINT8* in, int xsize) +{ + int x; + for (x = 0; x < xsize; x++, out += 4) { + UINT8 v = (*in++ != 0) ? 255 : 0; + out[0] = 0; + out[1] = 0; + out[2] = v; + out[3] = 255; + } +} + /* ----------------- */ /* RGB/L conversions */ /* ----------------- */ @@ -175,6 +188,19 @@ l2rgb(UINT8* out, const UINT8* in, int xsize) } } +static void +l2hsv(UINT8* out, const UINT8* in, int xsize) +{ + int x; + for (x = 0; x < xsize; x++, out += 4) { + UINT8 v = *in++; + out[0] = 0; + out[1] = 0; + out[2] = v; + out[3] = 255; + } +} + static void la2l(UINT8* out, const UINT8* in, int xsize) { @@ -196,6 +222,19 @@ la2rgb(UINT8* out, const UINT8* in, int xsize) } } +static void +la2hsv(UINT8* out, const UINT8* in, int xsize) +{ + int x; + for (x = 0; x < xsize; x++, in += 4, out += 4) { + UINT8 v = in[0]; + out[0] = 0; + out[1] = 0; + out[2] = v; + out[3] = in[3]; + } +} + static void rgb2bit(UINT8* out, const UINT8* in, int xsize) { @@ -283,54 +322,58 @@ rgb2bgr24(UINT8* out, const UINT8* in, int xsize) } static void -rgb2hsv(UINT8* out, const UINT8* in, int xsize) +rgb2hsv_row(UINT8* out, const UINT8* in) { // following colorsys.py float h,s,rc,gc,bc,cr; UINT8 maxc,minc; UINT8 r, g, b; UINT8 uh,us,uv; - int x; - for (x = 0; x < xsize; x++, in += 4) { - r = in[0]; - g = in[1]; - b = in[2]; - - maxc = MAX(r,MAX(g,b)); - minc = MIN(r,MIN(g,b)); - uv = maxc; - if (minc == maxc){ - *out++ = 0; - *out++ = 0; - *out++ = uv; + r = in[0]; + g = in[1]; + b = in[2]; + maxc = MAX(r,MAX(g,b)); + minc = MIN(r,MIN(g,b)); + uv = maxc; + if (minc == maxc){ + uh = 0; + us = 0; + } else { + cr = (float)(maxc-minc); + s = cr/(float)maxc; + rc = ((float)(maxc-r))/cr; + gc = ((float)(maxc-g))/cr; + bc = ((float)(maxc-b))/cr; + if (r == maxc) { + h = bc-gc; + } else if (g == maxc) { + h = 2.0 + rc-bc; } else { - cr = (float)(maxc-minc); - s = cr/(float)maxc; - rc = ((float)(maxc-r))/cr; - gc = ((float)(maxc-g))/cr; - bc = ((float)(maxc-b))/cr; - if (r == maxc) { - h = bc-gc; - } else if (g == maxc) { - h = 2.0 + rc-bc; - } else { - h = 4.0 + gc-rc; - } - // incorrect hue happens if h/6 is negative. - h = fmod((h/6.0 + 1.0), 1.0); - - uh = (UINT8)CLIP8((int)(h*255.0)); - us = (UINT8)CLIP8((int)(s*255.0)); + h = 4.0 + gc-rc; + } + // incorrect hue happens if h/6 is negative. + h = fmod((h/6.0 + 1.0), 1.0); - *out++ = uh; - *out++ = us; - *out++ = uv; + uh = (UINT8)CLIP8((int)(h*255.0)); + us = (UINT8)CLIP8((int)(s*255.0)); + } + out[0] = uh; + out[1] = us; + out[2] = uv; +} - } - *out++ = in[3]; +static void +rgb2hsv(UINT8* out, const UINT8* in, int xsize) +{ + int x; + for (x = 0; x < xsize; x++, in += 4, out += 4) { + rgb2hsv_row(out, in); + out[3] = in[3]; } } + + static void hsv2rgb(UINT8* out, const UINT8* in, int xsize) { // following colorsys.py @@ -562,6 +605,22 @@ cmyk2rgb(UINT8* out, const UINT8* in, int xsize) } } +static void +cmyk2hsv(UINT8* out, const UINT8* in, int xsize) +{ + int x, nk, tmp; + for (x = 0; x < xsize; x++) { + nk = 255 - in[3]; + out[0] = CLIP8(nk - MULDIV255(in[0], nk, tmp)); + out[1] = CLIP8(nk - MULDIV255(in[1], nk, tmp)); + out[2] = CLIP8(nk - MULDIV255(in[2], nk, tmp)); + rgb2hsv_row(out, out); + out[3] = 255; + out += 4; + in += 4; + } +} + /* ------------- */ /* I conversions */ /* ------------- */ @@ -631,6 +690,24 @@ i2rgb(UINT8* out, const UINT8* in_, int xsize) } } +static void +i2hsv(UINT8* out, const UINT8* in_, int xsize) +{ + int x; + INT32* in = (INT32*) in_; + for (x = 0; x < xsize; x++, in++, out+=4) { + out[0] = 0; + out[1] = 0; + if (*in <= 0) + out[2] = 0; + else if (*in >= 255) + out[2] = 255; + else + out[2] = (UINT8) *in; + out[3] = 255; + } +} + /* ------------- */ /* F conversions */ /* ------------- */ @@ -861,6 +938,7 @@ static struct { { "1", "RGBX", bit2rgb }, { "1", "CMYK", bit2cmyk }, { "1", "YCbCr", bit2ycbcr }, + { "1", "HSV", bit2hsv }, { "L", "1", l2bit }, { "L", "LA", l2la }, @@ -871,6 +949,7 @@ static struct { { "L", "RGBX", l2rgb }, { "L", "CMYK", l2cmyk }, { "L", "YCbCr", l2ycbcr }, + { "L", "HSV", l2hsv }, { "LA", "L", la2l }, { "LA", "La", lA2la }, @@ -879,6 +958,7 @@ static struct { { "LA", "RGBX", la2rgb }, { "LA", "CMYK", la2cmyk }, { "LA", "YCbCr", la2ycbcr }, + { "LA", "HSV", la2hsv }, { "La", "LA", la2lA }, @@ -887,6 +967,7 @@ static struct { { "I", "RGB", i2rgb }, { "I", "RGBA", i2rgb }, { "I", "RGBX", i2rgb }, + { "I", "HSV", i2hsv }, { "F", "L", f2l }, { "F", "I", f2i }, @@ -915,6 +996,7 @@ static struct { { "RGBA", "RGBX", rgb2rgba }, { "RGBA", "CMYK", rgb2cmyk }, { "RGBA", "YCbCr", ImagingConvertRGB2YCbCr }, + { "RGBA", "HSV", rgb2hsv }, { "RGBa", "RGBA", rgba2rgbA }, @@ -926,10 +1008,12 @@ static struct { { "RGBX", "RGB", rgba2rgb }, { "RGBX", "CMYK", rgb2cmyk }, { "RGBX", "YCbCr", ImagingConvertRGB2YCbCr }, + { "RGBX", "HSV", rgb2hsv }, { "CMYK", "RGB", cmyk2rgb }, { "CMYK", "RGBA", cmyk2rgb }, { "CMYK", "RGBX", cmyk2rgb }, + { "CMYK", "HSV", cmyk2hsv }, { "YCbCr", "L", ycbcr2l }, { "YCbCr", "LA", ycbcr2la }, @@ -1101,6 +1185,28 @@ pa2rgb(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) } } +static void +p2hsv(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) +{ + int x; + for (x = 0; x < xsize; x++, out += 4) { + const UINT8* rgb = &palette[*in++ * 4]; + rgb2hsv_row(out, rgb); + out[3] = 255; + } +} + +static void +pa2hsv(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) +{ + int x; + for (x = 0; x < xsize; x++, in += 4, out += 4) { + const UINT8* rgb = &palette[in[0] * 4]; + rgb2hsv_row(out, rgb); + out[3] = 255; + } +} + static void p2rgba(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) { @@ -1192,6 +1298,8 @@ frompalette(Imaging imOut, Imaging imIn, const char *mode) convert = alpha ? pa2cmyk : p2cmyk; else if (strcmp(mode, "YCbCr") == 0) convert = alpha ? pa2ycbcr : p2ycbcr; + else if (strcmp(mode, "HSV") == 0) + convert = alpha ? pa2hsv : p2hsv; else return (Imaging) ImagingError_ValueError("conversion not supported"); From 76e5bd0f0f1c74cb00e02a2b9ff78607e4c49ca2 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 6 Sep 2019 20:07:23 +1000 Subject: [PATCH 2/2] Added brackets --- src/libImaging/Convert.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libImaging/Convert.c b/src/libImaging/Convert.c index b31eb1ecc2e..60513c66d5e 100644 --- a/src/libImaging/Convert.c +++ b/src/libImaging/Convert.c @@ -698,12 +698,13 @@ i2hsv(UINT8* out, const UINT8* in_, int xsize) for (x = 0; x < xsize; x++, in++, out+=4) { out[0] = 0; out[1] = 0; - if (*in <= 0) + if (*in <= 0) { out[2] = 0; - else if (*in >= 255) + } else if (*in >= 255) { out[2] = 255; - else + } else { out[2] = (UINT8) *in; + } out[3] = 255; } }