blob: 06c5ce46b29588438ce32724ca957025edd779b3 [file] [log] [blame]
// 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);
}