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