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