0ee7a0da7d0d8b3f9de19d723f14e6d7e8162756
[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     FX_BOOL     v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
565     FX_BOOL GetRGB(FX_FLOAT* pBuf, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B) const override;
566     FX_BOOL     SetRGB(FX_FLOAT* pBuf, FX_FLOAT R, FX_FLOAT G, FX_FLOAT B) const override;
567     FX_BOOL     v_GetCMYK(FX_FLOAT* pBuf, FX_FLOAT& c, FX_FLOAT& m, FX_FLOAT& y, FX_FLOAT& k) const override;
568     void EnableStdConversion(FX_BOOL bEnabled) override;
569     void TranslateImageLine(uint8_t* pDestBuf, const uint8_t* pSrcBuf, int pixels, int image_width,
570                             int image_height, FX_BOOL bTransMask = FALSE) const override;
571
572     CPDF_ColorSpace* m_pAlterCS;
573     CPDF_IccProfile* m_pProfile;
574     uint8_t* m_pCache;
575     FX_FLOAT* m_pRanges;
576     FX_BOOL     m_bOwn;
577 };
578
579 CPDF_ICCBasedCS::~CPDF_ICCBasedCS()
580 {
581     if (m_pCache) {
582         FX_Free(m_pCache);
583     }
584     if (m_pRanges) {
585         FX_Free(m_pRanges);
586     }
587     if (m_pAlterCS && m_bOwn) {
588         m_pAlterCS->ReleaseCS();
589     }
590     if (m_pProfile && m_pDocument) {
591         m_pDocument->GetPageData()->ReleaseIccProfile(m_pProfile);
592     }
593 }
594
595 FX_BOOL CPDF_ICCBasedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray)
596 {
597     CPDF_Stream* pStream = pArray->GetStream(1);
598     if (pStream == NULL) {
599         return FALSE;
600     }
601     m_pProfile = pDoc->LoadIccProfile(pStream);
602     if (!m_pProfile) {
603         return FALSE;
604     }
605     m_nComponents = m_pProfile->GetComponents(); //Try using the nComponents from ICC profile
606     CPDF_Dictionary* pDict = pStream->GetDict();
607     if (m_pProfile->m_pTransform == NULL) { // No valid ICC profile or using sRGB
608         CPDF_Object* pAlterCSObj = pDict ? pDict->GetElementValue(FX_BSTRC("Alternate")) : NULL;
609         if (pAlterCSObj) {
610             CPDF_ColorSpace* pAlterCS = CPDF_ColorSpace::Load(pDoc, pAlterCSObj);
611             if (pAlterCS) {
612                 if (m_nComponents == 0) { // NO valid ICC profile
613                     if (pAlterCS->CountComponents() > 0) { // Use Alternative colorspace
614                         m_nComponents = pAlterCS->CountComponents();
615                         m_pAlterCS = pAlterCS;
616                         m_bOwn = TRUE;
617                     }
618                     else { // No valid alternative colorspace
619                         pAlterCS->ReleaseCS();
620                         int32_t nDictComponents = pDict ? pDict->GetInteger(FX_BSTRC("N")) : 0;
621                         if (nDictComponents != 1 && nDictComponents != 3 && nDictComponents != 4) {
622                             return FALSE;
623                         }
624                         m_nComponents = nDictComponents;
625                     }
626
627                 }
628                 else { // Using sRGB
629                     if (pAlterCS->CountComponents() != m_nComponents) {
630                         pAlterCS->ReleaseCS();
631                     }
632                     else {
633                         m_pAlterCS = pAlterCS;
634                         m_bOwn = TRUE;
635                     }
636                 }
637             }
638         }
639         if (!m_pAlterCS) {
640             if (m_nComponents == 1) {
641                 m_pAlterCS = GetStockCS(PDFCS_DEVICEGRAY);
642             }
643             else if (m_nComponents == 3) {
644                 m_pAlterCS = GetStockCS(PDFCS_DEVICERGB);
645             }
646             else if (m_nComponents == 4) {
647                 m_pAlterCS = GetStockCS(PDFCS_DEVICECMYK);
648             }
649         }
650     }
651     CPDF_Array* pRanges = pDict->GetArray(FX_BSTRC("Range"));
652     m_pRanges = FX_Alloc2D(FX_FLOAT, m_nComponents, 2);
653     for (int i = 0; i < m_nComponents * 2; i ++) {
654         if (pRanges) {
655             m_pRanges[i] = pRanges->GetNumber(i);
656         } else if (i % 2) {
657             m_pRanges[i] = 1.0f;
658         } else {
659             m_pRanges[i] = 0;
660         }
661     }
662     return TRUE;
663 }
664 FX_BOOL CPDF_ICCBasedCS::GetRGB(FX_FLOAT* pBuf, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B) const
665 {
666     if (m_pProfile && m_pProfile->m_bsRGB) {
667         R = pBuf[0];
668         G = pBuf[1];
669         B = pBuf[2];
670         return TRUE;
671     }
672     ICodec_IccModule *pIccModule = CPDF_ModuleMgr::Get()->GetIccModule();
673     if (m_pProfile->m_pTransform == NULL || pIccModule == NULL) {
674         if (m_pAlterCS) {
675             m_pAlterCS->GetRGB(pBuf, R, G, B);
676         } else {
677             R = G = B = 0.0f;
678         }
679         return TRUE;
680     }
681     FX_FLOAT rgb[3];
682     pIccModule->SetComponents(m_nComponents);
683     pIccModule->Translate(m_pProfile->m_pTransform, pBuf, rgb);
684     R = rgb[0];
685     G = rgb[1];
686     B = rgb[2];
687     return TRUE;
688 }
689 FX_BOOL CPDF_ICCBasedCS::v_GetCMYK(FX_FLOAT* pBuf, FX_FLOAT& c, FX_FLOAT& m, FX_FLOAT& y, FX_FLOAT& k) const
690 {
691     if (m_nComponents != 4) {
692         return FALSE;
693     }
694     c = pBuf[0];
695     m = pBuf[1];
696     y = pBuf[2];
697     k = pBuf[3];
698     return TRUE;
699 }
700 FX_BOOL CPDF_ICCBasedCS::SetRGB(FX_FLOAT* pBuf, FX_FLOAT R, FX_FLOAT G, FX_FLOAT B) const
701 {
702     return FALSE;
703 }
704 void CPDF_ICCBasedCS::EnableStdConversion(FX_BOOL bEnabled)
705 {
706     CPDF_ColorSpace::EnableStdConversion(bEnabled);
707     if (m_pAlterCS) {
708         m_pAlterCS->EnableStdConversion(bEnabled);
709     }
710 }
711 void CPDF_ICCBasedCS::TranslateImageLine(uint8_t* pDestBuf, const uint8_t* pSrcBuf, int pixels, int image_width, int image_height, FX_BOOL bTransMask) const
712 {
713     if (m_pProfile->m_bsRGB) {
714         ReverseRGB(pDestBuf, pSrcBuf, pixels);
715     } else if (m_pProfile->m_pTransform) {
716         int nMaxColors = 1;
717         for (int i = 0; i < m_nComponents; i ++) {
718             nMaxColors *= 52;
719         }
720         if (m_nComponents > 3 || image_width * image_height < nMaxColors * 3 / 2) {
721             CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(m_pProfile->m_pTransform, pDestBuf, pSrcBuf, pixels);
722         } else {
723             if (m_pCache == NULL) {
724                 ((CPDF_ICCBasedCS*)this)->m_pCache = FX_Alloc2D(uint8_t, nMaxColors, 3);
725                 uint8_t* temp_src = FX_Alloc2D(uint8_t, nMaxColors, m_nComponents);
726                 uint8_t* pSrc = temp_src;
727                 for (int i = 0; i < nMaxColors; i ++) {
728                     FX_DWORD color = i;
729                     FX_DWORD order = nMaxColors / 52;
730                     for (int c = 0; c < m_nComponents; c ++) {
731                         *pSrc++ = (uint8_t)(color / order * 5);
732                         color %= order;
733                         order /= 52;
734                     }
735                 }
736                 CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(m_pProfile->m_pTransform, m_pCache, temp_src, nMaxColors);
737                 FX_Free(temp_src);
738             }
739             for (int i = 0; i < pixels; i ++) {
740                 int index = 0;
741                 for (int c = 0; c < m_nComponents; c ++) {
742                     index = index * 52 + (*pSrcBuf) / 5;
743                     pSrcBuf ++;
744                 }
745                 index *= 3;
746                 *pDestBuf++ = m_pCache[index];
747                 *pDestBuf++ = m_pCache[index + 1];
748                 *pDestBuf++ = m_pCache[index + 2];
749             }
750         }
751     } else if (m_pAlterCS) {
752         m_pAlterCS->TranslateImageLine(pDestBuf, pSrcBuf, pixels, image_width, image_height);
753     }
754 }
755 class CPDF_IndexedCS : public CPDF_ColorSpace
756 {
757 public:
758     explicit CPDF_IndexedCS(CPDF_Document* pDoc)
759         : CPDF_ColorSpace(pDoc, PDFCS_INDEXED, 1),
760           m_pBaseCS(nullptr),
761           m_pCountedBaseCS(nullptr),
762           m_pCompMinMax(nullptr) {
763     }
764     ~CPDF_IndexedCS() override;
765
766     FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
767     FX_BOOL     GetRGB(FX_FLOAT* pBuf, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B) const override;
768     CPDF_ColorSpace* GetBaseCS() const override;
769     void EnableStdConversion(FX_BOOL bEnabled) override;
770
771     CPDF_ColorSpace* m_pBaseCS;
772     CPDF_CountedColorSpace* m_pCountedBaseCS;
773     int m_nBaseComponents;
774     int m_MaxIndex;
775     CFX_ByteString m_Table;
776     FX_FLOAT* m_pCompMinMax;
777 };
778 CPDF_IndexedCS::~CPDF_IndexedCS()
779 {
780     if (m_pCompMinMax) {
781         FX_Free(m_pCompMinMax);
782     }
783     CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : NULL;
784     if (pCS && m_pDocument) {
785         m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
786     }
787 }
788 FX_BOOL CPDF_IndexedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray)
789 {
790     if (pArray->GetCount() < 4) {
791         return FALSE;
792     }
793     CPDF_Object* pBaseObj = pArray->GetElementValue(1);
794     if (pBaseObj == m_pArray) {
795         return FALSE;
796     }
797     CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
798     m_pBaseCS = pDocPageData->GetColorSpace(pBaseObj, NULL);
799     if (m_pBaseCS == NULL) {
800         return FALSE;
801     }
802     m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
803     m_nBaseComponents = m_pBaseCS->CountComponents();
804     m_pCompMinMax = FX_Alloc2D(FX_FLOAT, m_nBaseComponents, 2);
805     FX_FLOAT defvalue;
806     for (int i = 0; i < m_nBaseComponents; i ++) {
807         m_pBaseCS->GetDefaultValue(i, defvalue, m_pCompMinMax[i * 2], m_pCompMinMax[i * 2 + 1]);
808         m_pCompMinMax[i * 2 + 1] -= m_pCompMinMax[i * 2];
809     }
810     m_MaxIndex = pArray->GetInteger(2);
811     CPDF_Object* pTableObj = pArray->GetElementValue(3);
812     if (pTableObj == NULL) {
813         return FALSE;
814     }
815     if (pTableObj->GetType() == PDFOBJ_STRING) {
816         m_Table = ((CPDF_String*)pTableObj)->GetString();
817     } else if (pTableObj->GetType() == PDFOBJ_STREAM) {
818         CPDF_StreamAcc acc;
819         acc.LoadAllData((CPDF_Stream*)pTableObj, FALSE);
820         m_Table = CFX_ByteStringC(acc.GetData(), acc.GetSize());
821     }
822     return TRUE;
823 }
824
825 FX_BOOL CPDF_IndexedCS::GetRGB(FX_FLOAT* pBuf, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B) const
826 {
827     int index = (int32_t)(*pBuf);
828     if (index < 0 || index > m_MaxIndex) {
829         return FALSE;
830     }
831     if (m_nBaseComponents) {
832         if (index == INT_MAX || (index + 1) > INT_MAX / m_nBaseComponents ||
833                 (index + 1)*m_nBaseComponents > (int)m_Table.GetLength()) {
834             R = G = B = 0;
835             return FALSE;
836         }
837     }
838     CFX_FixedBufGrow<FX_FLOAT, 16> Comps(m_nBaseComponents);
839     FX_FLOAT* comps = Comps;
840     const uint8_t* pTable = m_Table;
841     for (int i = 0; i < m_nBaseComponents; i ++) {
842         comps[i] = m_pCompMinMax[i * 2] + m_pCompMinMax[i * 2 + 1] * pTable[index * m_nBaseComponents + i] / 255;
843     }
844     m_pBaseCS->GetRGB(comps, R, G, B);
845     return TRUE;
846 }
847 CPDF_ColorSpace*CPDF_IndexedCS::GetBaseCS() const
848 {
849     return m_pBaseCS;
850 }
851 void CPDF_IndexedCS::EnableStdConversion(FX_BOOL bEnabled)
852 {
853     CPDF_ColorSpace::EnableStdConversion(bEnabled);
854     if (m_pBaseCS) {
855         m_pBaseCS->EnableStdConversion(bEnabled);
856     }
857 }
858 #define MAX_PATTERN_COLORCOMPS  16
859 typedef struct _PatternValue {
860     CPDF_Pattern*       m_pPattern;
861     CPDF_CountedPattern*        m_pCountedPattern;
862     int                         m_nComps;
863     FX_FLOAT            m_Comps[MAX_PATTERN_COLORCOMPS];
864 } PatternValue;
865 CPDF_PatternCS::~CPDF_PatternCS()
866 {
867     CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : NULL;
868     if (pCS && m_pDocument) {
869             m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
870     }
871 }
872 FX_BOOL CPDF_PatternCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray)
873 {
874     CPDF_Object* pBaseCS = pArray->GetElementValue(1);
875     if (pBaseCS == m_pArray) {
876         return FALSE;
877     }
878     CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
879     m_pBaseCS = pDocPageData->GetColorSpace(pBaseCS, NULL);
880     if (m_pBaseCS) {
881         if (m_pBaseCS->GetFamily() == PDFCS_PATTERN) {
882             return FALSE;
883         }
884         m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
885         m_nComponents = m_pBaseCS->CountComponents() + 1;
886         if (m_pBaseCS->CountComponents() > MAX_PATTERN_COLORCOMPS) {
887             return FALSE;
888         }
889     } else {
890         m_nComponents = 1;
891     }
892     return TRUE;
893 }
894 FX_BOOL CPDF_PatternCS::GetRGB(FX_FLOAT* pBuf, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B) const
895 {
896     if (m_pBaseCS) {
897         ASSERT(m_pBaseCS->GetFamily() != PDFCS_PATTERN);
898         PatternValue* pvalue = (PatternValue*)pBuf;
899         if (m_pBaseCS->GetRGB(pvalue->m_Comps, R, G, B)) {
900             return TRUE;
901         }
902     }
903     R = G = B = 0.75f;
904     return FALSE;
905 }
906 CPDF_ColorSpace* CPDF_PatternCS::GetBaseCS() const
907 {
908     return m_pBaseCS;
909 }
910 class CPDF_SeparationCS : public CPDF_ColorSpace
911 {
912 public:
913     CPDF_SeparationCS(CPDF_Document* pDoc)
914             : CPDF_ColorSpace(pDoc, PDFCS_SEPARATION, 1),
915               m_pAltCS(nullptr),
916               m_pFunc(nullptr) {
917     }
918     ~CPDF_SeparationCS() override;
919     void GetDefaultValue(int iComponent, FX_FLOAT& value, FX_FLOAT& min, FX_FLOAT& max) const override;
920     FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
921     FX_BOOL GetRGB(FX_FLOAT* pBuf, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B) const override;
922     void EnableStdConversion(FX_BOOL bEnabled) override;
923
924     CPDF_ColorSpace* m_pAltCS;
925     CPDF_Function* m_pFunc;
926     enum { None, All, Colorant } m_Type;
927 };
928 CPDF_SeparationCS::~CPDF_SeparationCS()
929 {
930     if (m_pAltCS) {
931         m_pAltCS->ReleaseCS();
932     }
933     delete m_pFunc;
934 }
935 void CPDF_SeparationCS::GetDefaultValue(int iComponent, FX_FLOAT& value, FX_FLOAT& min, FX_FLOAT& max) const
936 {
937     value = 1.0f;
938     min = 0;
939     max = 1.0f;
940 }
941 FX_BOOL CPDF_SeparationCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray)
942 {
943     CFX_ByteString name = pArray->GetString(1);
944     if (name == FX_BSTRC("None")) {
945         m_Type = None;
946     } else {
947         m_Type = Colorant;
948         CPDF_Object* pAltCS = pArray->GetElementValue(2);
949         if (pAltCS == m_pArray) {
950             return FALSE;
951         }
952         m_pAltCS = Load(pDoc, pAltCS);
953         CPDF_Object* pFuncObj = pArray->GetElementValue(3);
954         if (pFuncObj && pFuncObj->GetType() != PDFOBJ_NAME) {
955             m_pFunc = CPDF_Function::Load(pFuncObj);
956         }
957         if (m_pFunc && m_pAltCS && m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
958             delete m_pFunc;
959             m_pFunc = NULL;
960         }
961     }
962     return TRUE;
963 }
964 FX_BOOL CPDF_SeparationCS::GetRGB(FX_FLOAT* pBuf, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B) const
965 {
966     if (m_Type == None) {
967         return FALSE;
968     }
969     if (m_pFunc == NULL) {
970         if (m_pAltCS == NULL) {
971             return FALSE;
972         }
973         int nComps = m_pAltCS->CountComponents();
974         CFX_FixedBufGrow<FX_FLOAT, 16> results(nComps);
975         for (int i = 0; i < nComps; i ++) {
976             results[i] = *pBuf;
977         }
978         m_pAltCS->GetRGB(results, R, G, B);
979         return TRUE;
980     }
981     CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
982     int nresults = 0;
983     m_pFunc->Call(pBuf, 1, results, nresults);
984     if (nresults == 0) {
985         return FALSE;
986     }
987     if (m_pAltCS) {
988         m_pAltCS->GetRGB(results, R, G, B);
989         return TRUE;
990     } else {
991         R = G = B = 0;
992         return FALSE;
993     }
994 }
995 void CPDF_SeparationCS::EnableStdConversion(FX_BOOL bEnabled)
996 {
997     CPDF_ColorSpace::EnableStdConversion(bEnabled);
998     if (m_pAltCS) {
999         m_pAltCS->EnableStdConversion(bEnabled);
1000     }
1001 }
1002 class CPDF_DeviceNCS : public CPDF_ColorSpace
1003 {
1004 public:
1005     CPDF_DeviceNCS(CPDF_Document* pDoc)
1006             : CPDF_ColorSpace(pDoc, PDFCS_DEVICEN, 0),
1007               m_pAltCS(nullptr),
1008               m_pFunc(nullptr) {
1009     }
1010     ~CPDF_DeviceNCS() override;
1011     void GetDefaultValue(int iComponent, FX_FLOAT& value, FX_FLOAT& min, FX_FLOAT& max) const override;
1012     FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
1013     FX_BOOL GetRGB(FX_FLOAT* pBuf, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B) const override;
1014     void EnableStdConversion(FX_BOOL bEnabled) override;
1015
1016     CPDF_ColorSpace* m_pAltCS;
1017     CPDF_Function* m_pFunc;
1018 };
1019 CPDF_DeviceNCS::~CPDF_DeviceNCS()
1020 {
1021     delete m_pFunc;
1022     if (m_pAltCS) {
1023         m_pAltCS->ReleaseCS();
1024     }
1025 }
1026 void CPDF_DeviceNCS::GetDefaultValue(int iComponent, FX_FLOAT& value, FX_FLOAT& min, FX_FLOAT& max) const
1027 {
1028     value = 1.0f;
1029     min = 0;
1030     max = 1.0f;
1031 }
1032 FX_BOOL CPDF_DeviceNCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray)
1033 {
1034     CPDF_Object* pObj = pArray->GetElementValue(1);
1035     if (!pObj) {
1036         return FALSE;
1037     }
1038     if (pObj->GetType() != PDFOBJ_ARRAY) {
1039         return FALSE;
1040     }
1041     m_nComponents = ((CPDF_Array*)pObj)->GetCount();
1042     CPDF_Object* pAltCS = pArray->GetElementValue(2);
1043     if (!pAltCS || pAltCS == m_pArray) {
1044         return FALSE;
1045     }
1046     m_pAltCS = Load(pDoc, pAltCS);
1047     m_pFunc = CPDF_Function::Load(pArray->GetElementValue(3));
1048     if (m_pAltCS == NULL || m_pFunc == NULL) {
1049         return FALSE;
1050     }
1051     if (m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
1052         return FALSE;
1053     }
1054     return TRUE;
1055 }
1056 FX_BOOL CPDF_DeviceNCS::GetRGB(FX_FLOAT* pBuf, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B) const
1057 {
1058     if (m_pFunc == NULL) {
1059         return FALSE;
1060     }
1061     CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
1062     int nresults = 0;
1063     m_pFunc->Call(pBuf, m_nComponents, results, nresults);
1064     if (nresults == 0) {
1065         return FALSE;
1066     }
1067     m_pAltCS->GetRGB(results, R, G, B);
1068     return TRUE;
1069 }
1070 void CPDF_DeviceNCS::EnableStdConversion(FX_BOOL bEnabled)
1071 {
1072     CPDF_ColorSpace::EnableStdConversion(bEnabled);
1073     if (m_pAltCS) {
1074         m_pAltCS->EnableStdConversion(bEnabled);
1075     }
1076 }
1077 CPDF_ColorSpace* CPDF_ColorSpace::GetStockCS(int family)
1078 {
1079     return CPDF_ModuleMgr::Get()->GetPageModule()->GetStockCS(family);;
1080 }
1081 CPDF_ColorSpace* _CSFromName(const CFX_ByteString& name)
1082 {
1083     if (name == FX_BSTRC("DeviceRGB") || name == FX_BSTRC("RGB")) {
1084         return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
1085     }
1086     if (name == FX_BSTRC("DeviceGray") || name == FX_BSTRC("G")) {
1087         return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY);
1088     }
1089     if (name == FX_BSTRC("DeviceCMYK") || name == FX_BSTRC("CMYK")) {
1090         return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK);
1091     }
1092     if (name == FX_BSTRC("Pattern")) {
1093         return CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
1094     }
1095     return NULL;
1096 }
1097 CPDF_ColorSpace* CPDF_ColorSpace::Load(CPDF_Document* pDoc, CPDF_Object* pObj)
1098 {
1099     if (pObj == NULL) {
1100         return NULL;
1101     }
1102     if (pObj->GetType() == PDFOBJ_NAME) {
1103         return _CSFromName(pObj->GetString());
1104     }
1105     if (pObj->GetType() == PDFOBJ_STREAM) {
1106         CPDF_Dictionary *pDict = ((CPDF_Stream *)pObj)->GetDict();
1107         if (!pDict) {
1108             return NULL;
1109         }
1110         CPDF_ColorSpace *pRet = NULL;
1111         FX_POSITION pos = pDict->GetStartPos();
1112         while (pos) {
1113             CFX_ByteString bsKey;
1114             CPDF_Object *pValue = pDict->GetNextElement(pos, bsKey);
1115             if (pValue && pValue->GetType() == PDFOBJ_NAME) {
1116                 pRet = _CSFromName(pValue->GetString());
1117             }
1118             if (pRet) {
1119                 return pRet;
1120             }
1121         }
1122         return NULL;
1123     }
1124     if (pObj->GetType() != PDFOBJ_ARRAY) {
1125         return NULL;
1126     }
1127     CPDF_Array* pArray = (CPDF_Array*)pObj;
1128     if (pArray->GetCount() == 0) {
1129         return NULL;
1130     }
1131     CPDF_Object *pFamilyObj = pArray->GetElementValue(0);
1132     if (!pFamilyObj) {
1133         return NULL;
1134     }
1135     CFX_ByteString familyname = pFamilyObj->GetString();
1136     if (pArray->GetCount() == 1) {
1137         return _CSFromName(familyname);
1138     }
1139     CPDF_ColorSpace* pCS = NULL;
1140     FX_DWORD id = familyname.GetID();
1141     if (id == FXBSTR_ID('C', 'a', 'l', 'G')) {
1142         pCS = new CPDF_CalGray(pDoc);
1143     } else if (id == FXBSTR_ID('C', 'a', 'l', 'R')) {
1144         pCS = new CPDF_CalRGB(pDoc);
1145     } else if (id == FXBSTR_ID('L', 'a', 'b', 0)) {
1146         pCS = new CPDF_LabCS(pDoc);
1147     } else if (id == FXBSTR_ID('I', 'C', 'C', 'B')) {
1148         pCS = new CPDF_ICCBasedCS(pDoc);
1149     } else if (id == FXBSTR_ID('I', 'n', 'd', 'e') || id == FXBSTR_ID('I', 0, 0, 0)) {
1150         pCS = new CPDF_IndexedCS(pDoc);
1151     } else if (id == FXBSTR_ID('S', 'e', 'p', 'a')) {
1152         pCS = new CPDF_SeparationCS(pDoc);
1153     } else if (id == FXBSTR_ID('D', 'e', 'v', 'i')) {
1154         pCS = new CPDF_DeviceNCS(pDoc);
1155     } else if (id == FXBSTR_ID('P', 'a', 't', 't')) {
1156         pCS = new CPDF_PatternCS(pDoc);
1157     } else {
1158         return NULL;
1159     }
1160     pCS->m_pArray = pArray;
1161     if (!pCS->v_Load(pDoc, pArray)) {
1162         pCS->ReleaseCS();
1163         return NULL;
1164     }
1165     return pCS;
1166 }
1167 void CPDF_ColorSpace::ReleaseCS()
1168 {
1169     if (this == GetStockCS(PDFCS_DEVICERGB)) {
1170         return;
1171     }
1172     if (this == GetStockCS(PDFCS_DEVICEGRAY)) {
1173         return;
1174     }
1175     if (this == GetStockCS(PDFCS_DEVICECMYK)) {
1176         return;
1177     }
1178     if (this == GetStockCS(PDFCS_PATTERN)) {
1179         return;
1180     }
1181     delete this;
1182 }
1183 int CPDF_ColorSpace::GetBufSize() const
1184 {
1185     if (m_Family == PDFCS_PATTERN) {
1186         return sizeof(PatternValue);
1187     }
1188     return m_nComponents * sizeof(FX_FLOAT);
1189 }
1190 FX_FLOAT* CPDF_ColorSpace::CreateBuf()
1191 {
1192     int size = GetBufSize();
1193     uint8_t* pBuf = FX_Alloc(uint8_t, size);
1194     return (FX_FLOAT*)pBuf;
1195 }
1196 FX_BOOL CPDF_ColorSpace::sRGB() const
1197 {
1198     if (m_Family == PDFCS_DEVICERGB) {
1199         return TRUE;
1200     }
1201     if (m_Family != PDFCS_ICCBASED) {
1202         return FALSE;
1203     }
1204     CPDF_ICCBasedCS* pCS = (CPDF_ICCBasedCS*)this;
1205     return pCS->m_pProfile->m_bsRGB;
1206 }
1207 FX_BOOL CPDF_ColorSpace::GetCMYK(FX_FLOAT* pBuf, FX_FLOAT& c, FX_FLOAT& m, FX_FLOAT& y, FX_FLOAT& k) const
1208 {
1209     if (v_GetCMYK(pBuf, c, m, y, k)) {
1210         return TRUE;
1211     }
1212     FX_FLOAT R, G, B;
1213     if (!GetRGB(pBuf, R, G, B)) {
1214         return FALSE;
1215     }
1216     sRGB_to_AdobeCMYK(R, G, B, c, m, y, k);
1217     return TRUE;
1218 }
1219 FX_BOOL CPDF_ColorSpace::SetCMYK(FX_FLOAT* pBuf, FX_FLOAT c, FX_FLOAT m, FX_FLOAT y, FX_FLOAT k) const
1220 {
1221     if (v_SetCMYK(pBuf, c, m, y, k)) {
1222         return TRUE;
1223     }
1224     FX_FLOAT R, G, B;
1225     AdobeCMYK_to_sRGB(c, m, y, k, R, G, B);
1226     return SetRGB(pBuf, R, G, B);
1227 }
1228 void CPDF_ColorSpace::GetDefaultColor(FX_FLOAT* buf) const
1229 {
1230     if (buf == NULL || m_Family == PDFCS_PATTERN) {
1231         return;
1232     }
1233     FX_FLOAT min, max;
1234     for (int i = 0; i < m_nComponents; i ++) {
1235         GetDefaultValue(i, buf[i], min, max);
1236     }
1237 }
1238 int CPDF_ColorSpace::GetMaxIndex() const
1239 {
1240     if (m_Family != PDFCS_INDEXED) {
1241         return 0;
1242     }
1243     CPDF_IndexedCS* pCS = (CPDF_IndexedCS*)this;
1244     return pCS->m_MaxIndex;
1245 }
1246 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
1247 {
1248     CFX_FixedBufGrow<FX_FLOAT, 16> srcbuf(m_nComponents);
1249     FX_FLOAT* src = srcbuf;
1250     FX_FLOAT R, G, B;
1251     for (int i = 0; i < pixels; i ++) {
1252         for (int j = 0; j < m_nComponents; j ++)
1253             if (m_Family == PDFCS_INDEXED) {
1254                 src[j] = (FX_FLOAT)(*src_buf ++);
1255             } else {
1256                 src[j] = (FX_FLOAT)(*src_buf ++) / 255;
1257             }
1258         GetRGB(src, R, G, B);
1259         *dest_buf ++ = (int32_t)(B * 255);
1260         *dest_buf ++ = (int32_t)(G * 255);
1261         *dest_buf ++ = (int32_t)(R * 255);
1262     }
1263 }
1264 void CPDF_ColorSpace::EnableStdConversion(FX_BOOL bEnabled)
1265 {
1266     if (bEnabled) {
1267         m_dwStdConversion ++;
1268     } else if (m_dwStdConversion) {
1269         m_dwStdConversion --;
1270     }
1271 }
1272 CPDF_Color::CPDF_Color(int family)
1273 {
1274     m_pCS = CPDF_ColorSpace::GetStockCS(family);
1275     int nComps = 3;
1276     if (family == PDFCS_DEVICEGRAY) {
1277         nComps = 1;
1278     } else if (family == PDFCS_DEVICECMYK) {
1279         nComps = 4;
1280     }
1281     m_pBuffer = FX_Alloc(FX_FLOAT, nComps);
1282     for (int i = 0; i < nComps; i ++) {
1283         m_pBuffer[i] = 0;
1284     }
1285 }
1286 CPDF_Color::~CPDF_Color()
1287 {
1288     ReleaseBuffer();
1289     ReleaseColorSpace();
1290 }
1291 void CPDF_Color::ReleaseBuffer()
1292 {
1293     if (!m_pBuffer) {
1294         return;
1295     }
1296     if (m_pCS->GetFamily() == PDFCS_PATTERN) {
1297         PatternValue* pvalue = (PatternValue*)m_pBuffer;
1298         CPDF_Pattern* pPattern = pvalue->m_pCountedPattern ? pvalue->m_pCountedPattern->get() : NULL;
1299         if (pPattern && pPattern->m_pDocument) {
1300             CPDF_DocPageData *pPageData = pPattern->m_pDocument->GetPageData();
1301             if (pPageData) {
1302                 pPageData->ReleasePattern(pPattern->m_pPatternObj);
1303             }
1304         }
1305     }
1306     FX_Free(m_pBuffer);
1307     m_pBuffer = NULL;
1308 }
1309 void CPDF_Color::ReleaseColorSpace()
1310 {
1311     if (m_pCS && m_pCS->m_pDocument && m_pCS->GetArray()) {
1312         m_pCS->m_pDocument->GetPageData()->ReleaseColorSpace(m_pCS->GetArray());
1313         m_pCS = NULL;
1314     }
1315 }
1316 void CPDF_Color::SetColorSpace(CPDF_ColorSpace* pCS)
1317 {
1318     if (m_pCS == pCS) {
1319         if (m_pBuffer == NULL) {
1320             m_pBuffer = pCS->CreateBuf();
1321         }
1322         ReleaseColorSpace();
1323         m_pCS = pCS;
1324         return;
1325     }
1326     ReleaseBuffer();
1327     ReleaseColorSpace();
1328     m_pCS = pCS;
1329     if (m_pCS) {
1330         m_pBuffer = pCS->CreateBuf();
1331         pCS->GetDefaultColor(m_pBuffer);
1332     }
1333 }
1334 void CPDF_Color::SetValue(FX_FLOAT* comps)
1335 {
1336     if (m_pBuffer == NULL) {
1337         return;
1338     }
1339     if (m_pCS->GetFamily() != PDFCS_PATTERN) {
1340         FXSYS_memcpy(m_pBuffer, comps, m_pCS->CountComponents() * sizeof(FX_FLOAT));
1341     }
1342 }
1343 void CPDF_Color::SetValue(CPDF_Pattern* pPattern, FX_FLOAT* comps, int ncomps)
1344 {
1345     if (ncomps > MAX_PATTERN_COLORCOMPS) {
1346         return;
1347     }
1348     if (m_pCS == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1349         if (m_pBuffer) {
1350             FX_Free(m_pBuffer);
1351         }
1352         m_pCS = CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
1353         m_pBuffer = m_pCS->CreateBuf();
1354     }
1355     CPDF_DocPageData *pDocPageData = NULL;
1356     PatternValue* pvalue = (PatternValue*)m_pBuffer;
1357     if (pvalue->m_pPattern && pvalue->m_pPattern->m_pDocument) {
1358         pDocPageData = pvalue->m_pPattern->m_pDocument->GetPageData();
1359         if (pDocPageData) {
1360             pDocPageData->ReleasePattern(pvalue->m_pPattern->m_pPatternObj);
1361         }
1362     }
1363     pvalue->m_nComps = ncomps;
1364     pvalue->m_pPattern = pPattern;
1365     if (ncomps) {
1366         FXSYS_memcpy(pvalue->m_Comps, comps, ncomps * sizeof(FX_FLOAT));
1367     }
1368     pvalue->m_pCountedPattern = NULL;
1369     if (pPattern && pPattern->m_pDocument)
1370     {
1371         if (!pDocPageData) {
1372             pDocPageData = pPattern->m_pDocument->GetPageData();
1373         }
1374         pvalue->m_pCountedPattern = pDocPageData->FindPatternPtr(pPattern->m_pPatternObj);
1375     }
1376 }
1377 void CPDF_Color::Copy(const CPDF_Color* pSrc)
1378 {
1379     ReleaseBuffer();
1380     ReleaseColorSpace();
1381     m_pCS = pSrc->m_pCS;
1382     if (m_pCS && m_pCS->m_pDocument) {
1383         CPDF_Array* pArray = m_pCS->GetArray();
1384         if (pArray) {
1385             m_pCS = m_pCS->m_pDocument->GetPageData()->GetCopiedColorSpace(pArray);
1386         }
1387     }
1388     if (m_pCS == NULL) {
1389         return;
1390     }
1391     m_pBuffer = m_pCS->CreateBuf();
1392     FXSYS_memcpy(m_pBuffer, pSrc->m_pBuffer, m_pCS->GetBufSize());
1393     if (m_pCS->GetFamily() == PDFCS_PATTERN) {
1394         PatternValue* pvalue = (PatternValue*)m_pBuffer;
1395         if (pvalue->m_pPattern && pvalue->m_pPattern->m_pDocument) {
1396             pvalue->m_pPattern = pvalue->m_pPattern->m_pDocument->GetPageData()->GetPattern(pvalue->m_pPattern->m_pPatternObj, FALSE, &pvalue->m_pPattern->m_ParentMatrix);
1397         }
1398     }
1399 }
1400 FX_BOOL CPDF_Color::GetRGB(int& R, int& G, int& B) const
1401 {
1402     if (m_pCS == NULL || m_pBuffer == NULL) {
1403         return FALSE;
1404     }
1405     FX_FLOAT r=0.0f, g=0.0f, b=0.0f;
1406     if (!m_pCS->GetRGB(m_pBuffer, r, g, b)) {
1407         return FALSE;
1408     }
1409     R = (int32_t)(r * 255 + 0.5f);
1410     G = (int32_t)(g * 255 + 0.5f);
1411     B = (int32_t)(b * 255 + 0.5f);
1412     return TRUE;
1413 }
1414 CPDF_Pattern* CPDF_Color::GetPattern() const
1415 {
1416     if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1417         return NULL;
1418     }
1419     PatternValue* pvalue = (PatternValue*)m_pBuffer;
1420     return pvalue->m_pPattern;
1421 }
1422 CPDF_ColorSpace* CPDF_Color::GetPatternCS() const
1423 {
1424     if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1425         return NULL;
1426     }
1427     return m_pCS->GetBaseCS();
1428 }
1429 FX_FLOAT* CPDF_Color::GetPatternColor() const
1430 {
1431     if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1432         return NULL;
1433     }
1434     PatternValue* pvalue = (PatternValue*)m_pBuffer;
1435     return pvalue->m_nComps ? pvalue->m_Comps : NULL;
1436 }
1437 FX_BOOL CPDF_Color::IsEqual(const CPDF_Color& other) const
1438 {
1439     if (m_pCS != other.m_pCS || m_pCS == NULL) {
1440         return FALSE;
1441     }
1442     return FXSYS_memcmp(m_pBuffer, other.m_pBuffer, m_pCS->GetBufSize()) == 0;
1443 }