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