1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "pageint.h"
8
9 #include <limits.h>
10
11 #include <algorithm>
12
13 #include "core/include/fpdfapi/fpdf_page.h"
14 #include "core/include/fpdfapi/fpdf_module.h"
15 #include "core/include/fxcodec/fx_codec.h"
16
17 namespace {
18
sRGB_to_AdobeCMYK(FX_FLOAT R,FX_FLOAT G,FX_FLOAT B,FX_FLOAT & c,FX_FLOAT & m,FX_FLOAT & y,FX_FLOAT & k)19 void sRGB_to_AdobeCMYK(FX_FLOAT R,
20 FX_FLOAT G,
21 FX_FLOAT B,
22 FX_FLOAT& c,
23 FX_FLOAT& m,
24 FX_FLOAT& y,
25 FX_FLOAT& k) {
26 c = 1.0f - R;
27 m = 1.0f - G;
28 y = 1.0f - B;
29 k = c;
30 if (m < k) {
31 k = m;
32 }
33 if (y < k) {
34 k = y;
35 }
36 }
37
ComponentsForFamily(int family)38 int ComponentsForFamily(int family) {
39 if (family == PDFCS_DEVICERGB)
40 return 3;
41 if (family == PDFCS_DEVICEGRAY)
42 return 1;
43 return 4;
44 }
45
ReverseRGB(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels)46 void ReverseRGB(uint8_t* pDestBuf, const uint8_t* pSrcBuf, int pixels) {
47 if (pDestBuf == pSrcBuf) {
48 for (int i = 0; i < pixels; i++) {
49 uint8_t temp = pDestBuf[2];
50 pDestBuf[2] = pDestBuf[0];
51 pDestBuf[0] = temp;
52 pDestBuf += 3;
53 }
54 } else {
55 for (int i = 0; i < pixels; i++) {
56 *pDestBuf++ = pSrcBuf[2];
57 *pDestBuf++ = pSrcBuf[1];
58 *pDestBuf++ = pSrcBuf[0];
59 pSrcBuf += 3;
60 }
61 }
62 }
63
64 } // namespace
65
CPDF_DeviceCS(CPDF_Document * pDoc,int family)66 CPDF_DeviceCS::CPDF_DeviceCS(CPDF_Document* pDoc, int family)
67 : CPDF_ColorSpace(pDoc, family, ComponentsForFamily(family)) {}
68
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const69 FX_BOOL CPDF_DeviceCS::GetRGB(FX_FLOAT* pBuf,
70 FX_FLOAT& R,
71 FX_FLOAT& G,
72 FX_FLOAT& B) const {
73 if (m_Family == PDFCS_DEVICERGB) {
74 R = pBuf[0];
75 if (R < 0) {
76 R = 0;
77 } else if (R > 1) {
78 R = 1;
79 }
80 G = pBuf[1];
81 if (G < 0) {
82 G = 0;
83 } else if (G > 1) {
84 G = 1;
85 }
86 B = pBuf[2];
87 if (B < 0) {
88 B = 0;
89 } else if (B > 1) {
90 B = 1;
91 }
92 } else if (m_Family == PDFCS_DEVICEGRAY) {
93 R = *pBuf;
94 if (R < 0) {
95 R = 0;
96 } else if (R > 1) {
97 R = 1;
98 }
99 G = B = R;
100 } else if (m_Family == PDFCS_DEVICECMYK) {
101 if (!m_dwStdConversion) {
102 AdobeCMYK_to_sRGB(pBuf[0], pBuf[1], pBuf[2], pBuf[3], R, G, B);
103 } else {
104 FX_FLOAT k = pBuf[3];
105 R = 1.0f - std::min(1.0f, pBuf[0] + k);
106 G = 1.0f - std::min(1.0f, pBuf[1] + k);
107 B = 1.0f - std::min(1.0f, pBuf[2] + k);
108 }
109 } else {
110 ASSERT(m_Family == PDFCS_PATTERN);
111 R = G = B = 0;
112 return FALSE;
113 }
114 return TRUE;
115 }
v_GetCMYK(FX_FLOAT * pBuf,FX_FLOAT & c,FX_FLOAT & m,FX_FLOAT & y,FX_FLOAT & k) const116 FX_BOOL CPDF_DeviceCS::v_GetCMYK(FX_FLOAT* pBuf,
117 FX_FLOAT& c,
118 FX_FLOAT& m,
119 FX_FLOAT& y,
120 FX_FLOAT& k) const {
121 if (m_Family != PDFCS_DEVICECMYK) {
122 return FALSE;
123 }
124 c = pBuf[0];
125 m = pBuf[1];
126 y = pBuf[2];
127 k = pBuf[3];
128 return TRUE;
129 }
SetRGB(FX_FLOAT * pBuf,FX_FLOAT R,FX_FLOAT G,FX_FLOAT B) const130 FX_BOOL CPDF_DeviceCS::SetRGB(FX_FLOAT* pBuf,
131 FX_FLOAT R,
132 FX_FLOAT G,
133 FX_FLOAT B) const {
134 if (m_Family == PDFCS_DEVICERGB) {
135 pBuf[0] = R;
136 pBuf[1] = G;
137 pBuf[2] = B;
138 return TRUE;
139 }
140 if (m_Family == PDFCS_DEVICEGRAY) {
141 if (R == G && R == B) {
142 *pBuf = R;
143 return TRUE;
144 }
145 return FALSE;
146 }
147 if (m_Family == PDFCS_DEVICECMYK) {
148 sRGB_to_AdobeCMYK(R, G, B, pBuf[0], pBuf[1], pBuf[2], pBuf[3]);
149 return TRUE;
150 }
151 return FALSE;
152 }
v_SetCMYK(FX_FLOAT * pBuf,FX_FLOAT c,FX_FLOAT m,FX_FLOAT y,FX_FLOAT k) const153 FX_BOOL CPDF_DeviceCS::v_SetCMYK(FX_FLOAT* pBuf,
154 FX_FLOAT c,
155 FX_FLOAT m,
156 FX_FLOAT y,
157 FX_FLOAT k) const {
158 if (m_Family == PDFCS_DEVICERGB) {
159 AdobeCMYK_to_sRGB(c, m, y, k, pBuf[0], pBuf[1], pBuf[2]);
160 return TRUE;
161 }
162 if (m_Family == PDFCS_DEVICECMYK) {
163 pBuf[0] = c;
164 pBuf[1] = m;
165 pBuf[2] = y;
166 pBuf[3] = k;
167 return TRUE;
168 }
169 return FALSE;
170 }
171
TranslateImageLine(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels,int image_width,int image_height,FX_BOOL bTransMask) const172 void CPDF_DeviceCS::TranslateImageLine(uint8_t* pDestBuf,
173 const uint8_t* pSrcBuf,
174 int pixels,
175 int image_width,
176 int image_height,
177 FX_BOOL bTransMask) const {
178 if (bTransMask && m_Family == PDFCS_DEVICECMYK) {
179 for (int i = 0; i < pixels; i++) {
180 int k = 255 - pSrcBuf[3];
181 pDestBuf[0] = ((255 - pSrcBuf[0]) * k) / 255;
182 pDestBuf[1] = ((255 - pSrcBuf[1]) * k) / 255;
183 pDestBuf[2] = ((255 - pSrcBuf[2]) * k) / 255;
184 pDestBuf += 3;
185 pSrcBuf += 4;
186 }
187 return;
188 }
189 if (m_Family == PDFCS_DEVICERGB) {
190 ReverseRGB(pDestBuf, pSrcBuf, pixels);
191 } else if (m_Family == PDFCS_DEVICEGRAY) {
192 for (int i = 0; i < pixels; i++) {
193 *pDestBuf++ = pSrcBuf[i];
194 *pDestBuf++ = pSrcBuf[i];
195 *pDestBuf++ = pSrcBuf[i];
196 }
197 } else {
198 for (int i = 0; i < pixels; i++) {
199 if (!m_dwStdConversion) {
200 AdobeCMYK_to_sRGB1(pSrcBuf[0], pSrcBuf[1], pSrcBuf[2], pSrcBuf[3],
201 pDestBuf[2], pDestBuf[1], pDestBuf[0]);
202 } else {
203 uint8_t k = pSrcBuf[3];
204 pDestBuf[2] = 255 - std::min(255, pSrcBuf[0] + k);
205 pDestBuf[1] = 255 - std::min(255, pSrcBuf[1] + k);
206 pDestBuf[0] = 255 - std::min(255, pSrcBuf[2] + k);
207 }
208 pSrcBuf += 4;
209 pDestBuf += 3;
210 }
211 }
212 }
213 const uint8_t g_sRGBSamples1[] = {
214 0, 3, 6, 10, 13, 15, 18, 20, 22, 23, 25, 27, 28, 30, 31,
215 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
216 48, 49, 49, 50, 51, 52, 53, 53, 54, 55, 56, 56, 57, 58, 58,
217 59, 60, 61, 61, 62, 62, 63, 64, 64, 65, 66, 66, 67, 67, 68,
218 68, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 76, 76,
219 77, 77, 78, 78, 79, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83,
220 84, 84, 85, 85, 85, 86, 86, 87, 87, 88, 88, 88, 89, 89, 90,
221 90, 91, 91, 91, 92, 92, 93, 93, 93, 94, 94, 95, 95, 95, 96,
222 96, 97, 97, 97, 98, 98, 98, 99, 99, 99, 100, 100, 101, 101, 101,
223 102, 102, 102, 103, 103, 103, 104, 104, 104, 105, 105, 106, 106, 106, 107,
224 107, 107, 108, 108, 108, 109, 109, 109, 110, 110, 110, 110, 111, 111, 111,
225 112, 112, 112, 113, 113, 113, 114, 114, 114, 115, 115, 115, 115, 116, 116,
226 116, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 120,
227 };
228 const uint8_t g_sRGBSamples2[] = {
229 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
230 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149,
231 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 159, 160, 161, 162,
232 163, 163, 164, 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173,
233 174, 175, 175, 176, 177, 178, 178, 179, 180, 180, 181, 182, 182, 183, 184,
234 185, 185, 186, 187, 187, 188, 189, 189, 190, 190, 191, 192, 192, 193, 194,
235 194, 195, 196, 196, 197, 197, 198, 199, 199, 200, 200, 201, 202, 202, 203,
236 203, 204, 205, 205, 206, 206, 207, 208, 208, 209, 209, 210, 210, 211, 212,
237 212, 213, 213, 214, 214, 215, 215, 216, 216, 217, 218, 218, 219, 219, 220,
238 220, 221, 221, 222, 222, 223, 223, 224, 224, 225, 226, 226, 227, 227, 228,
239 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235,
240 236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242,
241 243, 243, 244, 244, 245, 245, 246, 246, 246, 247, 247, 248, 248, 249, 249,
242 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255,
243 };
244
RGB_Conversion(FX_FLOAT colorComponent)245 static FX_FLOAT RGB_Conversion(FX_FLOAT colorComponent) {
246 if (colorComponent > 1) {
247 colorComponent = 1;
248 }
249 if (colorComponent < 0) {
250 colorComponent = 0;
251 }
252 int scale = (int)(colorComponent * 1023);
253 if (scale < 0) {
254 scale = 0;
255 }
256 if (scale < 192) {
257 colorComponent = (g_sRGBSamples1[scale] / 255.0f);
258 } else {
259 colorComponent = (g_sRGBSamples2[scale / 4 - 48] / 255.0f);
260 }
261 return colorComponent;
262 }
263
XYZ_to_sRGB(FX_FLOAT X,FX_FLOAT Y,FX_FLOAT Z,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B)264 static void XYZ_to_sRGB(FX_FLOAT X,
265 FX_FLOAT Y,
266 FX_FLOAT Z,
267 FX_FLOAT& R,
268 FX_FLOAT& G,
269 FX_FLOAT& B) {
270 FX_FLOAT R1 = 3.2410f * X - 1.5374f * Y - 0.4986f * Z;
271 FX_FLOAT G1 = -0.9692f * X + 1.8760f * Y + 0.0416f * Z;
272 FX_FLOAT B1 = 0.0556f * X - 0.2040f * Y + 1.0570f * Z;
273
274 R = RGB_Conversion(R1);
275 G = RGB_Conversion(G1);
276 B = RGB_Conversion(B1);
277 }
278
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)279 static void XYZ_to_sRGB_WhitePoint(FX_FLOAT X,
280 FX_FLOAT Y,
281 FX_FLOAT Z,
282 FX_FLOAT& R,
283 FX_FLOAT& G,
284 FX_FLOAT& B,
285 FX_FLOAT Xw,
286 FX_FLOAT Yw,
287 FX_FLOAT Zw) {
288 // The following RGB_xyz is based on
289 // sRGB value {Rx,Ry}={0.64, 0.33}, {Gx,Gy}={0.30, 0.60}, {Bx,By}={0.15, 0.06}
290
291 FX_FLOAT Rx = 0.64f, Ry = 0.33f;
292 FX_FLOAT Gx = 0.30f, Gy = 0.60f;
293 FX_FLOAT Bx = 0.15f, By = 0.06f;
294 CFX_Matrix_3by3 RGB_xyz(Rx, Gx, Bx, Ry, Gy, By, 1 - Rx - Ry, 1 - Gx - Gy,
295 1 - Bx - By);
296 CFX_Vector_3by1 whitePoint(Xw, Yw, Zw);
297 CFX_Vector_3by1 XYZ(X, Y, Z);
298
299 CFX_Vector_3by1 RGB_Sum_XYZ = RGB_xyz.Inverse().TransformVector(whitePoint);
300 CFX_Matrix_3by3 RGB_SUM_XYZ_DIAG(RGB_Sum_XYZ.a, 0, 0, 0, RGB_Sum_XYZ.b, 0, 0,
301 0, RGB_Sum_XYZ.c);
302 CFX_Matrix_3by3 M = RGB_xyz.Multiply(RGB_SUM_XYZ_DIAG);
303 CFX_Vector_3by1 RGB = M.Inverse().TransformVector(XYZ);
304
305 R = RGB_Conversion(RGB.a);
306 G = RGB_Conversion(RGB.b);
307 B = RGB_Conversion(RGB.c);
308 }
309 class CPDF_CalGray : public CPDF_ColorSpace {
310 public:
CPDF_CalGray(CPDF_Document * pDoc)311 explicit CPDF_CalGray(CPDF_Document* pDoc)
312 : CPDF_ColorSpace(pDoc, PDFCS_CALGRAY, 1) {}
313 FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
314 FX_BOOL GetRGB(FX_FLOAT* pBuf,
315 FX_FLOAT& R,
316 FX_FLOAT& G,
317 FX_FLOAT& B) const override;
318 FX_BOOL SetRGB(FX_FLOAT* pBuf,
319 FX_FLOAT R,
320 FX_FLOAT G,
321 FX_FLOAT B) const override;
322 void TranslateImageLine(uint8_t* pDestBuf,
323 const uint8_t* pSrcBuf,
324 int pixels,
325 int image_width,
326 int image_height,
327 FX_BOOL bTransMask = FALSE) const override;
328
329 private:
330 FX_FLOAT m_WhitePoint[3];
331 FX_FLOAT m_BlackPoint[3];
332 FX_FLOAT m_Gamma;
333 };
334
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)335 FX_BOOL CPDF_CalGray::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
336 CPDF_Dictionary* pDict = pArray->GetDict(1);
337 if (!pDict)
338 return FALSE;
339
340 CPDF_Array* pParam = pDict->GetArray("WhitePoint");
341 int i;
342 for (i = 0; i < 3; i++) {
343 m_WhitePoint[i] = pParam ? pParam->GetNumber(i) : 0;
344 }
345 pParam = pDict->GetArray("BlackPoint");
346 for (i = 0; i < 3; i++) {
347 m_BlackPoint[i] = pParam ? pParam->GetNumber(i) : 0;
348 }
349 m_Gamma = pDict->GetNumber("Gamma");
350 if (m_Gamma == 0) {
351 m_Gamma = 1.0f;
352 }
353 return TRUE;
354 }
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const355 FX_BOOL CPDF_CalGray::GetRGB(FX_FLOAT* pBuf,
356 FX_FLOAT& R,
357 FX_FLOAT& G,
358 FX_FLOAT& B) const {
359 R = G = B = *pBuf;
360 return TRUE;
361 }
SetRGB(FX_FLOAT * pBuf,FX_FLOAT R,FX_FLOAT G,FX_FLOAT B) const362 FX_BOOL CPDF_CalGray::SetRGB(FX_FLOAT* pBuf,
363 FX_FLOAT R,
364 FX_FLOAT G,
365 FX_FLOAT B) const {
366 if (R == G && R == B) {
367 *pBuf = R;
368 return TRUE;
369 }
370 return FALSE;
371 }
TranslateImageLine(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels,int image_width,int image_height,FX_BOOL bTransMask) const372 void CPDF_CalGray::TranslateImageLine(uint8_t* pDestBuf,
373 const uint8_t* pSrcBuf,
374 int pixels,
375 int image_width,
376 int image_height,
377 FX_BOOL bTransMask) const {
378 for (int i = 0; i < pixels; i++) {
379 *pDestBuf++ = pSrcBuf[i];
380 *pDestBuf++ = pSrcBuf[i];
381 *pDestBuf++ = pSrcBuf[i];
382 }
383 }
384 class CPDF_CalRGB : public CPDF_ColorSpace {
385 public:
CPDF_CalRGB(CPDF_Document * pDoc)386 explicit CPDF_CalRGB(CPDF_Document* pDoc)
387 : CPDF_ColorSpace(pDoc, PDFCS_CALRGB, 3) {}
388 FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
389 FX_BOOL GetRGB(FX_FLOAT* pBuf,
390 FX_FLOAT& R,
391 FX_FLOAT& G,
392 FX_FLOAT& B) const override;
393 FX_BOOL SetRGB(FX_FLOAT* pBuf,
394 FX_FLOAT R,
395 FX_FLOAT G,
396 FX_FLOAT B) const override;
397 void TranslateImageLine(uint8_t* pDestBuf,
398 const uint8_t* pSrcBuf,
399 int pixels,
400 int image_width,
401 int image_height,
402 FX_BOOL bTransMask = FALSE) const override;
403
404 FX_FLOAT m_WhitePoint[3];
405 FX_FLOAT m_BlackPoint[3];
406 FX_FLOAT m_Gamma[3];
407 FX_FLOAT m_Matrix[9];
408 FX_BOOL m_bGamma;
409 FX_BOOL m_bMatrix;
410 };
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)411 FX_BOOL CPDF_CalRGB::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
412 CPDF_Dictionary* pDict = pArray->GetDict(1);
413 if (!pDict)
414 return FALSE;
415
416 CPDF_Array* pParam = pDict->GetArray("WhitePoint");
417 int i;
418 for (i = 0; i < 3; i++) {
419 m_WhitePoint[i] = pParam ? pParam->GetNumber(i) : 0;
420 }
421 pParam = pDict->GetArray("BlackPoint");
422 for (i = 0; i < 3; i++) {
423 m_BlackPoint[i] = pParam ? pParam->GetNumber(i) : 0;
424 }
425 pParam = pDict->GetArray("Gamma");
426 if (pParam) {
427 m_bGamma = TRUE;
428 for (i = 0; i < 3; i++) {
429 m_Gamma[i] = pParam->GetNumber(i);
430 }
431 } else {
432 m_bGamma = FALSE;
433 }
434 pParam = pDict->GetArray("Matrix");
435 if (pParam) {
436 m_bMatrix = TRUE;
437 for (i = 0; i < 9; i++) {
438 m_Matrix[i] = pParam->GetNumber(i);
439 }
440 } else {
441 m_bMatrix = FALSE;
442 }
443 return TRUE;
444 }
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const445 FX_BOOL CPDF_CalRGB::GetRGB(FX_FLOAT* pBuf,
446 FX_FLOAT& R,
447 FX_FLOAT& G,
448 FX_FLOAT& B) const {
449 FX_FLOAT A_ = pBuf[0];
450 FX_FLOAT B_ = pBuf[1];
451 FX_FLOAT C_ = pBuf[2];
452 if (m_bGamma) {
453 A_ = (FX_FLOAT)FXSYS_pow(A_, m_Gamma[0]);
454 B_ = (FX_FLOAT)FXSYS_pow(B_, m_Gamma[1]);
455 C_ = (FX_FLOAT)FXSYS_pow(C_, m_Gamma[2]);
456 }
457 FX_FLOAT X, Y, Z;
458 if (m_bMatrix) {
459 X = m_Matrix[0] * A_ + m_Matrix[3] * B_ + m_Matrix[6] * C_;
460 Y = m_Matrix[1] * A_ + m_Matrix[4] * B_ + m_Matrix[7] * C_;
461 Z = m_Matrix[2] * A_ + m_Matrix[5] * B_ + m_Matrix[8] * C_;
462 } else {
463 X = A_;
464 Y = B_;
465 Z = C_;
466 }
467 XYZ_to_sRGB_WhitePoint(X, Y, Z, R, G, B, m_WhitePoint[0], m_WhitePoint[1],
468 m_WhitePoint[2]);
469 return TRUE;
470 }
SetRGB(FX_FLOAT * pBuf,FX_FLOAT R,FX_FLOAT G,FX_FLOAT B) const471 FX_BOOL CPDF_CalRGB::SetRGB(FX_FLOAT* pBuf,
472 FX_FLOAT R,
473 FX_FLOAT G,
474 FX_FLOAT B) const {
475 pBuf[0] = R;
476 pBuf[1] = G;
477 pBuf[2] = B;
478 return TRUE;
479 }
TranslateImageLine(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels,int image_width,int image_height,FX_BOOL bTransMask) const480 void CPDF_CalRGB::TranslateImageLine(uint8_t* pDestBuf,
481 const uint8_t* pSrcBuf,
482 int pixels,
483 int image_width,
484 int image_height,
485 FX_BOOL bTransMask) const {
486 if (bTransMask) {
487 FX_FLOAT Cal[3];
488 FX_FLOAT R, G, B;
489 for (int i = 0; i < pixels; i++) {
490 Cal[0] = ((FX_FLOAT)pSrcBuf[2]) / 255;
491 Cal[1] = ((FX_FLOAT)pSrcBuf[1]) / 255;
492 Cal[2] = ((FX_FLOAT)pSrcBuf[0]) / 255;
493 GetRGB(Cal, R, G, B);
494 pDestBuf[0] = FXSYS_round(B * 255);
495 pDestBuf[1] = FXSYS_round(G * 255);
496 pDestBuf[2] = FXSYS_round(R * 255);
497 pSrcBuf += 3;
498 pDestBuf += 3;
499 }
500 }
501 ReverseRGB(pDestBuf, pSrcBuf, pixels);
502 }
503 class CPDF_LabCS : public CPDF_ColorSpace {
504 public:
CPDF_LabCS(CPDF_Document * pDoc)505 explicit CPDF_LabCS(CPDF_Document* pDoc)
506 : CPDF_ColorSpace(pDoc, PDFCS_LAB, 3) {}
507 void GetDefaultValue(int iComponent,
508 FX_FLOAT& value,
509 FX_FLOAT& min,
510 FX_FLOAT& max) const override;
511 FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
512 FX_BOOL GetRGB(FX_FLOAT* pBuf,
513 FX_FLOAT& R,
514 FX_FLOAT& G,
515 FX_FLOAT& B) const override;
516 FX_BOOL SetRGB(FX_FLOAT* pBuf,
517 FX_FLOAT R,
518 FX_FLOAT G,
519 FX_FLOAT B) const override;
520 void TranslateImageLine(uint8_t* pDestBuf,
521 const uint8_t* pSrcBuf,
522 int pixels,
523 int image_width,
524 int image_height,
525 FX_BOOL bTransMask = FALSE) const override;
526
527 FX_FLOAT m_WhitePoint[3];
528 FX_FLOAT m_BlackPoint[3];
529 FX_FLOAT m_Ranges[4];
530 };
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)531 FX_BOOL CPDF_LabCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
532 CPDF_Dictionary* pDict = pArray->GetDict(1);
533 if (!pDict) {
534 return FALSE;
535 }
536 CPDF_Array* pParam = pDict->GetArray("WhitePoint");
537 int i;
538 for (i = 0; i < 3; i++) {
539 m_WhitePoint[i] = pParam ? pParam->GetNumber(i) : 0;
540 }
541 pParam = pDict->GetArray("BlackPoint");
542 for (i = 0; i < 3; i++) {
543 m_BlackPoint[i] = pParam ? pParam->GetNumber(i) : 0;
544 }
545 pParam = pDict->GetArray("Range");
546 const FX_FLOAT def_ranges[4] = {-100 * 1.0f, 100 * 1.0f, -100 * 1.0f,
547 100 * 1.0f};
548 for (i = 0; i < 4; i++) {
549 m_Ranges[i] = pParam ? pParam->GetNumber(i) : def_ranges[i];
550 }
551 return TRUE;
552 }
GetDefaultValue(int iComponent,FX_FLOAT & value,FX_FLOAT & min,FX_FLOAT & max) const553 void CPDF_LabCS::GetDefaultValue(int iComponent,
554 FX_FLOAT& value,
555 FX_FLOAT& min,
556 FX_FLOAT& max) const {
557 assert(iComponent < 3);
558 value = 0;
559 if (iComponent == 0) {
560 min = 0;
561 max = 100 * 1.0f;
562 } else {
563 min = m_Ranges[iComponent * 2 - 2];
564 max = m_Ranges[iComponent * 2 - 1];
565 if (value < min) {
566 value = min;
567 } else if (value > max) {
568 value = max;
569 }
570 }
571 }
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const572 FX_BOOL CPDF_LabCS::GetRGB(FX_FLOAT* pBuf,
573 FX_FLOAT& R,
574 FX_FLOAT& G,
575 FX_FLOAT& B) const {
576 FX_FLOAT Lstar = pBuf[0];
577 FX_FLOAT astar = pBuf[1];
578 FX_FLOAT bstar = pBuf[2];
579 FX_FLOAT M = (Lstar + 16.0f) / 116.0f;
580 FX_FLOAT L = M + astar / 500.0f;
581 FX_FLOAT N = M - bstar / 200.0f;
582 FX_FLOAT X, Y, Z;
583 if (L < 0.2069f) {
584 X = 0.957f * 0.12842f * (L - 0.1379f);
585 } else {
586 X = 0.957f * L * L * L;
587 }
588 if (M < 0.2069f) {
589 Y = 0.12842f * (M - 0.1379f);
590 } else {
591 Y = M * M * M;
592 }
593 if (N < 0.2069f) {
594 Z = 1.0889f * 0.12842f * (N - 0.1379f);
595 } else {
596 Z = 1.0889f * N * N * N;
597 }
598 XYZ_to_sRGB(X, Y, Z, R, G, B);
599 return TRUE;
600 }
SetRGB(FX_FLOAT * pBuf,FX_FLOAT R,FX_FLOAT G,FX_FLOAT B) const601 FX_BOOL CPDF_LabCS::SetRGB(FX_FLOAT* pBuf,
602 FX_FLOAT R,
603 FX_FLOAT G,
604 FX_FLOAT B) const {
605 return FALSE;
606 }
TranslateImageLine(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels,int image_width,int image_height,FX_BOOL bTransMask) const607 void CPDF_LabCS::TranslateImageLine(uint8_t* pDestBuf,
608 const uint8_t* pSrcBuf,
609 int pixels,
610 int image_width,
611 int image_height,
612 FX_BOOL bTransMask) const {
613 for (int i = 0; i < pixels; i++) {
614 FX_FLOAT lab[3];
615 FX_FLOAT R, G, B;
616 lab[0] = (pSrcBuf[0] * 100 / 255.0f);
617 lab[1] = (FX_FLOAT)(pSrcBuf[1] - 128);
618 lab[2] = (FX_FLOAT)(pSrcBuf[2] - 128);
619 GetRGB(lab, R, G, B);
620 pDestBuf[0] = (int32_t)(B * 255);
621 pDestBuf[1] = (int32_t)(G * 255);
622 pDestBuf[2] = (int32_t)(R * 255);
623 pDestBuf += 3;
624 pSrcBuf += 3;
625 }
626 }
CPDF_IccProfile(const uint8_t * pData,FX_DWORD dwSize)627 CPDF_IccProfile::CPDF_IccProfile(const uint8_t* pData, FX_DWORD dwSize)
628 : m_bsRGB(FALSE), m_pTransform(NULL), m_nSrcComponents(0) {
629 if (dwSize == 3144 &&
630 FXSYS_memcmp(pData + 0x190, "sRGB IEC61966-2.1", 17) == 0) {
631 m_bsRGB = TRUE;
632 m_nSrcComponents = 3;
633 } else if (CPDF_ModuleMgr::Get()->GetIccModule()) {
634 m_pTransform = CPDF_ModuleMgr::Get()->GetIccModule()->CreateTransform_sRGB(
635 pData, dwSize, m_nSrcComponents);
636 }
637 }
~CPDF_IccProfile()638 CPDF_IccProfile::~CPDF_IccProfile() {
639 if (m_pTransform) {
640 CPDF_ModuleMgr::Get()->GetIccModule()->DestroyTransform(m_pTransform);
641 }
642 }
643 class CPDF_ICCBasedCS : public CPDF_ColorSpace {
644 public:
CPDF_ICCBasedCS(CPDF_Document * pDoc)645 explicit CPDF_ICCBasedCS(CPDF_Document* pDoc)
646 : CPDF_ColorSpace(pDoc, PDFCS_ICCBASED, 0),
647 m_pAlterCS(nullptr),
648 m_pProfile(nullptr),
649 m_pCache(nullptr),
650 m_pRanges(nullptr),
651 m_bOwn(FALSE) {}
652 ~CPDF_ICCBasedCS() override;
653
654 FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
655 FX_BOOL GetRGB(FX_FLOAT* pBuf,
656 FX_FLOAT& R,
657 FX_FLOAT& G,
658 FX_FLOAT& B) const override;
659 FX_BOOL SetRGB(FX_FLOAT* pBuf,
660 FX_FLOAT R,
661 FX_FLOAT G,
662 FX_FLOAT B) const override;
663 FX_BOOL v_GetCMYK(FX_FLOAT* pBuf,
664 FX_FLOAT& c,
665 FX_FLOAT& m,
666 FX_FLOAT& y,
667 FX_FLOAT& k) const override;
668 void EnableStdConversion(FX_BOOL bEnabled) override;
669 void TranslateImageLine(uint8_t* pDestBuf,
670 const uint8_t* pSrcBuf,
671 int pixels,
672 int image_width,
673 int image_height,
674 FX_BOOL bTransMask = FALSE) const override;
675
676 CPDF_ColorSpace* m_pAlterCS;
677 CPDF_IccProfile* m_pProfile;
678 uint8_t* m_pCache;
679 FX_FLOAT* m_pRanges;
680 FX_BOOL m_bOwn;
681 };
682
~CPDF_ICCBasedCS()683 CPDF_ICCBasedCS::~CPDF_ICCBasedCS() {
684 FX_Free(m_pCache);
685 FX_Free(m_pRanges);
686 if (m_pAlterCS && m_bOwn) {
687 m_pAlterCS->ReleaseCS();
688 }
689 if (m_pProfile && m_pDocument) {
690 m_pDocument->GetPageData()->ReleaseIccProfile(m_pProfile);
691 }
692 }
693
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)694 FX_BOOL CPDF_ICCBasedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
695 CPDF_Stream* pStream = pArray->GetStream(1);
696 if (!pStream) {
697 return FALSE;
698 }
699 m_pProfile = pDoc->LoadIccProfile(pStream);
700 if (!m_pProfile) {
701 return FALSE;
702 }
703 m_nComponents =
704 m_pProfile
705 ->GetComponents(); // Try using the nComponents from ICC profile
706 CPDF_Dictionary* pDict = pStream->GetDict();
707 if (!m_pProfile->m_pTransform) { // No valid ICC profile or using sRGB
708 CPDF_Object* pAlterCSObj =
709 pDict ? pDict->GetElementValue("Alternate") : NULL;
710 if (pAlterCSObj) {
711 CPDF_ColorSpace* pAlterCS = CPDF_ColorSpace::Load(pDoc, pAlterCSObj);
712 if (pAlterCS) {
713 if (m_nComponents == 0) { // NO valid ICC profile
714 if (pAlterCS->CountComponents() > 0) { // Use Alternative colorspace
715 m_nComponents = pAlterCS->CountComponents();
716 m_pAlterCS = pAlterCS;
717 m_bOwn = TRUE;
718 } else { // No valid alternative colorspace
719 pAlterCS->ReleaseCS();
720 int32_t nDictComponents = pDict ? pDict->GetInteger("N") : 0;
721 if (nDictComponents != 1 && nDictComponents != 3 &&
722 nDictComponents != 4) {
723 return FALSE;
724 }
725 m_nComponents = nDictComponents;
726 }
727
728 } else { // Using sRGB
729 if (pAlterCS->CountComponents() != m_nComponents) {
730 pAlterCS->ReleaseCS();
731 } else {
732 m_pAlterCS = pAlterCS;
733 m_bOwn = TRUE;
734 }
735 }
736 }
737 }
738 if (!m_pAlterCS) {
739 if (m_nComponents == 1) {
740 m_pAlterCS = GetStockCS(PDFCS_DEVICEGRAY);
741 } else if (m_nComponents == 3) {
742 m_pAlterCS = GetStockCS(PDFCS_DEVICERGB);
743 } else if (m_nComponents == 4) {
744 m_pAlterCS = GetStockCS(PDFCS_DEVICECMYK);
745 }
746 }
747 }
748 CPDF_Array* pRanges = pDict->GetArray("Range");
749 m_pRanges = FX_Alloc2D(FX_FLOAT, m_nComponents, 2);
750 for (int i = 0; i < m_nComponents * 2; i++) {
751 if (pRanges) {
752 m_pRanges[i] = pRanges->GetNumber(i);
753 } else if (i % 2) {
754 m_pRanges[i] = 1.0f;
755 } else {
756 m_pRanges[i] = 0;
757 }
758 }
759 return TRUE;
760 }
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const761 FX_BOOL CPDF_ICCBasedCS::GetRGB(FX_FLOAT* pBuf,
762 FX_FLOAT& R,
763 FX_FLOAT& G,
764 FX_FLOAT& B) const {
765 if (m_pProfile && m_pProfile->m_bsRGB) {
766 R = pBuf[0];
767 G = pBuf[1];
768 B = pBuf[2];
769 return TRUE;
770 }
771 ICodec_IccModule* pIccModule = CPDF_ModuleMgr::Get()->GetIccModule();
772 if (!m_pProfile->m_pTransform || !pIccModule) {
773 if (m_pAlterCS) {
774 return m_pAlterCS->GetRGB(pBuf, R, G, B);
775 }
776 R = G = B = 0.0f;
777 return TRUE;
778 }
779 FX_FLOAT rgb[3];
780 pIccModule->SetComponents(m_nComponents);
781 pIccModule->Translate(m_pProfile->m_pTransform, pBuf, rgb);
782 R = rgb[0];
783 G = rgb[1];
784 B = rgb[2];
785 return TRUE;
786 }
v_GetCMYK(FX_FLOAT * pBuf,FX_FLOAT & c,FX_FLOAT & m,FX_FLOAT & y,FX_FLOAT & k) const787 FX_BOOL CPDF_ICCBasedCS::v_GetCMYK(FX_FLOAT* pBuf,
788 FX_FLOAT& c,
789 FX_FLOAT& m,
790 FX_FLOAT& y,
791 FX_FLOAT& k) const {
792 if (m_nComponents != 4) {
793 return FALSE;
794 }
795 c = pBuf[0];
796 m = pBuf[1];
797 y = pBuf[2];
798 k = pBuf[3];
799 return TRUE;
800 }
SetRGB(FX_FLOAT * pBuf,FX_FLOAT R,FX_FLOAT G,FX_FLOAT B) const801 FX_BOOL CPDF_ICCBasedCS::SetRGB(FX_FLOAT* pBuf,
802 FX_FLOAT R,
803 FX_FLOAT G,
804 FX_FLOAT B) const {
805 return FALSE;
806 }
EnableStdConversion(FX_BOOL bEnabled)807 void CPDF_ICCBasedCS::EnableStdConversion(FX_BOOL bEnabled) {
808 CPDF_ColorSpace::EnableStdConversion(bEnabled);
809 if (m_pAlterCS) {
810 m_pAlterCS->EnableStdConversion(bEnabled);
811 }
812 }
TranslateImageLine(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels,int image_width,int image_height,FX_BOOL bTransMask) const813 void CPDF_ICCBasedCS::TranslateImageLine(uint8_t* pDestBuf,
814 const uint8_t* pSrcBuf,
815 int pixels,
816 int image_width,
817 int image_height,
818 FX_BOOL bTransMask) const {
819 if (m_pProfile->m_bsRGB) {
820 ReverseRGB(pDestBuf, pSrcBuf, pixels);
821 } else if (m_pProfile->m_pTransform) {
822 int nMaxColors = 1;
823 for (int i = 0; i < m_nComponents; i++) {
824 nMaxColors *= 52;
825 }
826 if (m_nComponents > 3 || image_width * image_height < nMaxColors * 3 / 2) {
827 CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(
828 m_pProfile->m_pTransform, pDestBuf, pSrcBuf, pixels);
829 } else {
830 if (!m_pCache) {
831 ((CPDF_ICCBasedCS*)this)->m_pCache = FX_Alloc2D(uint8_t, nMaxColors, 3);
832 uint8_t* temp_src = FX_Alloc2D(uint8_t, nMaxColors, m_nComponents);
833 uint8_t* pSrc = temp_src;
834 for (int i = 0; i < nMaxColors; i++) {
835 FX_DWORD color = i;
836 FX_DWORD order = nMaxColors / 52;
837 for (int c = 0; c < m_nComponents; c++) {
838 *pSrc++ = (uint8_t)(color / order * 5);
839 color %= order;
840 order /= 52;
841 }
842 }
843 CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(
844 m_pProfile->m_pTransform, m_pCache, temp_src, nMaxColors);
845 FX_Free(temp_src);
846 }
847 for (int i = 0; i < pixels; i++) {
848 int index = 0;
849 for (int c = 0; c < m_nComponents; c++) {
850 index = index * 52 + (*pSrcBuf) / 5;
851 pSrcBuf++;
852 }
853 index *= 3;
854 *pDestBuf++ = m_pCache[index];
855 *pDestBuf++ = m_pCache[index + 1];
856 *pDestBuf++ = m_pCache[index + 2];
857 }
858 }
859 } else if (m_pAlterCS) {
860 m_pAlterCS->TranslateImageLine(pDestBuf, pSrcBuf, pixels, image_width,
861 image_height);
862 }
863 }
864 class CPDF_IndexedCS : public CPDF_ColorSpace {
865 public:
CPDF_IndexedCS(CPDF_Document * pDoc)866 explicit CPDF_IndexedCS(CPDF_Document* pDoc)
867 : CPDF_ColorSpace(pDoc, PDFCS_INDEXED, 1),
868 m_pBaseCS(nullptr),
869 m_pCountedBaseCS(nullptr),
870 m_pCompMinMax(nullptr) {}
871 ~CPDF_IndexedCS() override;
872
873 FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
874 FX_BOOL GetRGB(FX_FLOAT* pBuf,
875 FX_FLOAT& R,
876 FX_FLOAT& G,
877 FX_FLOAT& B) const override;
878 CPDF_ColorSpace* GetBaseCS() const override;
879 void EnableStdConversion(FX_BOOL bEnabled) override;
880
881 CPDF_ColorSpace* m_pBaseCS;
882 CPDF_CountedColorSpace* m_pCountedBaseCS;
883 int m_nBaseComponents;
884 int m_MaxIndex;
885 CFX_ByteString m_Table;
886 FX_FLOAT* m_pCompMinMax;
887 };
~CPDF_IndexedCS()888 CPDF_IndexedCS::~CPDF_IndexedCS() {
889 FX_Free(m_pCompMinMax);
890 CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : NULL;
891 if (pCS && m_pDocument) {
892 m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
893 }
894 }
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)895 FX_BOOL CPDF_IndexedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
896 if (pArray->GetCount() < 4) {
897 return FALSE;
898 }
899 CPDF_Object* pBaseObj = pArray->GetElementValue(1);
900 if (pBaseObj == m_pArray) {
901 return FALSE;
902 }
903 CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
904 m_pBaseCS = pDocPageData->GetColorSpace(pBaseObj, NULL);
905 if (!m_pBaseCS) {
906 return FALSE;
907 }
908 m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
909 m_nBaseComponents = m_pBaseCS->CountComponents();
910 m_pCompMinMax = FX_Alloc2D(FX_FLOAT, m_nBaseComponents, 2);
911 FX_FLOAT defvalue;
912 for (int i = 0; i < m_nBaseComponents; i++) {
913 m_pBaseCS->GetDefaultValue(i, defvalue, m_pCompMinMax[i * 2],
914 m_pCompMinMax[i * 2 + 1]);
915 m_pCompMinMax[i * 2 + 1] -= m_pCompMinMax[i * 2];
916 }
917 m_MaxIndex = pArray->GetInteger(2);
918
919 CPDF_Object* pTableObj = pArray->GetElementValue(3);
920 if (!pTableObj)
921 return FALSE;
922
923 if (CPDF_String* pString = pTableObj->AsString()) {
924 m_Table = pString->GetString();
925 } else if (CPDF_Stream* pStream = pTableObj->AsStream()) {
926 CPDF_StreamAcc acc;
927 acc.LoadAllData(pStream, FALSE);
928 m_Table = CFX_ByteStringC(acc.GetData(), acc.GetSize());
929 }
930 return TRUE;
931 }
932
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const933 FX_BOOL CPDF_IndexedCS::GetRGB(FX_FLOAT* pBuf,
934 FX_FLOAT& R,
935 FX_FLOAT& G,
936 FX_FLOAT& B) const {
937 int index = (int32_t)(*pBuf);
938 if (index < 0 || index > m_MaxIndex) {
939 return FALSE;
940 }
941 if (m_nBaseComponents) {
942 if (index == INT_MAX || (index + 1) > INT_MAX / m_nBaseComponents ||
943 (index + 1) * m_nBaseComponents > (int)m_Table.GetLength()) {
944 R = G = B = 0;
945 return FALSE;
946 }
947 }
948 CFX_FixedBufGrow<FX_FLOAT, 16> Comps(m_nBaseComponents);
949 FX_FLOAT* comps = Comps;
950 const uint8_t* pTable = m_Table;
951 for (int i = 0; i < m_nBaseComponents; i++) {
952 comps[i] =
953 m_pCompMinMax[i * 2] +
954 m_pCompMinMax[i * 2 + 1] * pTable[index * m_nBaseComponents + i] / 255;
955 }
956 return m_pBaseCS->GetRGB(comps, R, G, B);
957 }
GetBaseCS() const958 CPDF_ColorSpace* CPDF_IndexedCS::GetBaseCS() const {
959 return m_pBaseCS;
960 }
EnableStdConversion(FX_BOOL bEnabled)961 void CPDF_IndexedCS::EnableStdConversion(FX_BOOL bEnabled) {
962 CPDF_ColorSpace::EnableStdConversion(bEnabled);
963 if (m_pBaseCS) {
964 m_pBaseCS->EnableStdConversion(bEnabled);
965 }
966 }
967 #define MAX_PATTERN_COLORCOMPS 16
968 typedef struct _PatternValue {
969 CPDF_Pattern* m_pPattern;
970 CPDF_CountedPattern* m_pCountedPattern;
971 int m_nComps;
972 FX_FLOAT m_Comps[MAX_PATTERN_COLORCOMPS];
973 } PatternValue;
~CPDF_PatternCS()974 CPDF_PatternCS::~CPDF_PatternCS() {
975 CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : NULL;
976 if (pCS && m_pDocument) {
977 m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
978 }
979 }
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)980 FX_BOOL CPDF_PatternCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
981 CPDF_Object* pBaseCS = pArray->GetElementValue(1);
982 if (pBaseCS == m_pArray) {
983 return FALSE;
984 }
985 CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
986 m_pBaseCS = pDocPageData->GetColorSpace(pBaseCS, NULL);
987 if (m_pBaseCS) {
988 if (m_pBaseCS->GetFamily() == PDFCS_PATTERN) {
989 return FALSE;
990 }
991 m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
992 m_nComponents = m_pBaseCS->CountComponents() + 1;
993 if (m_pBaseCS->CountComponents() > MAX_PATTERN_COLORCOMPS) {
994 return FALSE;
995 }
996 } else {
997 m_nComponents = 1;
998 }
999 return TRUE;
1000 }
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const1001 FX_BOOL CPDF_PatternCS::GetRGB(FX_FLOAT* pBuf,
1002 FX_FLOAT& R,
1003 FX_FLOAT& G,
1004 FX_FLOAT& B) const {
1005 if (m_pBaseCS) {
1006 ASSERT(m_pBaseCS->GetFamily() != PDFCS_PATTERN);
1007 PatternValue* pvalue = (PatternValue*)pBuf;
1008 if (m_pBaseCS->GetRGB(pvalue->m_Comps, R, G, B)) {
1009 return TRUE;
1010 }
1011 }
1012 R = G = B = 0.75f;
1013 return FALSE;
1014 }
GetBaseCS() const1015 CPDF_ColorSpace* CPDF_PatternCS::GetBaseCS() const {
1016 return m_pBaseCS;
1017 }
1018 class CPDF_SeparationCS : public CPDF_ColorSpace {
1019 public:
CPDF_SeparationCS(CPDF_Document * pDoc)1020 explicit CPDF_SeparationCS(CPDF_Document* pDoc)
1021 : CPDF_ColorSpace(pDoc, PDFCS_SEPARATION, 1),
1022 m_pAltCS(nullptr),
1023 m_pFunc(nullptr) {}
1024 ~CPDF_SeparationCS() override;
1025
1026 // CPDF_ColorSpace:
1027 void GetDefaultValue(int iComponent,
1028 FX_FLOAT& value,
1029 FX_FLOAT& min,
1030 FX_FLOAT& max) const override;
1031 FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
1032 FX_BOOL GetRGB(FX_FLOAT* pBuf,
1033 FX_FLOAT& R,
1034 FX_FLOAT& G,
1035 FX_FLOAT& B) const override;
1036 void EnableStdConversion(FX_BOOL bEnabled) override;
1037
1038 CPDF_ColorSpace* m_pAltCS;
1039 CPDF_Function* m_pFunc;
1040 enum { None, All, Colorant } m_Type;
1041 };
~CPDF_SeparationCS()1042 CPDF_SeparationCS::~CPDF_SeparationCS() {
1043 if (m_pAltCS) {
1044 m_pAltCS->ReleaseCS();
1045 }
1046 delete m_pFunc;
1047 }
GetDefaultValue(int iComponent,FX_FLOAT & value,FX_FLOAT & min,FX_FLOAT & max) const1048 void CPDF_SeparationCS::GetDefaultValue(int iComponent,
1049 FX_FLOAT& value,
1050 FX_FLOAT& min,
1051 FX_FLOAT& max) const {
1052 value = 1.0f;
1053 min = 0;
1054 max = 1.0f;
1055 }
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)1056 FX_BOOL CPDF_SeparationCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
1057 CFX_ByteString name = pArray->GetString(1);
1058 if (name == "None") {
1059 m_Type = None;
1060 } else {
1061 m_Type = Colorant;
1062 CPDF_Object* pAltCS = pArray->GetElementValue(2);
1063 if (pAltCS == m_pArray) {
1064 return FALSE;
1065 }
1066 m_pAltCS = Load(pDoc, pAltCS);
1067 if (!m_pAltCS) {
1068 return FALSE;
1069 }
1070 CPDF_Object* pFuncObj = pArray->GetElementValue(3);
1071 if (pFuncObj && !pFuncObj->IsName())
1072 m_pFunc = CPDF_Function::Load(pFuncObj);
1073
1074 if (m_pFunc && m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
1075 delete m_pFunc;
1076 m_pFunc = NULL;
1077 }
1078 }
1079 return TRUE;
1080 }
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const1081 FX_BOOL CPDF_SeparationCS::GetRGB(FX_FLOAT* pBuf,
1082 FX_FLOAT& R,
1083 FX_FLOAT& G,
1084 FX_FLOAT& B) const {
1085 if (m_Type == None) {
1086 return FALSE;
1087 }
1088 if (!m_pFunc) {
1089 if (!m_pAltCS) {
1090 return FALSE;
1091 }
1092 int nComps = m_pAltCS->CountComponents();
1093 CFX_FixedBufGrow<FX_FLOAT, 16> results(nComps);
1094 for (int i = 0; i < nComps; i++) {
1095 results[i] = *pBuf;
1096 }
1097 return m_pAltCS->GetRGB(results, R, G, B);
1098 }
1099 CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
1100 int nresults = 0;
1101 m_pFunc->Call(pBuf, 1, results, nresults);
1102 if (nresults == 0) {
1103 return FALSE;
1104 }
1105 if (m_pAltCS) {
1106 return m_pAltCS->GetRGB(results, R, G, B);
1107 }
1108 R = G = B = 0;
1109 return FALSE;
1110 }
EnableStdConversion(FX_BOOL bEnabled)1111 void CPDF_SeparationCS::EnableStdConversion(FX_BOOL bEnabled) {
1112 CPDF_ColorSpace::EnableStdConversion(bEnabled);
1113 if (m_pAltCS) {
1114 m_pAltCS->EnableStdConversion(bEnabled);
1115 }
1116 }
1117 class CPDF_DeviceNCS : public CPDF_ColorSpace {
1118 public:
CPDF_DeviceNCS(CPDF_Document * pDoc)1119 explicit CPDF_DeviceNCS(CPDF_Document* pDoc)
1120 : CPDF_ColorSpace(pDoc, PDFCS_DEVICEN, 0),
1121 m_pAltCS(nullptr),
1122 m_pFunc(nullptr) {}
1123 ~CPDF_DeviceNCS() override;
1124
1125 // CPDF_ColorSpace:
1126 void GetDefaultValue(int iComponent,
1127 FX_FLOAT& value,
1128 FX_FLOAT& min,
1129 FX_FLOAT& max) const override;
1130 FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
1131 FX_BOOL GetRGB(FX_FLOAT* pBuf,
1132 FX_FLOAT& R,
1133 FX_FLOAT& G,
1134 FX_FLOAT& B) const override;
1135 void EnableStdConversion(FX_BOOL bEnabled) override;
1136
1137 CPDF_ColorSpace* m_pAltCS;
1138 CPDF_Function* m_pFunc;
1139 };
~CPDF_DeviceNCS()1140 CPDF_DeviceNCS::~CPDF_DeviceNCS() {
1141 delete m_pFunc;
1142 if (m_pAltCS) {
1143 m_pAltCS->ReleaseCS();
1144 }
1145 }
GetDefaultValue(int iComponent,FX_FLOAT & value,FX_FLOAT & min,FX_FLOAT & max) const1146 void CPDF_DeviceNCS::GetDefaultValue(int iComponent,
1147 FX_FLOAT& value,
1148 FX_FLOAT& min,
1149 FX_FLOAT& max) const {
1150 value = 1.0f;
1151 min = 0;
1152 max = 1.0f;
1153 }
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)1154 FX_BOOL CPDF_DeviceNCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
1155 CPDF_Array* pObj = ToArray(pArray->GetElementValue(1));
1156 if (!pObj)
1157 return FALSE;
1158
1159 m_nComponents = pObj->GetCount();
1160 CPDF_Object* pAltCS = pArray->GetElementValue(2);
1161 if (!pAltCS || pAltCS == m_pArray) {
1162 return FALSE;
1163 }
1164 m_pAltCS = Load(pDoc, pAltCS);
1165 m_pFunc = CPDF_Function::Load(pArray->GetElementValue(3));
1166 if (!m_pAltCS || !m_pFunc) {
1167 return FALSE;
1168 }
1169 if (m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
1170 return FALSE;
1171 }
1172 return TRUE;
1173 }
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const1174 FX_BOOL CPDF_DeviceNCS::GetRGB(FX_FLOAT* pBuf,
1175 FX_FLOAT& R,
1176 FX_FLOAT& G,
1177 FX_FLOAT& B) const {
1178 if (!m_pFunc) {
1179 return FALSE;
1180 }
1181 CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
1182 int nresults = 0;
1183 m_pFunc->Call(pBuf, m_nComponents, results, nresults);
1184 if (nresults == 0) {
1185 return FALSE;
1186 }
1187 return m_pAltCS->GetRGB(results, R, G, B);
1188 }
EnableStdConversion(FX_BOOL bEnabled)1189 void CPDF_DeviceNCS::EnableStdConversion(FX_BOOL bEnabled) {
1190 CPDF_ColorSpace::EnableStdConversion(bEnabled);
1191 if (m_pAltCS) {
1192 m_pAltCS->EnableStdConversion(bEnabled);
1193 }
1194 }
1195
GetStockCS(int family)1196 CPDF_ColorSpace* CPDF_ColorSpace::GetStockCS(int family) {
1197 return CPDF_ModuleMgr::Get()->GetPageModule()->GetStockCS(family);
1198 }
1199
_CSFromName(const CFX_ByteString & name)1200 CPDF_ColorSpace* _CSFromName(const CFX_ByteString& name) {
1201 if (name == "DeviceRGB" || name == "RGB") {
1202 return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
1203 }
1204 if (name == "DeviceGray" || name == "G") {
1205 return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY);
1206 }
1207 if (name == "DeviceCMYK" || name == "CMYK") {
1208 return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK);
1209 }
1210 if (name == "Pattern") {
1211 return CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
1212 }
1213 return NULL;
1214 }
Load(CPDF_Document * pDoc,CPDF_Object * pObj)1215 CPDF_ColorSpace* CPDF_ColorSpace::Load(CPDF_Document* pDoc, CPDF_Object* pObj) {
1216 if (!pObj)
1217 return nullptr;
1218 if (pObj->IsName())
1219 return _CSFromName(pObj->GetString());
1220
1221 if (CPDF_Stream* pStream = pObj->AsStream()) {
1222 CPDF_Dictionary* pDict = pStream->GetDict();
1223 if (!pDict)
1224 return nullptr;
1225
1226 for (const auto& it : *pDict) {
1227 CPDF_ColorSpace* pRet = nullptr;
1228 CPDF_Object* pValue = it.second;
1229 if (ToName(pValue))
1230 pRet = _CSFromName(pValue->GetString());
1231 if (pRet)
1232 return pRet;
1233 }
1234 return nullptr;
1235 }
1236
1237 CPDF_Array* pArray = pObj->AsArray();
1238 if (!pArray || pArray->GetCount() == 0)
1239 return nullptr;
1240
1241 CPDF_Object* pFamilyObj = pArray->GetElementValue(0);
1242 if (!pFamilyObj)
1243 return nullptr;
1244
1245 CFX_ByteString familyname = pFamilyObj->GetString();
1246 if (pArray->GetCount() == 1)
1247 return _CSFromName(familyname);
1248
1249 CPDF_ColorSpace* pCS = NULL;
1250 FX_DWORD id = familyname.GetID();
1251 if (id == FXBSTR_ID('C', 'a', 'l', 'G')) {
1252 pCS = new CPDF_CalGray(pDoc);
1253 } else if (id == FXBSTR_ID('C', 'a', 'l', 'R')) {
1254 pCS = new CPDF_CalRGB(pDoc);
1255 } else if (id == FXBSTR_ID('L', 'a', 'b', 0)) {
1256 pCS = new CPDF_LabCS(pDoc);
1257 } else if (id == FXBSTR_ID('I', 'C', 'C', 'B')) {
1258 pCS = new CPDF_ICCBasedCS(pDoc);
1259 } else if (id == FXBSTR_ID('I', 'n', 'd', 'e') ||
1260 id == FXBSTR_ID('I', 0, 0, 0)) {
1261 pCS = new CPDF_IndexedCS(pDoc);
1262 } else if (id == FXBSTR_ID('S', 'e', 'p', 'a')) {
1263 pCS = new CPDF_SeparationCS(pDoc);
1264 } else if (id == FXBSTR_ID('D', 'e', 'v', 'i')) {
1265 pCS = new CPDF_DeviceNCS(pDoc);
1266 } else if (id == FXBSTR_ID('P', 'a', 't', 't')) {
1267 pCS = new CPDF_PatternCS(pDoc);
1268 } else {
1269 return NULL;
1270 }
1271 pCS->m_pArray = pArray;
1272 if (!pCS->v_Load(pDoc, pArray)) {
1273 pCS->ReleaseCS();
1274 return NULL;
1275 }
1276 return pCS;
1277 }
ReleaseCS()1278 void CPDF_ColorSpace::ReleaseCS() {
1279 if (this == GetStockCS(PDFCS_DEVICERGB)) {
1280 return;
1281 }
1282 if (this == GetStockCS(PDFCS_DEVICEGRAY)) {
1283 return;
1284 }
1285 if (this == GetStockCS(PDFCS_DEVICECMYK)) {
1286 return;
1287 }
1288 if (this == GetStockCS(PDFCS_PATTERN)) {
1289 return;
1290 }
1291 delete this;
1292 }
GetBufSize() const1293 int CPDF_ColorSpace::GetBufSize() const {
1294 if (m_Family == PDFCS_PATTERN) {
1295 return sizeof(PatternValue);
1296 }
1297 return m_nComponents * sizeof(FX_FLOAT);
1298 }
CreateBuf()1299 FX_FLOAT* CPDF_ColorSpace::CreateBuf() {
1300 int size = GetBufSize();
1301 uint8_t* pBuf = FX_Alloc(uint8_t, size);
1302 return (FX_FLOAT*)pBuf;
1303 }
sRGB() const1304 FX_BOOL CPDF_ColorSpace::sRGB() const {
1305 if (m_Family == PDFCS_DEVICERGB) {
1306 return TRUE;
1307 }
1308 if (m_Family != PDFCS_ICCBASED) {
1309 return FALSE;
1310 }
1311 CPDF_ICCBasedCS* pCS = (CPDF_ICCBasedCS*)this;
1312 return pCS->m_pProfile->m_bsRGB;
1313 }
GetCMYK(FX_FLOAT * pBuf,FX_FLOAT & c,FX_FLOAT & m,FX_FLOAT & y,FX_FLOAT & k) const1314 FX_BOOL CPDF_ColorSpace::GetCMYK(FX_FLOAT* pBuf,
1315 FX_FLOAT& c,
1316 FX_FLOAT& m,
1317 FX_FLOAT& y,
1318 FX_FLOAT& k) const {
1319 if (v_GetCMYK(pBuf, c, m, y, k)) {
1320 return TRUE;
1321 }
1322 FX_FLOAT R, G, B;
1323 if (!GetRGB(pBuf, R, G, B)) {
1324 return FALSE;
1325 }
1326 sRGB_to_AdobeCMYK(R, G, B, c, m, y, k);
1327 return TRUE;
1328 }
SetCMYK(FX_FLOAT * pBuf,FX_FLOAT c,FX_FLOAT m,FX_FLOAT y,FX_FLOAT k) const1329 FX_BOOL CPDF_ColorSpace::SetCMYK(FX_FLOAT* pBuf,
1330 FX_FLOAT c,
1331 FX_FLOAT m,
1332 FX_FLOAT y,
1333 FX_FLOAT k) const {
1334 if (v_SetCMYK(pBuf, c, m, y, k)) {
1335 return TRUE;
1336 }
1337 FX_FLOAT R, G, B;
1338 AdobeCMYK_to_sRGB(c, m, y, k, R, G, B);
1339 return SetRGB(pBuf, R, G, B);
1340 }
GetDefaultColor(FX_FLOAT * buf) const1341 void CPDF_ColorSpace::GetDefaultColor(FX_FLOAT* buf) const {
1342 if (!buf || m_Family == PDFCS_PATTERN) {
1343 return;
1344 }
1345 FX_FLOAT min, max;
1346 for (int i = 0; i < m_nComponents; i++) {
1347 GetDefaultValue(i, buf[i], min, max);
1348 }
1349 }
GetMaxIndex() const1350 int CPDF_ColorSpace::GetMaxIndex() const {
1351 if (m_Family != PDFCS_INDEXED) {
1352 return 0;
1353 }
1354 CPDF_IndexedCS* pCS = (CPDF_IndexedCS*)this;
1355 return pCS->m_MaxIndex;
1356 }
TranslateImageLine(uint8_t * dest_buf,const uint8_t * src_buf,int pixels,int image_width,int image_height,FX_BOOL bTransMask) const1357 void CPDF_ColorSpace::TranslateImageLine(uint8_t* dest_buf,
1358 const uint8_t* src_buf,
1359 int pixels,
1360 int image_width,
1361 int image_height,
1362 FX_BOOL bTransMask) const {
1363 CFX_FixedBufGrow<FX_FLOAT, 16> srcbuf(m_nComponents);
1364 FX_FLOAT* src = srcbuf;
1365 FX_FLOAT R, G, B;
1366 for (int i = 0; i < pixels; i++) {
1367 for (int j = 0; j < m_nComponents; j++)
1368 if (m_Family == PDFCS_INDEXED) {
1369 src[j] = (FX_FLOAT)(*src_buf++);
1370 } else {
1371 src[j] = (FX_FLOAT)(*src_buf++) / 255;
1372 }
1373 GetRGB(src, R, G, B);
1374 *dest_buf++ = (int32_t)(B * 255);
1375 *dest_buf++ = (int32_t)(G * 255);
1376 *dest_buf++ = (int32_t)(R * 255);
1377 }
1378 }
EnableStdConversion(FX_BOOL bEnabled)1379 void CPDF_ColorSpace::EnableStdConversion(FX_BOOL bEnabled) {
1380 if (bEnabled) {
1381 m_dwStdConversion++;
1382 } else if (m_dwStdConversion) {
1383 m_dwStdConversion--;
1384 }
1385 }
CPDF_Color(int family)1386 CPDF_Color::CPDF_Color(int family) {
1387 m_pCS = CPDF_ColorSpace::GetStockCS(family);
1388 int nComps = 3;
1389 if (family == PDFCS_DEVICEGRAY) {
1390 nComps = 1;
1391 } else if (family == PDFCS_DEVICECMYK) {
1392 nComps = 4;
1393 }
1394 m_pBuffer = FX_Alloc(FX_FLOAT, nComps);
1395 for (int i = 0; i < nComps; i++) {
1396 m_pBuffer[i] = 0;
1397 }
1398 }
~CPDF_Color()1399 CPDF_Color::~CPDF_Color() {
1400 ReleaseBuffer();
1401 ReleaseColorSpace();
1402 }
ReleaseBuffer()1403 void CPDF_Color::ReleaseBuffer() {
1404 if (!m_pBuffer) {
1405 return;
1406 }
1407 if (m_pCS->GetFamily() == PDFCS_PATTERN) {
1408 PatternValue* pvalue = (PatternValue*)m_pBuffer;
1409 CPDF_Pattern* pPattern =
1410 pvalue->m_pCountedPattern ? pvalue->m_pCountedPattern->get() : NULL;
1411 if (pPattern && pPattern->m_pDocument) {
1412 CPDF_DocPageData* pPageData = pPattern->m_pDocument->GetPageData();
1413 if (pPageData) {
1414 pPageData->ReleasePattern(pPattern->m_pPatternObj);
1415 }
1416 }
1417 }
1418 FX_Free(m_pBuffer);
1419 m_pBuffer = NULL;
1420 }
ReleaseColorSpace()1421 void CPDF_Color::ReleaseColorSpace() {
1422 if (m_pCS && m_pCS->m_pDocument && m_pCS->GetArray()) {
1423 m_pCS->m_pDocument->GetPageData()->ReleaseColorSpace(m_pCS->GetArray());
1424 m_pCS = NULL;
1425 }
1426 }
SetColorSpace(CPDF_ColorSpace * pCS)1427 void CPDF_Color::SetColorSpace(CPDF_ColorSpace* pCS) {
1428 if (m_pCS == pCS) {
1429 if (!m_pBuffer) {
1430 m_pBuffer = pCS->CreateBuf();
1431 }
1432 ReleaseColorSpace();
1433 m_pCS = pCS;
1434 return;
1435 }
1436 ReleaseBuffer();
1437 ReleaseColorSpace();
1438 m_pCS = pCS;
1439 if (m_pCS) {
1440 m_pBuffer = pCS->CreateBuf();
1441 pCS->GetDefaultColor(m_pBuffer);
1442 }
1443 }
SetValue(FX_FLOAT * comps)1444 void CPDF_Color::SetValue(FX_FLOAT* comps) {
1445 if (!m_pBuffer) {
1446 return;
1447 }
1448 if (m_pCS->GetFamily() != PDFCS_PATTERN) {
1449 FXSYS_memcpy(m_pBuffer, comps, m_pCS->CountComponents() * sizeof(FX_FLOAT));
1450 }
1451 }
SetValue(CPDF_Pattern * pPattern,FX_FLOAT * comps,int ncomps)1452 void CPDF_Color::SetValue(CPDF_Pattern* pPattern, FX_FLOAT* comps, int ncomps) {
1453 if (ncomps > MAX_PATTERN_COLORCOMPS) {
1454 return;
1455 }
1456 if (!m_pCS || m_pCS->GetFamily() != PDFCS_PATTERN) {
1457 FX_Free(m_pBuffer);
1458 m_pCS = CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
1459 m_pBuffer = m_pCS->CreateBuf();
1460 }
1461 CPDF_DocPageData* pDocPageData = NULL;
1462 PatternValue* pvalue = (PatternValue*)m_pBuffer;
1463 if (pvalue->m_pPattern && pvalue->m_pPattern->m_pDocument) {
1464 pDocPageData = pvalue->m_pPattern->m_pDocument->GetPageData();
1465 if (pDocPageData) {
1466 pDocPageData->ReleasePattern(pvalue->m_pPattern->m_pPatternObj);
1467 }
1468 }
1469 pvalue->m_nComps = ncomps;
1470 pvalue->m_pPattern = pPattern;
1471 if (ncomps) {
1472 FXSYS_memcpy(pvalue->m_Comps, comps, ncomps * sizeof(FX_FLOAT));
1473 }
1474 pvalue->m_pCountedPattern = NULL;
1475 if (pPattern && pPattern->m_pDocument) {
1476 if (!pDocPageData) {
1477 pDocPageData = pPattern->m_pDocument->GetPageData();
1478 }
1479 pvalue->m_pCountedPattern =
1480 pDocPageData->FindPatternPtr(pPattern->m_pPatternObj);
1481 }
1482 }
Copy(const CPDF_Color * pSrc)1483 void CPDF_Color::Copy(const CPDF_Color* pSrc) {
1484 ReleaseBuffer();
1485 ReleaseColorSpace();
1486 m_pCS = pSrc->m_pCS;
1487 if (m_pCS && m_pCS->m_pDocument) {
1488 CPDF_Array* pArray = m_pCS->GetArray();
1489 if (pArray) {
1490 m_pCS = m_pCS->m_pDocument->GetPageData()->GetCopiedColorSpace(pArray);
1491 }
1492 }
1493 if (!m_pCS) {
1494 return;
1495 }
1496 m_pBuffer = m_pCS->CreateBuf();
1497 FXSYS_memcpy(m_pBuffer, pSrc->m_pBuffer, m_pCS->GetBufSize());
1498 if (m_pCS->GetFamily() == PDFCS_PATTERN) {
1499 PatternValue* pvalue = (PatternValue*)m_pBuffer;
1500 if (pvalue->m_pPattern && pvalue->m_pPattern->m_pDocument) {
1501 pvalue->m_pPattern =
1502 pvalue->m_pPattern->m_pDocument->GetPageData()->GetPattern(
1503 pvalue->m_pPattern->m_pPatternObj, FALSE,
1504 &pvalue->m_pPattern->m_ParentMatrix);
1505 }
1506 }
1507 }
GetRGB(int & R,int & G,int & B) const1508 FX_BOOL CPDF_Color::GetRGB(int& R, int& G, int& B) const {
1509 if (!m_pCS || !m_pBuffer) {
1510 return FALSE;
1511 }
1512 FX_FLOAT r = 0.0f, g = 0.0f, b = 0.0f;
1513 if (!m_pCS->GetRGB(m_pBuffer, r, g, b)) {
1514 return FALSE;
1515 }
1516 R = (int32_t)(r * 255 + 0.5f);
1517 G = (int32_t)(g * 255 + 0.5f);
1518 B = (int32_t)(b * 255 + 0.5f);
1519 return TRUE;
1520 }
GetPattern() const1521 CPDF_Pattern* CPDF_Color::GetPattern() const {
1522 if (!m_pBuffer || m_pCS->GetFamily() != PDFCS_PATTERN) {
1523 return NULL;
1524 }
1525 PatternValue* pvalue = (PatternValue*)m_pBuffer;
1526 return pvalue->m_pPattern;
1527 }
GetPatternCS() const1528 CPDF_ColorSpace* CPDF_Color::GetPatternCS() const {
1529 if (!m_pBuffer || m_pCS->GetFamily() != PDFCS_PATTERN) {
1530 return NULL;
1531 }
1532 return m_pCS->GetBaseCS();
1533 }
GetPatternColor() const1534 FX_FLOAT* CPDF_Color::GetPatternColor() const {
1535 if (!m_pBuffer || m_pCS->GetFamily() != PDFCS_PATTERN) {
1536 return NULL;
1537 }
1538 PatternValue* pvalue = (PatternValue*)m_pBuffer;
1539 return pvalue->m_nComps ? pvalue->m_Comps : NULL;
1540 }
IsEqual(const CPDF_Color & other) const1541 FX_BOOL CPDF_Color::IsEqual(const CPDF_Color& other) const {
1542 return m_pCS && m_pCS == other.m_pCS &&
1543 FXSYS_memcmp(m_pBuffer, other.m_pBuffer, m_pCS->GetBufSize()) == 0;
1544 }
1545