summaryrefslogtreecommitdiff
path: root/core/fpdfapi/page/cpdf_sampledfunc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/fpdfapi/page/cpdf_sampledfunc.cpp')
-rw-r--r--core/fpdfapi/page/cpdf_sampledfunc.cpp156
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;
+}