1 // Copyright 2022 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 #include "core/fpdfapi/page/cpdf_indexedcs.h"
6
7 #include <set>
8 #include <vector>
9
10 #include "core/fpdfapi/page/cpdf_colorspace.h"
11 #include "core/fpdfapi/page/cpdf_docpagedata.h"
12 #include "core/fpdfapi/parser/cpdf_array.h"
13 #include "core/fpdfapi/parser/cpdf_document.h"
14 #include "core/fpdfapi/parser/cpdf_object.h"
15 #include "core/fpdfapi/parser/cpdf_stream.h"
16 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
17 #include "core/fpdfapi/parser/cpdf_string.h"
18 #include "core/fxcrt/data_vector.h"
19 #include "core/fxcrt/fx_2d_size.h"
20 #include "core/fxcrt/fx_safe_types.h"
21 #include "core/fxcrt/retain_ptr.h"
22 #include "third_party/base/check_op.h"
23 #include "third_party/base/span.h"
24
CPDF_IndexedCS()25 CPDF_IndexedCS::CPDF_IndexedCS() : CPDF_BasedCS(Family::kIndexed) {}
26
27 CPDF_IndexedCS::~CPDF_IndexedCS() = default;
28
AsIndexedCS() const29 const CPDF_IndexedCS* CPDF_IndexedCS::AsIndexedCS() const {
30 return this;
31 }
32
v_Load(CPDF_Document * pDoc,const CPDF_Array * pArray,std::set<const CPDF_Object * > * pVisited)33 uint32_t CPDF_IndexedCS::v_Load(CPDF_Document* pDoc,
34 const CPDF_Array* pArray,
35 std::set<const CPDF_Object*>* pVisited) {
36 if (pArray->size() < 4)
37 return 0;
38
39 RetainPtr<const CPDF_Object> pBaseObj = pArray->GetDirectObjectAt(1);
40 if (HasSameArray(pBaseObj.Get()))
41 return 0;
42
43 auto* pDocPageData = CPDF_DocPageData::FromDocument(pDoc);
44 m_pBaseCS =
45 pDocPageData->GetColorSpaceGuarded(pBaseObj.Get(), nullptr, pVisited);
46 if (!m_pBaseCS)
47 return 0;
48
49 // The base color space cannot be a Pattern or Indexed space, according to the
50 // PDF 1.7 spec, page 263.
51 Family family = m_pBaseCS->GetFamily();
52 if (family == Family::kIndexed || family == Family::kPattern)
53 return 0;
54
55 m_nBaseComponents = m_pBaseCS->CountComponents();
56 DCHECK(m_nBaseComponents);
57 m_pCompMinMax = DataVector<float>(Fx2DSizeOrDie(m_nBaseComponents, 2));
58 float defvalue;
59 for (uint32_t i = 0; i < m_nBaseComponents; i++) {
60 m_pBaseCS->GetDefaultValue(i, &defvalue, &m_pCompMinMax[i * 2],
61 &m_pCompMinMax[i * 2 + 1]);
62 m_pCompMinMax[i * 2 + 1] -= m_pCompMinMax[i * 2];
63 }
64 m_MaxIndex = pArray->GetIntegerAt(2);
65
66 RetainPtr<const CPDF_Object> pTableObj = pArray->GetDirectObjectAt(3);
67 if (!pTableObj)
68 return 0;
69
70 if (const CPDF_String* pString = pTableObj->AsString()) {
71 m_Table = pString->GetString();
72 } else if (const CPDF_Stream* pStream = pTableObj->AsStream()) {
73 auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pdfium::WrapRetain(pStream));
74 pAcc->LoadAllDataFiltered();
75 m_Table = ByteStringView(pAcc->GetSpan());
76 }
77 return 1;
78 }
79
GetRGB(pdfium::span<const float> pBuf,float * R,float * G,float * B) const80 bool CPDF_IndexedCS::GetRGB(pdfium::span<const float> pBuf,
81 float* R,
82 float* G,
83 float* B) const {
84 int32_t index = static_cast<int32_t>(pBuf[0]);
85 if (index < 0 || index > m_MaxIndex)
86 return false;
87
88 DCHECK(m_nBaseComponents);
89 DCHECK_EQ(m_nBaseComponents, m_pBaseCS->CountComponents());
90
91 FX_SAFE_SIZE_T length = index;
92 length += 1;
93 length *= m_nBaseComponents;
94 if (!length.IsValid() || length.ValueOrDie() > m_Table.GetLength()) {
95 *R = 0;
96 *G = 0;
97 *B = 0;
98 return false;
99 }
100
101 std::vector<float> comps(m_nBaseComponents);
102 const uint8_t* pTable = m_Table.raw_str();
103 for (uint32_t i = 0; i < m_nBaseComponents; ++i) {
104 comps[i] =
105 m_pCompMinMax[i * 2] +
106 m_pCompMinMax[i * 2 + 1] * pTable[index * m_nBaseComponents + i] / 255;
107 }
108 return m_pBaseCS->GetRGB(comps, R, G, B);
109 }
110