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