From 68e39815977c406b8ec39ee3e2fe975087b66303 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 22 Apr 2011 13:19:09 -0400 Subject: Make colors less abstract. --- libdimension/color.c | 308 +++-------------------------------------- libdimension/dimension/color.h | 98 ++++--------- libdimension/gl.c | 67 ++++----- libdimension/png.c | 145 +++++++------------ 4 files changed, 123 insertions(+), 495 deletions(-) (limited to 'libdimension') diff --git a/libdimension/color.c b/libdimension/color.c index 0af063f..24a4574 100644 --- a/libdimension/color.c +++ b/libdimension/color.c @@ -24,12 +24,6 @@ */ #include "dimension.h" -#include /* For pow(), sqrt() */ - -/* sRGB white point (CIE D50) */ -const dmnsn_CIE_XYZ dmnsn_whitepoint = { .X = 0.9504060171449392, - .Y = 0.9999085943425312, - .Z = 1.089062231497274 }; /* Standard colors */ const dmnsn_color dmnsn_black = { @@ -103,252 +97,19 @@ const dmnsn_color dmnsn_cyan = { .trans = 0.0 }; -bool -dmnsn_color_is_black(dmnsn_color color) -{ - return color.R == 0.0 && color.G == 0.0 && color.B == 0.0; -} - -/* Convert an sRGB color to a dmnsn_color (actually a no-op) */ -dmnsn_color -dmnsn_color_from_sRGB(dmnsn_sRGB sRGB) -{ - dmnsn_color ret = { - .R = sRGB.R, - .G = sRGB.G, - .B = sRGB.B, - .filter = 0.0, - .trans = 0.0 - }; - return ret; -} - -/** sRGB's `C' function. */ -static double -dmnsn_sRGB_C(double Clinear) -{ - /* - * If C represents R, G, and B, then the sRGB values are now found as follows: - * - * { 12.92*Clinear, Clinear <= 0.0031308 - * Csrgb = { 1/2.4 - * { (1.055)*Clinear - 0.055, Clinear > 0.0031308 - */ - if (Clinear <= 0.0031308) { - return 12.92*Clinear; - } else { - return 1.055*pow(Clinear, 1.0/2.4) - 0.055; - } -} - -/* Convert a CIE XYZ color to a dmnsn_color */ -dmnsn_color -dmnsn_color_from_XYZ(dmnsn_CIE_XYZ XYZ) -{ - dmnsn_color color = { - .R = 3.2410*XYZ.X - 1.5374*XYZ.Y - 0.4986*XYZ.Z, - .G = -0.9692*XYZ.X + 1.8760*XYZ.Y + 0.0416*XYZ.Z, - .B = 0.0556*XYZ.X - 0.2040*XYZ.Y + 1.0570*XYZ.Z, - .filter = 0.0, - .trans = 0.0 - }; - color.R = dmnsn_sRGB_C(color.R); - color.G = dmnsn_sRGB_C(color.G); - color.B = dmnsn_sRGB_C(color.B); - return color; -} - -/* Convert a CIE xyY color to a dmnsn_color */ -dmnsn_color -dmnsn_color_from_xyY(dmnsn_CIE_xyY xyY) -{ - dmnsn_CIE_XYZ ret = { - .X = xyY.Y*xyY.x/xyY.y, - .Y = xyY.Y, - .Z = xyY.Y*(1.0 - xyY.x - xyY.y)/xyY.y, - }; - return dmnsn_color_from_XYZ(ret); -} - -/** Inverse function of CIE L*a*b*'s `f' function, for the reverse - conversion. */ -static double -dmnsn_Lab_finv(double t) -{ - if (t > 6.0/29.0) { - return t*t*t; - } else { - return 108.0*(t - 16.0/116.0)/841.0; - } -} - -/* Convert a CIE L*a*b* color to a dmnsn_color, relative to the given - whitepoint. */ -dmnsn_color -dmnsn_color_from_Lab(dmnsn_CIE_Lab Lab, dmnsn_CIE_XYZ white) -{ - double fx, fy, fz; - dmnsn_CIE_XYZ ret; - - fy = (Lab.L + 16.0)/116.0; - fx = fy + Lab.a/500.0; - fz = fy - Lab.b/200.0; - - ret.X = white.X*dmnsn_Lab_finv(fx); - ret.Y = white.Y*dmnsn_Lab_finv(fy); - ret.Z = white.Z*dmnsn_Lab_finv(fz); - return dmnsn_color_from_XYZ(ret); -} - -/* Convert a CIE L*u*v* color to a dmnsn_color, relative to the given - whitepoint. */ -dmnsn_color -dmnsn_color_from_Luv(dmnsn_CIE_Luv Luv, dmnsn_CIE_XYZ white) -{ - double fy; - double uprime, unprime, vprime, vnprime; - dmnsn_CIE_XYZ ret; - - fy = (Luv.L + 16.0)/116.0; - - unprime = 4.0*white.X/(white.X + 15.0*white.Y + 3.0*white.Z); - uprime = Luv.u/Luv.L/13.0 + unprime; - vnprime = 9.0*white.Y/(white.X + 15.0*white.Y + 3.0*white.Z); - vprime = Luv.v/Luv.L/13.0 + vnprime; - - ret.Y = white.Y*dmnsn_Lab_finv(fy); - ret.X = ret.Y*9.0*uprime/vprime/4.0; - ret.Z = ret.Y*(12.0 - 3*uprime - 20*vprime)/vprime/4.0; - return dmnsn_color_from_XYZ(ret); -} - -/* Convert a dmnsn_color to an sRGB color (actually a no-op) */ -dmnsn_sRGB -dmnsn_sRGB_from_color(dmnsn_color color) -{ - dmnsn_sRGB sRGB = { .R = color.R, .G = color.G, .B = color.B }; - return sRGB; -} - -/** Inverse function of sRGB's `C' function, for the reverse conversion. */ -static double -dmnsn_sRGB_Cinv(double CsRGB) -{ - /* - * If C represents R, G, and B, then the Clinear values are now found as - * follows: - * - * { Csrgb/12.92, Csrgb <= 0.04045 - * Clinear = { 1/2.4 - * { ((Csrgb + 0.055)/1.055) , Csrgb > 0.04045 - */ - if (CsRGB <= 0.040449936) { - return CsRGB/12.92; - } else { - return pow((CsRGB + 0.055)/1.055, 2.4); - } -} - -/* Convert a dmnsn_color to a CIE XYZ color */ -dmnsn_CIE_XYZ -dmnsn_XYZ_from_color(dmnsn_color color) -{ - color.R = dmnsn_sRGB_Cinv(color.R); - color.G = dmnsn_sRGB_Cinv(color.G); - color.B = dmnsn_sRGB_Cinv(color.B); - - dmnsn_CIE_XYZ ret = { - .X = 0.4123808838268995*color.R + 0.3575728355732478*color.G - + 0.1804522977447919*color.B, - .Y = 0.2126198631048975*color.R + 0.7151387878413206*color.G - + 0.0721499433963131*color.B, - .Z = 0.0193434956789248*color.R + 0.1192121694056356*color.G - + 0.9505065664127130*color.B, - }; - return ret; -} - -/* Convert a dmnsn_color to a CIE xyY color */ -dmnsn_CIE_xyY -dmnsn_xyY_from_color(dmnsn_color color) -{ - dmnsn_CIE_XYZ XYZ = dmnsn_XYZ_from_color(color); - dmnsn_CIE_xyY ret = { - .x = XYZ.X/(XYZ.X + XYZ.Y + XYZ.Z), - .y = XYZ.Y/(XYZ.X + XYZ.Y + XYZ.Z), - .Y = XYZ.Y - }; - return ret; -} - -/** CIE L*a*b*'s `f' function. */ -static double -dmnsn_Lab_f(double t) -{ - if (t > 216.0/24389.0) { - return pow(t, 1.0/3.0); - } else { - return 841.0*t/108.0 + 4.0/29.0; - } -} - -/* Convert a dmnsn_color to a CIE L*a*b* color, relative to the given - whitepoint */ -dmnsn_CIE_Lab -dmnsn_Lab_from_color(dmnsn_color color, dmnsn_CIE_XYZ white) -{ - dmnsn_CIE_XYZ XYZ = dmnsn_XYZ_from_color(color); - dmnsn_CIE_Lab ret; - - ret.L = 116.0*dmnsn_Lab_f(XYZ.Y/white.Y) - 16.0; - ret.a = 500.0*(dmnsn_Lab_f(XYZ.X/white.X) - dmnsn_Lab_f(XYZ.Y/white.Y)); - ret.b = 200.0*(dmnsn_Lab_f(XYZ.Y/white.Y) - dmnsn_Lab_f(XYZ.Z/white.Z)); - return ret; -} - -/* Convert a dmnsn_color to a CIE L*u*v* color, relative to the given - whitepoint */ -dmnsn_CIE_Luv -dmnsn_Luv_from_color(dmnsn_color color, dmnsn_CIE_XYZ white) -{ - dmnsn_CIE_XYZ XYZ = dmnsn_XYZ_from_color(color); - double uprime, unprime, vprime, vnprime; - dmnsn_CIE_Luv ret; - - uprime = 4.0*XYZ.X / (XYZ.X + 15.0*XYZ.Y + 3.0*XYZ.Z); - unprime = 4.0*white.X / (white.X + 15.0*white.Y + 3.0*white.Z); - vprime = 9.0*XYZ.Y / (XYZ.X + 15.0*XYZ.Y + 3.0*XYZ.Z); - vnprime = 9.0*white.Y / (white.X + 15.0*white.Y + 3.0*white.Z); - - ret.L = 116.0*dmnsn_Lab_f(XYZ.Y/white.Y) - 16.0; - ret.u = 13.0*ret.L*(uprime - unprime); - ret.v = 13.0*ret.L*(vprime - vnprime); - return ret; -} - /* Greyscale color intensity */ double dmnsn_color_intensity(dmnsn_color color) { - dmnsn_sRGB sRGB = dmnsn_sRGB_from_color(color); - return 0.2126198631048975*sRGB.R + 0.7151387878413206*sRGB.G - + 0.0721499433963131*sRGB.B; + return 0.2126198631048975*color.R + 0.7151387878413206*color.G + + 0.0721499433963131*color.B; } /* Add two colors */ dmnsn_color dmnsn_color_add(dmnsn_color c1, dmnsn_color c2) { - dmnsn_sRGB sRGB1 = dmnsn_sRGB_from_color(c1); - dmnsn_sRGB sRGB2 = dmnsn_sRGB_from_color(c2); - - dmnsn_sRGB sRGB = { - .R = sRGB1.R + sRGB2.R, - .G = sRGB1.G + sRGB2.G, - .B = sRGB1.B + sRGB2.B - }; - - dmnsn_color ret = dmnsn_color_from_sRGB(sRGB); + dmnsn_color ret = dmnsn_new_color(c1.R + c2.R, c1.G + c2.G, c1.B + c2.B); double n1 = dmnsn_color_intensity(c1), n2 = dmnsn_color_intensity(c2); if (n1 + n2 != 0.0) { @@ -363,34 +124,23 @@ dmnsn_color_add(dmnsn_color c1, dmnsn_color c2) dmnsn_color dmnsn_color_mul(double n, dmnsn_color color) { - dmnsn_sRGB sRGB = dmnsn_sRGB_from_color(color); - sRGB.R *= n; - sRGB.G *= n; - sRGB.B *= n; - - dmnsn_color ret = dmnsn_color_from_sRGB(sRGB); - ret.filter = color.filter; - ret.trans = color.trans; - return ret; + color.R *= n; + color.G *= n; + color.B *= n; + return color; } /* For n in [0, 1] get the color in a gradient between c1 and c2 */ dmnsn_color dmnsn_color_gradient(dmnsn_color c1, dmnsn_color c2, double n) { - dmnsn_sRGB sRGB1 = dmnsn_sRGB_from_color(c1); - dmnsn_sRGB sRGB2 = dmnsn_sRGB_from_color(c2); - - dmnsn_sRGB sRGB = { - .R = n*(sRGB2.R - sRGB1.R) + sRGB1.R, - .G = n*(sRGB2.G - sRGB1.G) + sRGB1.G, - .B = n*(sRGB2.B - sRGB1.B) + sRGB1.B - }; - - dmnsn_color ret = dmnsn_color_from_sRGB(sRGB); - ret.filter = n*(c2.filter - c1.filter) + c1.filter; - ret.trans = n*(c2.trans - c1.trans) + c1.trans; - return ret; + return dmnsn_new_color5( + n*(c2.R - c1.R) + c1.R, + n*(c2.G - c1.G) + c1.G, + n*(c2.B - c1.B) + c1.B, + n*(c2.filter - c1.filter) + c1.filter, + n*(c2.trans - c1.trans) + c1.trans + ); } /* Filters `light' through `filter' */ @@ -433,32 +183,6 @@ dmnsn_apply_filter(dmnsn_color color, dmnsn_color filter) dmnsn_color dmnsn_color_illuminate(dmnsn_color light, dmnsn_color color) { - /* We use the sRGB primaries */ - dmnsn_sRGB sRGB1 = dmnsn_sRGB_from_color(light); - dmnsn_sRGB sRGB2 = dmnsn_sRGB_from_color(color); - - dmnsn_sRGB sRGB = { - .R = sRGB1.R*sRGB2.R, - .G = sRGB1.G*sRGB2.G, - .B = sRGB1.B*sRGB2.B - }; - - dmnsn_color ret = dmnsn_color_from_sRGB(sRGB); - ret.filter = color.filter; - ret.trans = color.trans; - return ret; -} - -/* Find the perceptual difference between two colors, using CIE L*a*b* */ -double -dmnsn_color_difference(dmnsn_color color1, dmnsn_color color2) -{ - dmnsn_CIE_Lab Lab1, Lab2; - - Lab1 = dmnsn_Lab_from_color(color1, dmnsn_whitepoint); - Lab2 = dmnsn_Lab_from_color(color2, dmnsn_whitepoint); - - return sqrt((Lab1.L - Lab2.L)*(Lab1.L - Lab2.L) - + (Lab1.a - Lab2.a)*(Lab1.a - Lab2.a) - + (Lab1.b - Lab2.b)*(Lab1.b - Lab2.b)); + return dmnsn_new_color5(light.R*color.R, light.G*color.G, light.B*color.B, + color.filter, color.trans); } diff --git a/libdimension/dimension/color.h b/libdimension/dimension/color.h index 887c2c7..8db5158 100644 --- a/libdimension/dimension/color.h +++ b/libdimension/dimension/color.h @@ -30,52 +30,16 @@ /** A color value. */ typedef struct { + double R; /**< sRGB red value. */ + double G; /**< sRGB green value. */ + double B; /**< sRGB blue value. */ + /** Filtered transparency. */ double filter; /** Unfiltered transparency; filter + trans should be <= 1. */ double trans; - - /* Internally we use sRGB color. */ - double R; /**< @internal sRGB red value. */ - double G; /**< @internal sRGB green value. */ - double B; /**< @internal sRGB blue value. */ } dmnsn_color; -/** sRGB color. */ -typedef struct { - double R; /**< sRGB red value. */ - double G; /**< sRGB green value. */ - double B; /**< sRGB blue value. */ -} dmnsn_sRGB; - -/** CIE XYZ color. */ -typedef struct { - double X; /**< X component. */ - double Y; /**< Y (luminance) component. */ - double Z; /**< Z component. */ -} dmnsn_CIE_XYZ; - -/** CIE xyY color. */ -typedef struct { - double x; /**< x chromaticity coordinate (in [0, 1]). */ - double y; /**< y chromaticity coordinate (in [0, 1]). */ - double Y; /**< Luminance, unbounded >= 0; 1 is diffuse white. */ -} dmnsn_CIE_xyY; - -/** CIE 1976 (L*, a*, b*) color. */ -typedef struct { - double L; /**< Luminance (100 is diffuse white). */ - double a; /**< Red/greed color-opponent value. */ - double b; /**< Yellow/blue color-opponent value. */ -} dmnsn_CIE_Lab; - -/** CIE 1976 (L*, u*, v*) color. */ -typedef struct { - double L; /**< Luminance (same L* as CIE L*, a*, b*). */ - double u; /**< u* coordinate. */ - double v; /**< v* coordinate. */ -} dmnsn_CIE_Luv; - /* Standard colors */ extern const dmnsn_color dmnsn_black; /**< Black. */ extern const dmnsn_color dmnsn_white; /**< White. */ @@ -88,36 +52,33 @@ extern const dmnsn_color dmnsn_orange; /**< Orange. */ extern const dmnsn_color dmnsn_yellow; /**< Yellow. */ extern const dmnsn_color dmnsn_cyan; /**< Cyan. */ -/** Standard whitepoint, determined by the conversion of sRGB white to - CIE XYZ */ -extern const dmnsn_CIE_XYZ dmnsn_whitepoint; - -/** Is this color black? */ -bool dmnsn_color_is_black(dmnsn_color color); +/* Color construction */ -/* Color conversions */ +/** Construct a new color. */ +DMNSN_INLINE dmnsn_color +dmnsn_new_color(double R, double G, double B) +{ + dmnsn_color ret = { R, G, B, 0.0, 0.0 }; + return ret; +} -/** Convert an sRGB color to a Dimension color. */ -dmnsn_color dmnsn_color_from_sRGB(dmnsn_sRGB sRGB); -/** Convert a CIE XYZ color to a Dimension color. */ -dmnsn_color dmnsn_color_from_XYZ(dmnsn_CIE_XYZ XYZ); -/** Convert a CIE xyY color to a Dimension color. */ -dmnsn_color dmnsn_color_from_xyY(dmnsn_CIE_xyY xyY); -/** Convert a CIE L*, a*, b* color to a Dimension color. */ -dmnsn_color dmnsn_color_from_Lab(dmnsn_CIE_Lab Lab, dmnsn_CIE_XYZ white); -/** Convert a CIE L*, u*, v* color to a Dimension color. */ -dmnsn_color dmnsn_color_from_Luv(dmnsn_CIE_Luv Luv, dmnsn_CIE_XYZ white); +/** Construct a new color with transparent components. */ +DMNSN_INLINE dmnsn_color +dmnsn_new_color5(double R, double G, double B, double filter, double trans) +{ + dmnsn_color ret = { R, G, B, filter, trans }; + return ret; +} -/** Convert a Dimension color to sRGB. */ -dmnsn_sRGB dmnsn_sRGB_from_color(dmnsn_color color); -/** Convert a Dimension color to CIE XYZ. */ -dmnsn_CIE_XYZ dmnsn_XYZ_from_color(dmnsn_color color); -/** Convert a Dimension color to CIE xyY. */ -dmnsn_CIE_xyY dmnsn_xyY_from_color(dmnsn_color color); -/** Convert a Dimension color to CIE L*, a*, b*. */ -dmnsn_CIE_Lab dmnsn_Lab_from_color(dmnsn_color color, dmnsn_CIE_XYZ white); -/** Convert a Dimension color to CIE L*, u*, v*. */ -dmnsn_CIE_Luv dmnsn_Luv_from_color(dmnsn_color color, dmnsn_CIE_XYZ white); +/** Is this color black? */ +DMNSN_INLINE bool +dmnsn_color_is_black(dmnsn_color color) +{ + return fabs(color.R) < dmnsn_epsilon + && fabs(color.G) < dmnsn_epsilon + && fabs(color.B) < dmnsn_epsilon + && fabs(color.trans) < dmnsn_epsilon; +} /* Perceptual color manipulation */ @@ -138,7 +99,4 @@ dmnsn_color dmnsn_apply_filter(dmnsn_color color, dmnsn_color filter); /** Illuminate \p color with \p light. */ dmnsn_color dmnsn_color_illuminate(dmnsn_color light, dmnsn_color color); -/** Return the perceptual difference between two colors. */ -double dmnsn_color_difference(dmnsn_color color1, dmnsn_color color2); - #endif /* DIMENSION_COLOR_H */ diff --git a/libdimension/gl.c b/libdimension/gl.c index 857c7de..587038f 100644 --- a/libdimension/gl.c +++ b/libdimension/gl.c @@ -62,7 +62,6 @@ dmnsn_gl_write_canvas(const dmnsn_canvas *canvas) { GLushort *pixels; /* Array of 16-bit ints in RGBA order */ GLushort *pixel; - dmnsn_sRGB sRGB; dmnsn_color color; size_t width = canvas->width; @@ -84,32 +83,31 @@ dmnsn_gl_write_canvas(const dmnsn_canvas *canvas) pixel = pixels + 4*(y*width + x); color = dmnsn_get_pixel(canvas, x, y); - sRGB = dmnsn_sRGB_from_color(color); /* Saturate R, G, and B to [0, UINT16_MAX] */ - if (sRGB.R <= 0.0) { + if (color.R <= 0.0) { pixel[0] = 0; - } else if (sRGB.R >= 1.0) { + } else if (color.R >= 1.0) { pixel[0] = UINT16_MAX; } else { - pixel[0] = sRGB.R*UINT16_MAX; + pixel[0] = color.R*UINT16_MAX; } - if (sRGB.G <= 0.0) { + if (color.G <= 0.0) { pixel[1] = 0; - } else if (sRGB.G >= 1.0) { + } else if (color.G >= 1.0) { pixel[1] = UINT16_MAX; } else { - pixel[1] = sRGB.G*UINT16_MAX; + pixel[1] = color.G*UINT16_MAX; } - if (sRGB.B <= 0.0) { + if (color.B <= 0.0) { pixel[2] = 0; - } else if (sRGB.B >= 1.0) { + } else if (color.B >= 1.0) { pixel[2] = UINT16_MAX; } else { - pixel[2] = sRGB.B*UINT16_MAX; + pixel[2] = color.B*UINT16_MAX; } double alpha = dmnsn_color_intensity(color)*color.filter + color.trans; @@ -134,14 +132,10 @@ dmnsn_canvas * dmnsn_gl_read_canvas(size_t x0, size_t y0, size_t width, size_t height) { - dmnsn_canvas *canvas; - GLushort *pixels; /* Array of 16-bit ints in RGBA order */ - GLushort *pixel; - dmnsn_sRGB sRGB; - dmnsn_color color; + dmnsn_canvas *canvas = dmnsn_new_canvas(width, height); - canvas = dmnsn_new_canvas(width, height); - pixels = dmnsn_malloc(4*width*height*sizeof(GLushort)); + /* Array of 16-bit ints in RGBA order */ + GLushort *pixels = dmnsn_malloc(4*width*height*sizeof(GLushort)); glReadPixels(x0, y0, width, height, GL_RGBA, GL_UNSIGNED_SHORT, pixels); @@ -153,14 +147,13 @@ dmnsn_gl_read_canvas(size_t x0, size_t y0, for (size_t y = 0; y < height; ++y) { for (size_t x = 0; x < width; ++x) { - pixel = pixels + 4*(y*width + x); - - sRGB.R = ((double)pixel[0])/UINT16_MAX; - sRGB.G = ((double)pixel[1])/UINT16_MAX; - sRGB.B = ((double)pixel[2])/UINT16_MAX; + GLushort *pixel = pixels + 4*(y*width + x); - color = dmnsn_color_from_sRGB(sRGB); - color.filter = ((double)pixel[3])/UINT16_MAX; + dmnsn_color color = dmnsn_new_color5((double)pixel[0]/UINT16_MAX, + (double)pixel[1]/UINT16_MAX, + (double)pixel[2]/UINT16_MAX, + 0.0, + (double)pixel[3]/UINT16_MAX); dmnsn_set_pixel(canvas, x, y, color); } } @@ -174,37 +167,33 @@ static void dmnsn_gl_optimizer_fn(const dmnsn_canvas *canvas, dmnsn_canvas_optimizer optimizer, size_t x, size_t y) { - dmnsn_color color; - dmnsn_sRGB sRGB; GLushort *pixel = (GLushort *)optimizer.ptr + 4*(y*canvas->width + x); - - color = dmnsn_get_pixel(canvas, x, y); - sRGB = dmnsn_sRGB_from_color(color); + dmnsn_color color = dmnsn_get_pixel(canvas, x, y); /* Saturate R, G, and B to [0, UINT16_MAX] */ - if (sRGB.R <= 0.0) { + if (color.R <= 0.0) { pixel[0] = 0; - } else if (sRGB.R >= 1.0) { + } else if (color.R >= 1.0) { pixel[0] = UINT16_MAX; } else { - pixel[0] = sRGB.R*UINT16_MAX; + pixel[0] = color.R*UINT16_MAX; } - if (sRGB.G <= 0.0) { + if (color.G <= 0.0) { pixel[1] = 0; - } else if (sRGB.G >= 1.0) { + } else if (color.G >= 1.0) { pixel[1] = UINT16_MAX; } else { - pixel[1] = sRGB.G*UINT16_MAX; + pixel[1] = color.G*UINT16_MAX; } - if (sRGB.B <= 0.0) { + if (color.B <= 0.0) { pixel[2] = 0; - } else if (sRGB.B >= 1.0) { + } else if (color.B >= 1.0) { pixel[2] = UINT16_MAX; } else { - pixel[2] = sRGB.B*UINT16_MAX; + pixel[2] = color.B*UINT16_MAX; } double alpha = dmnsn_color_intensity(color)*color.filter + color.trans; diff --git a/libdimension/png.c b/libdimension/png.c index 7a327d6..534a085 100644 --- a/libdimension/png.c +++ b/libdimension/png.c @@ -62,36 +62,34 @@ dmnsn_png_optimizer_fn(const dmnsn_canvas *canvas, dmnsn_canvas_optimizer optimizer, size_t x, size_t y) { dmnsn_color color; - dmnsn_sRGB sRGB; uint16_t *pixel = (uint16_t *)optimizer.ptr + 4*(y*canvas->width + x); color = dmnsn_get_pixel(canvas, x, y); - sRGB = dmnsn_sRGB_from_color(color); /* Saturate R, G, and B to [0, UINT16_MAX] */ - if (sRGB.R <= 0.0) { + if (color.R <= 0.0) { pixel[0] = 0; - } else if (sRGB.R >= 1.0) { + } else if (color.R >= 1.0) { pixel[0] = UINT16_MAX; } else { - pixel[0] = sRGB.R*UINT16_MAX; + pixel[0] = color.R*UINT16_MAX; } - if (sRGB.G <= 0.0) { + if (color.G <= 0.0) { pixel[1] = 0; - } else if (sRGB.G >= 1.0) { + } else if (color.G >= 1.0) { pixel[1] = UINT16_MAX; } else { - pixel[1] = sRGB.G*UINT16_MAX; + pixel[1] = color.G*UINT16_MAX; } - if (sRGB.B <= 0.0) { + if (color.B <= 0.0) { pixel[2] = 0; - } else if (sRGB.B >= 1.0) { + } else if (color.B >= 1.0) { pixel[2] = UINT16_MAX; } else { - pixel[2] = sRGB.B*UINT16_MAX; + pixel[2] = color.B*UINT16_MAX; } double alpha = dmnsn_color_intensity(color)*color.filter + color.trans; @@ -274,32 +272,31 @@ dmnsn_png_write_canvas_thread(void *ptr) for (size_t x = 0; x < width; ++x) { /* Invert the rows. PNG coordinates are fourth quadrant. */ dmnsn_color color = dmnsn_get_pixel(payload->canvas, x, height - y - 1); - dmnsn_sRGB sRGB = dmnsn_sRGB_from_color(color); /* Saturate R, G, and B to [0, UINT16_MAX] */ - if (sRGB.R <= 0.0) { + if (color.R <= 0.0) { row[4*x] = 0; - } else if (sRGB.R >= 1.0) { + } else if (color.R >= 1.0) { row[4*x] = UINT16_MAX; } else { - row[4*x] = sRGB.R*UINT16_MAX; + row[4*x] = color.R*UINT16_MAX; } - if (sRGB.G <= 0.0) { + if (color.G <= 0.0) { row[4*x + 1] = 0; - } else if (sRGB.G >= 1.0) { + } else if (color.G >= 1.0) { row[4*x + 1] = UINT16_MAX; } else { - row[4*x + 1] = sRGB.G*UINT16_MAX; + row[4*x + 1] = color.G*UINT16_MAX; } - if (sRGB.B <= 0.0) { + if (color.B <= 0.0) { row[4*x + 2] = 0; - } else if (sRGB.B >= 1.0) { + } else if (color.B >= 1.0) { row[4*x + 2] = UINT16_MAX; } else { - row[4*x + 2] = sRGB.B*UINT16_MAX; + row[4*x + 2] = color.B*UINT16_MAX; } double alpha = color.filter + color.trans; @@ -445,86 +442,46 @@ dmnsn_png_read_canvas_thread(void *ptr) /* Now we convert the image to our canvas format. This depends on the image bit depth (which has been scaled up to at least 8 or 16), and the presence - of an alpha channel. For performance reasons, the tests are outside the - loops, although that doesn't really matter for a decent compiler. */ - if (bit_depth == 16) { - if (color_type & PNG_COLOR_MASK_ALPHA) { - for (size_t y = 0; y < height; ++y) { - for (size_t x = 0; x < width; ++x) { - png_bytep png_pixel = image + 8*(y*width + x); - - dmnsn_sRGB sRGB = { - .R = ((double)((png_pixel[0] << UINT16_C(8)) + png_pixel[1])) - /UINT16_MAX, - .G = ((double)((png_pixel[2] << UINT16_C(8)) + png_pixel[3])) - /UINT16_MAX, - .B = ((double)((png_pixel[4] << UINT16_C(8)) + png_pixel[5])) - /UINT16_MAX - }; - - dmnsn_color color = dmnsn_color_from_sRGB(sRGB); - color.trans = ((double)((png_pixel[6] << UINT16_C(8)) - + png_pixel[7]))/UINT16_MAX; - dmnsn_set_pixel(*payload->canvas, x, height - y - 1, color); - } - dmnsn_increment_progress(payload->progress); - } - } else { - for (size_t y = 0; y < height; ++y) { - for (size_t x = 0; x < width; ++x) { - png_bytep png_pixel = image + 6*(y*width + x); + of an alpha channel. */ + for (size_t y = 0; y < height; ++y) { + for (size_t x = 0; x < width; ++x) { + dmnsn_color color; + color.filter = 0.0; - dmnsn_sRGB sRGB = { - .R = ((double)((png_pixel[0] << UINT16_C(8)) + png_pixel[1])) - /UINT16_MAX, - .G = ((double)((png_pixel[2] << UINT16_C(8)) + png_pixel[3])) - /UINT16_MAX, - .B = ((double)((png_pixel[4] << UINT16_C(8)) + png_pixel[5])) - /UINT16_MAX - }; - - dmnsn_color color = dmnsn_color_from_sRGB(sRGB); - dmnsn_set_pixel(*payload->canvas, x, height - y - 1, color); - } - dmnsn_increment_progress(payload->progress); - } - } - } else { - /* Bit depth is 8 */ - if (color_type & PNG_COLOR_MASK_ALPHA) { - for (size_t y = 0; y < height; ++y) { - for (size_t x = 0; x < width; ++x) { + if (color_type & PNG_COLOR_MASK_ALPHA) { + if (bit_depth == 16) { + png_bytep png_pixel = image + 8*(y*width + x); + color.R = (double)((png_pixel[0] << 8) + png_pixel[1])/UINT16_MAX; + color.G = (double)((png_pixel[2] << 8) + png_pixel[3])/UINT16_MAX; + color.R = (double)((png_pixel[4] << 8) + png_pixel[5])/UINT16_MAX; + color.trans = (double)((png_pixel[6] << 8) + png_pixel[7])/UINT16_MAX; + } else { png_bytep png_pixel = image + 4*(y*width + x); - - dmnsn_sRGB sRGB = { - .R = ((double)png_pixel[0])/UINT8_MAX, - .G = ((double)png_pixel[1])/UINT8_MAX, - .B = ((double)png_pixel[2])/UINT8_MAX - }; - - dmnsn_color color = dmnsn_color_from_sRGB(sRGB); - color.trans = ((double)png_pixel[3])/UINT8_MAX; - dmnsn_set_pixel(*payload->canvas, x, height - y - 1, color); + color.R = (double)png_pixel[0]/UINT16_MAX; + color.G = (double)png_pixel[1]/UINT16_MAX; + color.R = (double)png_pixel[2]/UINT16_MAX; + color.trans = (double)png_pixel[3]/UINT16_MAX; } - dmnsn_increment_progress(payload->progress); - } - } else { - for (size_t y = 0; y < height; ++y) { - for (size_t x = 0; x < width; ++x) { - png_bytep png_pixel = image + 3*(y*width + x); - - dmnsn_sRGB sRGB = { - sRGB.R = ((double)png_pixel[0])/UINT8_MAX, - sRGB.G = ((double)png_pixel[1])/UINT8_MAX, - sRGB.B = ((double)png_pixel[2])/UINT8_MAX - }; + } else { + color.trans = 0.0; - dmnsn_color color = dmnsn_color_from_sRGB(sRGB); - dmnsn_set_pixel(*payload->canvas, x, height - y - 1, color); + if (bit_depth == 16) { + png_bytep png_pixel = image + 6*(y*width + x); + color.R = (double)((png_pixel[0] << 8) + png_pixel[1])/UINT16_MAX; + color.G = (double)((png_pixel[2] << 8) + png_pixel[3])/UINT16_MAX; + color.R = (double)((png_pixel[4] << 8) + png_pixel[5])/UINT16_MAX; + } else { + png_bytep png_pixel = image + 3*(y*width + x); + color.R = (double)png_pixel[0]/UINT16_MAX; + color.G = (double)png_pixel[1]/UINT16_MAX; + color.R = (double)png_pixel[2]/UINT16_MAX; } - dmnsn_increment_progress(payload->progress); } + + dmnsn_set_pixel(*payload->canvas, x, height - y - 1, color); } + + dmnsn_increment_progress(payload->progress); } dmnsn_free(row_pointers); -- cgit v1.2.3