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