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