a3fef3df826107ba2d252375687fbf2b375505cd
[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   FX_Free(m_pCache);
675   FX_Free(m_pRanges);
676   if (m_pAlterCS && m_bOwn) {
677     m_pAlterCS->ReleaseCS();
678   }
679   if (m_pProfile && m_pDocument) {
680     m_pDocument->GetPageData()->ReleaseIccProfile(m_pProfile);
681   }
682 }
683
684 FX_BOOL CPDF_ICCBasedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
685   CPDF_Stream* pStream = pArray->GetStream(1);
686   if (pStream == NULL) {
687     return FALSE;
688   }
689   m_pProfile = pDoc->LoadIccProfile(pStream);
690   if (!m_pProfile) {
691     return FALSE;
692   }
693   m_nComponents =
694       m_pProfile
695           ->GetComponents();  // Try using the nComponents from ICC profile
696   CPDF_Dictionary* pDict = pStream->GetDict();
697   if (m_pProfile->m_pTransform == NULL) {  // No valid ICC profile or using sRGB
698     CPDF_Object* pAlterCSObj =
699         pDict ? pDict->GetElementValue(FX_BSTRC("Alternate")) : NULL;
700     if (pAlterCSObj) {
701       CPDF_ColorSpace* pAlterCS = CPDF_ColorSpace::Load(pDoc, pAlterCSObj);
702       if (pAlterCS) {
703         if (m_nComponents == 0) {                 // NO valid ICC profile
704           if (pAlterCS->CountComponents() > 0) {  // Use Alternative colorspace
705             m_nComponents = pAlterCS->CountComponents();
706             m_pAlterCS = pAlterCS;
707             m_bOwn = TRUE;
708           } else {  // No valid alternative colorspace
709             pAlterCS->ReleaseCS();
710             int32_t nDictComponents =
711                 pDict ? pDict->GetInteger(FX_BSTRC("N")) : 0;
712             if (nDictComponents != 1 && nDictComponents != 3 &&
713                 nDictComponents != 4) {
714               return FALSE;
715             }
716             m_nComponents = nDictComponents;
717           }
718
719         } else {  // Using sRGB
720           if (pAlterCS->CountComponents() != m_nComponents) {
721             pAlterCS->ReleaseCS();
722           } else {
723             m_pAlterCS = pAlterCS;
724             m_bOwn = TRUE;
725           }
726         }
727       }
728     }
729     if (!m_pAlterCS) {
730       if (m_nComponents == 1) {
731         m_pAlterCS = GetStockCS(PDFCS_DEVICEGRAY);
732       } else if (m_nComponents == 3) {
733         m_pAlterCS = GetStockCS(PDFCS_DEVICERGB);
734       } else if (m_nComponents == 4) {
735         m_pAlterCS = GetStockCS(PDFCS_DEVICECMYK);
736       }
737     }
738   }
739   CPDF_Array* pRanges = pDict->GetArray(FX_BSTRC("Range"));
740   m_pRanges = FX_Alloc2D(FX_FLOAT, m_nComponents, 2);
741   for (int i = 0; i < m_nComponents * 2; i++) {
742     if (pRanges) {
743       m_pRanges[i] = pRanges->GetNumber(i);
744     } else if (i % 2) {
745       m_pRanges[i] = 1.0f;
746     } else {
747       m_pRanges[i] = 0;
748     }
749   }
750   return TRUE;
751 }
752 FX_BOOL CPDF_ICCBasedCS::GetRGB(FX_FLOAT* pBuf,
753                                 FX_FLOAT& R,
754                                 FX_FLOAT& G,
755                                 FX_FLOAT& B) const {
756   if (m_pProfile && m_pProfile->m_bsRGB) {
757     R = pBuf[0];
758     G = pBuf[1];
759     B = pBuf[2];
760     return TRUE;
761   }
762   ICodec_IccModule* pIccModule = CPDF_ModuleMgr::Get()->GetIccModule();
763   if (m_pProfile->m_pTransform == NULL || pIccModule == NULL) {
764     if (m_pAlterCS) {
765       m_pAlterCS->GetRGB(pBuf, R, G, B);
766     } else {
767       R = G = B = 0.0f;
768     }
769     return TRUE;
770   }
771   FX_FLOAT rgb[3];
772   pIccModule->SetComponents(m_nComponents);
773   pIccModule->Translate(m_pProfile->m_pTransform, pBuf, rgb);
774   R = rgb[0];
775   G = rgb[1];
776   B = rgb[2];
777   return TRUE;
778 }
779 FX_BOOL CPDF_ICCBasedCS::v_GetCMYK(FX_FLOAT* pBuf,
780                                    FX_FLOAT& c,
781                                    FX_FLOAT& m,
782                                    FX_FLOAT& y,
783                                    FX_FLOAT& k) const {
784   if (m_nComponents != 4) {
785     return FALSE;
786   }
787   c = pBuf[0];
788   m = pBuf[1];
789   y = pBuf[2];
790   k = pBuf[3];
791   return TRUE;
792 }
793 FX_BOOL CPDF_ICCBasedCS::SetRGB(FX_FLOAT* pBuf,
794                                 FX_FLOAT R,
795                                 FX_FLOAT G,
796                                 FX_FLOAT B) const {
797   return FALSE;
798 }
799 void CPDF_ICCBasedCS::EnableStdConversion(FX_BOOL bEnabled) {
800   CPDF_ColorSpace::EnableStdConversion(bEnabled);
801   if (m_pAlterCS) {
802     m_pAlterCS->EnableStdConversion(bEnabled);
803   }
804 }
805 void CPDF_ICCBasedCS::TranslateImageLine(uint8_t* pDestBuf,
806                                          const uint8_t* pSrcBuf,
807                                          int pixels,
808                                          int image_width,
809                                          int image_height,
810                                          FX_BOOL bTransMask) const {
811   if (m_pProfile->m_bsRGB) {
812     ReverseRGB(pDestBuf, pSrcBuf, pixels);
813   } else if (m_pProfile->m_pTransform) {
814     int nMaxColors = 1;
815     for (int i = 0; i < m_nComponents; i++) {
816       nMaxColors *= 52;
817     }
818     if (m_nComponents > 3 || image_width * image_height < nMaxColors * 3 / 2) {
819       CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(
820           m_pProfile->m_pTransform, pDestBuf, pSrcBuf, pixels);
821     } else {
822       if (m_pCache == NULL) {
823         ((CPDF_ICCBasedCS*)this)->m_pCache = FX_Alloc2D(uint8_t, nMaxColors, 3);
824         uint8_t* temp_src = FX_Alloc2D(uint8_t, nMaxColors, m_nComponents);
825         uint8_t* pSrc = temp_src;
826         for (int i = 0; i < nMaxColors; i++) {
827           FX_DWORD color = i;
828           FX_DWORD order = nMaxColors / 52;
829           for (int c = 0; c < m_nComponents; c++) {
830             *pSrc++ = (uint8_t)(color / order * 5);
831             color %= order;
832             order /= 52;
833           }
834         }
835         CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(
836             m_pProfile->m_pTransform, m_pCache, temp_src, nMaxColors);
837         FX_Free(temp_src);
838       }
839       for (int i = 0; i < pixels; i++) {
840         int index = 0;
841         for (int c = 0; c < m_nComponents; c++) {
842           index = index * 52 + (*pSrcBuf) / 5;
843           pSrcBuf++;
844         }
845         index *= 3;
846         *pDestBuf++ = m_pCache[index];
847         *pDestBuf++ = m_pCache[index + 1];
848         *pDestBuf++ = m_pCache[index + 2];
849       }
850     }
851   } else if (m_pAlterCS) {
852     m_pAlterCS->TranslateImageLine(pDestBuf, pSrcBuf, pixels, image_width,
853                                    image_height);
854   }
855 }
856 class CPDF_IndexedCS : public CPDF_ColorSpace {
857  public:
858   explicit CPDF_IndexedCS(CPDF_Document* pDoc)
859       : CPDF_ColorSpace(pDoc, PDFCS_INDEXED, 1),
860         m_pBaseCS(nullptr),
861         m_pCountedBaseCS(nullptr),
862         m_pCompMinMax(nullptr) {}
863   ~CPDF_IndexedCS() override;
864
865   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
866   FX_BOOL GetRGB(FX_FLOAT* pBuf,
867                  FX_FLOAT& R,
868                  FX_FLOAT& G,
869                  FX_FLOAT& B) const override;
870   CPDF_ColorSpace* GetBaseCS() const override;
871   void EnableStdConversion(FX_BOOL bEnabled) override;
872
873   CPDF_ColorSpace* m_pBaseCS;
874   CPDF_CountedColorSpace* m_pCountedBaseCS;
875   int m_nBaseComponents;
876   int m_MaxIndex;
877   CFX_ByteString m_Table;
878   FX_FLOAT* m_pCompMinMax;
879 };
880 CPDF_IndexedCS::~CPDF_IndexedCS() {
881   FX_Free(m_pCompMinMax);
882   CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : NULL;
883   if (pCS && m_pDocument) {
884     m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
885   }
886 }
887 FX_BOOL CPDF_IndexedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
888   if (pArray->GetCount() < 4) {
889     return FALSE;
890   }
891   CPDF_Object* pBaseObj = pArray->GetElementValue(1);
892   if (pBaseObj == m_pArray) {
893     return FALSE;
894   }
895   CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
896   m_pBaseCS = pDocPageData->GetColorSpace(pBaseObj, NULL);
897   if (m_pBaseCS == NULL) {
898     return FALSE;
899   }
900   m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
901   m_nBaseComponents = m_pBaseCS->CountComponents();
902   m_pCompMinMax = FX_Alloc2D(FX_FLOAT, m_nBaseComponents, 2);
903   FX_FLOAT defvalue;
904   for (int i = 0; i < m_nBaseComponents; i++) {
905     m_pBaseCS->GetDefaultValue(i, defvalue, m_pCompMinMax[i * 2],
906                                m_pCompMinMax[i * 2 + 1]);
907     m_pCompMinMax[i * 2 + 1] -= m_pCompMinMax[i * 2];
908   }
909   m_MaxIndex = pArray->GetInteger(2);
910   CPDF_Object* pTableObj = pArray->GetElementValue(3);
911   if (pTableObj == NULL) {
912     return FALSE;
913   }
914   if (pTableObj->GetType() == PDFOBJ_STRING) {
915     m_Table = ((CPDF_String*)pTableObj)->GetString();
916   } else if (pTableObj->GetType() == PDFOBJ_STREAM) {
917     CPDF_StreamAcc acc;
918     acc.LoadAllData((CPDF_Stream*)pTableObj, FALSE);
919     m_Table = CFX_ByteStringC(acc.GetData(), acc.GetSize());
920   }
921   return TRUE;
922 }
923
924 FX_BOOL CPDF_IndexedCS::GetRGB(FX_FLOAT* pBuf,
925                                FX_FLOAT& R,
926                                FX_FLOAT& G,
927                                FX_FLOAT& B) const {
928   int index = (int32_t)(*pBuf);
929   if (index < 0 || index > m_MaxIndex) {
930     return FALSE;
931   }
932   if (m_nBaseComponents) {
933     if (index == INT_MAX || (index + 1) > INT_MAX / m_nBaseComponents ||
934         (index + 1) * m_nBaseComponents > (int)m_Table.GetLength()) {
935       R = G = B = 0;
936       return FALSE;
937     }
938   }
939   CFX_FixedBufGrow<FX_FLOAT, 16> Comps(m_nBaseComponents);
940   FX_FLOAT* comps = Comps;
941   const uint8_t* pTable = m_Table;
942   for (int i = 0; i < m_nBaseComponents; i++) {
943     comps[i] =
944         m_pCompMinMax[i * 2] +
945         m_pCompMinMax[i * 2 + 1] * pTable[index * m_nBaseComponents + i] / 255;
946   }
947   m_pBaseCS->GetRGB(comps, R, G, B);
948   return TRUE;
949 }
950 CPDF_ColorSpace* CPDF_IndexedCS::GetBaseCS() const {
951   return m_pBaseCS;
952 }
953 void CPDF_IndexedCS::EnableStdConversion(FX_BOOL bEnabled) {
954   CPDF_ColorSpace::EnableStdConversion(bEnabled);
955   if (m_pBaseCS) {
956     m_pBaseCS->EnableStdConversion(bEnabled);
957   }
958 }
959 #define MAX_PATTERN_COLORCOMPS 16
960 typedef struct _PatternValue {
961   CPDF_Pattern* m_pPattern;
962   CPDF_CountedPattern* m_pCountedPattern;
963   int m_nComps;
964   FX_FLOAT m_Comps[MAX_PATTERN_COLORCOMPS];
965 } PatternValue;
966 CPDF_PatternCS::~CPDF_PatternCS() {
967   CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : NULL;
968   if (pCS && m_pDocument) {
969     m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
970   }
971 }
972 FX_BOOL CPDF_PatternCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
973   CPDF_Object* pBaseCS = pArray->GetElementValue(1);
974   if (pBaseCS == m_pArray) {
975     return FALSE;
976   }
977   CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
978   m_pBaseCS = pDocPageData->GetColorSpace(pBaseCS, NULL);
979   if (m_pBaseCS) {
980     if (m_pBaseCS->GetFamily() == PDFCS_PATTERN) {
981       return FALSE;
982     }
983     m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
984     m_nComponents = m_pBaseCS->CountComponents() + 1;
985     if (m_pBaseCS->CountComponents() > MAX_PATTERN_COLORCOMPS) {
986       return FALSE;
987     }
988   } else {
989     m_nComponents = 1;
990   }
991   return TRUE;
992 }
993 FX_BOOL CPDF_PatternCS::GetRGB(FX_FLOAT* pBuf,
994                                FX_FLOAT& R,
995                                FX_FLOAT& G,
996                                FX_FLOAT& B) const {
997   if (m_pBaseCS) {
998     ASSERT(m_pBaseCS->GetFamily() != PDFCS_PATTERN);
999     PatternValue* pvalue = (PatternValue*)pBuf;
1000     if (m_pBaseCS->GetRGB(pvalue->m_Comps, R, G, B)) {
1001       return TRUE;
1002     }
1003   }
1004   R = G = B = 0.75f;
1005   return FALSE;
1006 }
1007 CPDF_ColorSpace* CPDF_PatternCS::GetBaseCS() const {
1008   return m_pBaseCS;
1009 }
1010 class CPDF_SeparationCS : public CPDF_ColorSpace {
1011  public:
1012   CPDF_SeparationCS(CPDF_Document* pDoc)
1013       : CPDF_ColorSpace(pDoc, PDFCS_SEPARATION, 1),
1014         m_pAltCS(nullptr),
1015         m_pFunc(nullptr) {}
1016   ~CPDF_SeparationCS() override;
1017   void GetDefaultValue(int iComponent,
1018                        FX_FLOAT& value,
1019                        FX_FLOAT& min,
1020                        FX_FLOAT& max) const override;
1021   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
1022   FX_BOOL GetRGB(FX_FLOAT* pBuf,
1023                  FX_FLOAT& R,
1024                  FX_FLOAT& G,
1025                  FX_FLOAT& B) const override;
1026   void EnableStdConversion(FX_BOOL bEnabled) override;
1027
1028   CPDF_ColorSpace* m_pAltCS;
1029   CPDF_Function* m_pFunc;
1030   enum { None, All, Colorant } m_Type;
1031 };
1032 CPDF_SeparationCS::~CPDF_SeparationCS() {
1033   if (m_pAltCS) {
1034     m_pAltCS->ReleaseCS();
1035   }
1036   delete m_pFunc;
1037 }
1038 void CPDF_SeparationCS::GetDefaultValue(int iComponent,
1039                                         FX_FLOAT& value,
1040                                         FX_FLOAT& min,
1041                                         FX_FLOAT& max) const {
1042   value = 1.0f;
1043   min = 0;
1044   max = 1.0f;
1045 }
1046 FX_BOOL CPDF_SeparationCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
1047   CFX_ByteString name = pArray->GetString(1);
1048   if (name == FX_BSTRC("None")) {
1049     m_Type = None;
1050   } else {
1051     m_Type = Colorant;
1052     CPDF_Object* pAltCS = pArray->GetElementValue(2);
1053     if (pAltCS == m_pArray) {
1054       return FALSE;
1055     }
1056     m_pAltCS = Load(pDoc, pAltCS);
1057     if (!m_pAltCS) {
1058       return FALSE;
1059     }
1060     CPDF_Object* pFuncObj = pArray->GetElementValue(3);
1061     if (pFuncObj && pFuncObj->GetType() != PDFOBJ_NAME) {
1062       m_pFunc = CPDF_Function::Load(pFuncObj);
1063     }
1064     if (m_pFunc && m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
1065       delete m_pFunc;
1066       m_pFunc = NULL;
1067     }
1068   }
1069   return TRUE;
1070 }
1071 FX_BOOL CPDF_SeparationCS::GetRGB(FX_FLOAT* pBuf,
1072                                   FX_FLOAT& R,
1073                                   FX_FLOAT& G,
1074                                   FX_FLOAT& B) const {
1075   if (m_Type == None) {
1076     return FALSE;
1077   }
1078   if (m_pFunc == NULL) {
1079     if (m_pAltCS == NULL) {
1080       return FALSE;
1081     }
1082     int nComps = m_pAltCS->CountComponents();
1083     CFX_FixedBufGrow<FX_FLOAT, 16> results(nComps);
1084     for (int i = 0; i < nComps; i++) {
1085       results[i] = *pBuf;
1086     }
1087     m_pAltCS->GetRGB(results, R, G, B);
1088     return TRUE;
1089   }
1090   CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
1091   int nresults = 0;
1092   m_pFunc->Call(pBuf, 1, results, nresults);
1093   if (nresults == 0) {
1094     return FALSE;
1095   }
1096   if (m_pAltCS) {
1097     m_pAltCS->GetRGB(results, R, G, B);
1098     return TRUE;
1099   }
1100   R = G = B = 0;
1101   return FALSE;
1102 }
1103 void CPDF_SeparationCS::EnableStdConversion(FX_BOOL bEnabled) {
1104   CPDF_ColorSpace::EnableStdConversion(bEnabled);
1105   if (m_pAltCS) {
1106     m_pAltCS->EnableStdConversion(bEnabled);
1107   }
1108 }
1109 class CPDF_DeviceNCS : public CPDF_ColorSpace {
1110  public:
1111   CPDF_DeviceNCS(CPDF_Document* pDoc)
1112       : CPDF_ColorSpace(pDoc, PDFCS_DEVICEN, 0),
1113         m_pAltCS(nullptr),
1114         m_pFunc(nullptr) {}
1115   ~CPDF_DeviceNCS() override;
1116   void GetDefaultValue(int iComponent,
1117                        FX_FLOAT& value,
1118                        FX_FLOAT& min,
1119                        FX_FLOAT& max) const override;
1120   FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
1121   FX_BOOL GetRGB(FX_FLOAT* pBuf,
1122                  FX_FLOAT& R,
1123                  FX_FLOAT& G,
1124                  FX_FLOAT& B) const override;
1125   void EnableStdConversion(FX_BOOL bEnabled) override;
1126
1127   CPDF_ColorSpace* m_pAltCS;
1128   CPDF_Function* m_pFunc;
1129 };
1130 CPDF_DeviceNCS::~CPDF_DeviceNCS() {
1131   delete m_pFunc;
1132   if (m_pAltCS) {
1133     m_pAltCS->ReleaseCS();
1134   }
1135 }
1136 void CPDF_DeviceNCS::GetDefaultValue(int iComponent,
1137                                      FX_FLOAT& value,
1138                                      FX_FLOAT& min,
1139                                      FX_FLOAT& max) const {
1140   value = 1.0f;
1141   min = 0;
1142   max = 1.0f;
1143 }
1144 FX_BOOL CPDF_DeviceNCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
1145   CPDF_Object* pObj = pArray->GetElementValue(1);
1146   if (!pObj) {
1147     return FALSE;
1148   }
1149   if (pObj->GetType() != PDFOBJ_ARRAY) {
1150     return FALSE;
1151   }
1152   m_nComponents = ((CPDF_Array*)pObj)->GetCount();
1153   CPDF_Object* pAltCS = pArray->GetElementValue(2);
1154   if (!pAltCS || pAltCS == m_pArray) {
1155     return FALSE;
1156   }
1157   m_pAltCS = Load(pDoc, pAltCS);
1158   m_pFunc = CPDF_Function::Load(pArray->GetElementValue(3));
1159   if (m_pAltCS == NULL || m_pFunc == NULL) {
1160     return FALSE;
1161   }
1162   if (m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
1163     return FALSE;
1164   }
1165   return TRUE;
1166 }
1167 FX_BOOL CPDF_DeviceNCS::GetRGB(FX_FLOAT* pBuf,
1168                                FX_FLOAT& R,
1169                                FX_FLOAT& G,
1170                                FX_FLOAT& B) const {
1171   if (m_pFunc == NULL) {
1172     return FALSE;
1173   }
1174   CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
1175   int nresults = 0;
1176   m_pFunc->Call(pBuf, m_nComponents, results, nresults);
1177   if (nresults == 0) {
1178     return FALSE;
1179   }
1180   m_pAltCS->GetRGB(results, R, G, B);
1181   return TRUE;
1182 }
1183 void CPDF_DeviceNCS::EnableStdConversion(FX_BOOL bEnabled) {
1184   CPDF_ColorSpace::EnableStdConversion(bEnabled);
1185   if (m_pAltCS) {
1186     m_pAltCS->EnableStdConversion(bEnabled);
1187   }
1188 }
1189 CPDF_ColorSpace* CPDF_ColorSpace::GetStockCS(int family) {
1190   return CPDF_ModuleMgr::Get()->GetPageModule()->GetStockCS(family);
1191   ;
1192 }
1193 CPDF_ColorSpace* _CSFromName(const CFX_ByteString& name) {
1194   if (name == FX_BSTRC("DeviceRGB") || name == FX_BSTRC("RGB")) {
1195     return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
1196   }
1197   if (name == FX_BSTRC("DeviceGray") || name == FX_BSTRC("G")) {
1198     return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY);
1199   }
1200   if (name == FX_BSTRC("DeviceCMYK") || name == FX_BSTRC("CMYK")) {
1201     return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK);
1202   }
1203   if (name == FX_BSTRC("Pattern")) {
1204     return CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
1205   }
1206   return NULL;
1207 }
1208 CPDF_ColorSpace* CPDF_ColorSpace::Load(CPDF_Document* pDoc, CPDF_Object* pObj) {
1209   if (pObj == NULL) {
1210     return NULL;
1211   }
1212   if (pObj->GetType() == PDFOBJ_NAME) {
1213     return _CSFromName(pObj->GetString());
1214   }
1215   if (pObj->GetType() == PDFOBJ_STREAM) {
1216     CPDF_Dictionary* pDict = ((CPDF_Stream*)pObj)->GetDict();
1217     if (!pDict) {
1218       return NULL;
1219     }
1220     CPDF_ColorSpace* pRet = NULL;
1221     FX_POSITION pos = pDict->GetStartPos();
1222     while (pos) {
1223       CFX_ByteString bsKey;
1224       CPDF_Object* pValue = pDict->GetNextElement(pos, bsKey);
1225       if (pValue && pValue->GetType() == PDFOBJ_NAME) {
1226         pRet = _CSFromName(pValue->GetString());
1227       }
1228       if (pRet) {
1229         return pRet;
1230       }
1231     }
1232     return NULL;
1233   }
1234   if (pObj->GetType() != PDFOBJ_ARRAY) {
1235     return NULL;
1236   }
1237   CPDF_Array* pArray = (CPDF_Array*)pObj;
1238   if (pArray->GetCount() == 0) {
1239     return NULL;
1240   }
1241   CPDF_Object* pFamilyObj = pArray->GetElementValue(0);
1242   if (!pFamilyObj) {
1243     return NULL;
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 }
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 }
1293 int CPDF_ColorSpace::GetBufSize() const {
1294   if (m_Family == PDFCS_PATTERN) {
1295     return sizeof(PatternValue);
1296   }
1297   return m_nComponents * sizeof(FX_FLOAT);
1298 }
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 }
1304 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 }
1314 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 }
1329 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 }
1341 void CPDF_ColorSpace::GetDefaultColor(FX_FLOAT* buf) const {
1342   if (buf == NULL || 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 }
1350 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 }
1357 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 }
1379 void CPDF_ColorSpace::EnableStdConversion(FX_BOOL bEnabled) {
1380   if (bEnabled) {
1381     m_dwStdConversion++;
1382   } else if (m_dwStdConversion) {
1383     m_dwStdConversion--;
1384   }
1385 }
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 }
1399 CPDF_Color::~CPDF_Color() {
1400   ReleaseBuffer();
1401   ReleaseColorSpace();
1402 }
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 }
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 }
1427 void CPDF_Color::SetColorSpace(CPDF_ColorSpace* pCS) {
1428   if (m_pCS == pCS) {
1429     if (m_pBuffer == NULL) {
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 }
1444 void CPDF_Color::SetValue(FX_FLOAT* comps) {
1445   if (m_pBuffer == NULL) {
1446     return;
1447   }
1448   if (m_pCS->GetFamily() != PDFCS_PATTERN) {
1449     FXSYS_memcpy(m_pBuffer, comps, m_pCS->CountComponents() * sizeof(FX_FLOAT));
1450   }
1451 }
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 == NULL || 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 }
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 == NULL) {
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 }
1508 FX_BOOL CPDF_Color::GetRGB(int& R, int& G, int& B) const {
1509   if (m_pCS == NULL || m_pBuffer == NULL) {
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 }
1521 CPDF_Pattern* CPDF_Color::GetPattern() const {
1522   if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1523     return NULL;
1524   }
1525   PatternValue* pvalue = (PatternValue*)m_pBuffer;
1526   return pvalue->m_pPattern;
1527 }
1528 CPDF_ColorSpace* CPDF_Color::GetPatternCS() const {
1529   if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1530     return NULL;
1531   }
1532   return m_pCS->GetBaseCS();
1533 }
1534 FX_FLOAT* CPDF_Color::GetPatternColor() const {
1535   if (m_pBuffer == NULL || 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 }
1541 FX_BOOL CPDF_Color::IsEqual(const CPDF_Color& other) const {
1542   if (m_pCS != other.m_pCS || m_pCS == NULL) {
1543     return FALSE;
1544   }
1545   return FXSYS_memcmp(m_pBuffer, other.m_pBuffer, m_pCS->GetBufSize()) == 0;
1546 }