diff options
Diffstat (limited to 'core/fpdfapi/page/cpdf_sampledfunc.cpp')
-rw-r--r-- | core/fpdfapi/page/cpdf_sampledfunc.cpp | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/core/fpdfapi/page/cpdf_sampledfunc.cpp b/core/fpdfapi/page/cpdf_sampledfunc.cpp new file mode 100644 index 0000000000..37b9a4e468 --- /dev/null +++ b/core/fpdfapi/page/cpdf_sampledfunc.cpp @@ -0,0 +1,156 @@ +// Copyright 2017 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. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fpdfapi/page/cpdf_sampledfunc.h" + +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fxcrt/fx_safe_types.h" + +namespace { + +// See PDF Reference 1.7, page 170, table 3.36. +bool IsValidBitsPerSample(uint32_t x) { + switch (x) { + case 1: + case 2: + case 4: + case 8: + case 12: + case 16: + case 24: + case 32: + return true; + default: + return false; + } +} + +} // namespace + +CPDF_SampledFunc::CPDF_SampledFunc() : CPDF_Function(Type::kType0Sampled) {} + +CPDF_SampledFunc::~CPDF_SampledFunc() {} + +bool CPDF_SampledFunc::v_Init(CPDF_Object* pObj) { + CPDF_Stream* pStream = pObj->AsStream(); + if (!pStream) + return false; + + CPDF_Dictionary* pDict = pStream->GetDict(); + CPDF_Array* pSize = pDict->GetArrayFor("Size"); + CPDF_Array* pEncode = pDict->GetArrayFor("Encode"); + CPDF_Array* pDecode = pDict->GetArrayFor("Decode"); + m_nBitsPerSample = pDict->GetIntegerFor("BitsPerSample"); + if (!IsValidBitsPerSample(m_nBitsPerSample)) + return false; + + m_SampleMax = 0xffffffff >> (32 - m_nBitsPerSample); + m_pSampleStream = pdfium::MakeRetain<CPDF_StreamAcc>(pStream); + m_pSampleStream->LoadAllData(false); + FX_SAFE_UINT32 nTotalSampleBits = 1; + m_EncodeInfo.resize(m_nInputs); + for (uint32_t i = 0; i < m_nInputs; i++) { + m_EncodeInfo[i].sizes = pSize ? pSize->GetIntegerAt(i) : 0; + if (!pSize && i == 0) + m_EncodeInfo[i].sizes = pDict->GetIntegerFor("Size"); + nTotalSampleBits *= m_EncodeInfo[i].sizes; + if (pEncode) { + m_EncodeInfo[i].encode_min = pEncode->GetFloatAt(i * 2); + m_EncodeInfo[i].encode_max = pEncode->GetFloatAt(i * 2 + 1); + } else { + m_EncodeInfo[i].encode_min = 0; + m_EncodeInfo[i].encode_max = + m_EncodeInfo[i].sizes == 1 ? 1 : (float)m_EncodeInfo[i].sizes - 1; + } + } + nTotalSampleBits *= m_nBitsPerSample; + nTotalSampleBits *= m_nOutputs; + FX_SAFE_UINT32 nTotalSampleBytes = nTotalSampleBits; + nTotalSampleBytes += 7; + nTotalSampleBytes /= 8; + if (!nTotalSampleBytes.IsValid() || nTotalSampleBytes.ValueOrDie() == 0 || + nTotalSampleBytes.ValueOrDie() > m_pSampleStream->GetSize()) { + return false; + } + m_DecodeInfo.resize(m_nOutputs); + for (uint32_t i = 0; i < m_nOutputs; i++) { + if (pDecode) { + m_DecodeInfo[i].decode_min = pDecode->GetFloatAt(2 * i); + m_DecodeInfo[i].decode_max = pDecode->GetFloatAt(2 * i + 1); + } else { + m_DecodeInfo[i].decode_min = m_pRanges[i * 2]; + m_DecodeInfo[i].decode_max = m_pRanges[i * 2 + 1]; + } + } + return true; +} + +bool CPDF_SampledFunc::v_Call(float* inputs, float* results) const { + int pos = 0; + CFX_FixedBufGrow<float, 16> encoded_input_buf(m_nInputs); + float* encoded_input = encoded_input_buf; + CFX_FixedBufGrow<uint32_t, 32> int_buf(m_nInputs * 2); + uint32_t* index = int_buf; + uint32_t* blocksize = index + m_nInputs; + for (uint32_t i = 0; i < m_nInputs; i++) { + if (i == 0) + blocksize[i] = 1; + else + blocksize[i] = blocksize[i - 1] * m_EncodeInfo[i - 1].sizes; + encoded_input[i] = + Interpolate(inputs[i], m_pDomains[i * 2], m_pDomains[i * 2 + 1], + m_EncodeInfo[i].encode_min, m_EncodeInfo[i].encode_max); + index[i] = pdfium::clamp(static_cast<uint32_t>(encoded_input[i]), 0U, + m_EncodeInfo[i].sizes - 1); + pos += index[i] * blocksize[i]; + } + FX_SAFE_INT32 bits_to_output = m_nOutputs; + bits_to_output *= m_nBitsPerSample; + if (!bits_to_output.IsValid()) + return false; + + FX_SAFE_INT32 bitpos = pos; + bitpos *= bits_to_output.ValueOrDie(); + if (!bitpos.IsValid()) + return false; + + FX_SAFE_INT32 range_check = bitpos; + range_check += bits_to_output.ValueOrDie(); + if (!range_check.IsValid()) + return false; + + const uint8_t* pSampleData = m_pSampleStream->GetData(); + if (!pSampleData) + return false; + + for (uint32_t j = 0; j < m_nOutputs; j++, bitpos += m_nBitsPerSample) { + uint32_t sample = + GetBits32(pSampleData, bitpos.ValueOrDie(), m_nBitsPerSample); + float encoded = (float)sample; + for (uint32_t i = 0; i < m_nInputs; i++) { + if (index[i] == m_EncodeInfo[i].sizes - 1) { + if (index[i] == 0) + encoded = encoded_input[i] * (float)sample; + } else { + FX_SAFE_INT32 bitpos2 = blocksize[i]; + bitpos2 += pos; + bitpos2 *= m_nOutputs; + bitpos2 += j; + bitpos2 *= m_nBitsPerSample; + if (!bitpos2.IsValid()) + return false; + uint32_t sample1 = + GetBits32(pSampleData, bitpos2.ValueOrDie(), m_nBitsPerSample); + encoded += + (encoded_input[i] - index[i]) * ((float)sample1 - (float)sample); + } + } + results[j] = + Interpolate(encoded, 0, (float)m_SampleMax, m_DecodeInfo[j].decode_min, + m_DecodeInfo[j].decode_max); + } + return true; +} |