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