blob: cc6c9e9d568df796814a39fd8ca918ce972301d9 [file] [log] [blame]
// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "../../../include/fpdfapi/fpdf_page.h"
#include "../../../include/fpdfapi/fpdf_module.h"
#include "../../../include/fxcodec/fx_codec.h"
#include "pageint.h"
#include <limits.h>
namespace {
void sRGB_to_AdobeCMYK(FX_FLOAT R,
FX_FLOAT G,
FX_FLOAT B,
FX_FLOAT& c,
FX_FLOAT& m,
FX_FLOAT& y,
FX_FLOAT& k) {
c = 1.0f - R;
m = 1.0f - G;
y = 1.0f - B;
k = c;
if (m < k) {
k = m;
}
if (y < k) {
k = y;
}
}
int ComponentsForFamily(int family) {
if (family == PDFCS_DEVICERGB)
return 3;
if (family == PDFCS_DEVICEGRAY)
return 1;
return 4;
}
} // namespace
CPDF_DeviceCS::CPDF_DeviceCS(CPDF_Document* pDoc, int family)
: CPDF_ColorSpace(pDoc, family, ComponentsForFamily(family)) {}
FX_BOOL CPDF_DeviceCS::GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const {
if (m_Family == PDFCS_DEVICERGB) {
R = pBuf[0];
if (R < 0) {
R = 0;
} else if (R > 1) {
R = 1;
}
G = pBuf[1];
if (G < 0) {
G = 0;
} else if (G > 1) {
G = 1;
}
B = pBuf[2];
if (B < 0) {
B = 0;
} else if (B > 1) {
B = 1;
}
} else if (m_Family == PDFCS_DEVICEGRAY) {
R = *pBuf;
if (R < 0) {
R = 0;
} else if (R > 1) {
R = 1;
}
G = B = R;
} else if (m_Family == PDFCS_DEVICECMYK) {
if (!m_dwStdConversion) {
AdobeCMYK_to_sRGB(pBuf[0], pBuf[1], pBuf[2], pBuf[3], R, G, B);
} else {
FX_FLOAT k = pBuf[3];
R = 1.0f - FX_MIN(1.0f, pBuf[0] + k);
G = 1.0f - FX_MIN(1.0f, pBuf[1] + k);
B = 1.0f - FX_MIN(1.0f, pBuf[2] + k);
}
} else {
ASSERT(m_Family == PDFCS_PATTERN);
R = G = B = 0;
return FALSE;
}
return TRUE;
}
FX_BOOL CPDF_DeviceCS::v_GetCMYK(FX_FLOAT* pBuf,
FX_FLOAT& c,
FX_FLOAT& m,
FX_FLOAT& y,
FX_FLOAT& k) const {
if (m_Family != PDFCS_DEVICECMYK) {
return FALSE;
}
c = pBuf[0];
m = pBuf[1];
y = pBuf[2];
k = pBuf[3];
return TRUE;
}
FX_BOOL CPDF_DeviceCS::SetRGB(FX_FLOAT* pBuf,
FX_FLOAT R,
FX_FLOAT G,
FX_FLOAT B) const {
if (m_Family == PDFCS_DEVICERGB) {
pBuf[0] = R;
pBuf[1] = G;
pBuf[2] = B;
return TRUE;
}
if (m_Family == PDFCS_DEVICEGRAY) {
if (R == G && R == B) {
*pBuf = R;
return TRUE;
}
return FALSE;
}
if (m_Family == PDFCS_DEVICECMYK) {
sRGB_to_AdobeCMYK(R, G, B, pBuf[0], pBuf[1], pBuf[2], pBuf[3]);
return TRUE;
}
return FALSE;
}
FX_BOOL CPDF_DeviceCS::v_SetCMYK(FX_FLOAT* pBuf,
FX_FLOAT c,
FX_FLOAT m,
FX_FLOAT y,
FX_FLOAT k) const {
if (m_Family == PDFCS_DEVICERGB) {
AdobeCMYK_to_sRGB(c, m, y, k, pBuf[0], pBuf[1], pBuf[2]);
return TRUE;
}
if (m_Family == PDFCS_DEVICECMYK) {
pBuf[0] = c;
pBuf[1] = m;
pBuf[2] = y;
pBuf[3] = k;
return TRUE;
}
return FALSE;
}
static void ReverseRGB(uint8_t* pDestBuf, const uint8_t* pSrcBuf, int pixels) {
if (pDestBuf == pSrcBuf)
for (int i = 0; i < pixels; i++) {
uint8_t temp = pDestBuf[2];
pDestBuf[2] = pDestBuf[0];
pDestBuf[0] = temp;
pDestBuf += 3;
}
else
for (int i = 0; i < pixels; i++) {
*pDestBuf++ = pSrcBuf[2];
*pDestBuf++ = pSrcBuf[1];
*pDestBuf++ = pSrcBuf[0];
pSrcBuf += 3;
}
}
void CPDF_DeviceCS::TranslateImageLine(uint8_t* pDestBuf,
const uint8_t* pSrcBuf,
int pixels,
int image_width,
int image_height,
FX_BOOL bTransMask) const {
if (bTransMask && m_Family == PDFCS_DEVICECMYK) {
for (int i = 0; i < pixels; i++) {
int k = 255 - pSrcBuf[3];
pDestBuf[0] = ((255 - pSrcBuf[0]) * k) / 255;
pDestBuf[1] = ((255 - pSrcBuf[1]) * k) / 255;
pDestBuf[2] = ((255 - pSrcBuf[2]) * k) / 255;
pDestBuf += 3;
pSrcBuf += 4;
}
return;
}
if (m_Family == PDFCS_DEVICERGB) {
ReverseRGB(pDestBuf, pSrcBuf, pixels);
} else if (m_Family == PDFCS_DEVICEGRAY) {
for (int i = 0; i < pixels; i++) {
*pDestBuf++ = pSrcBuf[i];
*pDestBuf++ = pSrcBuf[i];
*pDestBuf++ = pSrcBuf[i];
}
} else {
for (int i = 0; i < pixels; i++) {
if (!m_dwStdConversion) {
AdobeCMYK_to_sRGB1(pSrcBuf[0], pSrcBuf[1], pSrcBuf[2], pSrcBuf[3],
pDestBuf[2], pDestBuf[1], pDestBuf[0]);
} else {
uint8_t k = pSrcBuf[3];
pDestBuf[2] = 255 - FX_MIN(255, pSrcBuf[0] + k);
pDestBuf[1] = 255 - FX_MIN(255, pSrcBuf[1] + k);
pDestBuf[0] = 255 - FX_MIN(255, pSrcBuf[2] + k);
}
pSrcBuf += 4;
pDestBuf += 3;
}
}
}
const uint8_t g_sRGBSamples1[] = {
0, 3, 6, 10, 13, 15, 18, 20, 22, 23, 25, 27, 28, 30, 31,
32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 49, 50, 51, 52, 53, 53, 54, 55, 56, 56, 57, 58, 58,
59, 60, 61, 61, 62, 62, 63, 64, 64, 65, 66, 66, 67, 67, 68,
68, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 76, 76,
77, 77, 78, 78, 79, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83,
84, 84, 85, 85, 85, 86, 86, 87, 87, 88, 88, 88, 89, 89, 90,
90, 91, 91, 91, 92, 92, 93, 93, 93, 94, 94, 95, 95, 95, 96,
96, 97, 97, 97, 98, 98, 98, 99, 99, 99, 100, 100, 101, 101, 101,
102, 102, 102, 103, 103, 103, 104, 104, 104, 105, 105, 106, 106, 106, 107,
107, 107, 108, 108, 108, 109, 109, 109, 110, 110, 110, 110, 111, 111, 111,
112, 112, 112, 113, 113, 113, 114, 114, 114, 115, 115, 115, 115, 116, 116,
116, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 120,
};
const uint8_t g_sRGBSamples2[] = {
120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149,
150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 159, 160, 161, 162,
163, 163, 164, 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173,
174, 175, 175, 176, 177, 178, 178, 179, 180, 180, 181, 182, 182, 183, 184,
185, 185, 186, 187, 187, 188, 189, 189, 190, 190, 191, 192, 192, 193, 194,
194, 195, 196, 196, 197, 197, 198, 199, 199, 200, 200, 201, 202, 202, 203,
203, 204, 205, 205, 206, 206, 207, 208, 208, 209, 209, 210, 210, 211, 212,
212, 213, 213, 214, 214, 215, 215, 216, 216, 217, 218, 218, 219, 219, 220,
220, 221, 221, 222, 222, 223, 223, 224, 224, 225, 226, 226, 227, 227, 228,
228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235,
236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240, 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 FX_FLOAT RGB_Conversion(FX_FLOAT colorComponent) {
if (colorComponent > 1) {
colorComponent = 1;
}
if (colorComponent < 0) {
colorComponent = 0;
}
int scale = (int)(colorComponent * 1023);
if (scale < 0) {
scale = 0;
}
if (scale < 192) {
colorComponent = (g_sRGBSamples1[scale] / 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 {
public:
explicit CPDF_CalGray(CPDF_Document* pDoc)
: CPDF_ColorSpace(pDoc, PDFCS_CALGRAY, 1) {}
FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
FX_BOOL GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const override;
FX_BOOL SetRGB(FX_FLOAT* pBuf,
FX_FLOAT R,
FX_FLOAT G,
FX_FLOAT B) const override;
void TranslateImageLine(uint8_t* pDestBuf,
const uint8_t* pSrcBuf,
int pixels,
int image_width,
int image_height,
FX_BOOL bTransMask = FALSE) const override;
private:
FX_FLOAT m_WhitePoint[3];
FX_FLOAT m_BlackPoint[3];
FX_FLOAT m_Gamma;
};
FX_BOOL CPDF_CalGray::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
CPDF_Dictionary* pDict = pArray->GetDict(1);
CPDF_Array* pParam = pDict->GetArray(FX_BSTRC("WhitePoint"));
int i;
for (i = 0; i < 3; i++) {
m_WhitePoint[i] = pParam ? pParam->GetNumber(i) : 0;
}
pParam = pDict->GetArray(FX_BSTRC("BlackPoint"));
for (i = 0; i < 3; i++) {
m_BlackPoint[i] = pParam ? pParam->GetNumber(i) : 0;
}
m_Gamma = pDict->GetNumber(FX_BSTRC("Gamma"));
if (m_Gamma == 0) {
m_Gamma = 1.0f;
}
return TRUE;
}
FX_BOOL CPDF_CalGray::GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const {
R = G = B = *pBuf;
return TRUE;
}
FX_BOOL CPDF_CalGray::SetRGB(FX_FLOAT* pBuf,
FX_FLOAT R,
FX_FLOAT G,
FX_FLOAT B) const {
if (R == G && R == B) {
*pBuf = R;
return TRUE;
}
return FALSE;
}
void CPDF_CalGray::TranslateImageLine(uint8_t* pDestBuf,
const uint8_t* pSrcBuf,
int pixels,
int image_width,
int image_height,
FX_BOOL bTransMask) const {
for (int i = 0; i < pixels; i++) {
*pDestBuf++ = pSrcBuf[i];
*pDestBuf++ = pSrcBuf[i];
*pDestBuf++ = pSrcBuf[i];
}
}
class CPDF_CalRGB : public CPDF_ColorSpace {
public:
explicit CPDF_CalRGB(CPDF_Document* pDoc)
: CPDF_ColorSpace(pDoc, PDFCS_CALRGB, 3) {}
FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
FX_BOOL GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const override;
FX_BOOL SetRGB(FX_FLOAT* pBuf,
FX_FLOAT R,
FX_FLOAT G,
FX_FLOAT B) const override;
void TranslateImageLine(uint8_t* pDestBuf,
const uint8_t* pSrcBuf,
int pixels,
int image_width,
int image_height,
FX_BOOL bTransMask = FALSE) const override;
FX_FLOAT m_WhitePoint[3];
FX_FLOAT m_BlackPoint[3];
FX_FLOAT m_Gamma[3];
FX_FLOAT m_Matrix[9];
FX_BOOL m_bGamma;
FX_BOOL m_bMatrix;
};
FX_BOOL CPDF_CalRGB::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
CPDF_Dictionary* pDict = pArray->GetDict(1);
if (!pDict)
return FALSE;
CPDF_Array* pParam = pDict->GetArray(FX_BSTRC("WhitePoint"));
int i;
for (i = 0; i < 3; i++) {
m_WhitePoint[i] = pParam ? pParam->GetNumber(i) : 0;
}
pParam = pDict->GetArray(FX_BSTRC("BlackPoint"));
for (i = 0; i < 3; i++) {
m_BlackPoint[i] = pParam ? pParam->GetNumber(i) : 0;
}
pParam = pDict->GetArray(FX_BSTRC("Gamma"));
if (pParam) {
m_bGamma = TRUE;
for (i = 0; i < 3; i++) {
m_Gamma[i] = pParam->GetNumber(i);
}
} else {
m_bGamma = FALSE;
}
pParam = pDict->GetArray(FX_BSTRC("Matrix"));
if (pParam) {
m_bMatrix = TRUE;
for (i = 0; i < 9; i++) {
m_Matrix[i] = pParam->GetNumber(i);
}
} else {
m_bMatrix = FALSE;
}
return TRUE;
}
FX_BOOL CPDF_CalRGB::GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const {
FX_FLOAT A_ = pBuf[0];
FX_FLOAT B_ = pBuf[1];
FX_FLOAT C_ = pBuf[2];
if (m_bGamma) {
A_ = (FX_FLOAT)FXSYS_pow(A_, m_Gamma[0]);
B_ = (FX_FLOAT)FXSYS_pow(B_, m_Gamma[1]);
C_ = (FX_FLOAT)FXSYS_pow(C_, m_Gamma[2]);
}
FX_FLOAT X, Y, Z;
if (m_bMatrix) {
X = m_Matrix[0] * A_ + m_Matrix[3] * B_ + m_Matrix[6] * C_;
Y = m_Matrix[1] * A_ + m_Matrix[4] * B_ + m_Matrix[7] * C_;
Z = m_Matrix[2] * A_ + m_Matrix[5] * B_ + m_Matrix[8] * C_;
} else {
X = A_;
Y = B_;
Z = C_;
}
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 {
pBuf[0] = R;
pBuf[1] = G;
pBuf[2] = B;
return TRUE;
}
void CPDF_CalRGB::TranslateImageLine(uint8_t* pDestBuf,
const uint8_t* pSrcBuf,
int pixels,
int image_width,
int image_height,
FX_BOOL bTransMask) const {
if (bTransMask) {
FX_FLOAT Cal[3];
FX_FLOAT R, G, B;
for (int i = 0; i < pixels; i++) {
Cal[0] = ((FX_FLOAT)pSrcBuf[2]) / 255;
Cal[1] = ((FX_FLOAT)pSrcBuf[1]) / 255;
Cal[2] = ((FX_FLOAT)pSrcBuf[0]) / 255;
GetRGB(Cal, R, G, B);
pDestBuf[0] = FXSYS_round(B * 255);
pDestBuf[1] = FXSYS_round(G * 255);
pDestBuf[2] = FXSYS_round(R * 255);
pSrcBuf += 3;
pDestBuf += 3;
}
}
ReverseRGB(pDestBuf, pSrcBuf, pixels);
}
class CPDF_LabCS : public CPDF_ColorSpace {
public:
explicit CPDF_LabCS(CPDF_Document* pDoc)
: CPDF_ColorSpace(pDoc, PDFCS_LAB, 3) {}
void GetDefaultValue(int iComponent,
FX_FLOAT& value,
FX_FLOAT& min,
FX_FLOAT& max) const override;
FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
FX_BOOL GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const override;
FX_BOOL SetRGB(FX_FLOAT* pBuf,
FX_FLOAT R,
FX_FLOAT G,
FX_FLOAT B) const override;
void TranslateImageLine(uint8_t* pDestBuf,
const uint8_t* pSrcBuf,
int pixels,
int image_width,
int image_height,
FX_BOOL bTransMask = FALSE) const override;
FX_FLOAT m_WhitePoint[3];
FX_FLOAT m_BlackPoint[3];
FX_FLOAT m_Ranges[4];
};
FX_BOOL CPDF_LabCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
CPDF_Dictionary* pDict = pArray->GetDict(1);
if (!pDict) {
return FALSE;
}
CPDF_Array* pParam = pDict->GetArray(FX_BSTRC("WhitePoint"));
int i;
for (i = 0; i < 3; i++) {
m_WhitePoint[i] = pParam ? pParam->GetNumber(i) : 0;
}
pParam = pDict->GetArray(FX_BSTRC("BlackPoint"));
for (i = 0; i < 3; i++) {
m_BlackPoint[i] = pParam ? pParam->GetNumber(i) : 0;
}
pParam = pDict->GetArray(FX_BSTRC("Range"));
const FX_FLOAT def_ranges[4] = {-100 * 1.0f, 100 * 1.0f, -100 * 1.0f,
100 * 1.0f};
for (i = 0; i < 4; i++) {
m_Ranges[i] = pParam ? pParam->GetNumber(i) : def_ranges[i];
}
return TRUE;
}
void CPDF_LabCS::GetDefaultValue(int iComponent,
FX_FLOAT& value,
FX_FLOAT& min,
FX_FLOAT& max) const {
assert(iComponent < 3);
value = 0;
if (iComponent == 0) {
min = 0;
max = 100 * 1.0f;
} else {
min = m_Ranges[iComponent * 2 - 2];
max = m_Ranges[iComponent * 2 - 1];
if (value < min) {
value = min;
} else if (value > max) {
value = max;
}
}
}
FX_BOOL CPDF_LabCS::GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const {
FX_FLOAT Lstar = pBuf[0];
FX_FLOAT astar = pBuf[1];
FX_FLOAT bstar = pBuf[2];
FX_FLOAT M = (Lstar + 16.0f) / 116.0f;
FX_FLOAT L = M + astar / 500.0f;
FX_FLOAT N = M - bstar / 200.0f;
FX_FLOAT X, Y, Z;
if (L < 0.2069f) {
X = 0.957f * 0.12842f * (L - 0.1379f);
} else {
X = 0.957f * L * L * L;
}
if (M < 0.2069f) {
Y = 0.12842f * (M - 0.1379f);
} else {
Y = M * M * M;
}
if (N < 0.2069f) {
Z = 1.0889f * 0.12842f * (N - 0.1379f);
} else {
Z = 1.0889f * N * N * N;
}
XYZ_to_sRGB(X, Y, Z, R, G, B);
return TRUE;
}
FX_BOOL CPDF_LabCS::SetRGB(FX_FLOAT* pBuf,
FX_FLOAT R,
FX_FLOAT G,
FX_FLOAT B) const {
return FALSE;
}
void CPDF_LabCS::TranslateImageLine(uint8_t* pDestBuf,
const uint8_t* pSrcBuf,
int pixels,
int image_width,
int image_height,
FX_BOOL bTransMask) const {
for (int i = 0; i < pixels; i++) {
FX_FLOAT lab[3];
FX_FLOAT R, G, B;
lab[0] = (pSrcBuf[0] * 100 / 255.0f);
lab[1] = (FX_FLOAT)(pSrcBuf[1] - 128);
lab[2] = (FX_FLOAT)(pSrcBuf[2] - 128);
GetRGB(lab, R, G, B);
pDestBuf[0] = (int32_t)(B * 255);
pDestBuf[1] = (int32_t)(G * 255);
pDestBuf[2] = (int32_t)(R * 255);
pDestBuf += 3;
pSrcBuf += 3;
}
}
CPDF_IccProfile::CPDF_IccProfile(const uint8_t* pData, FX_DWORD dwSize)
: m_bsRGB(FALSE), m_pTransform(NULL), m_nSrcComponents(0) {
if (dwSize == 3144 &&
FXSYS_memcmp(pData + 0x190, "sRGB IEC61966-2.1", 17) == 0) {
m_bsRGB = TRUE;
m_nSrcComponents = 3;
} else if (CPDF_ModuleMgr::Get()->GetIccModule()) {
m_pTransform = CPDF_ModuleMgr::Get()->GetIccModule()->CreateTransform_sRGB(
pData, dwSize, m_nSrcComponents);
}
}
CPDF_IccProfile::~CPDF_IccProfile() {
if (m_pTransform) {
CPDF_ModuleMgr::Get()->GetIccModule()->DestroyTransform(m_pTransform);
}
}
class CPDF_ICCBasedCS : public CPDF_ColorSpace {
public:
explicit CPDF_ICCBasedCS(CPDF_Document* pDoc)
: CPDF_ColorSpace(pDoc, PDFCS_ICCBASED, 0),
m_pAlterCS(nullptr),
m_pProfile(nullptr),
m_pCache(nullptr),
m_pRanges(nullptr),
m_bOwn(FALSE) {}
~CPDF_ICCBasedCS() override;
FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
FX_BOOL GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const override;
FX_BOOL SetRGB(FX_FLOAT* pBuf,
FX_FLOAT R,
FX_FLOAT G,
FX_FLOAT B) const override;
FX_BOOL v_GetCMYK(FX_FLOAT* pBuf,
FX_FLOAT& c,
FX_FLOAT& m,
FX_FLOAT& y,
FX_FLOAT& k) const override;
void EnableStdConversion(FX_BOOL bEnabled) override;
void TranslateImageLine(uint8_t* pDestBuf,
const uint8_t* pSrcBuf,
int pixels,
int image_width,
int image_height,
FX_BOOL bTransMask = FALSE) const override;
CPDF_ColorSpace* m_pAlterCS;
CPDF_IccProfile* m_pProfile;
uint8_t* m_pCache;
FX_FLOAT* m_pRanges;
FX_BOOL m_bOwn;
};
CPDF_ICCBasedCS::~CPDF_ICCBasedCS() {
if (m_pCache) {
FX_Free(m_pCache);
}
if (m_pRanges) {
FX_Free(m_pRanges);
}
if (m_pAlterCS && m_bOwn) {
m_pAlterCS->ReleaseCS();
}
if (m_pProfile && m_pDocument) {
m_pDocument->GetPageData()->ReleaseIccProfile(m_pProfile);
}
}
FX_BOOL CPDF_ICCBasedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
CPDF_Stream* pStream = pArray->GetStream(1);
if (pStream == NULL) {
return FALSE;
}
m_pProfile = pDoc->LoadIccProfile(pStream);
if (!m_pProfile) {
return FALSE;
}
m_nComponents =
m_pProfile
->GetComponents(); // Try using the nComponents from ICC profile
CPDF_Dictionary* pDict = pStream->GetDict();
if (m_pProfile->m_pTransform == NULL) { // No valid ICC profile or using sRGB
CPDF_Object* pAlterCSObj =
pDict ? pDict->GetElementValue(FX_BSTRC("Alternate")) : NULL;
if (pAlterCSObj) {
CPDF_ColorSpace* pAlterCS = CPDF_ColorSpace::Load(pDoc, pAlterCSObj);
if (pAlterCS) {
if (m_nComponents == 0) { // NO valid ICC profile
if (pAlterCS->CountComponents() > 0) { // Use Alternative colorspace
m_nComponents = pAlterCS->CountComponents();
m_pAlterCS = pAlterCS;
m_bOwn = TRUE;
} else { // No valid alternative colorspace
pAlterCS->ReleaseCS();
int32_t nDictComponents =
pDict ? pDict->GetInteger(FX_BSTRC("N")) : 0;
if (nDictComponents != 1 && nDictComponents != 3 &&
nDictComponents != 4) {
return FALSE;
}
m_nComponents = nDictComponents;
}
} else { // Using sRGB
if (pAlterCS->CountComponents() != m_nComponents) {
pAlterCS->ReleaseCS();
} else {
m_pAlterCS = pAlterCS;
m_bOwn = TRUE;
}
}
}
}
if (!m_pAlterCS) {
if (m_nComponents == 1) {
m_pAlterCS = GetStockCS(PDFCS_DEVICEGRAY);
} else if (m_nComponents == 3) {
m_pAlterCS = GetStockCS(PDFCS_DEVICERGB);
} else if (m_nComponents == 4) {
m_pAlterCS = GetStockCS(PDFCS_DEVICECMYK);
}
}
}
CPDF_Array* pRanges = pDict->GetArray(FX_BSTRC("Range"));
m_pRanges = FX_Alloc2D(FX_FLOAT, m_nComponents, 2);
for (int i = 0; i < m_nComponents * 2; i++) {
if (pRanges) {
m_pRanges[i] = pRanges->GetNumber(i);
} else if (i % 2) {
m_pRanges[i] = 1.0f;
} else {
m_pRanges[i] = 0;
}
}
return TRUE;
}
FX_BOOL CPDF_ICCBasedCS::GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const {
if (m_pProfile && m_pProfile->m_bsRGB) {
R = pBuf[0];
G = pBuf[1];
B = pBuf[2];
return TRUE;
}
ICodec_IccModule* pIccModule = CPDF_ModuleMgr::Get()->GetIccModule();
if (m_pProfile->m_pTransform == NULL || pIccModule == NULL) {
if (m_pAlterCS) {
m_pAlterCS->GetRGB(pBuf, R, G, B);
} else {
R = G = B = 0.0f;
}
return TRUE;
}
FX_FLOAT rgb[3];
pIccModule->SetComponents(m_nComponents);
pIccModule->Translate(m_pProfile->m_pTransform, pBuf, rgb);
R = rgb[0];
G = rgb[1];
B = rgb[2];
return TRUE;
}
FX_BOOL CPDF_ICCBasedCS::v_GetCMYK(FX_FLOAT* pBuf,
FX_FLOAT& c,
FX_FLOAT& m,
FX_FLOAT& y,
FX_FLOAT& k) const {
if (m_nComponents != 4) {
return FALSE;
}
c = pBuf[0];
m = pBuf[1];
y = pBuf[2];
k = pBuf[3];
return TRUE;
}
FX_BOOL CPDF_ICCBasedCS::SetRGB(FX_FLOAT* pBuf,
FX_FLOAT R,
FX_FLOAT G,
FX_FLOAT B) const {
return FALSE;
}
void CPDF_ICCBasedCS::EnableStdConversion(FX_BOOL bEnabled) {
CPDF_ColorSpace::EnableStdConversion(bEnabled);
if (m_pAlterCS) {
m_pAlterCS->EnableStdConversion(bEnabled);
}
}
void CPDF_ICCBasedCS::TranslateImageLine(uint8_t* pDestBuf,
const uint8_t* pSrcBuf,
int pixels,
int image_width,
int image_height,
FX_BOOL bTransMask) const {
if (m_pProfile->m_bsRGB) {
ReverseRGB(pDestBuf, pSrcBuf, pixels);
} else if (m_pProfile->m_pTransform) {
int nMaxColors = 1;
for (int i = 0; i < m_nComponents; i++) {
nMaxColors *= 52;
}
if (m_nComponents > 3 || image_width * image_height < nMaxColors * 3 / 2) {
CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(
m_pProfile->m_pTransform, pDestBuf, pSrcBuf, pixels);
} else {
if (m_pCache == NULL) {
((CPDF_ICCBasedCS*)this)->m_pCache = FX_Alloc2D(uint8_t, nMaxColors, 3);
uint8_t* temp_src = FX_Alloc2D(uint8_t, nMaxColors, m_nComponents);
uint8_t* pSrc = temp_src;
for (int i = 0; i < nMaxColors; i++) {
FX_DWORD color = i;
FX_DWORD order = nMaxColors / 52;
for (int c = 0; c < m_nComponents; c++) {
*pSrc++ = (uint8_t)(color / order * 5);
color %= order;
order /= 52;
}
}
CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(
m_pProfile->m_pTransform, m_pCache, temp_src, nMaxColors);
FX_Free(temp_src);
}
for (int i = 0; i < pixels; i++) {
int index = 0;
for (int c = 0; c < m_nComponents; c++) {
index = index * 52 + (*pSrcBuf) / 5;
pSrcBuf++;
}
index *= 3;
*pDestBuf++ = m_pCache[index];
*pDestBuf++ = m_pCache[index + 1];
*pDestBuf++ = m_pCache[index + 2];
}
}
} else if (m_pAlterCS) {
m_pAlterCS->TranslateImageLine(pDestBuf, pSrcBuf, pixels, image_width,
image_height);
}
}
class CPDF_IndexedCS : public CPDF_ColorSpace {
public:
explicit CPDF_IndexedCS(CPDF_Document* pDoc)
: CPDF_ColorSpace(pDoc, PDFCS_INDEXED, 1),
m_pBaseCS(nullptr),
m_pCountedBaseCS(nullptr),
m_pCompMinMax(nullptr) {}
~CPDF_IndexedCS() override;
FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
FX_BOOL GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const override;
CPDF_ColorSpace* GetBaseCS() const override;
void EnableStdConversion(FX_BOOL bEnabled) override;
CPDF_ColorSpace* m_pBaseCS;
CPDF_CountedColorSpace* m_pCountedBaseCS;
int m_nBaseComponents;
int m_MaxIndex;
CFX_ByteString m_Table;
FX_FLOAT* m_pCompMinMax;
};
CPDF_IndexedCS::~CPDF_IndexedCS() {
if (m_pCompMinMax) {
FX_Free(m_pCompMinMax);
}
CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : NULL;
if (pCS && m_pDocument) {
m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
}
}
FX_BOOL CPDF_IndexedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
if (pArray->GetCount() < 4) {
return FALSE;
}
CPDF_Object* pBaseObj = pArray->GetElementValue(1);
if (pBaseObj == m_pArray) {
return FALSE;
}
CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
m_pBaseCS = pDocPageData->GetColorSpace(pBaseObj, NULL);
if (m_pBaseCS == NULL) {
return FALSE;
}
m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
m_nBaseComponents = m_pBaseCS->CountComponents();
m_pCompMinMax = FX_Alloc2D(FX_FLOAT, m_nBaseComponents, 2);
FX_FLOAT defvalue;
for (int i = 0; i < m_nBaseComponents; i++) {
m_pBaseCS->GetDefaultValue(i, defvalue, m_pCompMinMax[i * 2],
m_pCompMinMax[i * 2 + 1]);
m_pCompMinMax[i * 2 + 1] -= m_pCompMinMax[i * 2];
}
m_MaxIndex = pArray->GetInteger(2);
CPDF_Object* pTableObj = pArray->GetElementValue(3);
if (pTableObj == NULL) {
return FALSE;
}
if (pTableObj->GetType() == PDFOBJ_STRING) {
m_Table = ((CPDF_String*)pTableObj)->GetString();
} else if (pTableObj->GetType() == PDFOBJ_STREAM) {
CPDF_StreamAcc acc;
acc.LoadAllData((CPDF_Stream*)pTableObj, FALSE);
m_Table = CFX_ByteStringC(acc.GetData(), acc.GetSize());
}
return TRUE;
}
FX_BOOL CPDF_IndexedCS::GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const {
int index = (int32_t)(*pBuf);
if (index < 0 || index > m_MaxIndex) {
return FALSE;
}
if (m_nBaseComponents) {
if (index == INT_MAX || (index + 1) > INT_MAX / m_nBaseComponents ||
(index + 1) * m_nBaseComponents > (int)m_Table.GetLength()) {
R = G = B = 0;
return FALSE;
}
}
CFX_FixedBufGrow<FX_FLOAT, 16> Comps(m_nBaseComponents);
FX_FLOAT* comps = Comps;
const uint8_t* pTable = m_Table;
for (int i = 0; i < m_nBaseComponents; i++) {
comps[i] =
m_pCompMinMax[i * 2] +
m_pCompMinMax[i * 2 + 1] * pTable[index * m_nBaseComponents + i] / 255;
}
m_pBaseCS->GetRGB(comps, R, G, B);
return TRUE;
}
CPDF_ColorSpace* CPDF_IndexedCS::GetBaseCS() const {
return m_pBaseCS;
}
void CPDF_IndexedCS::EnableStdConversion(FX_BOOL bEnabled) {
CPDF_ColorSpace::EnableStdConversion(bEnabled);
if (m_pBaseCS) {
m_pBaseCS->EnableStdConversion(bEnabled);
}
}
#define MAX_PATTERN_COLORCOMPS 16
typedef struct _PatternValue {
CPDF_Pattern* m_pPattern;
CPDF_CountedPattern* m_pCountedPattern;
int m_nComps;
FX_FLOAT m_Comps[MAX_PATTERN_COLORCOMPS];
} PatternValue;
CPDF_PatternCS::~CPDF_PatternCS() {
CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : NULL;
if (pCS && m_pDocument) {
m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
}
}
FX_BOOL CPDF_PatternCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
CPDF_Object* pBaseCS = pArray->GetElementValue(1);
if (pBaseCS == m_pArray) {
return FALSE;
}
CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
m_pBaseCS = pDocPageData->GetColorSpace(pBaseCS, NULL);
if (m_pBaseCS) {
if (m_pBaseCS->GetFamily() == PDFCS_PATTERN) {
return FALSE;
}
m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
m_nComponents = m_pBaseCS->CountComponents() + 1;
if (m_pBaseCS->CountComponents() > MAX_PATTERN_COLORCOMPS) {
return FALSE;
}
} else {
m_nComponents = 1;
}
return TRUE;
}
FX_BOOL CPDF_PatternCS::GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const {
if (m_pBaseCS) {
ASSERT(m_pBaseCS->GetFamily() != PDFCS_PATTERN);
PatternValue* pvalue = (PatternValue*)pBuf;
if (m_pBaseCS->GetRGB(pvalue->m_Comps, R, G, B)) {
return TRUE;
}
}
R = G = B = 0.75f;
return FALSE;
}
CPDF_ColorSpace* CPDF_PatternCS::GetBaseCS() const {
return m_pBaseCS;
}
class CPDF_SeparationCS : public CPDF_ColorSpace {
public:
CPDF_SeparationCS(CPDF_Document* pDoc)
: CPDF_ColorSpace(pDoc, PDFCS_SEPARATION, 1),
m_pAltCS(nullptr),
m_pFunc(nullptr) {}
~CPDF_SeparationCS() override;
void GetDefaultValue(int iComponent,
FX_FLOAT& value,
FX_FLOAT& min,
FX_FLOAT& max) const override;
FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
FX_BOOL GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const override;
void EnableStdConversion(FX_BOOL bEnabled) override;
CPDF_ColorSpace* m_pAltCS;
CPDF_Function* m_pFunc;
enum { None, All, Colorant } m_Type;
};
CPDF_SeparationCS::~CPDF_SeparationCS() {
if (m_pAltCS) {
m_pAltCS->ReleaseCS();
}
delete m_pFunc;
}
void CPDF_SeparationCS::GetDefaultValue(int iComponent,
FX_FLOAT& value,
FX_FLOAT& min,
FX_FLOAT& max) const {
value = 1.0f;
min = 0;
max = 1.0f;
}
FX_BOOL CPDF_SeparationCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
CFX_ByteString name = pArray->GetString(1);
if (name == FX_BSTRC("None")) {
m_Type = None;
} else {
m_Type = Colorant;
CPDF_Object* pAltCS = pArray->GetElementValue(2);
if (pAltCS == m_pArray) {
return FALSE;
}
m_pAltCS = Load(pDoc, pAltCS);
if (!m_pAltCS) {
return FALSE;
}
CPDF_Object* pFuncObj = pArray->GetElementValue(3);
if (pFuncObj && pFuncObj->GetType() != PDFOBJ_NAME) {
m_pFunc = CPDF_Function::Load(pFuncObj);
}
if (m_pFunc && m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
delete m_pFunc;
m_pFunc = NULL;
}
}
return TRUE;
}
FX_BOOL CPDF_SeparationCS::GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const {
if (m_Type == None) {
return FALSE;
}
if (m_pFunc == NULL) {
if (m_pAltCS == NULL) {
return FALSE;
}
int nComps = m_pAltCS->CountComponents();
CFX_FixedBufGrow<FX_FLOAT, 16> results(nComps);
for (int i = 0; i < nComps; i++) {
results[i] = *pBuf;
}
m_pAltCS->GetRGB(results, R, G, B);
return TRUE;
}
CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
int nresults = 0;
m_pFunc->Call(pBuf, 1, results, nresults);
if (nresults == 0) {
return FALSE;
}
if (m_pAltCS) {
m_pAltCS->GetRGB(results, R, G, B);
return TRUE;
}
R = G = B = 0;
return FALSE;
}
void CPDF_SeparationCS::EnableStdConversion(FX_BOOL bEnabled) {
CPDF_ColorSpace::EnableStdConversion(bEnabled);
if (m_pAltCS) {
m_pAltCS->EnableStdConversion(bEnabled);
}
}
class CPDF_DeviceNCS : public CPDF_ColorSpace {
public:
CPDF_DeviceNCS(CPDF_Document* pDoc)
: CPDF_ColorSpace(pDoc, PDFCS_DEVICEN, 0),
m_pAltCS(nullptr),
m_pFunc(nullptr) {}
~CPDF_DeviceNCS() override;
void GetDefaultValue(int iComponent,
FX_FLOAT& value,
FX_FLOAT& min,
FX_FLOAT& max) const override;
FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
FX_BOOL GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const override;
void EnableStdConversion(FX_BOOL bEnabled) override;
CPDF_ColorSpace* m_pAltCS;
CPDF_Function* m_pFunc;
};
CPDF_DeviceNCS::~CPDF_DeviceNCS() {
delete m_pFunc;
if (m_pAltCS) {
m_pAltCS->ReleaseCS();
}
}
void CPDF_DeviceNCS::GetDefaultValue(int iComponent,
FX_FLOAT& value,
FX_FLOAT& min,
FX_FLOAT& max) const {
value = 1.0f;
min = 0;
max = 1.0f;
}
FX_BOOL CPDF_DeviceNCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
CPDF_Object* pObj = pArray->GetElementValue(1);
if (!pObj) {
return FALSE;
}
if (pObj->GetType() != PDFOBJ_ARRAY) {
return FALSE;
}
m_nComponents = ((CPDF_Array*)pObj)->GetCount();
CPDF_Object* pAltCS = pArray->GetElementValue(2);
if (!pAltCS || pAltCS == m_pArray) {
return FALSE;
}
m_pAltCS = Load(pDoc, pAltCS);
m_pFunc = CPDF_Function::Load(pArray->GetElementValue(3));
if (m_pAltCS == NULL || m_pFunc == NULL) {
return FALSE;
}
if (m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
return FALSE;
}
return TRUE;
}
FX_BOOL CPDF_DeviceNCS::GetRGB(FX_FLOAT* pBuf,
FX_FLOAT& R,
FX_FLOAT& G,
FX_FLOAT& B) const {
if (m_pFunc == NULL) {
return FALSE;
}
CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
int nresults = 0;
m_pFunc->Call(pBuf, m_nComponents, results, nresults);
if (nresults == 0) {
return FALSE;
}
m_pAltCS->GetRGB(results, R, G, B);
return TRUE;
}
void CPDF_DeviceNCS::EnableStdConversion(FX_BOOL bEnabled) {
CPDF_ColorSpace::EnableStdConversion(bEnabled);
if (m_pAltCS) {
m_pAltCS->EnableStdConversion(bEnabled);
}
}
CPDF_ColorSpace* CPDF_ColorSpace::GetStockCS(int family) {
return CPDF_ModuleMgr::Get()->GetPageModule()->GetStockCS(family);
;
}
CPDF_ColorSpace* _CSFromName(const CFX_ByteString& name) {
if (name == FX_BSTRC("DeviceRGB") || name == FX_BSTRC("RGB")) {
return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
}
if (name == FX_BSTRC("DeviceGray") || name == FX_BSTRC("G")) {
return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY);
}
if (name == FX_BSTRC("DeviceCMYK") || name == FX_BSTRC("CMYK")) {
return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK);
}
if (name == FX_BSTRC("Pattern")) {
return CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
}
return NULL;
}
CPDF_ColorSpace* CPDF_ColorSpace::Load(CPDF_Document* pDoc, CPDF_Object* pObj) {
if (pObj == NULL) {
return NULL;
}
if (pObj->GetType() == PDFOBJ_NAME) {
return _CSFromName(pObj->GetString());
}
if (pObj->GetType() == PDFOBJ_STREAM) {
CPDF_Dictionary* pDict = ((CPDF_Stream*)pObj)->GetDict();
if (!pDict) {
return NULL;
}
CPDF_ColorSpace* pRet = NULL;
FX_POSITION pos = pDict->GetStartPos();
while (pos) {
CFX_ByteString bsKey;
CPDF_Object* pValue = pDict->GetNextElement(pos, bsKey);
if (pValue && pValue->GetType() == PDFOBJ_NAME) {
pRet = _CSFromName(pValue->GetString());
}
if (pRet) {
return pRet;
}
}
return NULL;
}
if (pObj->GetType() != PDFOBJ_ARRAY) {
return NULL;
}
CPDF_Array* pArray = (CPDF_Array*)pObj;
if (pArray->GetCount() == 0) {
return NULL;
}
CPDF_Object* pFamilyObj = pArray->GetElementValue(0);
if (!pFamilyObj) {
return NULL;
}
CFX_ByteString familyname = pFamilyObj->GetString();
if (pArray->GetCount() == 1) {
return _CSFromName(familyname);
}
CPDF_ColorSpace* pCS = NULL;
FX_DWORD id = familyname.GetID();
if (id == FXBSTR_ID('C', 'a', 'l', 'G')) {
pCS = new CPDF_CalGray(pDoc);
} else if (id == FXBSTR_ID('C', 'a', 'l', 'R')) {
pCS = new CPDF_CalRGB(pDoc);
} else if (id == FXBSTR_ID('L', 'a', 'b', 0)) {
pCS = new CPDF_LabCS(pDoc);
} else if (id == FXBSTR_ID('I', 'C', 'C', 'B')) {
pCS = new CPDF_ICCBasedCS(pDoc);
} else if (id == FXBSTR_ID('I', 'n', 'd', 'e') ||
id == FXBSTR_ID('I', 0, 0, 0)) {
pCS = new CPDF_IndexedCS(pDoc);
} else if (id == FXBSTR_ID('S', 'e', 'p', 'a')) {
pCS = new CPDF_SeparationCS(pDoc);
} else if (id == FXBSTR_ID('D', 'e', 'v', 'i')) {
pCS = new CPDF_DeviceNCS(pDoc);
} else if (id == FXBSTR_ID('P', 'a', 't', 't')) {
pCS = new CPDF_PatternCS(pDoc);
} else {
return NULL;
}
pCS->m_pArray = pArray;
if (!pCS->v_Load(pDoc, pArray)) {
pCS->ReleaseCS();
return NULL;
}
return pCS;
}
void CPDF_ColorSpace::ReleaseCS() {
if (this == GetStockCS(PDFCS_DEVICERGB)) {
return;
}
if (this == GetStockCS(PDFCS_DEVICEGRAY)) {
return;
}
if (this == GetStockCS(PDFCS_DEVICECMYK)) {
return;
}
if (this == GetStockCS(PDFCS_PATTERN)) {
return;
}
delete this;
}
int CPDF_ColorSpace::GetBufSize() const {
if (m_Family == PDFCS_PATTERN) {
return sizeof(PatternValue);
}
return m_nComponents * sizeof(FX_FLOAT);
}
FX_FLOAT* CPDF_ColorSpace::CreateBuf() {
int size = GetBufSize();
uint8_t* pBuf = FX_Alloc(uint8_t, size);
return (FX_FLOAT*)pBuf;
}
FX_BOOL CPDF_ColorSpace::sRGB() const {
if (m_Family == PDFCS_DEVICERGB) {
return TRUE;
}
if (m_Family != PDFCS_ICCBASED) {
return FALSE;
}
CPDF_ICCBasedCS* pCS = (CPDF_ICCBasedCS*)this;
return pCS->m_pProfile->m_bsRGB;
}
FX_BOOL CPDF_ColorSpace::GetCMYK(FX_FLOAT* pBuf,
FX_FLOAT& c,
FX_FLOAT& m,
FX_FLOAT& y,
FX_FLOAT& k) const {
if (v_GetCMYK(pBuf, c, m, y, k)) {
return TRUE;
}
FX_FLOAT R, G, B;
if (!GetRGB(pBuf, R, G, B)) {
return FALSE;
}
sRGB_to_AdobeCMYK(R, G, B, c, m, y, k);
return TRUE;
}
FX_BOOL CPDF_ColorSpace::SetCMYK(FX_FLOAT* pBuf,
FX_FLOAT c,
FX_FLOAT m,
FX_FLOAT y,
FX_FLOAT k) const {
if (v_SetCMYK(pBuf, c, m, y, k)) {
return TRUE;
}
FX_FLOAT R, G, B;
AdobeCMYK_to_sRGB(c, m, y, k, R, G, B);
return SetRGB(pBuf, R, G, B);
}
void CPDF_ColorSpace::GetDefaultColor(FX_FLOAT* buf) const {
if (buf == NULL || m_Family == PDFCS_PATTERN) {
return;
}
FX_FLOAT min, max;
for (int i = 0; i < m_nComponents; i++) {
GetDefaultValue(i, buf[i], min, max);
}
}
int CPDF_ColorSpace::GetMaxIndex() const {
if (m_Family != PDFCS_INDEXED) {
return 0;
}
CPDF_IndexedCS* pCS = (CPDF_IndexedCS*)this;
return pCS->m_MaxIndex;
}
void CPDF_ColorSpace::TranslateImageLine(uint8_t* dest_buf,
const uint8_t* src_buf,
int pixels,
int image_width,
int image_height,
FX_BOOL bTransMask) const {
CFX_FixedBufGrow<FX_FLOAT, 16> srcbuf(m_nComponents);
FX_FLOAT* src = srcbuf;
FX_FLOAT R, G, B;
for (int i = 0; i < pixels; i++) {
for (int j = 0; j < m_nComponents; j++)
if (m_Family == PDFCS_INDEXED) {
src[j] = (FX_FLOAT)(*src_buf++);
} else {
src[j] = (FX_FLOAT)(*src_buf++) / 255;
}
GetRGB(src, R, G, B);
*dest_buf++ = (int32_t)(B * 255);
*dest_buf++ = (int32_t)(G * 255);
*dest_buf++ = (int32_t)(R * 255);
}
}
void CPDF_ColorSpace::EnableStdConversion(FX_BOOL bEnabled) {
if (bEnabled) {
m_dwStdConversion++;
} else if (m_dwStdConversion) {
m_dwStdConversion--;
}
}
CPDF_Color::CPDF_Color(int family) {
m_pCS = CPDF_ColorSpace::GetStockCS(family);
int nComps = 3;
if (family == PDFCS_DEVICEGRAY) {
nComps = 1;
} else if (family == PDFCS_DEVICECMYK) {
nComps = 4;
}
m_pBuffer = FX_Alloc(FX_FLOAT, nComps);
for (int i = 0; i < nComps; i++) {
m_pBuffer[i] = 0;
}
}
CPDF_Color::~CPDF_Color() {
ReleaseBuffer();
ReleaseColorSpace();
}
void CPDF_Color::ReleaseBuffer() {
if (!m_pBuffer) {
return;
}
if (m_pCS->GetFamily() == PDFCS_PATTERN) {
PatternValue* pvalue = (PatternValue*)m_pBuffer;
CPDF_Pattern* pPattern =
pvalue->m_pCountedPattern ? pvalue->m_pCountedPattern->get() : NULL;
if (pPattern && pPattern->m_pDocument) {
CPDF_DocPageData* pPageData = pPattern->m_pDocument->GetPageData();
if (pPageData) {
pPageData->ReleasePattern(pPattern->m_pPatternObj);
}
}
}
FX_Free(m_pBuffer);
m_pBuffer = NULL;
}
void CPDF_Color::ReleaseColorSpace() {
if (m_pCS && m_pCS->m_pDocument && m_pCS->GetArray()) {
m_pCS->m_pDocument->GetPageData()->ReleaseColorSpace(m_pCS->GetArray());
m_pCS = NULL;
}
}
void CPDF_Color::SetColorSpace(CPDF_ColorSpace* pCS) {
if (m_pCS == pCS) {
if (m_pBuffer == NULL) {
m_pBuffer = pCS->CreateBuf();
}
ReleaseColorSpace();
m_pCS = pCS;
return;
}
ReleaseBuffer();
ReleaseColorSpace();
m_pCS = pCS;
if (m_pCS) {
m_pBuffer = pCS->CreateBuf();
pCS->GetDefaultColor(m_pBuffer);
}
}
void CPDF_Color::SetValue(FX_FLOAT* comps) {
if (m_pBuffer == NULL) {
return;
}
if (m_pCS->GetFamily() != PDFCS_PATTERN) {
FXSYS_memcpy(m_pBuffer, comps, m_pCS->CountComponents() * sizeof(FX_FLOAT));
}
}
void CPDF_Color::SetValue(CPDF_Pattern* pPattern, FX_FLOAT* comps, int ncomps) {
if (ncomps > MAX_PATTERN_COLORCOMPS) {
return;
}
if (m_pCS == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
if (m_pBuffer) {
FX_Free(m_pBuffer);
}
m_pCS = CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
m_pBuffer = m_pCS->CreateBuf();
}
CPDF_DocPageData* pDocPageData = NULL;
PatternValue* pvalue = (PatternValue*)m_pBuffer;
if (pvalue->m_pPattern && pvalue->m_pPattern->m_pDocument) {
pDocPageData = pvalue->m_pPattern->m_pDocument->GetPageData();
if (pDocPageData) {
pDocPageData->ReleasePattern(pvalue->m_pPattern->m_pPatternObj);
}
}
pvalue->m_nComps = ncomps;
pvalue->m_pPattern = pPattern;
if (ncomps) {
FXSYS_memcpy(pvalue->m_Comps, comps, ncomps * sizeof(FX_FLOAT));
}
pvalue->m_pCountedPattern = NULL;
if (pPattern && pPattern->m_pDocument) {
if (!pDocPageData) {
pDocPageData = pPattern->m_pDocument->GetPageData();
}
pvalue->m_pCountedPattern =
pDocPageData->FindPatternPtr(pPattern->m_pPatternObj);
}
}
void CPDF_Color::Copy(const CPDF_Color* pSrc) {
ReleaseBuffer();
ReleaseColorSpace();
m_pCS = pSrc->m_pCS;
if (m_pCS && m_pCS->m_pDocument) {
CPDF_Array* pArray = m_pCS->GetArray();
if (pArray) {
m_pCS = m_pCS->m_pDocument->GetPageData()->GetCopiedColorSpace(pArray);
}
}
if (m_pCS == NULL) {
return;
}
m_pBuffer = m_pCS->CreateBuf();
FXSYS_memcpy(m_pBuffer, pSrc->m_pBuffer, m_pCS->GetBufSize());
if (m_pCS->GetFamily() == PDFCS_PATTERN) {
PatternValue* pvalue = (PatternValue*)m_pBuffer;
if (pvalue->m_pPattern && pvalue->m_pPattern->m_pDocument) {
pvalue->m_pPattern =
pvalue->m_pPattern->m_pDocument->GetPageData()->GetPattern(
pvalue->m_pPattern->m_pPatternObj, FALSE,
&pvalue->m_pPattern->m_ParentMatrix);
}
}
}
FX_BOOL CPDF_Color::GetRGB(int& R, int& G, int& B) const {
if (m_pCS == NULL || m_pBuffer == NULL) {
return FALSE;
}
FX_FLOAT r = 0.0f, g = 0.0f, b = 0.0f;
if (!m_pCS->GetRGB(m_pBuffer, r, g, b)) {
return FALSE;
}
R = (int32_t)(r * 255 + 0.5f);
G = (int32_t)(g * 255 + 0.5f);
B = (int32_t)(b * 255 + 0.5f);
return TRUE;
}
CPDF_Pattern* CPDF_Color::GetPattern() const {
if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
return NULL;
}
PatternValue* pvalue = (PatternValue*)m_pBuffer;
return pvalue->m_pPattern;
}
CPDF_ColorSpace* CPDF_Color::GetPatternCS() const {
if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
return NULL;
}
return m_pCS->GetBaseCS();
}
FX_FLOAT* CPDF_Color::GetPatternColor() const {
if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
return NULL;
}
PatternValue* pvalue = (PatternValue*)m_pBuffer;
return pvalue->m_nComps ? pvalue->m_Comps : NULL;
}
FX_BOOL CPDF_Color::IsEqual(const CPDF_Color& other) const {
if (m_pCS != other.m_pCS || m_pCS == NULL) {
return FALSE;
}
return FXSYS_memcmp(m_pBuffer, other.m_pBuffer, m_pCS->GetBufSize()) == 0;
}