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