Fix CPDF_ICCBasedCS::GetDefaultValue heap-buffer-overflow.
[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     if (m_pFunc) {
934         delete m_pFunc;
935     }
936 }
937 void CPDF_SeparationCS::GetDefaultValue(int iComponent, FX_FLOAT& value, FX_FLOAT& min, FX_FLOAT& max) const
938 {
939     value = 1.0f;
940     min = 0;
941     max = 1.0f;
942 }
943 FX_BOOL CPDF_SeparationCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray)
944 {
945     CFX_ByteString name = pArray->GetString(1);
946     if (name == FX_BSTRC("None")) {
947         m_Type = None;
948     } else {
949         m_Type = Colorant;
950         CPDF_Object* pAltCS = pArray->GetElementValue(2);
951         if (pAltCS == m_pArray) {
952             return FALSE;
953         }
954         m_pAltCS = Load(pDoc, pAltCS);
955         CPDF_Object* pFuncObj = pArray->GetElementValue(3);
956         if (pFuncObj && pFuncObj->GetType() != PDFOBJ_NAME) {
957             m_pFunc = CPDF_Function::Load(pFuncObj);
958         }
959         if (m_pFunc && m_pAltCS && m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
960             delete m_pFunc;
961             m_pFunc = NULL;
962         }
963     }
964     return TRUE;
965 }
966 FX_BOOL CPDF_SeparationCS::GetRGB(FX_FLOAT* pBuf, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B) const
967 {
968     if (m_Type == None) {
969         return FALSE;
970     }
971     if (m_pFunc == NULL) {
972         if (m_pAltCS == NULL) {
973             return FALSE;
974         }
975         int nComps = m_pAltCS->CountComponents();
976         CFX_FixedBufGrow<FX_FLOAT, 16> results(nComps);
977         for (int i = 0; i < nComps; i ++) {
978             results[i] = *pBuf;
979         }
980         m_pAltCS->GetRGB(results, R, G, B);
981         return TRUE;
982     }
983     CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
984     int nresults = 0;
985     m_pFunc->Call(pBuf, 1, results, nresults);
986     if (nresults == 0) {
987         return FALSE;
988     }
989     if (m_pAltCS) {
990         m_pAltCS->GetRGB(results, R, G, B);
991         return TRUE;
992     } else {
993         R = G = B = 0;
994         return FALSE;
995     }
996 }
997 void CPDF_SeparationCS::EnableStdConversion(FX_BOOL bEnabled)
998 {
999     CPDF_ColorSpace::EnableStdConversion(bEnabled);
1000     if (m_pAltCS) {
1001         m_pAltCS->EnableStdConversion(bEnabled);
1002     }
1003 }
1004 class CPDF_DeviceNCS : public CPDF_ColorSpace
1005 {
1006 public:
1007     CPDF_DeviceNCS(CPDF_Document* pDoc)
1008             : CPDF_ColorSpace(pDoc, PDFCS_DEVICEN, 0),
1009               m_pAltCS(nullptr),
1010               m_pFunc(nullptr) {
1011     }
1012     ~CPDF_DeviceNCS() override;
1013     void GetDefaultValue(int iComponent, FX_FLOAT& value, FX_FLOAT& min, FX_FLOAT& max) const override;
1014     FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
1015     FX_BOOL GetRGB(FX_FLOAT* pBuf, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B) const override;
1016     void EnableStdConversion(FX_BOOL bEnabled) override;
1017
1018     CPDF_ColorSpace* m_pAltCS;
1019     CPDF_Function* m_pFunc;
1020 };
1021 CPDF_DeviceNCS::~CPDF_DeviceNCS()
1022 {
1023     if (m_pFunc) {
1024         delete m_pFunc;
1025     }
1026     if (m_pAltCS) {
1027         m_pAltCS->ReleaseCS();
1028     }
1029 }
1030 void CPDF_DeviceNCS::GetDefaultValue(int iComponent, FX_FLOAT& value, FX_FLOAT& min, FX_FLOAT& max) const
1031 {
1032     value = 1.0f;
1033     min = 0;
1034     max = 1.0f;
1035 }
1036 FX_BOOL CPDF_DeviceNCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray)
1037 {
1038     CPDF_Object* pObj = pArray->GetElementValue(1);
1039     if (!pObj) {
1040         return FALSE;
1041     }
1042     if (pObj->GetType() != PDFOBJ_ARRAY) {
1043         return FALSE;
1044     }
1045     m_nComponents = ((CPDF_Array*)pObj)->GetCount();
1046     CPDF_Object* pAltCS = pArray->GetElementValue(2);
1047     if (!pAltCS || pAltCS == m_pArray) {
1048         return FALSE;
1049     }
1050     m_pAltCS = Load(pDoc, pAltCS);
1051     m_pFunc = CPDF_Function::Load(pArray->GetElementValue(3));
1052     if (m_pAltCS == NULL || m_pFunc == NULL) {
1053         return FALSE;
1054     }
1055     if (m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
1056         return FALSE;
1057     }
1058     return TRUE;
1059 }
1060 FX_BOOL CPDF_DeviceNCS::GetRGB(FX_FLOAT* pBuf, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B) const
1061 {
1062     if (m_pFunc == NULL) {
1063         return FALSE;
1064     }
1065     CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
1066     int nresults = 0;
1067     m_pFunc->Call(pBuf, m_nComponents, results, nresults);
1068     if (nresults == 0) {
1069         return FALSE;
1070     }
1071     m_pAltCS->GetRGB(results, R, G, B);
1072     return TRUE;
1073 }
1074 void CPDF_DeviceNCS::EnableStdConversion(FX_BOOL bEnabled)
1075 {
1076     CPDF_ColorSpace::EnableStdConversion(bEnabled);
1077     if (m_pAltCS) {
1078         m_pAltCS->EnableStdConversion(bEnabled);
1079     }
1080 }
1081 CPDF_ColorSpace* CPDF_ColorSpace::GetStockCS(int family)
1082 {
1083     return CPDF_ModuleMgr::Get()->GetPageModule()->GetStockCS(family);;
1084 }
1085 CPDF_ColorSpace* _CSFromName(const CFX_ByteString& name)
1086 {
1087     if (name == FX_BSTRC("DeviceRGB") || name == FX_BSTRC("RGB")) {
1088         return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
1089     }
1090     if (name == FX_BSTRC("DeviceGray") || name == FX_BSTRC("G")) {
1091         return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY);
1092     }
1093     if (name == FX_BSTRC("DeviceCMYK") || name == FX_BSTRC("CMYK")) {
1094         return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK);
1095     }
1096     if (name == FX_BSTRC("Pattern")) {
1097         return CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
1098     }
1099     return NULL;
1100 }
1101 CPDF_ColorSpace* CPDF_ColorSpace::Load(CPDF_Document* pDoc, CPDF_Object* pObj)
1102 {
1103     if (pObj == NULL) {
1104         return NULL;
1105     }
1106     if (pObj->GetType() == PDFOBJ_NAME) {
1107         return _CSFromName(pObj->GetString());
1108     }
1109     if (pObj->GetType() == PDFOBJ_STREAM) {
1110         CPDF_Dictionary *pDict = ((CPDF_Stream *)pObj)->GetDict();
1111         if (!pDict) {
1112             return NULL;
1113         }
1114         CPDF_ColorSpace *pRet = NULL;
1115         FX_POSITION pos = pDict->GetStartPos();
1116         while (pos) {
1117             CFX_ByteString bsKey;
1118             CPDF_Object *pValue = pDict->GetNextElement(pos, bsKey);
1119             if (pValue && pValue->GetType() == PDFOBJ_NAME) {
1120                 pRet = _CSFromName(pValue->GetString());
1121             }
1122             if (pRet) {
1123                 return pRet;
1124             }
1125         }
1126         return NULL;
1127     }
1128     if (pObj->GetType() != PDFOBJ_ARRAY) {
1129         return NULL;
1130     }
1131     CPDF_Array* pArray = (CPDF_Array*)pObj;
1132     if (pArray->GetCount() == 0) {
1133         return NULL;
1134     }
1135     CPDF_Object *pFamilyObj = pArray->GetElementValue(0);
1136     if (!pFamilyObj) {
1137         return NULL;
1138     }
1139     CFX_ByteString familyname = pFamilyObj->GetString();
1140     if (pArray->GetCount() == 1) {
1141         return _CSFromName(familyname);
1142     }
1143     CPDF_ColorSpace* pCS = NULL;
1144     FX_DWORD id = familyname.GetID();
1145     if (id == FXBSTR_ID('C', 'a', 'l', 'G')) {
1146         pCS = new CPDF_CalGray(pDoc);
1147     } else if (id == FXBSTR_ID('C', 'a', 'l', 'R')) {
1148         pCS = new CPDF_CalRGB(pDoc);
1149     } else if (id == FXBSTR_ID('L', 'a', 'b', 0)) {
1150         pCS = new CPDF_LabCS(pDoc);
1151     } else if (id == FXBSTR_ID('I', 'C', 'C', 'B')) {
1152         pCS = new CPDF_ICCBasedCS(pDoc);
1153     } else if (id == FXBSTR_ID('I', 'n', 'd', 'e') || id == FXBSTR_ID('I', 0, 0, 0)) {
1154         pCS = new CPDF_IndexedCS(pDoc);
1155     } else if (id == FXBSTR_ID('S', 'e', 'p', 'a')) {
1156         pCS = new CPDF_SeparationCS(pDoc);
1157     } else if (id == FXBSTR_ID('D', 'e', 'v', 'i')) {
1158         pCS = new CPDF_DeviceNCS(pDoc);
1159     } else if (id == FXBSTR_ID('P', 'a', 't', 't')) {
1160         pCS = new CPDF_PatternCS(pDoc);
1161     } else {
1162         return NULL;
1163     }
1164     pCS->m_pArray = pArray;
1165     if (!pCS->v_Load(pDoc, pArray)) {
1166         pCS->ReleaseCS();
1167         return NULL;
1168     }
1169     return pCS;
1170 }
1171 void CPDF_ColorSpace::ReleaseCS()
1172 {
1173     if (this == GetStockCS(PDFCS_DEVICERGB)) {
1174         return;
1175     }
1176     if (this == GetStockCS(PDFCS_DEVICEGRAY)) {
1177         return;
1178     }
1179     if (this == GetStockCS(PDFCS_DEVICECMYK)) {
1180         return;
1181     }
1182     if (this == GetStockCS(PDFCS_PATTERN)) {
1183         return;
1184     }
1185     delete this;
1186 }
1187 int CPDF_ColorSpace::GetBufSize() const
1188 {
1189     if (m_Family == PDFCS_PATTERN) {
1190         return sizeof(PatternValue);
1191     }
1192     return m_nComponents * sizeof(FX_FLOAT);
1193 }
1194 FX_FLOAT* CPDF_ColorSpace::CreateBuf()
1195 {
1196     int size = GetBufSize();
1197     uint8_t* pBuf = FX_Alloc(uint8_t, size);
1198     return (FX_FLOAT*)pBuf;
1199 }
1200 FX_BOOL CPDF_ColorSpace::sRGB() const
1201 {
1202     if (m_Family == PDFCS_DEVICERGB) {
1203         return TRUE;
1204     }
1205     if (m_Family != PDFCS_ICCBASED) {
1206         return FALSE;
1207     }
1208     CPDF_ICCBasedCS* pCS = (CPDF_ICCBasedCS*)this;
1209     return pCS->m_pProfile->m_bsRGB;
1210 }
1211 FX_BOOL CPDF_ColorSpace::GetCMYK(FX_FLOAT* pBuf, FX_FLOAT& c, FX_FLOAT& m, FX_FLOAT& y, FX_FLOAT& k) const
1212 {
1213     if (v_GetCMYK(pBuf, c, m, y, k)) {
1214         return TRUE;
1215     }
1216     FX_FLOAT R, G, B;
1217     if (!GetRGB(pBuf, R, G, B)) {
1218         return FALSE;
1219     }
1220     sRGB_to_AdobeCMYK(R, G, B, c, m, y, k);
1221     return TRUE;
1222 }
1223 FX_BOOL CPDF_ColorSpace::SetCMYK(FX_FLOAT* pBuf, FX_FLOAT c, FX_FLOAT m, FX_FLOAT y, FX_FLOAT k) const
1224 {
1225     if (v_SetCMYK(pBuf, c, m, y, k)) {
1226         return TRUE;
1227     }
1228     FX_FLOAT R, G, B;
1229     AdobeCMYK_to_sRGB(c, m, y, k, R, G, B);
1230     return SetRGB(pBuf, R, G, B);
1231 }
1232 void CPDF_ColorSpace::GetDefaultColor(FX_FLOAT* buf) const
1233 {
1234     if (buf == NULL || m_Family == PDFCS_PATTERN) {
1235         return;
1236     }
1237     FX_FLOAT min, max;
1238     for (int i = 0; i < m_nComponents; i ++) {
1239         GetDefaultValue(i, buf[i], min, max);
1240     }
1241 }
1242 int CPDF_ColorSpace::GetMaxIndex() const
1243 {
1244     if (m_Family != PDFCS_INDEXED) {
1245         return 0;
1246     }
1247     CPDF_IndexedCS* pCS = (CPDF_IndexedCS*)this;
1248     return pCS->m_MaxIndex;
1249 }
1250 void CPDF_ColorSpace::TranslateImageLine(uint8_t* dest_buf, const uint8_t* src_buf, int pixels, int image_width, int image_height, FX_BOOL bTransMask) const
1251 {
1252     CFX_FixedBufGrow<FX_FLOAT, 16> srcbuf(m_nComponents);
1253     FX_FLOAT* src = srcbuf;
1254     FX_FLOAT R, G, B;
1255     for (int i = 0; i < pixels; i ++) {
1256         for (int j = 0; j < m_nComponents; j ++)
1257             if (m_Family == PDFCS_INDEXED) {
1258                 src[j] = (FX_FLOAT)(*src_buf ++);
1259             } else {
1260                 src[j] = (FX_FLOAT)(*src_buf ++) / 255;
1261             }
1262         GetRGB(src, R, G, B);
1263         *dest_buf ++ = (int32_t)(B * 255);
1264         *dest_buf ++ = (int32_t)(G * 255);
1265         *dest_buf ++ = (int32_t)(R * 255);
1266     }
1267 }
1268 void CPDF_ColorSpace::EnableStdConversion(FX_BOOL bEnabled)
1269 {
1270     if (bEnabled) {
1271         m_dwStdConversion ++;
1272     } else if (m_dwStdConversion) {
1273         m_dwStdConversion --;
1274     }
1275 }
1276 CPDF_Color::CPDF_Color(int family)
1277 {
1278     m_pCS = CPDF_ColorSpace::GetStockCS(family);
1279     int nComps = 3;
1280     if (family == PDFCS_DEVICEGRAY) {
1281         nComps = 1;
1282     } else if (family == PDFCS_DEVICECMYK) {
1283         nComps = 4;
1284     }
1285     m_pBuffer = FX_Alloc(FX_FLOAT, nComps);
1286     for (int i = 0; i < nComps; i ++) {
1287         m_pBuffer[i] = 0;
1288     }
1289 }
1290 CPDF_Color::~CPDF_Color()
1291 {
1292     ReleaseBuffer();
1293     ReleaseColorSpace();
1294 }
1295 void CPDF_Color::ReleaseBuffer()
1296 {
1297     if (!m_pBuffer) {
1298         return;
1299     }
1300     if (m_pCS->GetFamily() == PDFCS_PATTERN) {
1301         PatternValue* pvalue = (PatternValue*)m_pBuffer;
1302         CPDF_Pattern* pPattern = pvalue->m_pCountedPattern ? pvalue->m_pCountedPattern->get() : NULL;
1303         if (pPattern && pPattern->m_pDocument) {
1304             CPDF_DocPageData *pPageData = pPattern->m_pDocument->GetPageData();
1305             if (pPageData) {
1306                 pPageData->ReleasePattern(pPattern->m_pPatternObj);
1307             }
1308         }
1309     }
1310     FX_Free(m_pBuffer);
1311     m_pBuffer = NULL;
1312 }
1313 void CPDF_Color::ReleaseColorSpace()
1314 {
1315     if (m_pCS && m_pCS->m_pDocument && m_pCS->GetArray()) {
1316         m_pCS->m_pDocument->GetPageData()->ReleaseColorSpace(m_pCS->GetArray());
1317         m_pCS = NULL;
1318     }
1319 }
1320 void CPDF_Color::SetColorSpace(CPDF_ColorSpace* pCS)
1321 {
1322     if (m_pCS == pCS) {
1323         if (m_pBuffer == NULL) {
1324             m_pBuffer = pCS->CreateBuf();
1325         }
1326         ReleaseColorSpace();
1327         m_pCS = pCS;
1328         return;
1329     }
1330     ReleaseBuffer();
1331     ReleaseColorSpace();
1332     m_pCS = pCS;
1333     if (m_pCS) {
1334         m_pBuffer = pCS->CreateBuf();
1335         pCS->GetDefaultColor(m_pBuffer);
1336     }
1337 }
1338 void CPDF_Color::SetValue(FX_FLOAT* comps)
1339 {
1340     if (m_pBuffer == NULL) {
1341         return;
1342     }
1343     if (m_pCS->GetFamily() != PDFCS_PATTERN) {
1344         FXSYS_memcpy(m_pBuffer, comps, m_pCS->CountComponents() * sizeof(FX_FLOAT));
1345     }
1346 }
1347 void CPDF_Color::SetValue(CPDF_Pattern* pPattern, FX_FLOAT* comps, int ncomps)
1348 {
1349     if (ncomps > MAX_PATTERN_COLORCOMPS) {
1350         return;
1351     }
1352     if (m_pCS == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1353         if (m_pBuffer) {
1354             FX_Free(m_pBuffer);
1355         }
1356         m_pCS = CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
1357         m_pBuffer = m_pCS->CreateBuf();
1358     }
1359     CPDF_DocPageData *pDocPageData = NULL;
1360     PatternValue* pvalue = (PatternValue*)m_pBuffer;
1361     if (pvalue->m_pPattern && pvalue->m_pPattern->m_pDocument) {
1362         pDocPageData = pvalue->m_pPattern->m_pDocument->GetPageData();
1363         if (pDocPageData) {
1364             pDocPageData->ReleasePattern(pvalue->m_pPattern->m_pPatternObj);
1365         }
1366     }
1367     pvalue->m_nComps = ncomps;
1368     pvalue->m_pPattern = pPattern;
1369     if (ncomps) {
1370         FXSYS_memcpy(pvalue->m_Comps, comps, ncomps * sizeof(FX_FLOAT));
1371     }
1372     pvalue->m_pCountedPattern = NULL;
1373     if (pPattern && pPattern->m_pDocument)
1374     {
1375         if (!pDocPageData) {
1376             pDocPageData = pPattern->m_pDocument->GetPageData();
1377         }
1378         pvalue->m_pCountedPattern = pDocPageData->FindPatternPtr(pPattern->m_pPatternObj);
1379     }
1380 }
1381 void CPDF_Color::Copy(const CPDF_Color* pSrc)
1382 {
1383     ReleaseBuffer();
1384     ReleaseColorSpace();
1385     m_pCS = pSrc->m_pCS;
1386     if (m_pCS && m_pCS->m_pDocument) {
1387         CPDF_Array* pArray = m_pCS->GetArray();
1388         if (pArray) {
1389             m_pCS = m_pCS->m_pDocument->GetPageData()->GetCopiedColorSpace(pArray);
1390         }
1391     }
1392     if (m_pCS == NULL) {
1393         return;
1394     }
1395     m_pBuffer = m_pCS->CreateBuf();
1396     FXSYS_memcpy(m_pBuffer, pSrc->m_pBuffer, m_pCS->GetBufSize());
1397     if (m_pCS->GetFamily() == PDFCS_PATTERN) {
1398         PatternValue* pvalue = (PatternValue*)m_pBuffer;
1399         if (pvalue->m_pPattern && pvalue->m_pPattern->m_pDocument) {
1400             pvalue->m_pPattern = pvalue->m_pPattern->m_pDocument->GetPageData()->GetPattern(pvalue->m_pPattern->m_pPatternObj, FALSE, &pvalue->m_pPattern->m_ParentMatrix);
1401         }
1402     }
1403 }
1404 FX_BOOL CPDF_Color::GetRGB(int& R, int& G, int& B) const
1405 {
1406     if (m_pCS == NULL || m_pBuffer == NULL) {
1407         return FALSE;
1408     }
1409     FX_FLOAT r=0.0f, g=0.0f, b=0.0f;
1410     if (!m_pCS->GetRGB(m_pBuffer, r, g, b)) {
1411         return FALSE;
1412     }
1413     R = (int32_t)(r * 255 + 0.5f);
1414     G = (int32_t)(g * 255 + 0.5f);
1415     B = (int32_t)(b * 255 + 0.5f);
1416     return TRUE;
1417 }
1418 CPDF_Pattern* CPDF_Color::GetPattern() const
1419 {
1420     if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1421         return NULL;
1422     }
1423     PatternValue* pvalue = (PatternValue*)m_pBuffer;
1424     return pvalue->m_pPattern;
1425 }
1426 CPDF_ColorSpace* CPDF_Color::GetPatternCS() const
1427 {
1428     if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1429         return NULL;
1430     }
1431     return m_pCS->GetBaseCS();
1432 }
1433 FX_FLOAT* CPDF_Color::GetPatternColor() const
1434 {
1435     if (m_pBuffer == NULL || m_pCS->GetFamily() != PDFCS_PATTERN) {
1436         return NULL;
1437     }
1438     PatternValue* pvalue = (PatternValue*)m_pBuffer;
1439     return pvalue->m_nComps ? pvalue->m_Comps : NULL;
1440 }
1441 FX_BOOL CPDF_Color::IsEqual(const CPDF_Color& other) const
1442 {
1443     if (m_pCS != other.m_pCS || m_pCS == NULL) {
1444         return FALSE;
1445     }
1446     return FXSYS_memcmp(m_pBuffer, other.m_pBuffer, m_pCS->GetBufSize()) == 0;
1447 }