/* * Copyright 2006, Haiku. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Stephan Aßmus */ #include #include #include "support.h" #include "lab_convert.h" #define GAMMA_ZERO_ENTRIES 256 #define GAMMA_ENTRIES 10240 #define GAMMA_MAX_ENTRIES 256 #define GAMMA_TOTAL_ENTRIES GAMMA_ZERO_ENTRIES + GAMMA_ENTRIES + GAMMA_MAX_ENTRIES // init_gamma_table uint8* init_gamma_table() { uint8* table = new uint8[GAMMA_TOTAL_ENTRIES]; for (int32 i = 0; i < GAMMA_ZERO_ENTRIES; i++) table[i] = 0; for (int32 i = 0; i < GAMMA_ENTRIES; i++) table[i + GAMMA_ZERO_ENTRIES] = (uint8)(pow((float)i / (float)(GAMMA_ENTRIES - 1), 0.4) * 255.0 + 0.5); for (int32 i = 0; i < GAMMA_MAX_ENTRIES; i++) table[i + GAMMA_ZERO_ENTRIES + GAMMA_ENTRIES] = 255; return table; } // init_linear_table float* init_linear_table() { float* table = new float[256]; for (int32 i = 0; i < 256; i++) table[i] = pow((float)i / 255.0, 2.5); return table; } // conversion from RGB (0...255) to linear and normalized RGB (0...1) /*static uint8* gammaTable = init_gamma_table();*/ static float* linearTable = init_linear_table(); // matrix entries: XYZ -> RGB (709 RGB, D65 Whitepoint) /*const float Rx = 3.240479; const float Ry = -1.537150; const float Rz = -0.498535; const float Gx = -0.969256; const float Gy = 1.875992; const float Gz = 0.041556; const float Bx = 0.055648; const float By = -0.204043; const float Bz = 1.057311;*/ // matrix entries: XYZ -> sRGB (D65 Whitepoint) const float Rx = 3.24071; const float Ry = -1.53726; const float Rz = -0.498571; const float Gx = -0.969258; const float Gy = 1.87599; const float Gz = 0.0415557; const float Bx = 0.0556352; const float By = -0.203996; const float Bz = 1.05707; // matrix entries scaled: XYZ(0...1) -> RGB(0...255) const float RX = Rx * 255; const float RY = Ry * 255; const float RZ = Rz * 255; const float GX = Gx * 255; const float GY = Gy * 255; const float GZ = Gz * 255; const float BX = Bx * 255; const float BY = By * 255; const float BZ = Bz * 255; // matrix etries: RGB -> XYZ /*const float Xr = 0.412453; const float Xg = 0.357580; const float Xb = 0.189423; const float Yr = 0.212671; const float Yg = 0.715160; const float Yb = 0.072169; const float Zr = 0.019334; const float Zg = 0.119193; const float Zb = 0.950227;*/ // matrix etries: sRGB -> XYZ (D65 Whitepoint) const float Xr = 0.412424; const float Xg = 0.357579; const float Xb = 0.180464; const float Yr = 0.212656; const float Yg = 0.715158; const float Yb = 0.0721856; const float Zr = 0.0193324; const float Zg = 0.119193; const float Zb = 0.950444; // matrix entries scaled: RGB(0...255) -> XYZ(0...1) const float XR = Xr / 255; const float XG = Xg / 255; const float XB = Xb / 255; const float YR = Yr / 255; const float YG = Yg / 255; const float YB = Yb / 255; const float ZR = Zr / 255; const float ZG = Zg / 255; const float ZB = Zb / 255; // white point const float Xn = Xr + Xg + Xb; const float Yn = Yr + Yg + Yb; const float Zn = Zr + Zg + Zb; // matrix entries scaled and white point normalized: RGB(0...255) -> XYZ(0...1/WP) const float XRn = Xr / Xn; const float XGn = Xg / Xn; const float XBn = Xb / Xn; const float YRn = Yr / Yn; const float YGn = Yg / Yn; const float YBn = Yb / Yn; const float ZRn = Zr / Zn; const float ZGn = Zg / Zn; const float ZBn = Zb / Zn; // lab2rgb void lab2rgb(float L, float a, float b, uint8& R, uint8& G, uint8& B) { float P = (L + 16) / 116; float Pa500 = P + a / 500; float Pb200 = P - b / 200; float X = Xn * Pa500 * Pa500 * Pa500; float Y = Yn * P * P * P; float Z = Zn * Pb200 * Pb200 * Pb200; /* float linearR = max_c(0.0, min_c(1.0, Rx * X + Ry * Y + Rz * Z)); float linearG = max_c(0.0, min_c(1.0, Gx * X + Gy * Y + Gz * Z)); float linearB = max_c(0.0, min_c(1.0, Bx * X + By * Y + Bz * Z)); R = (uint8)(pow(linearR, 0.4) * 255.0 + 0.5); G = (uint8)(pow(linearG, 0.4) * 255.0 + 0.5); B = (uint8)(pow(linearB, 0.4) * 255.0 + 0.5);*/ float linearR = Rx * X + Ry * Y + Rz * Z; float linearG = Gx * X + Gy * Y + Gz * Z; float linearB = Bx * X + By * Y + Bz * Z; R = (uint8)constrain_int32_0_255((int32)(pow(linearR, 0.4) * 255.0 + 0.5)); G = (uint8)constrain_int32_0_255((int32)(pow(linearG, 0.4) * 255.0 + 0.5)); B = (uint8)constrain_int32_0_255((int32)(pow(linearB, 0.4) * 255.0 + 0.5)); /* float linearR = Rx * X + Ry * Y + Rz * Z; float linearG = Gx * X + Gy * Y + Gz * Z; float linearB = Bx * X + By * Y + Bz * Z; R = gammaTable[(uint32)(linearR * (GAMMA_ENTRIES - 1) + 0.5) + GAMMA_ZERO_ENTRIES]; G = gammaTable[(uint32)(linearG * (GAMMA_ENTRIES - 1) + 0.5) + GAMMA_ZERO_ENTRIES]; B = gammaTable[(uint32)(linearB * (GAMMA_ENTRIES - 1) + 0.5) + GAMMA_ZERO_ENTRIES];*/ } inline float f(float t) { if (t > 0.008856) return pow(t, 1.0 / 3.0); return 7.787 * t + 16.0 / 116; } // rgb2lab void rgb2lab(uint8 R, uint8 G, uint8 B, float& L, float& a, float& b) { /* float linearR = pow((float)R / 255.0, 2.5); float linearG = pow((float)G / 255.0, 2.5); float linearB = pow((float)B / 255.0, 2.5);*/ float linearR = linearTable[R]; float linearG = linearTable[G]; float linearB = linearTable[B]; float Xq = XRn * linearR + XGn * linearG + XBn * linearB; // == X/Xn float Yq = YRn * linearR + YGn * linearG + YBn * linearB; // == Y/Yn float Zq = ZRn * linearR + ZGn * linearG + ZBn * linearB; // == Z/Zn if (Yq > 0.008856) L = 116.0 * pow(Yq, 1.0 / 3.0) - 16; else L = 903.3 * Yq; a = 500 * (f(Xq) - f(Yq)); b = 200 * (f(Yq) - f(Zq)); } // replace_luminance void replace_luminance(uint8& r1, uint8& g1, uint8& b1, uint8 r2, uint8 g2, uint8 b2) { float CIEL1, CIEa1, CIEb1, CIEL2;//, CIEa2, CIEb2; rgb2lab(r1, g1, b1, CIEL1, CIEa1, CIEb1); // rgb2lab(r2, g2, b2, CIEL2, CIEa2, CIEb2); CIEL2 = ((linearTable[r2] + linearTable[g2] + linearTable[b2]) / 3.0) * 100.0; lab2rgb(CIEL2, CIEa1, CIEb1, r1, g1, b1); }