From e7e6ca4355209af3a3a8142519f12cebe36889b1 Mon Sep 17 00:00:00 2001 From: Bo Xu Date: Thu, 24 Jul 2014 17:50:59 -0700 Subject: CalRGB color correction BUG=pdfium:19 R=thestig@chromium.org Review URL: https://codereview.chromium.org/403163002 --- core/include/fxcrt/fx_basic.h | 46 +++++++++++++ core/src/fpdfapi/fpdf_page/fpdf_page_colors.cpp | 87 +++++++++++++------------ core/src/fxcrt/fx_basic_util.cpp | 43 ++++++++++++ 3 files changed, 134 insertions(+), 42 deletions(-) diff --git a/core/include/fxcrt/fx_basic.h b/core/include/fxcrt/fx_basic.h index ece2b43a2e..22ba611a77 100644 --- a/core/include/fxcrt/fx_basic.h +++ b/core/include/fxcrt/fx_basic.h @@ -1578,4 +1578,50 @@ typedef enum { } FX_ProgressiveStatus; #define ProgressiveStatus FX_ProgressiveStatus #define FX_NAMESPACE_DECLARE(namespace, type) namespace::type + +class CFX_Vector_3by1 : public CFX_Object +{ +public: + + CFX_Vector_3by1() : + a(0.0f), b(0.0f), c(0.0f) + {} + + CFX_Vector_3by1(FX_FLOAT a1, FX_FLOAT b1, FX_FLOAT c1): + a(a1), b(b1), c(c1) + {} + + FX_FLOAT a; + FX_FLOAT b; + FX_FLOAT c; +}; +class CFX_Matrix_3by3 : public CFX_Object +{ +public: + + CFX_Matrix_3by3(): + a(0.0f), b(0.0f), c(0.0f), d(0.0f), e(0.0f), f(0.0f), g(0.0f), h(0.0f), i(0.0f) + {} + + CFX_Matrix_3by3(FX_FLOAT a1, FX_FLOAT b1, FX_FLOAT c1, FX_FLOAT d1, FX_FLOAT e1, FX_FLOAT f1, FX_FLOAT g1, FX_FLOAT h1, FX_FLOAT i1) : + a(a1), b(b1), c(c1), d(d1), e(e1), f(f1), g(g1), h(h1), i(i1) + {} + + CFX_Matrix_3by3 Inverse(); + + CFX_Matrix_3by3 Multiply(const CFX_Matrix_3by3 &m); + + CFX_Vector_3by1 TransformVector(const CFX_Vector_3by1 &v); + + FX_FLOAT a; + FX_FLOAT b; + FX_FLOAT c; + FX_FLOAT d; + FX_FLOAT e; + FX_FLOAT f; + FX_FLOAT g; + FX_FLOAT h; + FX_FLOAT i; +}; + #endif diff --git a/core/src/fpdfapi/fpdf_page/fpdf_page_colors.cpp b/core/src/fpdfapi/fpdf_page/fpdf_page_colors.cpp index 1cd109784d..467fb63f47 100644 --- a/core/src/fpdfapi/fpdf_page/fpdf_page_colors.cpp +++ b/core/src/fpdfapi/fpdf_page/fpdf_page_colors.cpp @@ -207,56 +207,59 @@ const FX_BYTE g_sRGBSamples2[] = { 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255, }; -static void XYZ_to_sRGB(FX_FLOAT X, FX_FLOAT Y, FX_FLOAT Z, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B) + +static FX_FLOAT RGB_Conversion(FX_FLOAT colorComponent) { - FX_FLOAT R1 = 3.2410f * X - 1.5374f * Y - 0.4986f * Z; - FX_FLOAT G1 = -0.9692f * X + 1.8760f * Y + 0.0416f * Z; - FX_FLOAT B1 = 0.0556f * X - 0.2040f * Y + 1.0570f * Z; - if (R1 > 1) { - R1 = 1; - } - if (R1 < 0) { - R1 = 0; - } - if (G1 > 1) { - G1 = 1; - } - if (G1 < 0) { - G1 = 0; - } - if (B1 > 1) { - B1 = 1; + if (colorComponent > 1) { + colorComponent = 1; } - if (B1 < 0) { - B1 = 0; + if (colorComponent < 0) { + colorComponent = 0; } - int scale = (int)(R1 * 1023); + int scale = (int)(colorComponent * 1023); if (scale < 0) { scale = 0; } if (scale < 192) { - R = (g_sRGBSamples1[scale] / 255.0f); - } else { - R = (g_sRGBSamples2[scale / 4 - 48] / 255.0f); - } - scale = (int)(G1 * 1023); - if (scale < 0) { - scale = 0; - } - if (scale < 192) { - G = (g_sRGBSamples1[scale] / 255.0f); - } else { - G = (g_sRGBSamples2[scale / 4 - 48] / 255.0f); - } - scale = (int)(B1 * 1023); - if (scale < 0) { - scale = 0; + colorComponent = (g_sRGBSamples1[scale] / 255.0f); } - if (scale < 192) { - B = (g_sRGBSamples1[scale] / 255.0f); - } else { - B = (g_sRGBSamples2[scale / 4 - 48] / 255.0f); + else { + colorComponent = (g_sRGBSamples2[scale / 4 - 48] / 255.0f); } + return colorComponent; +} + +static void XYZ_to_sRGB(FX_FLOAT X, FX_FLOAT Y, FX_FLOAT Z, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B) +{ + FX_FLOAT R1 = 3.2410f * X - 1.5374f * Y - 0.4986f * Z; + FX_FLOAT G1 = -0.9692f * X + 1.8760f * Y + 0.0416f * Z; + FX_FLOAT B1 = 0.0556f * X - 0.2040f * Y + 1.0570f * Z; + + R = RGB_Conversion(R1); + G = RGB_Conversion(G1); + B = RGB_Conversion(B1); +} + +static void XYZ_to_sRGB_WhitePoint(FX_FLOAT X, FX_FLOAT Y, FX_FLOAT Z, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B, FX_FLOAT Xw, FX_FLOAT Yw, FX_FLOAT Zw) +{ + // The following RGB_xyz is based on + // sRGB value {Rx,Ry}={0.64, 0.33}, {Gx,Gy}={0.30, 0.60}, {Bx,By}={0.15, 0.06} + + FX_FLOAT Rx = 0.64f, Ry = 0.33f; + FX_FLOAT Gx = 0.30f, Gy = 0.60f; + FX_FLOAT Bx = 0.15f, By = 0.06f; + CFX_Matrix_3by3 RGB_xyz(Rx, Gx, Bx, Ry, Gy, By, 1 - Rx - Ry, 1 - Gx - Gy, 1 - Bx - By); + CFX_Vector_3by1 whitePoint(Xw, Yw, Zw); + CFX_Vector_3by1 XYZ(X, Y, Z); + + CFX_Vector_3by1 RGB_Sum_XYZ = RGB_xyz.Inverse().TransformVector(whitePoint); + CFX_Matrix_3by3 RGB_SUM_XYZ_DIAG(RGB_Sum_XYZ.a, 0, 0, 0, RGB_Sum_XYZ.b, 0, 0, 0, RGB_Sum_XYZ.c); + CFX_Matrix_3by3 M = RGB_xyz.Multiply(RGB_SUM_XYZ_DIAG); + CFX_Vector_3by1 RGB = M.Inverse().TransformVector(XYZ); + + R = RGB_Conversion(RGB.a); + G = RGB_Conversion(RGB.b); + B = RGB_Conversion(RGB.c); } class CPDF_CalGray : public CPDF_ColorSpace { @@ -386,7 +389,7 @@ FX_BOOL CPDF_CalRGB::GetRGB(FX_FLOAT* pBuf, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& Y = B_; Z = C_; } - XYZ_to_sRGB(X, Y, Z, R, G, B); + XYZ_to_sRGB_WhitePoint(X, Y, Z, R, G, B, m_WhitePoint[0], m_WhitePoint[1], m_WhitePoint[2]); return TRUE; } FX_BOOL CPDF_CalRGB::SetRGB(FX_FLOAT* pBuf, FX_FLOAT R, FX_FLOAT G, FX_FLOAT B) const diff --git a/core/src/fxcrt/fx_basic_util.cpp b/core/src/fxcrt/fx_basic_util.cpp index dc5eea7821..5a40c2b4be 100644 --- a/core/src/fxcrt/fx_basic_util.cpp +++ b/core/src/fxcrt/fx_basic_util.cpp @@ -442,3 +442,46 @@ FX_WCHAR FX_GetFolderSeparator() return '/'; #endif } + +CFX_Matrix_3by3 CFX_Matrix_3by3::Inverse() +{ + FX_FLOAT det = a*(e*i - f*h) - b*(i*d - f*g) + c*(d*h - e*g); + if (FXSYS_fabs(det) < 0.0000001) + return CFX_Matrix_3by3(); + else + return CFX_Matrix_3by3( + (e*i - f*h) / det, + -(b*i - c*h) / det, + (b*f - c*e) / det, + -(d*i - f*g) / det, + (a*i - c*g) / det, + -(a*f - c*d) / det, + (d*h - e*g) / det, + -(a*h - b*g) / det, + (a*e - b*d) / det + ); +} + +CFX_Matrix_3by3 CFX_Matrix_3by3::Multiply(const CFX_Matrix_3by3 &m) +{ + return CFX_Matrix_3by3( + a*m.a + b*m.d + c*m.g, + a*m.b + b*m.e + c*m.h, + a*m.c + b*m.f + c*m.i, + d*m.a + e*m.d + f*m.g, + d*m.b + e*m.e + f*m.h, + d*m.c + e*m.f + f*m.i, + g*m.a + h*m.d + i*m.g, + g*m.b + h*m.e + i*m.h, + g*m.c + h*m.f + i*m.i + ); +} + +CFX_Vector_3by1 CFX_Matrix_3by3::TransformVector(const CFX_Vector_3by1 &v) +{ + return CFX_Vector_3by1( + a * v.a + b * v.b + c * v.c, + d * v.a + e * v.b + f * v.c, + g * v.a + h * v.b + i * v.c + ); +} -- cgit v1.2.3