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