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