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