• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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 "core/fpdfapi/page/cpdf_colorspace.h"
8 
9 #include <memory>
10 #include <utility>
11 
12 #include "core/fpdfapi/cpdf_modulemgr.h"
13 #include "core/fpdfapi/page/cpdf_docpagedata.h"
14 #include "core/fpdfapi/page/cpdf_pagemodule.h"
15 #include "core/fpdfapi/parser/cpdf_array.h"
16 #include "core/fpdfapi/parser/cpdf_dictionary.h"
17 #include "core/fpdfapi/parser/cpdf_document.h"
18 #include "core/fpdfapi/parser/cpdf_name.h"
19 #include "core/fpdfapi/parser/cpdf_object.h"
20 #include "core/fpdfapi/parser/cpdf_stream.h"
21 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
22 #include "core/fpdfapi/parser/cpdf_string.h"
23 #include "core/fxcodec/fx_codec.h"
24 #include "core/fxcrt/cfx_maybe_owned.h"
25 #include "core/fxcrt/fx_memory.h"
26 
27 namespace {
28 
29 const uint8_t g_sRGBSamples1[] = {
30     0,   3,   6,   10,  13,  15,  18,  20,  22,  23,  25,  27,  28,  30,  31,
31     32,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,
32     48,  49,  49,  50,  51,  52,  53,  53,  54,  55,  56,  56,  57,  58,  58,
33     59,  60,  61,  61,  62,  62,  63,  64,  64,  65,  66,  66,  67,  67,  68,
34     68,  69,  70,  70,  71,  71,  72,  72,  73,  73,  74,  74,  75,  76,  76,
35     77,  77,  78,  78,  79,  79,  79,  80,  80,  81,  81,  82,  82,  83,  83,
36     84,  84,  85,  85,  85,  86,  86,  87,  87,  88,  88,  88,  89,  89,  90,
37     90,  91,  91,  91,  92,  92,  93,  93,  93,  94,  94,  95,  95,  95,  96,
38     96,  97,  97,  97,  98,  98,  98,  99,  99,  99,  100, 100, 101, 101, 101,
39     102, 102, 102, 103, 103, 103, 104, 104, 104, 105, 105, 106, 106, 106, 107,
40     107, 107, 108, 108, 108, 109, 109, 109, 110, 110, 110, 110, 111, 111, 111,
41     112, 112, 112, 113, 113, 113, 114, 114, 114, 115, 115, 115, 115, 116, 116,
42     116, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 120,
43 };
44 
45 const uint8_t g_sRGBSamples2[] = {
46     120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
47     136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149,
48     150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 159, 160, 161, 162,
49     163, 163, 164, 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173,
50     174, 175, 175, 176, 177, 178, 178, 179, 180, 180, 181, 182, 182, 183, 184,
51     185, 185, 186, 187, 187, 188, 189, 189, 190, 190, 191, 192, 192, 193, 194,
52     194, 195, 196, 196, 197, 197, 198, 199, 199, 200, 200, 201, 202, 202, 203,
53     203, 204, 205, 205, 206, 206, 207, 208, 208, 209, 209, 210, 210, 211, 212,
54     212, 213, 213, 214, 214, 215, 215, 216, 216, 217, 218, 218, 219, 219, 220,
55     220, 221, 221, 222, 222, 223, 223, 224, 224, 225, 226, 226, 227, 227, 228,
56     228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235,
57     236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242,
58     243, 243, 244, 244, 245, 245, 246, 246, 246, 247, 247, 248, 248, 249, 249,
59     250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255,
60 };
61 
62 class CPDF_CalGray : public CPDF_ColorSpace {
63  public:
64   explicit CPDF_CalGray(CPDF_Document* pDoc);
65 
66   bool v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
67 
68   bool GetRGB(FX_FLOAT* pBuf,
69               FX_FLOAT& R,
70               FX_FLOAT& G,
71               FX_FLOAT& B) const override;
72   bool SetRGB(FX_FLOAT* pBuf,
73               FX_FLOAT R,
74               FX_FLOAT G,
75               FX_FLOAT B) const override;
76 
77   void TranslateImageLine(uint8_t* pDestBuf,
78                           const uint8_t* pSrcBuf,
79                           int pixels,
80                           int image_width,
81                           int image_height,
82                           bool bTransMask = false) const override;
83 
84  private:
85   FX_FLOAT m_WhitePoint[3];
86   FX_FLOAT m_BlackPoint[3];
87   FX_FLOAT m_Gamma;
88 };
89 
90 class CPDF_CalRGB : public CPDF_ColorSpace {
91  public:
92   explicit CPDF_CalRGB(CPDF_Document* pDoc);
93 
94   bool v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
95 
96   bool GetRGB(FX_FLOAT* pBuf,
97               FX_FLOAT& R,
98               FX_FLOAT& G,
99               FX_FLOAT& B) const override;
100   bool SetRGB(FX_FLOAT* pBuf,
101               FX_FLOAT R,
102               FX_FLOAT G,
103               FX_FLOAT B) const override;
104 
105   void TranslateImageLine(uint8_t* pDestBuf,
106                           const uint8_t* pSrcBuf,
107                           int pixels,
108                           int image_width,
109                           int image_height,
110                           bool bTransMask = false) const override;
111 
112   FX_FLOAT m_WhitePoint[3];
113   FX_FLOAT m_BlackPoint[3];
114   FX_FLOAT m_Gamma[3];
115   FX_FLOAT m_Matrix[9];
116   bool m_bGamma;
117   bool m_bMatrix;
118 };
119 
120 class CPDF_LabCS : public CPDF_ColorSpace {
121  public:
122   explicit CPDF_LabCS(CPDF_Document* pDoc);
123 
124   bool v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
125 
126   void GetDefaultValue(int iComponent,
127                        FX_FLOAT& value,
128                        FX_FLOAT& min,
129                        FX_FLOAT& max) const override;
130   bool GetRGB(FX_FLOAT* pBuf,
131               FX_FLOAT& R,
132               FX_FLOAT& G,
133               FX_FLOAT& B) const override;
134   bool SetRGB(FX_FLOAT* pBuf,
135               FX_FLOAT R,
136               FX_FLOAT G,
137               FX_FLOAT B) const override;
138 
139   void TranslateImageLine(uint8_t* pDestBuf,
140                           const uint8_t* pSrcBuf,
141                           int pixels,
142                           int image_width,
143                           int image_height,
144                           bool bTransMask = false) const override;
145 
146   FX_FLOAT m_WhitePoint[3];
147   FX_FLOAT m_BlackPoint[3];
148   FX_FLOAT m_Ranges[4];
149 };
150 
151 class CPDF_ICCBasedCS : public CPDF_ColorSpace {
152  public:
153   explicit CPDF_ICCBasedCS(CPDF_Document* pDoc);
154   ~CPDF_ICCBasedCS() override;
155 
156   bool v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
157 
158   bool GetRGB(FX_FLOAT* pBuf,
159               FX_FLOAT& R,
160               FX_FLOAT& G,
161               FX_FLOAT& B) const override;
162   bool SetRGB(FX_FLOAT* pBuf,
163               FX_FLOAT R,
164               FX_FLOAT G,
165               FX_FLOAT B) const override;
166 
167   bool v_GetCMYK(FX_FLOAT* pBuf,
168                  FX_FLOAT& c,
169                  FX_FLOAT& m,
170                  FX_FLOAT& y,
171                  FX_FLOAT& k) const override;
172 
173   void EnableStdConversion(bool bEnabled) override;
174   void TranslateImageLine(uint8_t* pDestBuf,
175                           const uint8_t* pSrcBuf,
176                           int pixels,
177                           int image_width,
178                           int image_height,
179                           bool bTransMask = false) const override;
180 
181   CFX_MaybeOwned<CPDF_ColorSpace> m_pAlterCS;
182   CPDF_IccProfile* m_pProfile;
183   uint8_t* m_pCache;
184   FX_FLOAT* m_pRanges;
185 };
186 
187 class CPDF_IndexedCS : public CPDF_ColorSpace {
188  public:
189   explicit CPDF_IndexedCS(CPDF_Document* pDoc);
190   ~CPDF_IndexedCS() override;
191 
192   bool v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
193 
194   bool GetRGB(FX_FLOAT* pBuf,
195               FX_FLOAT& R,
196               FX_FLOAT& G,
197               FX_FLOAT& B) const override;
198   CPDF_ColorSpace* GetBaseCS() const override;
199 
200   void EnableStdConversion(bool bEnabled) override;
201 
202   CPDF_ColorSpace* m_pBaseCS;
203   CPDF_CountedColorSpace* m_pCountedBaseCS;
204   int m_nBaseComponents;
205   int m_MaxIndex;
206   CFX_ByteString m_Table;
207   FX_FLOAT* m_pCompMinMax;
208 };
209 
210 class CPDF_SeparationCS : public CPDF_ColorSpace {
211  public:
212   explicit CPDF_SeparationCS(CPDF_Document* pDoc);
213   ~CPDF_SeparationCS() override;
214 
215   // CPDF_ColorSpace:
216   void GetDefaultValue(int iComponent,
217                        FX_FLOAT& value,
218                        FX_FLOAT& min,
219                        FX_FLOAT& max) const override;
220   bool v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
221   bool GetRGB(FX_FLOAT* pBuf,
222               FX_FLOAT& R,
223               FX_FLOAT& G,
224               FX_FLOAT& B) const override;
225   void EnableStdConversion(bool bEnabled) override;
226 
227   std::unique_ptr<CPDF_ColorSpace> m_pAltCS;
228   std::unique_ptr<CPDF_Function> m_pFunc;
229   enum { None, All, Colorant } m_Type;
230 };
231 
232 class CPDF_DeviceNCS : public CPDF_ColorSpace {
233  public:
234   explicit CPDF_DeviceNCS(CPDF_Document* pDoc);
235   ~CPDF_DeviceNCS() override;
236 
237   // CPDF_ColorSpace:
238   void GetDefaultValue(int iComponent,
239                        FX_FLOAT& value,
240                        FX_FLOAT& min,
241                        FX_FLOAT& max) const override;
242   bool v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
243   bool GetRGB(FX_FLOAT* pBuf,
244               FX_FLOAT& R,
245               FX_FLOAT& G,
246               FX_FLOAT& B) const override;
247   void EnableStdConversion(bool bEnabled) override;
248 
249   std::unique_ptr<CPDF_ColorSpace> m_pAltCS;
250   std::unique_ptr<CPDF_Function> m_pFunc;
251 };
252 
RGB_Conversion(FX_FLOAT colorComponent)253 FX_FLOAT RGB_Conversion(FX_FLOAT colorComponent) {
254   if (colorComponent > 1)
255     colorComponent = 1;
256   if (colorComponent < 0)
257     colorComponent = 0;
258 
259   int scale = (int)(colorComponent * 1023);
260   if (scale < 0)
261     scale = 0;
262   if (scale < 192)
263     colorComponent = (g_sRGBSamples1[scale] / 255.0f);
264   else
265     colorComponent = (g_sRGBSamples2[scale / 4 - 48] / 255.0f);
266   return colorComponent;
267 }
268 
XYZ_to_sRGB(FX_FLOAT X,FX_FLOAT Y,FX_FLOAT Z,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B)269 void XYZ_to_sRGB(FX_FLOAT X,
270                  FX_FLOAT Y,
271                  FX_FLOAT Z,
272                  FX_FLOAT& R,
273                  FX_FLOAT& G,
274                  FX_FLOAT& B) {
275   FX_FLOAT R1 = 3.2410f * X - 1.5374f * Y - 0.4986f * Z;
276   FX_FLOAT G1 = -0.9692f * X + 1.8760f * Y + 0.0416f * Z;
277   FX_FLOAT B1 = 0.0556f * X - 0.2040f * Y + 1.0570f * Z;
278 
279   R = RGB_Conversion(R1);
280   G = RGB_Conversion(G1);
281   B = RGB_Conversion(B1);
282 }
283 
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)284 void XYZ_to_sRGB_WhitePoint(FX_FLOAT X,
285                             FX_FLOAT Y,
286                             FX_FLOAT Z,
287                             FX_FLOAT& R,
288                             FX_FLOAT& G,
289                             FX_FLOAT& B,
290                             FX_FLOAT Xw,
291                             FX_FLOAT Yw,
292                             FX_FLOAT Zw) {
293   // The following RGB_xyz is based on
294   // sRGB value {Rx,Ry}={0.64, 0.33}, {Gx,Gy}={0.30, 0.60}, {Bx,By}={0.15, 0.06}
295 
296   FX_FLOAT Rx = 0.64f, Ry = 0.33f;
297   FX_FLOAT Gx = 0.30f, Gy = 0.60f;
298   FX_FLOAT Bx = 0.15f, By = 0.06f;
299   CFX_Matrix_3by3 RGB_xyz(Rx, Gx, Bx, Ry, Gy, By, 1 - Rx - Ry, 1 - Gx - Gy,
300                           1 - Bx - By);
301   CFX_Vector_3by1 whitePoint(Xw, Yw, Zw);
302   CFX_Vector_3by1 XYZ(X, Y, Z);
303 
304   CFX_Vector_3by1 RGB_Sum_XYZ = RGB_xyz.Inverse().TransformVector(whitePoint);
305   CFX_Matrix_3by3 RGB_SUM_XYZ_DIAG(RGB_Sum_XYZ.a, 0, 0, 0, RGB_Sum_XYZ.b, 0, 0,
306                                    0, RGB_Sum_XYZ.c);
307   CFX_Matrix_3by3 M = RGB_xyz.Multiply(RGB_SUM_XYZ_DIAG);
308   CFX_Vector_3by1 RGB = M.Inverse().TransformVector(XYZ);
309 
310   R = RGB_Conversion(RGB.a);
311   G = RGB_Conversion(RGB.b);
312   B = RGB_Conversion(RGB.c);
313 }
314 
315 }  // namespace
316 
ColorspaceFromName(const CFX_ByteString & name)317 CPDF_ColorSpace* CPDF_ColorSpace::ColorspaceFromName(
318     const CFX_ByteString& name) {
319   if (name == "DeviceRGB" || name == "RGB")
320     return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
321   if (name == "DeviceGray" || name == "G")
322     return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY);
323   if (name == "DeviceCMYK" || name == "CMYK")
324     return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK);
325   if (name == "Pattern")
326     return CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
327   return nullptr;
328 }
329 
GetStockCS(int family)330 CPDF_ColorSpace* CPDF_ColorSpace::GetStockCS(int family) {
331   return CPDF_ModuleMgr::Get()->GetPageModule()->GetStockCS(family);
332 }
333 
Load(CPDF_Document * pDoc,CPDF_Object * pObj)334 std::unique_ptr<CPDF_ColorSpace> CPDF_ColorSpace::Load(CPDF_Document* pDoc,
335                                                        CPDF_Object* pObj) {
336   if (!pObj)
337     return nullptr;
338 
339   if (pObj->IsName()) {
340     return std::unique_ptr<CPDF_ColorSpace>(
341         ColorspaceFromName(pObj->GetString()));
342   }
343   if (CPDF_Stream* pStream = pObj->AsStream()) {
344     CPDF_Dictionary* pDict = pStream->GetDict();
345     if (!pDict)
346       return nullptr;
347 
348     for (const auto& it : *pDict) {
349       std::unique_ptr<CPDF_ColorSpace> pRet;
350       CPDF_Object* pValue = it.second.get();
351       if (ToName(pValue))
352         pRet.reset(ColorspaceFromName(pValue->GetString()));
353       if (pRet)
354         return pRet;
355     }
356     return nullptr;
357   }
358 
359   CPDF_Array* pArray = pObj->AsArray();
360   if (!pArray || pArray->IsEmpty())
361     return nullptr;
362 
363   CPDF_Object* pFamilyObj = pArray->GetDirectObjectAt(0);
364   if (!pFamilyObj)
365     return nullptr;
366 
367   CFX_ByteString familyname = pFamilyObj->GetString();
368   if (pArray->GetCount() == 1)
369     return std::unique_ptr<CPDF_ColorSpace>(ColorspaceFromName(familyname));
370 
371   std::unique_ptr<CPDF_ColorSpace> pCS;
372   uint32_t id = familyname.GetID();
373   if (id == FXBSTR_ID('C', 'a', 'l', 'G')) {
374     pCS.reset(new CPDF_CalGray(pDoc));
375   } else if (id == FXBSTR_ID('C', 'a', 'l', 'R')) {
376     pCS.reset(new CPDF_CalRGB(pDoc));
377   } else if (id == FXBSTR_ID('L', 'a', 'b', 0)) {
378     pCS.reset(new CPDF_LabCS(pDoc));
379   } else if (id == FXBSTR_ID('I', 'C', 'C', 'B')) {
380     pCS.reset(new CPDF_ICCBasedCS(pDoc));
381   } else if (id == FXBSTR_ID('I', 'n', 'd', 'e') ||
382              id == FXBSTR_ID('I', 0, 0, 0)) {
383     pCS.reset(new CPDF_IndexedCS(pDoc));
384   } else if (id == FXBSTR_ID('S', 'e', 'p', 'a')) {
385     pCS.reset(new CPDF_SeparationCS(pDoc));
386   } else if (id == FXBSTR_ID('D', 'e', 'v', 'i')) {
387     pCS.reset(new CPDF_DeviceNCS(pDoc));
388   } else if (id == FXBSTR_ID('P', 'a', 't', 't')) {
389     pCS.reset(new CPDF_PatternCS(pDoc));
390   } else {
391     return nullptr;
392   }
393   pCS->m_pArray = pArray;
394   if (!pCS->v_Load(pDoc, pArray))
395     return nullptr;
396 
397   return pCS;
398 }
399 
Release()400 void CPDF_ColorSpace::Release() {
401   if (this == GetStockCS(PDFCS_DEVICERGB) ||
402       this == GetStockCS(PDFCS_DEVICEGRAY) ||
403       this == GetStockCS(PDFCS_DEVICECMYK) ||
404       this == GetStockCS(PDFCS_PATTERN)) {
405     return;
406   }
407   delete this;
408 }
409 
GetBufSize() const410 int CPDF_ColorSpace::GetBufSize() const {
411   if (m_Family == PDFCS_PATTERN) {
412     return sizeof(PatternValue);
413   }
414   return m_nComponents * sizeof(FX_FLOAT);
415 }
416 
CreateBuf()417 FX_FLOAT* CPDF_ColorSpace::CreateBuf() {
418   int size = GetBufSize();
419   uint8_t* pBuf = FX_Alloc(uint8_t, size);
420   return (FX_FLOAT*)pBuf;
421 }
422 
sRGB() const423 bool CPDF_ColorSpace::sRGB() const {
424   if (m_Family == PDFCS_DEVICERGB) {
425     return true;
426   }
427   if (m_Family != PDFCS_ICCBASED) {
428     return false;
429   }
430   CPDF_ICCBasedCS* pCS = (CPDF_ICCBasedCS*)this;
431   return pCS->m_pProfile->m_bsRGB;
432 }
433 
SetRGB(FX_FLOAT * pBuf,FX_FLOAT R,FX_FLOAT G,FX_FLOAT B) const434 bool CPDF_ColorSpace::SetRGB(FX_FLOAT* pBuf,
435                              FX_FLOAT R,
436                              FX_FLOAT G,
437                              FX_FLOAT B) const {
438   return false;
439 }
440 
GetCMYK(FX_FLOAT * pBuf,FX_FLOAT & c,FX_FLOAT & m,FX_FLOAT & y,FX_FLOAT & k) const441 bool CPDF_ColorSpace::GetCMYK(FX_FLOAT* pBuf,
442                               FX_FLOAT& c,
443                               FX_FLOAT& m,
444                               FX_FLOAT& y,
445                               FX_FLOAT& k) const {
446   if (v_GetCMYK(pBuf, c, m, y, k)) {
447     return true;
448   }
449   FX_FLOAT R, G, B;
450   if (!GetRGB(pBuf, R, G, B)) {
451     return false;
452   }
453   sRGB_to_AdobeCMYK(R, G, B, c, m, y, k);
454   return true;
455 }
456 
SetCMYK(FX_FLOAT * pBuf,FX_FLOAT c,FX_FLOAT m,FX_FLOAT y,FX_FLOAT k) const457 bool CPDF_ColorSpace::SetCMYK(FX_FLOAT* pBuf,
458                               FX_FLOAT c,
459                               FX_FLOAT m,
460                               FX_FLOAT y,
461                               FX_FLOAT k) const {
462   if (v_SetCMYK(pBuf, c, m, y, k)) {
463     return true;
464   }
465   FX_FLOAT R, G, B;
466   AdobeCMYK_to_sRGB(c, m, y, k, R, G, B);
467   return SetRGB(pBuf, R, G, B);
468 }
469 
GetDefaultColor(FX_FLOAT * buf) const470 void CPDF_ColorSpace::GetDefaultColor(FX_FLOAT* buf) const {
471   if (!buf || m_Family == PDFCS_PATTERN) {
472     return;
473   }
474   FX_FLOAT min, max;
475   for (uint32_t i = 0; i < m_nComponents; i++) {
476     GetDefaultValue(i, buf[i], min, max);
477   }
478 }
479 
CountComponents() const480 uint32_t CPDF_ColorSpace::CountComponents() const {
481   return m_nComponents;
482 }
483 
GetDefaultValue(int iComponent,FX_FLOAT & value,FX_FLOAT & min,FX_FLOAT & max) const484 void CPDF_ColorSpace::GetDefaultValue(int iComponent,
485                                       FX_FLOAT& value,
486                                       FX_FLOAT& min,
487                                       FX_FLOAT& max) const {
488   value = 0;
489   min = 0;
490   max = 1.0f;
491 }
492 
TranslateImageLine(uint8_t * dest_buf,const uint8_t * src_buf,int pixels,int image_width,int image_height,bool bTransMask) const493 void CPDF_ColorSpace::TranslateImageLine(uint8_t* dest_buf,
494                                          const uint8_t* src_buf,
495                                          int pixels,
496                                          int image_width,
497                                          int image_height,
498                                          bool bTransMask) const {
499   CFX_FixedBufGrow<FX_FLOAT, 16> srcbuf(m_nComponents);
500   FX_FLOAT* src = srcbuf;
501   FX_FLOAT R, G, B;
502   for (int i = 0; i < pixels; i++) {
503     for (uint32_t j = 0; j < m_nComponents; j++)
504       if (m_Family == PDFCS_INDEXED) {
505         src[j] = (FX_FLOAT)(*src_buf++);
506       } else {
507         src[j] = (FX_FLOAT)(*src_buf++) / 255;
508       }
509     GetRGB(src, R, G, B);
510     *dest_buf++ = (int32_t)(B * 255);
511     *dest_buf++ = (int32_t)(G * 255);
512     *dest_buf++ = (int32_t)(R * 255);
513   }
514 }
515 
GetBaseCS() const516 CPDF_ColorSpace* CPDF_ColorSpace::GetBaseCS() const {
517   return nullptr;
518 }
519 
EnableStdConversion(bool bEnabled)520 void CPDF_ColorSpace::EnableStdConversion(bool bEnabled) {
521   if (bEnabled)
522     m_dwStdConversion++;
523   else if (m_dwStdConversion)
524     m_dwStdConversion--;
525 }
526 
CPDF_ColorSpace(CPDF_Document * pDoc,int family,uint32_t nComponents)527 CPDF_ColorSpace::CPDF_ColorSpace(CPDF_Document* pDoc,
528                                  int family,
529                                  uint32_t nComponents)
530     : m_pDocument(pDoc),
531       m_Family(family),
532       m_nComponents(nComponents),
533       m_pArray(nullptr),
534       m_dwStdConversion(0) {}
535 
~CPDF_ColorSpace()536 CPDF_ColorSpace::~CPDF_ColorSpace() {}
537 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)538 bool CPDF_ColorSpace::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
539   return true;
540 }
541 
v_GetCMYK(FX_FLOAT * pBuf,FX_FLOAT & c,FX_FLOAT & m,FX_FLOAT & y,FX_FLOAT & k) const542 bool CPDF_ColorSpace::v_GetCMYK(FX_FLOAT* pBuf,
543                                 FX_FLOAT& c,
544                                 FX_FLOAT& m,
545                                 FX_FLOAT& y,
546                                 FX_FLOAT& k) const {
547   return false;
548 }
549 
v_SetCMYK(FX_FLOAT * pBuf,FX_FLOAT c,FX_FLOAT m,FX_FLOAT y,FX_FLOAT k) const550 bool CPDF_ColorSpace::v_SetCMYK(FX_FLOAT* pBuf,
551                                 FX_FLOAT c,
552                                 FX_FLOAT m,
553                                 FX_FLOAT y,
554                                 FX_FLOAT k) const {
555   return false;
556 }
557 
CPDF_CalGray(CPDF_Document * pDoc)558 CPDF_CalGray::CPDF_CalGray(CPDF_Document* pDoc)
559     : CPDF_ColorSpace(pDoc, PDFCS_CALGRAY, 1) {}
560 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)561 bool CPDF_CalGray::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
562   CPDF_Dictionary* pDict = pArray->GetDictAt(1);
563   if (!pDict)
564     return false;
565 
566   CPDF_Array* pParam = pDict->GetArrayFor("WhitePoint");
567   int i;
568   for (i = 0; i < 3; i++)
569     m_WhitePoint[i] = pParam ? pParam->GetNumberAt(i) : 0;
570 
571   pParam = pDict->GetArrayFor("BlackPoint");
572   for (i = 0; i < 3; i++)
573     m_BlackPoint[i] = pParam ? pParam->GetNumberAt(i) : 0;
574 
575   m_Gamma = pDict->GetNumberFor("Gamma");
576   if (m_Gamma == 0)
577     m_Gamma = 1.0f;
578   return true;
579 }
580 
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const581 bool CPDF_CalGray::GetRGB(FX_FLOAT* pBuf,
582                           FX_FLOAT& R,
583                           FX_FLOAT& G,
584                           FX_FLOAT& B) const {
585   R = G = B = *pBuf;
586   return true;
587 }
588 
SetRGB(FX_FLOAT * pBuf,FX_FLOAT R,FX_FLOAT G,FX_FLOAT B) const589 bool CPDF_CalGray::SetRGB(FX_FLOAT* pBuf,
590                           FX_FLOAT R,
591                           FX_FLOAT G,
592                           FX_FLOAT B) const {
593   if (R == G && R == B) {
594     *pBuf = R;
595     return true;
596   }
597   return false;
598 }
599 
TranslateImageLine(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels,int image_width,int image_height,bool bTransMask) const600 void CPDF_CalGray::TranslateImageLine(uint8_t* pDestBuf,
601                                       const uint8_t* pSrcBuf,
602                                       int pixels,
603                                       int image_width,
604                                       int image_height,
605                                       bool bTransMask) const {
606   for (int i = 0; i < pixels; i++) {
607     *pDestBuf++ = pSrcBuf[i];
608     *pDestBuf++ = pSrcBuf[i];
609     *pDestBuf++ = pSrcBuf[i];
610   }
611 }
612 
CPDF_CalRGB(CPDF_Document * pDoc)613 CPDF_CalRGB::CPDF_CalRGB(CPDF_Document* pDoc)
614     : CPDF_ColorSpace(pDoc, PDFCS_CALRGB, 3) {}
615 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)616 bool CPDF_CalRGB::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
617   CPDF_Dictionary* pDict = pArray->GetDictAt(1);
618   if (!pDict)
619     return false;
620 
621   CPDF_Array* pParam = pDict->GetArrayFor("WhitePoint");
622   int i;
623   for (i = 0; i < 3; i++)
624     m_WhitePoint[i] = pParam ? pParam->GetNumberAt(i) : 0;
625 
626   pParam = pDict->GetArrayFor("BlackPoint");
627   for (i = 0; i < 3; i++)
628     m_BlackPoint[i] = pParam ? pParam->GetNumberAt(i) : 0;
629 
630   pParam = pDict->GetArrayFor("Gamma");
631   if (pParam) {
632     m_bGamma = true;
633     for (i = 0; i < 3; i++)
634       m_Gamma[i] = pParam->GetNumberAt(i);
635   } else {
636     m_bGamma = false;
637   }
638 
639   pParam = pDict->GetArrayFor("Matrix");
640   if (pParam) {
641     m_bMatrix = true;
642     for (i = 0; i < 9; i++)
643       m_Matrix[i] = pParam->GetNumberAt(i);
644   } else {
645     m_bMatrix = false;
646   }
647   return true;
648 }
649 
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const650 bool CPDF_CalRGB::GetRGB(FX_FLOAT* pBuf,
651                          FX_FLOAT& R,
652                          FX_FLOAT& G,
653                          FX_FLOAT& B) const {
654   FX_FLOAT A_ = pBuf[0];
655   FX_FLOAT B_ = pBuf[1];
656   FX_FLOAT C_ = pBuf[2];
657   if (m_bGamma) {
658     A_ = (FX_FLOAT)FXSYS_pow(A_, m_Gamma[0]);
659     B_ = (FX_FLOAT)FXSYS_pow(B_, m_Gamma[1]);
660     C_ = (FX_FLOAT)FXSYS_pow(C_, m_Gamma[2]);
661   }
662 
663   FX_FLOAT X;
664   FX_FLOAT Y;
665   FX_FLOAT Z;
666   if (m_bMatrix) {
667     X = m_Matrix[0] * A_ + m_Matrix[3] * B_ + m_Matrix[6] * C_;
668     Y = m_Matrix[1] * A_ + m_Matrix[4] * B_ + m_Matrix[7] * C_;
669     Z = m_Matrix[2] * A_ + m_Matrix[5] * B_ + m_Matrix[8] * C_;
670   } else {
671     X = A_;
672     Y = B_;
673     Z = C_;
674   }
675   XYZ_to_sRGB_WhitePoint(X, Y, Z, R, G, B, m_WhitePoint[0], m_WhitePoint[1],
676                          m_WhitePoint[2]);
677   return true;
678 }
679 
SetRGB(FX_FLOAT * pBuf,FX_FLOAT R,FX_FLOAT G,FX_FLOAT B) const680 bool CPDF_CalRGB::SetRGB(FX_FLOAT* pBuf,
681                          FX_FLOAT R,
682                          FX_FLOAT G,
683                          FX_FLOAT B) const {
684   pBuf[0] = R;
685   pBuf[1] = G;
686   pBuf[2] = B;
687   return true;
688 }
689 
TranslateImageLine(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels,int image_width,int image_height,bool bTransMask) const690 void CPDF_CalRGB::TranslateImageLine(uint8_t* pDestBuf,
691                                      const uint8_t* pSrcBuf,
692                                      int pixels,
693                                      int image_width,
694                                      int image_height,
695                                      bool bTransMask) const {
696   if (bTransMask) {
697     FX_FLOAT Cal[3];
698     FX_FLOAT R;
699     FX_FLOAT G;
700     FX_FLOAT B;
701     for (int i = 0; i < pixels; i++) {
702       Cal[0] = ((FX_FLOAT)pSrcBuf[2]) / 255;
703       Cal[1] = ((FX_FLOAT)pSrcBuf[1]) / 255;
704       Cal[2] = ((FX_FLOAT)pSrcBuf[0]) / 255;
705       GetRGB(Cal, R, G, B);
706       pDestBuf[0] = FXSYS_round(B * 255);
707       pDestBuf[1] = FXSYS_round(G * 255);
708       pDestBuf[2] = FXSYS_round(R * 255);
709       pSrcBuf += 3;
710       pDestBuf += 3;
711     }
712   }
713   ReverseRGB(pDestBuf, pSrcBuf, pixels);
714 }
715 
CPDF_LabCS(CPDF_Document * pDoc)716 CPDF_LabCS::CPDF_LabCS(CPDF_Document* pDoc)
717     : CPDF_ColorSpace(pDoc, PDFCS_LAB, 3) {}
718 
GetDefaultValue(int iComponent,FX_FLOAT & value,FX_FLOAT & min,FX_FLOAT & max) const719 void CPDF_LabCS::GetDefaultValue(int iComponent,
720                                  FX_FLOAT& value,
721                                  FX_FLOAT& min,
722                                  FX_FLOAT& max) const {
723   ASSERT(iComponent < 3);
724   value = 0;
725   if (iComponent == 0) {
726     min = 0;
727     max = 100 * 1.0f;
728   } else {
729     min = m_Ranges[iComponent * 2 - 2];
730     max = m_Ranges[iComponent * 2 - 1];
731     if (value < min)
732       value = min;
733     else if (value > max)
734       value = max;
735   }
736 }
737 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)738 bool CPDF_LabCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
739   CPDF_Dictionary* pDict = pArray->GetDictAt(1);
740   if (!pDict)
741     return false;
742 
743   CPDF_Array* pParam = pDict->GetArrayFor("WhitePoint");
744   int i;
745   for (i = 0; i < 3; i++)
746     m_WhitePoint[i] = pParam ? pParam->GetNumberAt(i) : 0;
747 
748   pParam = pDict->GetArrayFor("BlackPoint");
749   for (i = 0; i < 3; i++)
750     m_BlackPoint[i] = pParam ? pParam->GetNumberAt(i) : 0;
751 
752   pParam = pDict->GetArrayFor("Range");
753   const FX_FLOAT def_ranges[4] = {-100 * 1.0f, 100 * 1.0f, -100 * 1.0f,
754                                   100 * 1.0f};
755   for (i = 0; i < 4; i++)
756     m_Ranges[i] = pParam ? pParam->GetNumberAt(i) : def_ranges[i];
757   return true;
758 }
759 
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const760 bool CPDF_LabCS::GetRGB(FX_FLOAT* pBuf,
761                         FX_FLOAT& R,
762                         FX_FLOAT& G,
763                         FX_FLOAT& B) const {
764   FX_FLOAT Lstar = pBuf[0];
765   FX_FLOAT astar = pBuf[1];
766   FX_FLOAT bstar = pBuf[2];
767   FX_FLOAT M = (Lstar + 16.0f) / 116.0f;
768   FX_FLOAT L = M + astar / 500.0f;
769   FX_FLOAT N = M - bstar / 200.0f;
770   FX_FLOAT X, Y, Z;
771   if (L < 0.2069f)
772     X = 0.957f * 0.12842f * (L - 0.1379f);
773   else
774     X = 0.957f * L * L * L;
775 
776   if (M < 0.2069f)
777     Y = 0.12842f * (M - 0.1379f);
778   else
779     Y = M * M * M;
780 
781   if (N < 0.2069f)
782     Z = 1.0889f * 0.12842f * (N - 0.1379f);
783   else
784     Z = 1.0889f * N * N * N;
785 
786   XYZ_to_sRGB(X, Y, Z, R, G, B);
787   return true;
788 }
789 
SetRGB(FX_FLOAT * pBuf,FX_FLOAT R,FX_FLOAT G,FX_FLOAT B) const790 bool CPDF_LabCS::SetRGB(FX_FLOAT* pBuf,
791                         FX_FLOAT R,
792                         FX_FLOAT G,
793                         FX_FLOAT B) const {
794   return false;
795 }
796 
TranslateImageLine(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels,int image_width,int image_height,bool bTransMask) const797 void CPDF_LabCS::TranslateImageLine(uint8_t* pDestBuf,
798                                     const uint8_t* pSrcBuf,
799                                     int pixels,
800                                     int image_width,
801                                     int image_height,
802                                     bool bTransMask) const {
803   for (int i = 0; i < pixels; i++) {
804     FX_FLOAT lab[3];
805     FX_FLOAT R, G, B;
806     lab[0] = (pSrcBuf[0] * 100 / 255.0f);
807     lab[1] = (FX_FLOAT)(pSrcBuf[1] - 128);
808     lab[2] = (FX_FLOAT)(pSrcBuf[2] - 128);
809     GetRGB(lab, R, G, B);
810     pDestBuf[0] = (int32_t)(B * 255);
811     pDestBuf[1] = (int32_t)(G * 255);
812     pDestBuf[2] = (int32_t)(R * 255);
813     pDestBuf += 3;
814     pSrcBuf += 3;
815   }
816 }
817 
CPDF_ICCBasedCS(CPDF_Document * pDoc)818 CPDF_ICCBasedCS::CPDF_ICCBasedCS(CPDF_Document* pDoc)
819     : CPDF_ColorSpace(pDoc, PDFCS_ICCBASED, 0),
820       m_pProfile(nullptr),
821       m_pCache(nullptr),
822       m_pRanges(nullptr) {}
823 
~CPDF_ICCBasedCS()824 CPDF_ICCBasedCS::~CPDF_ICCBasedCS() {
825   FX_Free(m_pCache);
826   FX_Free(m_pRanges);
827   if (m_pProfile && m_pDocument)
828     m_pDocument->GetPageData()->ReleaseIccProfile(m_pProfile);
829 }
830 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)831 bool CPDF_ICCBasedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
832   CPDF_Stream* pStream = pArray->GetStreamAt(1);
833   if (!pStream)
834     return false;
835 
836   m_pProfile = pDoc->LoadIccProfile(pStream);
837   if (!m_pProfile)
838     return false;
839 
840   // Try using the |nComponents| from ICC profile
841   m_nComponents = m_pProfile->GetComponents();
842   CPDF_Dictionary* pDict = pStream->GetDict();
843   if (!m_pProfile->m_pTransform) {  // No valid ICC profile or using sRGB
844     CPDF_Object* pAlterCSObj =
845         pDict ? pDict->GetDirectObjectFor("Alternate") : nullptr;
846     if (pAlterCSObj) {
847       std::unique_ptr<CPDF_ColorSpace> pAlterCS =
848           CPDF_ColorSpace::Load(pDoc, pAlterCSObj);
849       if (pAlterCS) {
850         if (m_nComponents == 0) {                 // NO valid ICC profile
851           if (pAlterCS->CountComponents() > 0) {  // Use Alternative colorspace
852             m_nComponents = pAlterCS->CountComponents();
853             m_pAlterCS = std::move(pAlterCS);
854           } else {  // No valid alternative colorspace
855             int32_t nDictComponents = pDict ? pDict->GetIntegerFor("N") : 0;
856             if (nDictComponents != 1 && nDictComponents != 3 &&
857                 nDictComponents != 4) {
858               return false;
859             }
860             m_nComponents = nDictComponents;
861           }
862         } else {  // Using sRGB
863           if (pAlterCS->CountComponents() == m_nComponents)
864             m_pAlterCS = std::move(pAlterCS);
865         }
866       }
867     }
868     if (!m_pAlterCS) {
869       if (m_nComponents == 1)
870         m_pAlterCS = GetStockCS(PDFCS_DEVICEGRAY);
871       else if (m_nComponents == 3)
872         m_pAlterCS = GetStockCS(PDFCS_DEVICERGB);
873       else if (m_nComponents == 4)
874         m_pAlterCS = GetStockCS(PDFCS_DEVICECMYK);
875     }
876   }
877   CPDF_Array* pRanges = pDict->GetArrayFor("Range");
878   m_pRanges = FX_Alloc2D(FX_FLOAT, m_nComponents, 2);
879   for (uint32_t i = 0; i < m_nComponents * 2; i++) {
880     if (pRanges)
881       m_pRanges[i] = pRanges->GetNumberAt(i);
882     else if (i % 2)
883       m_pRanges[i] = 1.0f;
884     else
885       m_pRanges[i] = 0;
886   }
887   return true;
888 }
889 
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const890 bool CPDF_ICCBasedCS::GetRGB(FX_FLOAT* pBuf,
891                              FX_FLOAT& R,
892                              FX_FLOAT& G,
893                              FX_FLOAT& B) const {
894   if (m_pProfile && m_pProfile->m_bsRGB) {
895     R = pBuf[0];
896     G = pBuf[1];
897     B = pBuf[2];
898     return true;
899   }
900   CCodec_IccModule* pIccModule = CPDF_ModuleMgr::Get()->GetIccModule();
901   if (!m_pProfile->m_pTransform || !pIccModule) {
902     if (m_pAlterCS)
903       return m_pAlterCS->GetRGB(pBuf, R, G, B);
904 
905     R = 0.0f;
906     G = 0.0f;
907     B = 0.0f;
908     return true;
909   }
910   FX_FLOAT rgb[3];
911   pIccModule->SetComponents(m_nComponents);
912   pIccModule->Translate(m_pProfile->m_pTransform, pBuf, rgb);
913   R = rgb[0];
914   G = rgb[1];
915   B = rgb[2];
916   return true;
917 }
918 
SetRGB(FX_FLOAT * pBuf,FX_FLOAT R,FX_FLOAT G,FX_FLOAT B) const919 bool CPDF_ICCBasedCS::SetRGB(FX_FLOAT* pBuf,
920                              FX_FLOAT R,
921                              FX_FLOAT G,
922                              FX_FLOAT B) const {
923   return false;
924 }
925 
v_GetCMYK(FX_FLOAT * pBuf,FX_FLOAT & c,FX_FLOAT & m,FX_FLOAT & y,FX_FLOAT & k) const926 bool CPDF_ICCBasedCS::v_GetCMYK(FX_FLOAT* pBuf,
927                                 FX_FLOAT& c,
928                                 FX_FLOAT& m,
929                                 FX_FLOAT& y,
930                                 FX_FLOAT& k) const {
931   if (m_nComponents != 4)
932     return false;
933 
934   c = pBuf[0];
935   m = pBuf[1];
936   y = pBuf[2];
937   k = pBuf[3];
938   return true;
939 }
940 
EnableStdConversion(bool bEnabled)941 void CPDF_ICCBasedCS::EnableStdConversion(bool bEnabled) {
942   CPDF_ColorSpace::EnableStdConversion(bEnabled);
943   if (m_pAlterCS)
944     m_pAlterCS->EnableStdConversion(bEnabled);
945 }
946 
TranslateImageLine(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels,int image_width,int image_height,bool bTransMask) const947 void CPDF_ICCBasedCS::TranslateImageLine(uint8_t* pDestBuf,
948                                          const uint8_t* pSrcBuf,
949                                          int pixels,
950                                          int image_width,
951                                          int image_height,
952                                          bool bTransMask) const {
953   if (m_pProfile->m_bsRGB) {
954     ReverseRGB(pDestBuf, pSrcBuf, pixels);
955   } else if (m_pProfile->m_pTransform) {
956     int nMaxColors = 1;
957     for (uint32_t i = 0; i < m_nComponents; i++) {
958       nMaxColors *= 52;
959     }
960     if (m_nComponents > 3 || image_width * image_height < nMaxColors * 3 / 2) {
961       CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(
962           m_pProfile->m_pTransform, pDestBuf, pSrcBuf, pixels);
963     } else {
964       if (!m_pCache) {
965         ((CPDF_ICCBasedCS*)this)->m_pCache = FX_Alloc2D(uint8_t, nMaxColors, 3);
966         uint8_t* temp_src = FX_Alloc2D(uint8_t, nMaxColors, m_nComponents);
967         uint8_t* pSrc = temp_src;
968         for (int i = 0; i < nMaxColors; i++) {
969           uint32_t color = i;
970           uint32_t order = nMaxColors / 52;
971           for (uint32_t c = 0; c < m_nComponents; c++) {
972             *pSrc++ = (uint8_t)(color / order * 5);
973             color %= order;
974             order /= 52;
975           }
976         }
977         CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(
978             m_pProfile->m_pTransform, m_pCache, temp_src, nMaxColors);
979         FX_Free(temp_src);
980       }
981       for (int i = 0; i < pixels; i++) {
982         int index = 0;
983         for (uint32_t c = 0; c < m_nComponents; c++) {
984           index = index * 52 + (*pSrcBuf) / 5;
985           pSrcBuf++;
986         }
987         index *= 3;
988         *pDestBuf++ = m_pCache[index];
989         *pDestBuf++ = m_pCache[index + 1];
990         *pDestBuf++ = m_pCache[index + 2];
991       }
992     }
993   } else if (m_pAlterCS) {
994     m_pAlterCS->TranslateImageLine(pDestBuf, pSrcBuf, pixels, image_width,
995                                    image_height);
996   }
997 }
998 
CPDF_IndexedCS(CPDF_Document * pDoc)999 CPDF_IndexedCS::CPDF_IndexedCS(CPDF_Document* pDoc)
1000     : CPDF_ColorSpace(pDoc, PDFCS_INDEXED, 1),
1001       m_pBaseCS(nullptr),
1002       m_pCountedBaseCS(nullptr),
1003       m_pCompMinMax(nullptr) {}
1004 
~CPDF_IndexedCS()1005 CPDF_IndexedCS::~CPDF_IndexedCS() {
1006   FX_Free(m_pCompMinMax);
1007   CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : nullptr;
1008   if (pCS && m_pDocument) {
1009     m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
1010   }
1011 }
1012 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)1013 bool CPDF_IndexedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
1014   if (pArray->GetCount() < 4) {
1015     return false;
1016   }
1017   CPDF_Object* pBaseObj = pArray->GetDirectObjectAt(1);
1018   if (pBaseObj == m_pArray) {
1019     return false;
1020   }
1021   CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
1022   m_pBaseCS = pDocPageData->GetColorSpace(pBaseObj, nullptr);
1023   if (!m_pBaseCS) {
1024     return false;
1025   }
1026   m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
1027   m_nBaseComponents = m_pBaseCS->CountComponents();
1028   m_pCompMinMax = FX_Alloc2D(FX_FLOAT, m_nBaseComponents, 2);
1029   FX_FLOAT defvalue;
1030   for (int i = 0; i < m_nBaseComponents; i++) {
1031     m_pBaseCS->GetDefaultValue(i, defvalue, m_pCompMinMax[i * 2],
1032                                m_pCompMinMax[i * 2 + 1]);
1033     m_pCompMinMax[i * 2 + 1] -= m_pCompMinMax[i * 2];
1034   }
1035   m_MaxIndex = pArray->GetIntegerAt(2);
1036 
1037   CPDF_Object* pTableObj = pArray->GetDirectObjectAt(3);
1038   if (!pTableObj)
1039     return false;
1040 
1041   if (CPDF_String* pString = pTableObj->AsString()) {
1042     m_Table = pString->GetString();
1043   } else if (CPDF_Stream* pStream = pTableObj->AsStream()) {
1044     CPDF_StreamAcc acc;
1045     acc.LoadAllData(pStream, false);
1046     m_Table = CFX_ByteStringC(acc.GetData(), acc.GetSize());
1047   }
1048   return true;
1049 }
1050 
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const1051 bool CPDF_IndexedCS::GetRGB(FX_FLOAT* pBuf,
1052                             FX_FLOAT& R,
1053                             FX_FLOAT& G,
1054                             FX_FLOAT& B) const {
1055   int index = (int32_t)(*pBuf);
1056   if (index < 0 || index > m_MaxIndex) {
1057     return false;
1058   }
1059   if (m_nBaseComponents) {
1060     if (index == INT_MAX || (index + 1) > INT_MAX / m_nBaseComponents ||
1061         (index + 1) * m_nBaseComponents > (int)m_Table.GetLength()) {
1062       R = G = B = 0;
1063       return false;
1064     }
1065   }
1066   CFX_FixedBufGrow<FX_FLOAT, 16> Comps(m_nBaseComponents);
1067   FX_FLOAT* comps = Comps;
1068   const uint8_t* pTable = m_Table.raw_str();
1069   for (int i = 0; i < m_nBaseComponents; i++) {
1070     comps[i] =
1071         m_pCompMinMax[i * 2] +
1072         m_pCompMinMax[i * 2 + 1] * pTable[index * m_nBaseComponents + i] / 255;
1073   }
1074   return m_pBaseCS->GetRGB(comps, R, G, B);
1075 }
1076 
GetBaseCS() const1077 CPDF_ColorSpace* CPDF_IndexedCS::GetBaseCS() const {
1078   return m_pBaseCS;
1079 }
1080 
EnableStdConversion(bool bEnabled)1081 void CPDF_IndexedCS::EnableStdConversion(bool bEnabled) {
1082   CPDF_ColorSpace::EnableStdConversion(bEnabled);
1083   if (m_pBaseCS) {
1084     m_pBaseCS->EnableStdConversion(bEnabled);
1085   }
1086 }
1087 
CPDF_PatternCS(CPDF_Document * pDoc)1088 CPDF_PatternCS::CPDF_PatternCS(CPDF_Document* pDoc)
1089     : CPDF_ColorSpace(pDoc, PDFCS_PATTERN, 1),
1090       m_pBaseCS(nullptr),
1091       m_pCountedBaseCS(nullptr) {}
1092 
~CPDF_PatternCS()1093 CPDF_PatternCS::~CPDF_PatternCS() {
1094   CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : nullptr;
1095   if (pCS && m_pDocument) {
1096     m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
1097   }
1098 }
1099 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)1100 bool CPDF_PatternCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
1101   CPDF_Object* pBaseCS = pArray->GetDirectObjectAt(1);
1102   if (pBaseCS == m_pArray) {
1103     return false;
1104   }
1105   CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
1106   m_pBaseCS = pDocPageData->GetColorSpace(pBaseCS, nullptr);
1107   if (m_pBaseCS) {
1108     if (m_pBaseCS->GetFamily() == PDFCS_PATTERN) {
1109       return false;
1110     }
1111     m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
1112     m_nComponents = m_pBaseCS->CountComponents() + 1;
1113     if (m_pBaseCS->CountComponents() > MAX_PATTERN_COLORCOMPS) {
1114       return false;
1115     }
1116   } else {
1117     m_nComponents = 1;
1118   }
1119   return true;
1120 }
1121 
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const1122 bool CPDF_PatternCS::GetRGB(FX_FLOAT* pBuf,
1123                             FX_FLOAT& R,
1124                             FX_FLOAT& G,
1125                             FX_FLOAT& B) const {
1126   if (m_pBaseCS) {
1127     ASSERT(m_pBaseCS->GetFamily() != PDFCS_PATTERN);
1128     PatternValue* pvalue = (PatternValue*)pBuf;
1129     if (m_pBaseCS->GetRGB(pvalue->m_Comps, R, G, B)) {
1130       return true;
1131     }
1132   }
1133   R = G = B = 0.75f;
1134   return false;
1135 }
1136 
GetBaseCS() const1137 CPDF_ColorSpace* CPDF_PatternCS::GetBaseCS() const {
1138   return m_pBaseCS;
1139 }
1140 
CPDF_SeparationCS(CPDF_Document * pDoc)1141 CPDF_SeparationCS::CPDF_SeparationCS(CPDF_Document* pDoc)
1142     : CPDF_ColorSpace(pDoc, PDFCS_SEPARATION, 1) {}
1143 
~CPDF_SeparationCS()1144 CPDF_SeparationCS::~CPDF_SeparationCS() {}
1145 
GetDefaultValue(int iComponent,FX_FLOAT & value,FX_FLOAT & min,FX_FLOAT & max) const1146 void CPDF_SeparationCS::GetDefaultValue(int iComponent,
1147                                         FX_FLOAT& value,
1148                                         FX_FLOAT& min,
1149                                         FX_FLOAT& max) const {
1150   value = 1.0f;
1151   min = 0;
1152   max = 1.0f;
1153 }
1154 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)1155 bool CPDF_SeparationCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
1156   CFX_ByteString name = pArray->GetStringAt(1);
1157   if (name == "None") {
1158     m_Type = None;
1159     return true;
1160   }
1161 
1162   m_Type = Colorant;
1163   CPDF_Object* pAltCS = pArray->GetDirectObjectAt(2);
1164   if (pAltCS == m_pArray)
1165     return false;
1166 
1167   m_pAltCS = Load(pDoc, pAltCS);
1168   if (!m_pAltCS)
1169     return false;
1170 
1171   CPDF_Object* pFuncObj = pArray->GetDirectObjectAt(3);
1172   if (pFuncObj && !pFuncObj->IsName())
1173     m_pFunc = CPDF_Function::Load(pFuncObj);
1174 
1175   if (m_pFunc && m_pFunc->CountOutputs() < m_pAltCS->CountComponents())
1176     m_pFunc.reset();
1177   return true;
1178 }
1179 
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const1180 bool CPDF_SeparationCS::GetRGB(FX_FLOAT* pBuf,
1181                                FX_FLOAT& R,
1182                                FX_FLOAT& G,
1183                                FX_FLOAT& B) const {
1184   if (m_Type == None)
1185     return false;
1186 
1187   if (!m_pFunc) {
1188     if (!m_pAltCS)
1189       return false;
1190 
1191     int nComps = m_pAltCS->CountComponents();
1192     CFX_FixedBufGrow<FX_FLOAT, 16> results(nComps);
1193     for (int i = 0; i < nComps; i++)
1194       results[i] = *pBuf;
1195     return m_pAltCS->GetRGB(results, R, G, B);
1196   }
1197 
1198   CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
1199   int nresults = 0;
1200   m_pFunc->Call(pBuf, 1, results, nresults);
1201   if (nresults == 0)
1202     return false;
1203 
1204   if (m_pAltCS)
1205     return m_pAltCS->GetRGB(results, R, G, B);
1206 
1207   R = 0;
1208   G = 0;
1209   B = 0;
1210   return false;
1211 }
1212 
EnableStdConversion(bool bEnabled)1213 void CPDF_SeparationCS::EnableStdConversion(bool bEnabled) {
1214   CPDF_ColorSpace::EnableStdConversion(bEnabled);
1215   if (m_pAltCS)
1216     m_pAltCS->EnableStdConversion(bEnabled);
1217 }
1218 
CPDF_DeviceNCS(CPDF_Document * pDoc)1219 CPDF_DeviceNCS::CPDF_DeviceNCS(CPDF_Document* pDoc)
1220     : CPDF_ColorSpace(pDoc, PDFCS_DEVICEN, 0) {}
1221 
~CPDF_DeviceNCS()1222 CPDF_DeviceNCS::~CPDF_DeviceNCS() {}
1223 
GetDefaultValue(int iComponent,FX_FLOAT & value,FX_FLOAT & min,FX_FLOAT & max) const1224 void CPDF_DeviceNCS::GetDefaultValue(int iComponent,
1225                                      FX_FLOAT& value,
1226                                      FX_FLOAT& min,
1227                                      FX_FLOAT& max) const {
1228   value = 1.0f;
1229   min = 0;
1230   max = 1.0f;
1231 }
1232 
v_Load(CPDF_Document * pDoc,CPDF_Array * pArray)1233 bool CPDF_DeviceNCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
1234   CPDF_Array* pObj = ToArray(pArray->GetDirectObjectAt(1));
1235   if (!pObj)
1236     return false;
1237 
1238   m_nComponents = pObj->GetCount();
1239   CPDF_Object* pAltCS = pArray->GetDirectObjectAt(2);
1240   if (!pAltCS || pAltCS == m_pArray)
1241     return false;
1242 
1243   m_pAltCS = Load(pDoc, pAltCS);
1244   m_pFunc = CPDF_Function::Load(pArray->GetDirectObjectAt(3));
1245   if (!m_pAltCS || !m_pFunc)
1246     return false;
1247 
1248   return m_pFunc->CountOutputs() >= m_pAltCS->CountComponents();
1249 }
1250 
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const1251 bool CPDF_DeviceNCS::GetRGB(FX_FLOAT* pBuf,
1252                             FX_FLOAT& R,
1253                             FX_FLOAT& G,
1254                             FX_FLOAT& B) const {
1255   if (!m_pFunc)
1256     return false;
1257 
1258   CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
1259   int nresults = 0;
1260   m_pFunc->Call(pBuf, m_nComponents, results, nresults);
1261   if (nresults == 0)
1262     return false;
1263 
1264   return m_pAltCS->GetRGB(results, R, G, B);
1265 }
1266 
EnableStdConversion(bool bEnabled)1267 void CPDF_DeviceNCS::EnableStdConversion(bool bEnabled) {
1268   CPDF_ColorSpace::EnableStdConversion(bEnabled);
1269   if (m_pAltCS) {
1270     m_pAltCS->EnableStdConversion(bEnabled);
1271   }
1272 }
1273