Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cpdf_colorspace.cpp
Go to the documentation of this file.
1// Copyright 2016 The PDFium Authors
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 <math.h>
10#include <stdint.h>
11
12#include <algorithm>
13#include <limits>
14#include <memory>
15#include <type_traits>
16#include <utility>
17#include <vector>
18
19#include "core/fpdfapi/page/cpdf_devicecs.h"
20#include "core/fpdfapi/page/cpdf_docpagedata.h"
21#include "core/fpdfapi/page/cpdf_function.h"
22#include "core/fpdfapi/page/cpdf_iccprofile.h"
23#include "core/fpdfapi/page/cpdf_indexedcs.h"
24#include "core/fpdfapi/page/cpdf_pattern.h"
25#include "core/fpdfapi/page/cpdf_patterncs.h"
26#include "core/fpdfapi/parser/cpdf_array.h"
27#include "core/fpdfapi/parser/cpdf_dictionary.h"
28#include "core/fpdfapi/parser/cpdf_document.h"
29#include "core/fpdfapi/parser/cpdf_name.h"
30#include "core/fpdfapi/parser/cpdf_object.h"
31#include "core/fpdfapi/parser/cpdf_stream.h"
32#include "core/fpdfapi/parser/fpdf_parser_utility.h"
33#include "core/fxcodec/fx_codec.h"
34#include "core/fxcodec/icc/icc_transform.h"
35#include "core/fxcrt/data_vector.h"
36#include "core/fxcrt/fx_2d_size.h"
37#include "core/fxcrt/fx_memory_wrappers.h"
38#include "core/fxcrt/fx_safe_types.h"
39#include "core/fxcrt/maybe_owned.h"
40#include "core/fxcrt/scoped_set_insertion.h"
41#include "core/fxcrt/span_util.h"
42#include "core/fxcrt/stl_util.h"
43#include "third_party/base/check.h"
44#include "third_party/base/check_op.h"
45#include "third_party/base/containers/contains.h"
46#include "third_party/base/notreached.h"
47
48namespace {
49
50constexpr uint8_t kSRGBSamples1[] = {
51 0, 3, 6, 10, 13, 15, 18, 20, 22, 23, 25, 27, 28, 30, 31,
52 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
53 48, 49, 49, 50, 51, 52, 53, 53, 54, 55, 56, 56, 57, 58, 58,
54 59, 60, 61, 61, 62, 62, 63, 64, 64, 65, 66, 66, 67, 67, 68,
55 68, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 76, 76,
56 77, 77, 78, 78, 79, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83,
57 84, 84, 85, 85, 85, 86, 86, 87, 87, 88, 88, 88, 89, 89, 90,
58 90, 91, 91, 91, 92, 92, 93, 93, 93, 94, 94, 95, 95, 95, 96,
59 96, 97, 97, 97, 98, 98, 98, 99, 99, 99, 100, 100, 101, 101, 101,
60 102, 102, 102, 103, 103, 103, 104, 104, 104, 105, 105, 106, 106, 106, 107,
61 107, 107, 108, 108, 108, 109, 109, 109, 110, 110, 110, 110, 111, 111, 111,
62 112, 112, 112, 113, 113, 113, 114, 114, 114, 115, 115, 115, 115, 116, 116,
63 116, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 120,
64};
65
66constexpr uint8_t kSRGBSamples2[] = {
67 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
68 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149,
69 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 159, 160, 161, 162,
70 163, 163, 164, 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173,
71 174, 175, 175, 176, 177, 178, 178, 179, 180, 180, 181, 182, 182, 183, 184,
72 185, 185, 186, 187, 187, 188, 189, 189, 190, 190, 191, 192, 192, 193, 194,
73 194, 195, 196, 196, 197, 197, 198, 199, 199, 200, 200, 201, 202, 202, 203,
74 203, 204, 205, 205, 206, 206, 207, 208, 208, 209, 209, 210, 210, 211, 212,
75 212, 213, 213, 214, 214, 215, 215, 216, 216, 217, 218, 218, 219, 219, 220,
76 220, 221, 221, 222, 222, 223, 223, 224, 224, 225, 226, 226, 227, 227, 228,
77 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235,
78 236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242,
79 243, 243, 244, 244, 245, 245, 246, 246, 246, 247, 247, 248, 248, 249, 249,
80 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255,
81};
82
83constexpr size_t kBlackWhitePointCount = 3;
84
85void GetDefaultBlackPoint(float* pPoints) {
86 static constexpr float kDefaultValue = 0.0f;
87 for (size_t i = 0; i < kBlackWhitePointCount; ++i)
88 pPoints[i] = kDefaultValue;
89}
90
91void GetBlackPoint(const CPDF_Dictionary* pDict, float* pPoints) {
92 RetainPtr<const CPDF_Array> pParam = pDict->GetArrayFor("BlackPoint");
93 if (!pParam || pParam->size() != kBlackWhitePointCount) {
94 GetDefaultBlackPoint(pPoints);
95 return;
96 }
97
98 // Check to make sure all values are non-negative.
99 for (size_t i = 0; i < kBlackWhitePointCount; ++i) {
100 pPoints[i] = pParam->GetFloatAt(i);
101 if (pPoints[i] < 0) {
102 GetDefaultBlackPoint(pPoints);
103 return;
104 }
105 }
106}
107
108bool GetWhitePoint(const CPDF_Dictionary* pDict, float* pPoints) {
109 RetainPtr<const CPDF_Array> pParam = pDict->GetArrayFor("WhitePoint");
110 if (!pParam || pParam->size() != kBlackWhitePointCount)
111 return false;
112
113 for (size_t i = 0; i < kBlackWhitePointCount; ++i)
114 pPoints[i] = pParam->GetFloatAt(i);
115 return pPoints[0] > 0.0f && pPoints[1] == 1.0f && pPoints[2] > 0.0f;
116}
117
118class CPDF_CalGray final : public CPDF_ColorSpace {
119 public:
121 ~CPDF_CalGray() override;
122
123 // CPDF_ColorSpace:
124 bool GetRGB(pdfium::span<const float> pBuf,
125 float* R,
126 float* G,
127 float* B) const override;
128 uint32_t v_Load(CPDF_Document* pDoc,
129 const CPDF_Array* pArray,
130 std::set<const CPDF_Object*>* pVisited) override;
131 void TranslateImageLine(pdfium::span<uint8_t> dest_span,
132 pdfium::span<const uint8_t> src_span,
133 int pixels,
134 int image_width,
135 int image_height,
136 bool bTransMask) const override;
137
138 private:
139 static constexpr float kDefaultGamma = 1.0f;
140
141 CPDF_CalGray();
142
143 float m_Gamma = kDefaultGamma;
144 float m_WhitePoint[kBlackWhitePointCount] = {1.0f, 1.0f, 1.0f};
145 float m_BlackPoint[kBlackWhitePointCount] = {0.0f, 0.0f, 0.0f};
146};
147
148class CPDF_CalRGB final : public CPDF_ColorSpace {
149 public:
151 ~CPDF_CalRGB() override;
152
153 // CPDF_ColorSpace:
154 bool GetRGB(pdfium::span<const float> pBuf,
155 float* R,
156 float* G,
157 float* B) const override;
158 void TranslateImageLine(pdfium::span<uint8_t> dest_span,
159 pdfium::span<const uint8_t> src_span,
160 int pixels,
161 int image_width,
162 int image_height,
163 bool bTransMask) const override;
164 uint32_t v_Load(CPDF_Document* pDoc,
165 const CPDF_Array* pArray,
166 std::set<const CPDF_Object*>* pVisited) override;
167
168 private:
169 static constexpr size_t kGammaCount = 3;
170 static constexpr size_t kMatrixCount = 9;
171
172 CPDF_CalRGB();
173
174 float m_WhitePoint[kBlackWhitePointCount] = {1.0f, 1.0f, 1.0f};
175 float m_BlackPoint[kBlackWhitePointCount] = {0.0f, 0.0f, 0.0f};
176 float m_Gamma[kGammaCount] = {};
177 float m_Matrix[kMatrixCount] = {};
178 bool m_bHasGamma = false;
179 bool m_bHasMatrix = false;
180};
181
182class CPDF_LabCS final : public CPDF_ColorSpace {
183 public:
185 ~CPDF_LabCS() override;
186
187 // CPDF_ColorSpace:
188 bool GetRGB(pdfium::span<const float> pBuf,
189 float* R,
190 float* G,
191 float* B) const override;
192 void GetDefaultValue(int iComponent,
193 float* value,
194 float* min,
195 float* max) const override;
196 void TranslateImageLine(pdfium::span<uint8_t> dest_span,
197 pdfium::span<const uint8_t> src_span,
198 int pixels,
199 int image_width,
200 int image_height,
201 bool bTransMask) const override;
202 uint32_t v_Load(CPDF_Document* pDoc,
203 const CPDF_Array* pArray,
204 std::set<const CPDF_Object*>* pVisited) override;
205
206 private:
207 static constexpr size_t kRangesCount = 4;
208
209 CPDF_LabCS();
210
211 float m_WhitePoint[kBlackWhitePointCount] = {1.0f, 1.0f, 1.0f};
212 float m_BlackPoint[kBlackWhitePointCount] = {0.0f, 0.0f, 0.0f};
213 float m_Ranges[kRangesCount] = {};
214};
215
216class CPDF_ICCBasedCS final : public CPDF_BasedCS {
217 public:
219 ~CPDF_ICCBasedCS() override;
220
221 // CPDF_ColorSpace:
222 bool GetRGB(pdfium::span<const float> pBuf,
223 float* R,
224 float* G,
225 float* B) const override;
226 void TranslateImageLine(pdfium::span<uint8_t> dest_span,
227 pdfium::span<const uint8_t> src_span,
228 int pixels,
229 int image_width,
230 int image_height,
231 bool bTransMask) const override;
232 bool IsNormal() const override;
233 uint32_t v_Load(CPDF_Document* pDoc,
234 const CPDF_Array* pArray,
235 std::set<const CPDF_Object*>* pVisited) override;
236
237 private:
238 CPDF_ICCBasedCS();
239
240 // If no valid ICC profile or using sRGB, try looking for an alternate.
241 bool FindAlternateProfile(CPDF_Document* pDoc,
242 const CPDF_Dictionary* pDict,
243 std::set<const CPDF_Object*>* pVisited,
244 uint32_t nExpectedComponents);
245 static RetainPtr<CPDF_ColorSpace> GetStockAlternateProfile(
246 uint32_t nComponents);
247 static std::vector<float> GetRanges(const CPDF_Dictionary* pDict,
248 uint32_t nComponents);
249
250 RetainPtr<CPDF_IccProfile> m_pProfile;
251 mutable DataVector<uint8_t> m_pCache;
252 std::vector<float> m_pRanges;
253};
254
255class CPDF_SeparationCS final : public CPDF_BasedCS {
256 public:
258 ~CPDF_SeparationCS() override;
259
260 // CPDF_ColorSpace:
261 bool GetRGB(pdfium::span<const float> pBuf,
262 float* R,
263 float* G,
264 float* B) const override;
265 void GetDefaultValue(int iComponent,
266 float* value,
267 float* min,
268 float* max) const override;
269 uint32_t v_Load(CPDF_Document* pDoc,
270 const CPDF_Array* pArray,
271 std::set<const CPDF_Object*>* pVisited) override;
272
273 private:
274 CPDF_SeparationCS();
275
276 bool m_IsNoneType = false;
277 std::unique_ptr<const CPDF_Function> m_pFunc;
278};
279
280class CPDF_DeviceNCS final : public CPDF_BasedCS {
281 public:
283 ~CPDF_DeviceNCS() override;
284
285 // CPDF_ColorSpace:
286 bool GetRGB(pdfium::span<const float> pBuf,
287 float* R,
288 float* G,
289 float* B) const override;
290 void GetDefaultValue(int iComponent,
291 float* value,
292 float* min,
293 float* max) const override;
294 uint32_t v_Load(CPDF_Document* pDoc,
295 const CPDF_Array* pArray,
296 std::set<const CPDF_Object*>* pVisited) override;
297
298 private:
299 CPDF_DeviceNCS();
300
301 std::unique_ptr<const CPDF_Function> m_pFunc;
302};
303
304class Vector_3by1 {
305 public:
306 Vector_3by1() : a(0.0f), b(0.0f), c(0.0f) {}
307
308 Vector_3by1(float a1, float b1, float c1) : a(a1), b(b1), c(c1) {}
309
310 float a;
311 float b;
312 float c;
313};
314
315class Matrix_3by3 {
316 public:
317 Matrix_3by3()
318 : a(0.0f),
319 b(0.0f),
320 c(0.0f),
321 d(0.0f),
322 e(0.0f),
323 f(0.0f),
324 g(0.0f),
325 h(0.0f),
326 i(0.0f) {}
327
328 Matrix_3by3(float a1,
329 float b1,
330 float c1,
331 float d1,
332 float e1,
333 float f1,
334 float g1,
335 float h1,
336 float i1)
337 : a(a1), b(b1), c(c1), d(d1), e(e1), f(f1), g(g1), h(h1), i(i1) {}
338
339 Matrix_3by3 Inverse() {
340 float det = a * (e * i - f * h) - b * (i * d - f * g) + c * (d * h - e * g);
341 if (fabs(det) < std::numeric_limits<float>::epsilon())
342 return Matrix_3by3();
343
344 return Matrix_3by3(
345 (e * i - f * h) / det, -(b * i - c * h) / det, (b * f - c * e) / det,
346 -(d * i - f * g) / det, (a * i - c * g) / det, -(a * f - c * d) / det,
347 (d * h - e * g) / det, -(a * h - b * g) / det, (a * e - b * d) / det);
348 }
349
350 Matrix_3by3 Multiply(const Matrix_3by3& m) {
351 return Matrix_3by3(a * m.a + b * m.d + c * m.g, a * m.b + b * m.e + c * m.h,
352 a * m.c + b * m.f + c * m.i, d * m.a + e * m.d + f * m.g,
353 d * m.b + e * m.e + f * m.h, d * m.c + e * m.f + f * m.i,
354 g * m.a + h * m.d + i * m.g, g * m.b + h * m.e + i * m.h,
355 g * m.c + h * m.f + i * m.i);
356 }
357
358 Vector_3by1 TransformVector(const Vector_3by1& v) {
359 return Vector_3by1(a * v.a + b * v.b + c * v.c, d * v.a + e * v.b + f * v.c,
360 g * v.a + h * v.b + i * v.c);
361 }
362
363 float a;
364 float b;
365 float c;
366 float d;
367 float e;
368 float f;
369 float g;
370 float h;
371 float i;
372};
373
374float RGB_Conversion(float colorComponent) {
375 colorComponent = std::clamp(colorComponent, 0.0f, 1.0f);
376 int scale = std::max(static_cast<int>(colorComponent * 1023), 0);
377 if (scale < 192)
378 return kSRGBSamples1[scale] / 255.0f;
379 return kSRGBSamples2[scale / 4 - 48] / 255.0f;
380}
381
382void XYZ_to_sRGB(float X, float Y, float Z, float* R, float* G, float* B) {
383 float R1 = 3.2410f * X - 1.5374f * Y - 0.4986f * Z;
384 float G1 = -0.9692f * X + 1.8760f * Y + 0.0416f * Z;
385 float B1 = 0.0556f * X - 0.2040f * Y + 1.0570f * Z;
386
387 *R = RGB_Conversion(R1);
388 *G = RGB_Conversion(G1);
389 *B = RGB_Conversion(B1);
390}
391
392void XYZ_to_sRGB_WhitePoint(float X,
393 float Y,
394 float Z,
395 float Xw,
396 float Yw,
397 float Zw,
398 float* R,
399 float* G,
400 float* B) {
401 // The following RGB_xyz is based on
402 // sRGB value {Rx,Ry}={0.64, 0.33}, {Gx,Gy}={0.30, 0.60}, {Bx,By}={0.15, 0.06}
403
404 constexpr float Rx = 0.64f;
405 constexpr float Ry = 0.33f;
406 constexpr float Gx = 0.30f;
407 constexpr float Gy = 0.60f;
408 constexpr float Bx = 0.15f;
409 constexpr float By = 0.06f;
410 Matrix_3by3 RGB_xyz(Rx, Gx, Bx, Ry, Gy, By, 1 - Rx - Ry, 1 - Gx - Gy,
411 1 - Bx - By);
412 Vector_3by1 whitePoint(Xw, Yw, Zw);
413 Vector_3by1 XYZ(X, Y, Z);
414
415 Vector_3by1 RGB_Sum_XYZ = RGB_xyz.Inverse().TransformVector(whitePoint);
416 Matrix_3by3 RGB_SUM_XYZ_DIAG(RGB_Sum_XYZ.a, 0, 0, 0, RGB_Sum_XYZ.b, 0, 0, 0,
417 RGB_Sum_XYZ.c);
418 Matrix_3by3 M = RGB_xyz.Multiply(RGB_SUM_XYZ_DIAG);
419 Vector_3by1 RGB = M.Inverse().TransformVector(XYZ);
420
421 *R = RGB_Conversion(RGB.a);
422 *G = RGB_Conversion(RGB.b);
423 *B = RGB_Conversion(RGB.c);
424}
425
426class StockColorSpaces {
427 public:
428 StockColorSpaces()
429 : gray_(pdfium::MakeRetain<CPDF_DeviceCS>(
430 CPDF_ColorSpace::Family::kDeviceGray)),
431 rgb_(pdfium::MakeRetain<CPDF_DeviceCS>(
432 CPDF_ColorSpace::Family::kDeviceRGB)),
433 cmyk_(pdfium::MakeRetain<CPDF_DeviceCS>(
434 CPDF_ColorSpace::Family::kDeviceCMYK)),
435 pattern_(pdfium::MakeRetain<CPDF_PatternCS>()) {
436 pattern_->InitializeStockPattern();
437 }
438 StockColorSpaces(const StockColorSpaces&) = delete;
439 StockColorSpaces& operator=(const StockColorSpaces&) = delete;
440 ~StockColorSpaces() = default;
441
442 RetainPtr<CPDF_ColorSpace> GetStockCS(CPDF_ColorSpace::Family family) {
444 return gray_;
445 }
447 return rgb_;
448 }
450 return cmyk_;
451 }
452 if (family == CPDF_ColorSpace::Family::kPattern) {
453 return pattern_;
454 }
455 NOTREACHED_NORETURN();
456 }
457
458 private:
459 RetainPtr<CPDF_DeviceCS> gray_;
460 RetainPtr<CPDF_DeviceCS> rgb_;
461 RetainPtr<CPDF_DeviceCS> cmyk_;
462 RetainPtr<CPDF_PatternCS> pattern_;
463};
464
465StockColorSpaces* g_stock_colorspaces = nullptr;
466
467} // namespace
468
469PatternValue::PatternValue() = default;
470
471PatternValue::PatternValue(const PatternValue& that) = default;
472
473PatternValue::~PatternValue() = default;
474
475void PatternValue::SetComps(pdfium::span<const float> comps) {
476 fxcrt::spancpy(pdfium::make_span(m_Comps), comps);
477}
478
479// static
481 CHECK(!g_stock_colorspaces);
482 g_stock_colorspaces = new StockColorSpaces();
483}
484
485// static
487 delete g_stock_colorspaces;
488 g_stock_colorspaces = nullptr;
489}
490
491// static
493 return g_stock_colorspaces->GetStockCS(family);
494}
495
496// static
498 const ByteString& name) {
499 if (name == "DeviceRGB" || name == "RGB")
500 return GetStockCS(Family::kDeviceRGB);
501 if (name == "DeviceGray" || name == "G")
502 return GetStockCS(Family::kDeviceGray);
503 if (name == "DeviceCMYK" || name == "CMYK")
504 return GetStockCS(Family::kDeviceCMYK);
505 if (name == "Pattern")
506 return GetStockCS(Family::kPattern);
507 return nullptr;
508}
509
510// static
512 CPDF_Document* pDoc,
513 const CPDF_Object* pObj,
514 std::set<const CPDF_Object*>* pVisited) {
515 if (!pObj)
516 return nullptr;
517
518 if (pdfium::Contains(*pVisited, pObj))
519 return nullptr;
520
521 ScopedSetInsertion<const CPDF_Object*> insertion(pVisited, pObj);
522
523 if (pObj->IsName())
524 return GetStockCSForName(pObj->GetString());
525
526 if (const CPDF_Stream* pStream = pObj->AsStream()) {
527 RetainPtr<const CPDF_Dictionary> pDict = pStream->GetDict();
528 if (!pDict)
529 return nullptr;
530
531 CPDF_DictionaryLocker locker(std::move(pDict));
532 for (const auto& it : locker) {
533 RetainPtr<const CPDF_Name> pValue = ToName(it.second);
534 if (pValue) {
535 RetainPtr<CPDF_ColorSpace> pRet =
536 GetStockCSForName(pValue->GetString());
537 if (pRet)
538 return pRet;
539 }
540 }
541 return nullptr;
542 }
543
544 const CPDF_Array* pArray = pObj->AsArray();
545 if (!pArray || pArray->IsEmpty())
546 return nullptr;
547
548 RetainPtr<const CPDF_Object> pFamilyObj = pArray->GetDirectObjectAt(0);
549 if (!pFamilyObj)
550 return nullptr;
551
552 ByteString familyname = pFamilyObj->GetString();
553 if (pArray->size() == 1)
554 return GetStockCSForName(familyname);
555
557 CPDF_ColorSpace::AllocateColorSpace(familyname.AsStringView());
558 if (!pCS)
559 return nullptr;
560
561 pCS->m_pArray.Reset(pArray);
562 pCS->m_nComponents = pCS->v_Load(pDoc, pArray, pVisited);
563 if (pCS->m_nComponents == 0)
564 return nullptr;
565
566 return pCS;
567}
568
569// static
570RetainPtr<CPDF_ColorSpace> CPDF_ColorSpace::AllocateColorSpace(
571 ByteStringView bsFamilyName) {
572 switch (bsFamilyName.GetID()) {
573 case FXBSTR_ID('C', 'a', 'l', 'G'):
574 return pdfium::MakeRetain<CPDF_CalGray>();
575 case FXBSTR_ID('C', 'a', 'l', 'R'):
576 return pdfium::MakeRetain<CPDF_CalRGB>();
577 case FXBSTR_ID('L', 'a', 'b', 0):
578 return pdfium::MakeRetain<CPDF_LabCS>();
579 case FXBSTR_ID('I', 'C', 'C', 'B'):
580 return pdfium::MakeRetain<CPDF_ICCBasedCS>();
581 case FXBSTR_ID('I', 'n', 'd', 'e'):
582 case FXBSTR_ID('I', 0, 0, 0):
583 return pdfium::MakeRetain<CPDF_IndexedCS>();
584 case FXBSTR_ID('S', 'e', 'p', 'a'):
585 return pdfium::MakeRetain<CPDF_SeparationCS>();
586 case FXBSTR_ID('D', 'e', 'v', 'i'):
587 return pdfium::MakeRetain<CPDF_DeviceNCS>();
588 case FXBSTR_ID('P', 'a', 't', 't'):
589 return pdfium::MakeRetain<CPDF_PatternCS>();
590 default:
591 return nullptr;
592 }
593}
594
595// static
597 switch (family) {
599 return 1;
601 return 3;
603 return 4;
604 default:
605 NOTREACHED_NORETURN();
606 }
607}
608
610 DCHECK(m_Family != Family::kPattern);
611
612 float min;
613 float max;
614 std::vector<float> buf(m_nComponents);
615 for (uint32_t i = 0; i < m_nComponents; i++)
616 GetDefaultValue(i, &buf[i], &min, &max);
617
618 return buf;
619}
620
622 return m_nComponents;
623}
624
625void CPDF_ColorSpace::GetDefaultValue(int iComponent,
626 float* value,
627 float* min,
628 float* max) const {
629 *value = 0.0f;
630 *min = 0.0f;
631 *max = 1.0f;
632}
633
634void CPDF_ColorSpace::TranslateImageLine(pdfium::span<uint8_t> dest_span,
635 pdfium::span<const uint8_t> src_span,
636 int pixels,
637 int image_width,
638 int image_height,
639 bool bTransMask) const {
640 uint8_t* dest_buf = dest_span.data();
641 const uint8_t* src_buf = src_span.data();
642 std::vector<float> src(m_nComponents);
643 float R;
644 float G;
645 float B;
646 const int divisor = m_Family != Family::kIndexed ? 255 : 1;
647 for (int i = 0; i < pixels; i++) {
648 for (uint32_t j = 0; j < m_nComponents; j++)
649 src[j] = static_cast<float>(*src_buf++) / divisor;
650 GetRGB(src, &R, &G, &B);
651 *dest_buf++ = static_cast<int32_t>(B * 255);
652 *dest_buf++ = static_cast<int32_t>(G * 255);
653 *dest_buf++ = static_cast<int32_t>(R * 255);
654 }
655}
656
658 if (bEnabled)
659 m_dwStdConversion++;
660 else if (m_dwStdConversion)
661 m_dwStdConversion--;
662}
663
670
671const CPDF_PatternCS* CPDF_ColorSpace::AsPatternCS() const {
672 return nullptr;
673}
674
675const CPDF_IndexedCS* CPDF_ColorSpace::AsIndexedCS() const {
676 return nullptr;
677}
678
679CPDF_ColorSpace::CPDF_ColorSpace(Family family) : m_Family(family) {}
680
681CPDF_ColorSpace::~CPDF_ColorSpace() = default;
682
683void CPDF_ColorSpace::SetComponentsForStockCS(uint32_t nComponents) {
684 m_nComponents = nComponents;
685}
686
687CPDF_CalGray::CPDF_CalGray() : CPDF_ColorSpace(Family::kCalGray) {}
688
689CPDF_CalGray::~CPDF_CalGray() = default;
690
691uint32_t CPDF_CalGray::v_Load(CPDF_Document* pDoc,
692 const CPDF_Array* pArray,
693 std::set<const CPDF_Object*>* pVisited) {
694 RetainPtr<const CPDF_Dictionary> pDict = pArray->GetDictAt(1);
695 if (!pDict)
696 return 0;
697
698 if (!GetWhitePoint(pDict.Get(), m_WhitePoint))
699 return 0;
700
701 GetBlackPoint(pDict.Get(), m_BlackPoint);
702
703 m_Gamma = pDict->GetFloatFor("Gamma");
704 if (m_Gamma == 0)
705 m_Gamma = kDefaultGamma;
706 return 1;
707}
708
709bool CPDF_CalGray::GetRGB(pdfium::span<const float> pBuf,
710 float* R,
711 float* G,
712 float* B) const {
713 *R = pBuf[0];
714 *G = pBuf[0];
715 *B = pBuf[0];
716 return true;
717}
718
719void CPDF_CalGray::TranslateImageLine(pdfium::span<uint8_t> dest_span,
720 pdfium::span<const uint8_t> src_span,
721 int pixels,
722 int image_width,
723 int image_height,
724 bool bTransMask) const {
725 uint8_t* pDestBuf = dest_span.data();
726 const uint8_t* pSrcBuf = src_span.data();
727 for (int i = 0; i < pixels; i++) {
728 // Compiler can not conclude that src/dest don't overlap.
729 const uint8_t pix = pSrcBuf[i];
730 *pDestBuf++ = pix;
731 *pDestBuf++ = pix;
732 *pDestBuf++ = pix;
733 }
734}
735
736CPDF_CalRGB::CPDF_CalRGB() : CPDF_ColorSpace(Family::kCalRGB) {}
737
738CPDF_CalRGB::~CPDF_CalRGB() = default;
739
740uint32_t CPDF_CalRGB::v_Load(CPDF_Document* pDoc,
741 const CPDF_Array* pArray,
742 std::set<const CPDF_Object*>* pVisited) {
743 RetainPtr<const CPDF_Dictionary> pDict = pArray->GetDictAt(1);
744 if (!pDict)
745 return 0;
746
747 if (!GetWhitePoint(pDict.Get(), m_WhitePoint))
748 return 0;
749
750 GetBlackPoint(pDict.Get(), m_BlackPoint);
751
752 RetainPtr<const CPDF_Array> pGamma = pDict->GetArrayFor("Gamma");
753 if (pGamma) {
754 m_bHasGamma = true;
755 for (size_t i = 0; i < std::size(m_Gamma); ++i)
756 m_Gamma[i] = pGamma->GetFloatAt(i);
757 }
758
759 RetainPtr<const CPDF_Array> pMatrix = pDict->GetArrayFor("Matrix");
760 if (pMatrix) {
761 m_bHasMatrix = true;
762 for (size_t i = 0; i < std::size(m_Matrix); ++i)
763 m_Matrix[i] = pMatrix->GetFloatAt(i);
764 }
765 return 3;
766}
767
768bool CPDF_CalRGB::GetRGB(pdfium::span<const float> pBuf,
769 float* R,
770 float* G,
771 float* B) const {
772 float A_ = pBuf[0];
773 float B_ = pBuf[1];
774 float C_ = pBuf[2];
775 if (m_bHasGamma) {
776 A_ = powf(A_, m_Gamma[0]);
777 B_ = powf(B_, m_Gamma[1]);
778 C_ = powf(C_, m_Gamma[2]);
779 }
780
781 float X;
782 float Y;
783 float Z;
784 if (m_bHasMatrix) {
785 X = m_Matrix[0] * A_ + m_Matrix[3] * B_ + m_Matrix[6] * C_;
786 Y = m_Matrix[1] * A_ + m_Matrix[4] * B_ + m_Matrix[7] * C_;
787 Z = m_Matrix[2] * A_ + m_Matrix[5] * B_ + m_Matrix[8] * C_;
788 } else {
789 X = A_;
790 Y = B_;
791 Z = C_;
792 }
793 XYZ_to_sRGB_WhitePoint(X, Y, Z, m_WhitePoint[0], m_WhitePoint[1],
794 m_WhitePoint[2], R, G, B);
795 return true;
796}
797
798void CPDF_CalRGB::TranslateImageLine(pdfium::span<uint8_t> dest_span,
799 pdfium::span<const uint8_t> src_span,
800 int pixels,
801 int image_width,
802 int image_height,
803 bool bTransMask) const {
804 uint8_t* pDestBuf = dest_span.data();
805 const uint8_t* pSrcBuf = src_span.data();
806 if (!bTransMask) {
807 fxcodec::ReverseRGB(pDestBuf, pSrcBuf, pixels);
808 return;
809 }
810
811 float Cal[3];
812 float R;
813 float G;
814 float B;
815 for (int i = 0; i < pixels; i++) {
816 Cal[0] = static_cast<float>(pSrcBuf[2]) / 255;
817 Cal[1] = static_cast<float>(pSrcBuf[1]) / 255;
818 Cal[2] = static_cast<float>(pSrcBuf[0]) / 255;
819 GetRGB(Cal, &R, &G, &B);
820 pDestBuf[0] = FXSYS_roundf(B * 255);
821 pDestBuf[1] = FXSYS_roundf(G * 255);
822 pDestBuf[2] = FXSYS_roundf(R * 255);
823 pSrcBuf += 3;
824 pDestBuf += 3;
825 }
826}
827
828CPDF_LabCS::CPDF_LabCS() : CPDF_ColorSpace(Family::kLab) {}
829
830CPDF_LabCS::~CPDF_LabCS() = default;
831
832void CPDF_LabCS::GetDefaultValue(int iComponent,
833 float* value,
834 float* min,
835 float* max) const {
836 DCHECK_LT(iComponent, 3);
837
838 if (iComponent > 0) {
839 float range_min = m_Ranges[iComponent * 2 - 2];
840 float range_max = m_Ranges[iComponent * 2 - 1];
841 if (range_min <= range_max) {
842 *min = range_min;
843 *max = range_max;
844 *value = std::clamp(0.0f, *min, *max);
845 return;
846 }
847 }
848
849 *min = 0.0f;
850 *max = 100.0f;
851 *value = 0.0f;
852}
853
854uint32_t CPDF_LabCS::v_Load(CPDF_Document* pDoc,
855 const CPDF_Array* pArray,
856 std::set<const CPDF_Object*>* pVisited) {
857 RetainPtr<const CPDF_Dictionary> pDict = pArray->GetDictAt(1);
858 if (!pDict)
859 return 0;
860
861 if (!GetWhitePoint(pDict.Get(), m_WhitePoint))
862 return 0;
863
864 GetBlackPoint(pDict.Get(), m_BlackPoint);
865
866 RetainPtr<const CPDF_Array> pParam = pDict->GetArrayFor("Range");
867 static constexpr float kDefaultRanges[kRangesCount] = {-100.0f, 100.0f,
868 -100.0f, 100.0f};
869 static_assert(std::size(kDefaultRanges) == std::extent<decltype(m_Ranges)>(),
870 "Range size mismatch");
871 for (size_t i = 0; i < std::size(kDefaultRanges); ++i)
872 m_Ranges[i] = pParam ? pParam->GetFloatAt(i) : kDefaultRanges[i];
873 return 3;
874}
875
876bool CPDF_LabCS::GetRGB(pdfium::span<const float> pBuf,
877 float* R,
878 float* G,
879 float* B) const {
880 float Lstar = pBuf[0];
881 float astar = pBuf[1];
882 float bstar = pBuf[2];
883 float M = (Lstar + 16.0f) / 116.0f;
884 float L = M + astar / 500.0f;
885 float N = M - bstar / 200.0f;
886 float X;
887 float Y;
888 float Z;
889 if (L < 0.2069f)
890 X = 0.957f * 0.12842f * (L - 0.1379f);
891 else
892 X = 0.957f * L * L * L;
893
894 if (M < 0.2069f)
895 Y = 0.12842f * (M - 0.1379f);
896 else
897 Y = M * M * M;
898
899 if (N < 0.2069f)
900 Z = 1.0889f * 0.12842f * (N - 0.1379f);
901 else
902 Z = 1.0889f * N * N * N;
903
904 XYZ_to_sRGB(X, Y, Z, R, G, B);
905 return true;
906}
907
908void CPDF_LabCS::TranslateImageLine(pdfium::span<uint8_t> dest_span,
909 pdfium::span<const uint8_t> src_span,
910 int pixels,
911 int image_width,
912 int image_height,
913 bool bTransMask) const {
914 uint8_t* pDestBuf = dest_span.data();
915 const uint8_t* pSrcBuf = src_span.data();
916 for (int i = 0; i < pixels; i++) {
917 float lab[3];
918 lab[0] = pSrcBuf[0] * 100 / 255.0f;
919 lab[1] = pSrcBuf[1] - 128;
920 lab[2] = pSrcBuf[2] - 128;
921
922 float R;
923 float G;
924 float B;
925 GetRGB(lab, &R, &G, &B);
926 pDestBuf[0] = static_cast<int32_t>(B * 255);
927 pDestBuf[1] = static_cast<int32_t>(G * 255);
928 pDestBuf[2] = static_cast<int32_t>(R * 255);
929 pDestBuf += 3;
930 pSrcBuf += 3;
931 }
932}
933
934CPDF_ICCBasedCS::CPDF_ICCBasedCS() : CPDF_BasedCS(Family::kICCBased) {}
935
936CPDF_ICCBasedCS::~CPDF_ICCBasedCS() = default;
937
938uint32_t CPDF_ICCBasedCS::v_Load(CPDF_Document* pDoc,
939 const CPDF_Array* pArray,
940 std::set<const CPDF_Object*>* pVisited) {
941 RetainPtr<const CPDF_Stream> pStream = pArray->GetStreamAt(1);
942 if (!pStream)
943 return 0;
944
945 // The PDF 1.7 spec says the number of components must be valid. While some
946 // PDF viewers tolerate invalid values, Acrobat does not, so be consistent
947 // with Acrobat and reject bad values.
948 RetainPtr<const CPDF_Dictionary> pDict = pStream->GetDict();
949 const int32_t nDictComponents = pDict ? pDict->GetIntegerFor("N") : 0;
951 return 0;
952 }
953
954 // Safe to cast, as the value just got validated.
955 const uint32_t nComponents = static_cast<uint32_t>(nDictComponents);
956 m_pProfile = CPDF_DocPageData::FromDocument(pDoc)->GetIccProfile(pStream);
957 if (!m_pProfile)
958 return 0;
959
960 // If PDFium does not understand the ICC profile format at all, or if it's
961 // SRGB, a profile PDFium recognizes but does not support well, then try the
962 // alternate profile.
963 if (!m_pProfile->IsSupported() &&
964 !FindAlternateProfile(pDoc, pDict.Get(), pVisited, nComponents)) {
965 // If there is no alternate profile, use a stock profile as mentioned in
966 // the PDF 1.7 spec in table 4.16 in the "Alternate" key description.
967 DCHECK(!m_pBaseCS);
968 m_pBaseCS = GetStockAlternateProfile(nComponents);
969 }
970
971 m_pRanges = GetRanges(pDict.Get(), nComponents);
972 return nComponents;
973}
974
975bool CPDF_ICCBasedCS::GetRGB(pdfium::span<const float> pBuf,
976 float* R,
977 float* G,
978 float* B) const {
979 DCHECK(m_pProfile);
980 if (m_pProfile->IsSRGB()) {
981 *R = pBuf[0];
982 *G = pBuf[1];
983 *B = pBuf[2];
984 return true;
985 }
986 if (m_pProfile->IsSupported()) {
987 float rgb[3];
988 m_pProfile->Translate(pBuf.first(CountComponents()), rgb);
989 *R = rgb[0];
990 *G = rgb[1];
991 *B = rgb[2];
992 return true;
993 }
994 if (m_pBaseCS)
995 return m_pBaseCS->GetRGB(pBuf, R, G, B);
996
997 *R = 0.0f;
998 *G = 0.0f;
999 *B = 0.0f;
1000 return true;
1001}
1002
1003void CPDF_ICCBasedCS::TranslateImageLine(pdfium::span<uint8_t> dest_span,
1004 pdfium::span<const uint8_t> src_span,
1005 int pixels,
1006 int image_width,
1007 int image_height,
1008 bool bTransMask) const {
1009 if (m_pProfile->IsSRGB()) {
1010 fxcodec::ReverseRGB(dest_span.data(), src_span.data(), pixels);
1011 return;
1012 }
1013 if (!m_pProfile->IsSupported()) {
1014 if (m_pBaseCS) {
1015 m_pBaseCS->TranslateImageLine(dest_span, src_span, pixels, image_width,
1016 image_height, false);
1017 }
1018 return;
1019 }
1020
1021 // |nMaxColors| will not overflow since |nComponents| is limited in size.
1022 const uint32_t nComponents = CountComponents();
1023 DCHECK(fxcodec::IccTransform::IsValidIccComponents(nComponents));
1024 int nMaxColors = 1;
1025 for (uint32_t i = 0; i < nComponents; i++)
1026 nMaxColors *= 52;
1027
1028 bool bTranslate = nComponents > 3;
1029 if (!bTranslate) {
1030 FX_SAFE_INT32 nPixelCount = image_width;
1031 nPixelCount *= image_height;
1032 if (nPixelCount.IsValid())
1033 bTranslate = nPixelCount.ValueOrDie() < nMaxColors * 3 / 2;
1034 }
1035 if (bTranslate && m_pProfile->IsSupported()) {
1036 m_pProfile->TranslateScanline(dest_span, src_span, pixels);
1037 return;
1038 }
1039 if (m_pCache.empty()) {
1040 m_pCache.resize(Fx2DSizeOrDie(nMaxColors, 3));
1041 DataVector<uint8_t> temp_src(Fx2DSizeOrDie(nMaxColors, nComponents));
1042 size_t src_index = 0;
1043 for (int i = 0; i < nMaxColors; i++) {
1044 uint32_t color = i;
1045 uint32_t order = nMaxColors / 52;
1046 for (uint32_t c = 0; c < nComponents; c++) {
1047 temp_src[src_index++] = static_cast<uint8_t>(color / order * 5);
1048 color %= order;
1049 order /= 52;
1050 }
1051 }
1052 if (m_pProfile->IsSupported()) {
1053 m_pProfile->TranslateScanline(m_pCache, temp_src, nMaxColors);
1054 }
1055 }
1056 uint8_t* pDestBuf = dest_span.data();
1057 const uint8_t* pSrcBuf = src_span.data();
1058 for (int i = 0; i < pixels; i++) {
1059 int index = 0;
1060 for (uint32_t c = 0; c < nComponents; c++) {
1061 index = index * 52 + (*pSrcBuf) / 5;
1062 pSrcBuf++;
1063 }
1064 index *= 3;
1065 *pDestBuf++ = m_pCache[index];
1066 *pDestBuf++ = m_pCache[index + 1];
1067 *pDestBuf++ = m_pCache[index + 2];
1068 }
1069}
1070
1071bool CPDF_ICCBasedCS::IsNormal() const {
1072 if (m_pProfile->IsSRGB())
1073 return true;
1074 if (m_pProfile->IsSupported())
1075 return m_pProfile->IsNormal();
1076 if (m_pBaseCS)
1077 return m_pBaseCS->IsNormal();
1078 return false;
1079}
1080
1081bool CPDF_ICCBasedCS::FindAlternateProfile(
1082 CPDF_Document* pDoc,
1083 const CPDF_Dictionary* pDict,
1084 std::set<const CPDF_Object*>* pVisited,
1085 uint32_t nExpectedComponents) {
1086 RetainPtr<const CPDF_Object> pAlterCSObj =
1087 pDict->GetDirectObjectFor("Alternate");
1088 if (!pAlterCSObj)
1089 return false;
1090
1091 auto pAlterCS = CPDF_ColorSpace::Load(pDoc, pAlterCSObj.Get(), pVisited);
1092 if (!pAlterCS)
1093 return false;
1094
1095 if (pAlterCS->GetFamily() == Family::kPattern)
1096 return false;
1097
1098 if (pAlterCS->CountComponents() != nExpectedComponents)
1099 return false;
1100
1101 m_pBaseCS = std::move(pAlterCS);
1102 return true;
1103}
1104
1105// static
1106RetainPtr<CPDF_ColorSpace> CPDF_ICCBasedCS::GetStockAlternateProfile(
1107 uint32_t nComponents) {
1108 if (nComponents == 1)
1109 return GetStockCS(Family::kDeviceGray);
1110 if (nComponents == 3)
1111 return GetStockCS(Family::kDeviceRGB);
1112 if (nComponents == 4)
1113 return GetStockCS(Family::kDeviceCMYK);
1114 NOTREACHED_NORETURN();
1115}
1116
1117// static
1118std::vector<float> CPDF_ICCBasedCS::GetRanges(const CPDF_Dictionary* pDict,
1119 uint32_t nComponents) {
1120 DCHECK(fxcodec::IccTransform::IsValidIccComponents(nComponents));
1121 RetainPtr<const CPDF_Array> pRanges = pDict->GetArrayFor("Range");
1122 if (pRanges && pRanges->size() >= nComponents * 2)
1123 return ReadArrayElementsToVector(pRanges.Get(), nComponents * 2);
1124
1125 std::vector<float> ranges;
1126 ranges.reserve(nComponents * 2);
1127 for (uint32_t i = 0; i < nComponents; i++) {
1128 ranges.push_back(0.0f);
1129 ranges.push_back(1.0f);
1130 }
1131 return ranges;
1132}
1133
1134CPDF_SeparationCS::CPDF_SeparationCS() : CPDF_BasedCS(Family::kSeparation) {}
1135
1136CPDF_SeparationCS::~CPDF_SeparationCS() = default;
1137
1138void CPDF_SeparationCS::GetDefaultValue(int iComponent,
1139 float* value,
1140 float* min,
1141 float* max) const {
1142 *value = 1.0f;
1143 *min = 0;
1144 *max = 1.0f;
1145}
1146
1147uint32_t CPDF_SeparationCS::v_Load(CPDF_Document* pDoc,
1148 const CPDF_Array* pArray,
1149 std::set<const CPDF_Object*>* pVisited) {
1150 m_IsNoneType = pArray->GetByteStringAt(1) == "None";
1151 if (m_IsNoneType)
1152 return 1;
1153
1154 RetainPtr<const CPDF_Object> pAltArray = pArray->GetDirectObjectAt(2);
1155 if (HasSameArray(pAltArray.Get()))
1156 return 0;
1157
1158 m_pBaseCS = Load(pDoc, pAltArray.Get(), pVisited);
1159 if (!m_pBaseCS)
1160 return 0;
1161
1162 if (m_pBaseCS->IsSpecial())
1163 return 0;
1164
1165 RetainPtr<const CPDF_Object> pFuncObj = pArray->GetDirectObjectAt(3);
1166 if (pFuncObj && !pFuncObj->IsName()) {
1167 auto pFunc = CPDF_Function::Load(std::move(pFuncObj));
1168 if (pFunc && pFunc->CountOutputs() >= m_pBaseCS->CountComponents())
1169 m_pFunc = std::move(pFunc);
1170 }
1171 return 1;
1172}
1173
1174bool CPDF_SeparationCS::GetRGB(pdfium::span<const float> pBuf,
1175 float* R,
1176 float* G,
1177 float* B) const {
1178 if (m_IsNoneType)
1179 return false;
1180
1181 if (!m_pFunc) {
1182 if (!m_pBaseCS)
1183 return false;
1184
1185 int nComps = m_pBaseCS->CountComponents();
1186 std::vector<float> results(nComps);
1187 for (int i = 0; i < nComps; i++)
1188 results[i] = pBuf[0];
1189 return m_pBaseCS->GetRGB(results, R, G, B);
1190 }
1191
1192 // Using at least 16 elements due to the call m_pAltCS->GetRGB() below.
1193 std::vector<float> results(std::max(m_pFunc->CountOutputs(), 16u));
1194 uint32_t nresults = m_pFunc->Call(pBuf.first(1), results).value_or(0);
1195 if (nresults == 0)
1196 return false;
1197
1198 if (m_pBaseCS)
1199 return m_pBaseCS->GetRGB(results, R, G, B);
1200
1201 *R = 0.0f;
1202 *G = 0.0f;
1203 *B = 0.0f;
1204 return false;
1205}
1206
1207CPDF_DeviceNCS::CPDF_DeviceNCS() : CPDF_BasedCS(Family::kDeviceN) {}
1208
1209CPDF_DeviceNCS::~CPDF_DeviceNCS() = default;
1210
1211void CPDF_DeviceNCS::GetDefaultValue(int iComponent,
1212 float* value,
1213 float* min,
1214 float* max) const {
1215 *value = 1.0f;
1216 *min = 0;
1217 *max = 1.0f;
1218}
1219
1220uint32_t CPDF_DeviceNCS::v_Load(CPDF_Document* pDoc,
1221 const CPDF_Array* pArray,
1222 std::set<const CPDF_Object*>* pVisited) {
1223 RetainPtr<const CPDF_Array> pObj = ToArray(pArray->GetDirectObjectAt(1));
1224 if (!pObj)
1225 return 0;
1226
1227 RetainPtr<const CPDF_Object> pAltCS = pArray->GetDirectObjectAt(2);
1228 if (!pAltCS || HasSameArray(pAltCS.Get()))
1229 return 0;
1230
1231 m_pBaseCS = Load(pDoc, pAltCS.Get(), pVisited);
1232 m_pFunc = CPDF_Function::Load(pArray->GetDirectObjectAt(3));
1233 if (!m_pBaseCS || !m_pFunc)
1234 return 0;
1235
1236 if (m_pBaseCS->IsSpecial())
1237 return 0;
1238
1239 if (m_pFunc->CountOutputs() < m_pBaseCS->CountComponents())
1240 return 0;
1241
1242 return fxcrt::CollectionSize<uint32_t>(*pObj);
1243}
1244
1245bool CPDF_DeviceNCS::GetRGB(pdfium::span<const float> pBuf,
1246 float* R,
1247 float* G,
1248 float* B) const {
1249 if (!m_pFunc)
1250 return false;
1251
1252 // Using at least 16 elements due to the call m_pAltCS->GetRGB() below.
1253 std::vector<float> results(std::max(m_pFunc->CountOutputs(), 16u));
1254 uint32_t nresults =
1255 m_pFunc->Call(pBuf.first(CountComponents()), pdfium::make_span(results))
1256 .value_or(0);
1257
1258 if (nresults == 0)
1259 return false;
1260
1261 return m_pBaseCS->GetRGB(results, R, G, B);
1262}
bool IsEmpty() const
Definition cpdf_array.h:40
CPDF_BasedCS(Family family)
virtual const CPDF_IndexedCS * AsIndexedCS() const
static void InitializeGlobals()
Family GetFamily() const
~CPDF_ColorSpace() override
static void DestroyGlobals()
virtual const CPDF_PatternCS * AsPatternCS() const
virtual bool IsNormal() const
virtual void EnableStdConversion(bool bEnabled)
std::vector< float > CreateBufAndSetDefaultColor() const
CPDF_ColorSpace(Family family)
virtual bool GetRGB(pdfium::span< const float > pBuf, float *R, float *G, float *B) const =0
static uint32_t ComponentsForFamily(Family family)
virtual void TranslateImageLine(pdfium::span< uint8_t > dest_span, pdfium::span< const uint8_t > src_span, int pixels, int image_width, int image_height, bool bTransMask) const
static RetainPtr< CPDF_ColorSpace > GetStockCSForName(const ByteString &name)
bool HasSameArray(const CPDF_Object *pObj) const
void SetComponentsForStockCS(uint32_t nComponents)
static RetainPtr< CPDF_ColorSpace > GetStockCS(Family family)
uint32_t CountComponents() const
virtual void GetDefaultValue(int iComponent, float *value, float *min, float *max) const
virtual ByteString GetString() const
bool IsName() const
const CPDF_Array * AsArray() const
const CPDF_Stream * AsStream() const
void SetComps(pdfium::span< const float > comps)
PatternValue(const PatternValue &that)
static bool IsValidIccComponents(int components)
bool operator==(const char *ptr) const
constexpr uint32_t FXBSTR_ID(uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4)
Definition fx_string.h:19
int FXSYS_roundf(float f)
Definition fx_system.cpp:92
void ReverseRGB(uint8_t *pDestBuf, const uint8_t *pSrcBuf, int pixels)
Definition fx_codec.cpp:21
#define CHECK(cvref)
#define CONSTRUCT_VIA_MAKE_RETAIN
Definition retain_ptr.h:224