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