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