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