|  | // Copyright 2022 PDFium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "core/fpdfapi/page/cpdf_indexedcs.h" | 
|  |  | 
|  | #include <set> | 
|  |  | 
|  | #include "core/fpdfapi/page/cpdf_colorspace.h" | 
|  | #include "core/fpdfapi/page/cpdf_docpagedata.h" | 
|  | #include "core/fpdfapi/parser/cpdf_array.h" | 
|  | #include "core/fpdfapi/parser/cpdf_document.h" | 
|  | #include "core/fpdfapi/parser/cpdf_object.h" | 
|  | #include "core/fpdfapi/parser/cpdf_stream.h" | 
|  | #include "core/fpdfapi/parser/cpdf_stream_acc.h" | 
|  | #include "core/fpdfapi/parser/cpdf_string.h" | 
|  | #include "core/fxcrt/fx_safe_types.h" | 
|  | #include "core/fxcrt/retain_ptr.h" | 
|  | #include "core/fxcrt/stl_util.h" | 
|  | #include "third_party/base/check_op.h" | 
|  | #include "third_party/base/span.h" | 
|  |  | 
|  | CPDF_IndexedCS::CPDF_IndexedCS() : CPDF_BasedCS(Family::kIndexed) {} | 
|  |  | 
|  | CPDF_IndexedCS::~CPDF_IndexedCS() = default; | 
|  |  | 
|  | const CPDF_IndexedCS* CPDF_IndexedCS::AsIndexedCS() const { | 
|  | return this; | 
|  | } | 
|  |  | 
|  | uint32_t CPDF_IndexedCS::v_Load(CPDF_Document* pDoc, | 
|  | const CPDF_Array* pArray, | 
|  | std::set<const CPDF_Object*>* pVisited) { | 
|  | if (pArray->size() < 4) | 
|  | return 0; | 
|  |  | 
|  | const CPDF_Object* pBaseObj = pArray->GetDirectObjectAt(1); | 
|  | if (pBaseObj == m_pArray) | 
|  | return 0; | 
|  |  | 
|  | auto* pDocPageData = CPDF_DocPageData::FromDocument(pDoc); | 
|  | m_pBaseCS = pDocPageData->GetColorSpaceGuarded(pBaseObj, nullptr, pVisited); | 
|  | if (!m_pBaseCS) | 
|  | return 0; | 
|  |  | 
|  | // The base color space cannot be a Pattern or Indexed space, according to the | 
|  | // PDF 1.7 spec, page 263. | 
|  | Family family = m_pBaseCS->GetFamily(); | 
|  | if (family == Family::kIndexed || family == Family::kPattern) | 
|  | return 0; | 
|  |  | 
|  | m_nBaseComponents = m_pBaseCS->CountComponents(); | 
|  | m_pCompMinMax = fxcrt::Vector2D<float>(m_nBaseComponents, 2); | 
|  | float defvalue; | 
|  | for (uint32_t i = 0; i < m_nBaseComponents; i++) { | 
|  | m_pBaseCS->GetDefaultValue(i, &defvalue, &m_pCompMinMax[i * 2], | 
|  | &m_pCompMinMax[i * 2 + 1]); | 
|  | m_pCompMinMax[i * 2 + 1] -= m_pCompMinMax[i * 2]; | 
|  | } | 
|  | m_MaxIndex = pArray->GetIntegerAt(2); | 
|  |  | 
|  | const CPDF_Object* pTableObj = pArray->GetDirectObjectAt(3); | 
|  | if (!pTableObj) | 
|  | return 0; | 
|  |  | 
|  | if (const CPDF_String* pString = pTableObj->AsString()) { | 
|  | m_Table = pString->GetString(); | 
|  | } else if (const CPDF_Stream* pStream = pTableObj->AsStream()) { | 
|  | auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream); | 
|  | pAcc->LoadAllDataFiltered(); | 
|  | m_Table = ByteStringView(pAcc->GetSpan()); | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | bool CPDF_IndexedCS::GetRGB(pdfium::span<const float> pBuf, | 
|  | float* R, | 
|  | float* G, | 
|  | float* B) const { | 
|  | int32_t index = static_cast<int32_t>(pBuf[0]); | 
|  | if (index < 0 || index > m_MaxIndex) | 
|  | return false; | 
|  |  | 
|  | if (m_nBaseComponents) { | 
|  | FX_SAFE_SIZE_T length = index; | 
|  | length += 1; | 
|  | length *= m_nBaseComponents; | 
|  | if (!length.IsValid() || length.ValueOrDie() > m_Table.GetLength()) { | 
|  | *R = 0; | 
|  | *G = 0; | 
|  | *B = 0; | 
|  | return false; | 
|  | } | 
|  | } | 
|  | std::vector<float> comps(m_nBaseComponents); | 
|  | const uint8_t* pTable = m_Table.raw_str(); | 
|  | for (uint32_t i = 0; i < m_nBaseComponents; ++i) { | 
|  | comps[i] = | 
|  | m_pCompMinMax[i * 2] + | 
|  | m_pCompMinMax[i * 2 + 1] * pTable[index * m_nBaseComponents + i] / 255; | 
|  | } | 
|  | DCHECK_EQ(m_nBaseComponents, m_pBaseCS->CountComponents()); | 
|  | return m_pBaseCS->GetRGB(comps, R, G, B); | 
|  | } |