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