2198 lines
76 KiB
C++
2198 lines
76 KiB
C++
|
|
// Copyright 2014 The PDFium Authors
|
||
|
|
// 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/fxcodec/progressive_decoder.h"
|
||
|
|
|
||
|
|
#include <algorithm>
|
||
|
|
#include <memory>
|
||
|
|
#include <utility>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
#include "build/build_config.h"
|
||
|
|
#include "core/fxcodec/cfx_codec_memory.h"
|
||
|
|
#include "core/fxcodec/jpeg/jpeg_progressive_decoder.h"
|
||
|
|
#include "core/fxcrt/fx_safe_types.h"
|
||
|
|
#include "core/fxcrt/fx_stream.h"
|
||
|
|
#include "core/fxcrt/fx_system.h"
|
||
|
|
#include "core/fxcrt/span_util.h"
|
||
|
|
#include "core/fxge/dib/cfx_cmyk_to_srgb.h"
|
||
|
|
#include "core/fxge/dib/cfx_dibitmap.h"
|
||
|
|
#include "core/fxge/dib/fx_dib.h"
|
||
|
|
#include "third_party/base/check.h"
|
||
|
|
#include "third_party/base/check_op.h"
|
||
|
|
#include "third_party/base/notreached.h"
|
||
|
|
#include "third_party/base/numerics/safe_conversions.h"
|
||
|
|
|
||
|
|
#ifdef PDF_ENABLE_XFA_BMP
|
||
|
|
#include "core/fxcodec/bmp/bmp_progressive_decoder.h"
|
||
|
|
#endif // PDF_ENABLE_XFA_BMP
|
||
|
|
|
||
|
|
#ifdef PDF_ENABLE_XFA_GIF
|
||
|
|
#include "core/fxcodec/gif/gif_progressive_decoder.h"
|
||
|
|
#endif // PDF_ENABLE_XFA_GIF
|
||
|
|
|
||
|
|
#ifdef PDF_ENABLE_XFA_TIFF
|
||
|
|
#include "core/fxcodec/tiff/tiff_decoder.h"
|
||
|
|
#endif // PDF_ENABLE_XFA_TIFF
|
||
|
|
|
||
|
|
namespace fxcodec {
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
constexpr size_t kBlockSize = 4096;
|
||
|
|
|
||
|
|
#ifdef PDF_ENABLE_XFA_PNG
|
||
|
|
#if BUILDFLAG(IS_APPLE)
|
||
|
|
const double kPngGamma = 1.7;
|
||
|
|
#else
|
||
|
|
const double kPngGamma = 2.2;
|
||
|
|
#endif // BUILDFLAG(IS_APPLE)
|
||
|
|
#endif // PDF_ENABLE_XFA_PNG
|
||
|
|
|
||
|
|
void RGB2BGR(uint8_t* buffer, int width = 1) {
|
||
|
|
if (buffer && width > 0) {
|
||
|
|
uint8_t temp;
|
||
|
|
int i = 0;
|
||
|
|
int j = 0;
|
||
|
|
for (; i < width; i++, j += 3) {
|
||
|
|
temp = buffer[j];
|
||
|
|
buffer[j] = buffer[j + 2];
|
||
|
|
buffer[j + 2] = temp;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
|
||
|
|
ProgressiveDecoder::HorzTable::HorzTable() = default;
|
||
|
|
|
||
|
|
ProgressiveDecoder::HorzTable::~HorzTable() = default;
|
||
|
|
|
||
|
|
void ProgressiveDecoder::HorzTable::CalculateWeights(int dest_len,
|
||
|
|
int src_len) {
|
||
|
|
CHECK_GE(dest_len, 0);
|
||
|
|
m_ItemSize =
|
||
|
|
pdfium::base::checked_cast<int>(PixelWeight::TotalBytesForWeightCount(2));
|
||
|
|
FX_SAFE_SIZE_T safe_size = m_ItemSize;
|
||
|
|
safe_size *= dest_len;
|
||
|
|
m_pWeightTables.resize(safe_size.ValueOrDie(), 0);
|
||
|
|
double scale = (double)dest_len / (double)src_len;
|
||
|
|
if (scale > 1) {
|
||
|
|
int pre_dest_col = 0;
|
||
|
|
for (int src_col = 0; src_col < src_len; src_col++) {
|
||
|
|
double dest_col_f = src_col * scale;
|
||
|
|
int dest_col = FXSYS_roundf((float)dest_col_f);
|
||
|
|
PixelWeight* pWeight = GetPixelWeight(dest_col);
|
||
|
|
pWeight->m_SrcStart = pWeight->m_SrcEnd = src_col;
|
||
|
|
pWeight->m_Weights[0] = CStretchEngine::kFixedPointOne;
|
||
|
|
pWeight->m_Weights[1] = 0;
|
||
|
|
if (src_col == src_len - 1 && dest_col < dest_len - 1) {
|
||
|
|
for (int dest_col_index = pre_dest_col + 1; dest_col_index < dest_len;
|
||
|
|
dest_col_index++) {
|
||
|
|
pWeight = GetPixelWeight(dest_col_index);
|
||
|
|
pWeight->m_SrcStart = pWeight->m_SrcEnd = src_col;
|
||
|
|
pWeight->m_Weights[0] = CStretchEngine::kFixedPointOne;
|
||
|
|
pWeight->m_Weights[1] = 0;
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
int dest_col_len = dest_col - pre_dest_col;
|
||
|
|
for (int dest_col_index = pre_dest_col + 1; dest_col_index < dest_col;
|
||
|
|
dest_col_index++) {
|
||
|
|
pWeight = GetPixelWeight(dest_col_index);
|
||
|
|
pWeight->m_SrcStart = src_col - 1;
|
||
|
|
pWeight->m_SrcEnd = src_col;
|
||
|
|
pWeight->m_Weights[0] = CStretchEngine::FixedFromFloat(
|
||
|
|
((float)dest_col - (float)dest_col_index) / (float)dest_col_len);
|
||
|
|
pWeight->m_Weights[1] =
|
||
|
|
CStretchEngine::kFixedPointOne - pWeight->m_Weights[0];
|
||
|
|
}
|
||
|
|
pre_dest_col = dest_col;
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
for (int dest_col = 0; dest_col < dest_len; dest_col++) {
|
||
|
|
double src_col_f = dest_col / scale;
|
||
|
|
int src_col = FXSYS_roundf((float)src_col_f);
|
||
|
|
PixelWeight* pWeight = GetPixelWeight(dest_col);
|
||
|
|
pWeight->m_SrcStart = pWeight->m_SrcEnd = src_col;
|
||
|
|
pWeight->m_Weights[0] = CStretchEngine::kFixedPointOne;
|
||
|
|
pWeight->m_Weights[1] = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
ProgressiveDecoder::VertTable::VertTable() = default;
|
||
|
|
|
||
|
|
ProgressiveDecoder::VertTable::~VertTable() = default;
|
||
|
|
|
||
|
|
void ProgressiveDecoder::VertTable::CalculateWeights(int dest_len,
|
||
|
|
int src_len) {
|
||
|
|
CHECK_GE(dest_len, 0);
|
||
|
|
m_ItemSize =
|
||
|
|
pdfium::base::checked_cast<int>(PixelWeight::TotalBytesForWeightCount(2));
|
||
|
|
FX_SAFE_SIZE_T safe_size = m_ItemSize;
|
||
|
|
safe_size *= dest_len;
|
||
|
|
m_pWeightTables.resize(safe_size.ValueOrDie(), 0);
|
||
|
|
double scale = (double)dest_len / (double)src_len;
|
||
|
|
if (scale <= 1) {
|
||
|
|
for (int dest_row = 0; dest_row < dest_len; dest_row++) {
|
||
|
|
PixelWeight* pWeight = GetPixelWeight(dest_row);
|
||
|
|
pWeight->m_SrcStart = dest_row;
|
||
|
|
pWeight->m_SrcEnd = dest_row;
|
||
|
|
pWeight->m_Weights[0] = CStretchEngine::kFixedPointOne;
|
||
|
|
pWeight->m_Weights[1] = 0;
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
double step = 0.0;
|
||
|
|
int src_row = 0;
|
||
|
|
while (step < (double)dest_len) {
|
||
|
|
int start_step = (int)step;
|
||
|
|
step = scale * (++src_row);
|
||
|
|
int end_step = (int)step;
|
||
|
|
if (end_step >= dest_len) {
|
||
|
|
end_step = dest_len;
|
||
|
|
for (int dest_row = start_step; dest_row < end_step; dest_row++) {
|
||
|
|
PixelWeight* pWeight = GetPixelWeight(dest_row);
|
||
|
|
pWeight->m_SrcStart = start_step;
|
||
|
|
pWeight->m_SrcEnd = start_step;
|
||
|
|
pWeight->m_Weights[0] = CStretchEngine::kFixedPointOne;
|
||
|
|
pWeight->m_Weights[1] = 0;
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
int length = end_step - start_step;
|
||
|
|
{
|
||
|
|
PixelWeight* pWeight = GetPixelWeight(start_step);
|
||
|
|
pWeight->m_SrcStart = start_step;
|
||
|
|
pWeight->m_SrcEnd = start_step;
|
||
|
|
pWeight->m_Weights[0] = CStretchEngine::kFixedPointOne;
|
||
|
|
pWeight->m_Weights[1] = 0;
|
||
|
|
}
|
||
|
|
for (int dest_row = start_step + 1; dest_row < end_step; dest_row++) {
|
||
|
|
PixelWeight* pWeight = GetPixelWeight(dest_row);
|
||
|
|
pWeight->m_SrcStart = start_step;
|
||
|
|
pWeight->m_SrcEnd = end_step;
|
||
|
|
pWeight->m_Weights[0] = CStretchEngine::FixedFromFloat(
|
||
|
|
(float)(end_step - dest_row) / (float)length);
|
||
|
|
pWeight->m_Weights[1] =
|
||
|
|
CStretchEngine::kFixedPointOne - pWeight->m_Weights[0];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
ProgressiveDecoder::ProgressiveDecoder() = default;
|
||
|
|
|
||
|
|
ProgressiveDecoder::~ProgressiveDecoder() = default;
|
||
|
|
|
||
|
|
#ifdef PDF_ENABLE_XFA_PNG
|
||
|
|
bool ProgressiveDecoder::PngReadHeader(int width,
|
||
|
|
int height,
|
||
|
|
int bpc,
|
||
|
|
int pass,
|
||
|
|
int* color_type,
|
||
|
|
double* gamma) {
|
||
|
|
if (!m_pDeviceBitmap) {
|
||
|
|
m_SrcWidth = width;
|
||
|
|
m_SrcHeight = height;
|
||
|
|
m_SrcBPC = bpc;
|
||
|
|
m_SrcPassNumber = pass;
|
||
|
|
switch (*color_type) {
|
||
|
|
case 0:
|
||
|
|
m_SrcComponents = 1;
|
||
|
|
break;
|
||
|
|
case 4:
|
||
|
|
m_SrcComponents = 2;
|
||
|
|
break;
|
||
|
|
case 2:
|
||
|
|
m_SrcComponents = 3;
|
||
|
|
break;
|
||
|
|
case 3:
|
||
|
|
case 6:
|
||
|
|
m_SrcComponents = 4;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
m_SrcComponents = 0;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
m_clipBox = FX_RECT(0, 0, width, height);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
FXDIB_Format format = m_pDeviceBitmap->GetFormat();
|
||
|
|
switch (format) {
|
||
|
|
case FXDIB_Format::k1bppMask:
|
||
|
|
case FXDIB_Format::k1bppRgb:
|
||
|
|
NOTREACHED_NORETURN();
|
||
|
|
case FXDIB_Format::k8bppMask:
|
||
|
|
case FXDIB_Format::k8bppRgb:
|
||
|
|
*color_type = 0;
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::kRgb:
|
||
|
|
*color_type = 2;
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::kRgb32:
|
||
|
|
case FXDIB_Format::kArgb:
|
||
|
|
*color_type = 6;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
NOTREACHED_NORETURN();
|
||
|
|
}
|
||
|
|
*gamma = kPngGamma;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ProgressiveDecoder::PngAskScanlineBuf(int line, uint8_t** pSrcBuf) {
|
||
|
|
RetainPtr<CFX_DIBitmap> pDIBitmap = m_pDeviceBitmap;
|
||
|
|
CHECK(pDIBitmap);
|
||
|
|
if (line < m_clipBox.top || line >= m_clipBox.bottom)
|
||
|
|
return true;
|
||
|
|
|
||
|
|
double scale_y = static_cast<double>(m_sizeY) / m_clipBox.Height();
|
||
|
|
int32_t row =
|
||
|
|
static_cast<int32_t>((line - m_clipBox.top) * scale_y) + m_startY;
|
||
|
|
*pSrcBuf = m_DecodeBuf.data();
|
||
|
|
int32_t src_Bpp = pDIBitmap->GetBPP() >> 3;
|
||
|
|
int32_t dest_Bpp = (m_SrcFormat & 0xff) >> 3;
|
||
|
|
int32_t src_left = m_startX;
|
||
|
|
int32_t dest_left = m_clipBox.left;
|
||
|
|
pdfium::span<const uint8_t> src_span =
|
||
|
|
pDIBitmap->GetScanline(row).subspan(src_left * src_Bpp);
|
||
|
|
pdfium::span<uint8_t> dest_span =
|
||
|
|
pdfium::make_span(m_DecodeBuf).subspan(dest_left * dest_Bpp);
|
||
|
|
const uint8_t* src_scan = src_span.data();
|
||
|
|
uint8_t* dest_scan = dest_span.data();
|
||
|
|
switch (pDIBitmap->GetFormat()) {
|
||
|
|
case FXDIB_Format::k1bppMask:
|
||
|
|
case FXDIB_Format::k1bppRgb:
|
||
|
|
for (int32_t src_col = 0; src_col < m_sizeX; src_col++) {
|
||
|
|
PixelWeight* pPixelWeights = m_WeightHorzOO.GetPixelWeight(src_col);
|
||
|
|
if (pPixelWeights->m_SrcStart != pPixelWeights->m_SrcEnd)
|
||
|
|
continue;
|
||
|
|
NOTREACHED_NORETURN();
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
case FXDIB_Format::k8bppMask:
|
||
|
|
case FXDIB_Format::k8bppRgb:
|
||
|
|
if (pDIBitmap->HasPalette())
|
||
|
|
return false;
|
||
|
|
for (int32_t src_col = 0; src_col < m_sizeX; src_col++) {
|
||
|
|
PixelWeight* pPixelWeights = m_WeightHorzOO.GetPixelWeight(src_col);
|
||
|
|
if (pPixelWeights->m_SrcStart != pPixelWeights->m_SrcEnd)
|
||
|
|
continue;
|
||
|
|
uint32_t dest_g = pPixelWeights->m_Weights[0] * src_scan[src_col];
|
||
|
|
dest_scan[pPixelWeights->m_SrcStart] =
|
||
|
|
CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
case FXDIB_Format::kRgb:
|
||
|
|
case FXDIB_Format::kRgb32:
|
||
|
|
for (int32_t src_col = 0; src_col < m_sizeX; src_col++) {
|
||
|
|
PixelWeight* pPixelWeights = m_WeightHorzOO.GetPixelWeight(src_col);
|
||
|
|
if (pPixelWeights->m_SrcStart != pPixelWeights->m_SrcEnd)
|
||
|
|
continue;
|
||
|
|
const uint8_t* p = src_scan + src_col * src_Bpp;
|
||
|
|
uint32_t dest_b = pPixelWeights->m_Weights[0] * (*p++);
|
||
|
|
uint32_t dest_g = pPixelWeights->m_Weights[0] * (*p++);
|
||
|
|
uint32_t dest_r = pPixelWeights->m_Weights[0] * (*p);
|
||
|
|
uint8_t* pDes = &dest_scan[pPixelWeights->m_SrcStart * dest_Bpp];
|
||
|
|
*pDes++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*pDes++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*pDes = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
case FXDIB_Format::kArgb:
|
||
|
|
for (int32_t src_col = 0; src_col < m_sizeX; src_col++) {
|
||
|
|
PixelWeight* pPixelWeights = m_WeightHorzOO.GetPixelWeight(src_col);
|
||
|
|
if (pPixelWeights->m_SrcStart != pPixelWeights->m_SrcEnd)
|
||
|
|
continue;
|
||
|
|
const uint8_t* p = src_scan + src_col * src_Bpp;
|
||
|
|
uint32_t dest_b = pPixelWeights->m_Weights[0] * (*p++);
|
||
|
|
uint32_t dest_g = pPixelWeights->m_Weights[0] * (*p++);
|
||
|
|
uint32_t dest_r = pPixelWeights->m_Weights[0] * (*p++);
|
||
|
|
uint8_t dest_a = *p;
|
||
|
|
uint8_t* pDes = &dest_scan[pPixelWeights->m_SrcStart * dest_Bpp];
|
||
|
|
*pDes++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*pDes++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*pDes++ = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
*pDes = dest_a;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
default:
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void ProgressiveDecoder::PngFillScanlineBufCompleted(int pass, int line) {
|
||
|
|
RetainPtr<CFX_DIBitmap> pDIBitmap = m_pDeviceBitmap;
|
||
|
|
DCHECK(pDIBitmap);
|
||
|
|
int src_top = m_clipBox.top;
|
||
|
|
int src_bottom = m_clipBox.bottom;
|
||
|
|
int dest_top = m_startY;
|
||
|
|
int src_height = m_clipBox.Height();
|
||
|
|
int dest_height = m_sizeY;
|
||
|
|
if (line >= src_top && line < src_bottom) {
|
||
|
|
double scale_y = static_cast<double>(dest_height) / src_height;
|
||
|
|
int src_row = line - src_top;
|
||
|
|
int dest_row = (int)(src_row * scale_y) + dest_top;
|
||
|
|
if (dest_row >= dest_top + dest_height) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
PngOneOneMapResampleHorz(pDIBitmap, dest_row, m_DecodeBuf, m_SrcFormat);
|
||
|
|
if (m_SrcPassNumber == 1 && scale_y > 1.0) {
|
||
|
|
ResampleVert(pDIBitmap, scale_y, dest_row);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (pass == 6 && scale_y > 1.0) {
|
||
|
|
ResampleVert(pDIBitmap, scale_y, dest_row);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif // PDF_ENABLE_XFA_PNG
|
||
|
|
|
||
|
|
#ifdef PDF_ENABLE_XFA_GIF
|
||
|
|
uint32_t ProgressiveDecoder::GifCurrentPosition() const {
|
||
|
|
uint32_t remain_size = pdfium::base::checked_cast<uint32_t>(
|
||
|
|
GifDecoder::GetAvailInput(m_pGifContext.get()));
|
||
|
|
return m_offSet - remain_size;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ProgressiveDecoder::GifInputRecordPositionBuf(uint32_t rcd_pos,
|
||
|
|
const FX_RECT& img_rc,
|
||
|
|
int32_t pal_num,
|
||
|
|
CFX_GifPalette* pal_ptr,
|
||
|
|
int32_t trans_index,
|
||
|
|
bool interlace) {
|
||
|
|
m_offSet = rcd_pos;
|
||
|
|
|
||
|
|
FXCODEC_STATUS error_status = FXCODEC_STATUS::kError;
|
||
|
|
m_pCodecMemory->Seek(m_pCodecMemory->GetSize());
|
||
|
|
if (!GifReadMoreData(&error_status))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
CFX_GifPalette* pPalette = nullptr;
|
||
|
|
if (pal_num != 0 && pal_ptr) {
|
||
|
|
pPalette = pal_ptr;
|
||
|
|
} else {
|
||
|
|
if (!m_pGifPalette)
|
||
|
|
return false;
|
||
|
|
pal_num = m_GifPltNumber;
|
||
|
|
pPalette = m_pGifPalette;
|
||
|
|
}
|
||
|
|
m_SrcPalette.resize(pal_num);
|
||
|
|
m_SrcPaletteNumber = pal_num;
|
||
|
|
for (int i = 0; i < pal_num; i++) {
|
||
|
|
m_SrcPalette[i] =
|
||
|
|
ArgbEncode(0xff, pPalette[i].r, pPalette[i].g, pPalette[i].b);
|
||
|
|
}
|
||
|
|
m_GifTransIndex = trans_index;
|
||
|
|
m_GifFrameRect = img_rc;
|
||
|
|
m_SrcPassNumber = interlace ? 4 : 1;
|
||
|
|
int32_t pal_index = m_GifBgIndex;
|
||
|
|
RetainPtr<CFX_DIBitmap> pDevice = m_pDeviceBitmap;
|
||
|
|
if (trans_index >= pal_num)
|
||
|
|
trans_index = -1;
|
||
|
|
if (trans_index != -1) {
|
||
|
|
m_SrcPalette[trans_index] &= 0x00ffffff;
|
||
|
|
if (pDevice->IsAlphaFormat())
|
||
|
|
pal_index = trans_index;
|
||
|
|
}
|
||
|
|
if (pal_index >= pal_num)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
int startX = m_startX;
|
||
|
|
int startY = m_startY;
|
||
|
|
int sizeX = m_sizeX;
|
||
|
|
int sizeY = m_sizeY;
|
||
|
|
int Bpp = pDevice->GetBPP() / 8;
|
||
|
|
FX_ARGB argb = m_SrcPalette[pal_index];
|
||
|
|
for (int row = 0; row < sizeY; row++) {
|
||
|
|
uint8_t* pScanline =
|
||
|
|
pDevice->GetWritableScanline(row + startY).subspan(startX * Bpp).data();
|
||
|
|
switch (m_TransMethod) {
|
||
|
|
case 3: {
|
||
|
|
uint8_t gray =
|
||
|
|
FXRGB2GRAY(FXARGB_R(argb), FXARGB_G(argb), FXARGB_B(argb));
|
||
|
|
memset(pScanline, gray, sizeX);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case 8: {
|
||
|
|
for (int col = 0; col < sizeX; col++) {
|
||
|
|
*pScanline++ = FXARGB_B(argb);
|
||
|
|
*pScanline++ = FXARGB_G(argb);
|
||
|
|
*pScanline++ = FXARGB_R(argb);
|
||
|
|
pScanline += Bpp - 3;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case 12: {
|
||
|
|
for (int col = 0; col < sizeX; col++) {
|
||
|
|
FXARGB_SETDIB(pScanline, argb);
|
||
|
|
pScanline += 4;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void ProgressiveDecoder::GifReadScanline(int32_t row_num,
|
||
|
|
pdfium::span<uint8_t> row_buf) {
|
||
|
|
RetainPtr<CFX_DIBitmap> pDIBitmap = m_pDeviceBitmap;
|
||
|
|
DCHECK(pDIBitmap);
|
||
|
|
int32_t img_width = m_GifFrameRect.Width();
|
||
|
|
if (!pDIBitmap->IsAlphaFormat()) {
|
||
|
|
pdfium::span<uint8_t> byte_span = row_buf;
|
||
|
|
for (int i = 0; i < img_width; i++) {
|
||
|
|
if (byte_span.front() == m_GifTransIndex) {
|
||
|
|
byte_span.front() = m_GifBgIndex;
|
||
|
|
}
|
||
|
|
byte_span = byte_span.subspan(1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
int32_t pal_index = m_GifBgIndex;
|
||
|
|
if (m_GifTransIndex != -1 && m_pDeviceBitmap->IsAlphaFormat()) {
|
||
|
|
pal_index = m_GifTransIndex;
|
||
|
|
}
|
||
|
|
const int32_t left = m_GifFrameRect.left;
|
||
|
|
const pdfium::span<uint8_t> decode_span = m_DecodeBuf;
|
||
|
|
fxcrt::spanset(decode_span.first(m_SrcWidth), pal_index);
|
||
|
|
fxcrt::spancpy(decode_span.subspan(left), row_buf.first(img_width));
|
||
|
|
|
||
|
|
bool bLastPass = (row_num % 2) == 1;
|
||
|
|
int32_t line = row_num + m_GifFrameRect.top;
|
||
|
|
int src_top = m_clipBox.top;
|
||
|
|
int src_bottom = m_clipBox.bottom;
|
||
|
|
int dest_top = m_startY;
|
||
|
|
int src_height = m_clipBox.Height();
|
||
|
|
int dest_height = m_sizeY;
|
||
|
|
if (line < src_top || line >= src_bottom)
|
||
|
|
return;
|
||
|
|
|
||
|
|
double scale_y = static_cast<double>(dest_height) / src_height;
|
||
|
|
int src_row = line - src_top;
|
||
|
|
int dest_row = (int)(src_row * scale_y) + dest_top;
|
||
|
|
if (dest_row >= dest_top + dest_height)
|
||
|
|
return;
|
||
|
|
|
||
|
|
ResampleScanline(pDIBitmap, dest_row, decode_span, m_SrcFormat);
|
||
|
|
if (scale_y > 1.0 && m_SrcPassNumber == 1) {
|
||
|
|
ResampleVert(pDIBitmap, scale_y, dest_row);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (scale_y <= 1.0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
int dest_bottom = dest_top + m_sizeY;
|
||
|
|
int dest_Bpp = pDIBitmap->GetBPP() >> 3;
|
||
|
|
uint32_t dest_ScanOffset = m_startX * dest_Bpp;
|
||
|
|
if (dest_row + (int)scale_y >= dest_bottom - 1) {
|
||
|
|
const uint8_t* scan_src =
|
||
|
|
pDIBitmap->GetScanline(dest_row).subspan(dest_ScanOffset).data();
|
||
|
|
int cur_row = dest_row;
|
||
|
|
while (++cur_row < dest_bottom) {
|
||
|
|
uint8_t* scan_des = pDIBitmap->GetWritableScanline(cur_row)
|
||
|
|
.subspan(dest_ScanOffset)
|
||
|
|
.data();
|
||
|
|
uint32_t size = m_sizeX * dest_Bpp;
|
||
|
|
memmove(scan_des, scan_src, size);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (bLastPass)
|
||
|
|
GifDoubleLineResampleVert(pDIBitmap, scale_y, dest_row);
|
||
|
|
}
|
||
|
|
#endif // PDF_ENABLE_XFA_GIF
|
||
|
|
|
||
|
|
#ifdef PDF_ENABLE_XFA_BMP
|
||
|
|
bool ProgressiveDecoder::BmpInputImagePositionBuf(uint32_t rcd_pos) {
|
||
|
|
m_offSet = rcd_pos;
|
||
|
|
FXCODEC_STATUS error_status = FXCODEC_STATUS::kError;
|
||
|
|
return BmpReadMoreData(m_pBmpContext.get(), &error_status);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ProgressiveDecoder::BmpReadScanline(uint32_t row_num,
|
||
|
|
pdfium::span<const uint8_t> row_buf) {
|
||
|
|
RetainPtr<CFX_DIBitmap> pDIBitmap = m_pDeviceBitmap;
|
||
|
|
DCHECK(pDIBitmap);
|
||
|
|
|
||
|
|
fxcrt::spancpy(pdfium::make_span(m_DecodeBuf), row_buf.first(m_ScanlineSize));
|
||
|
|
|
||
|
|
int src_top = m_clipBox.top;
|
||
|
|
int src_bottom = m_clipBox.bottom;
|
||
|
|
int dest_top = m_startY;
|
||
|
|
int src_height = m_clipBox.Height();
|
||
|
|
int dest_height = m_sizeY;
|
||
|
|
if ((src_top >= 0 && row_num < static_cast<uint32_t>(src_top)) ||
|
||
|
|
src_bottom < 0 || row_num >= static_cast<uint32_t>(src_bottom)) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
double scale_y = static_cast<double>(dest_height) / src_height;
|
||
|
|
int src_row = row_num - src_top;
|
||
|
|
int dest_row = (int)(src_row * scale_y) + dest_top;
|
||
|
|
if (dest_row >= dest_top + dest_height)
|
||
|
|
return;
|
||
|
|
|
||
|
|
ResampleScanline(pDIBitmap, dest_row, m_DecodeBuf, m_SrcFormat);
|
||
|
|
if (scale_y <= 1.0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
if (m_BmpIsTopBottom) {
|
||
|
|
ResampleVert(pDIBitmap, scale_y, dest_row);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
ResampleVertBT(pDIBitmap, scale_y, dest_row);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ProgressiveDecoder::ResampleVertBT(
|
||
|
|
const RetainPtr<CFX_DIBitmap>& pDeviceBitmap,
|
||
|
|
double scale_y,
|
||
|
|
int dest_row) {
|
||
|
|
int dest_Bpp = pDeviceBitmap->GetBPP() >> 3;
|
||
|
|
uint32_t dest_ScanOffset = m_startX * dest_Bpp;
|
||
|
|
int dest_top = m_startY;
|
||
|
|
int dest_bottom = m_startY + m_sizeY;
|
||
|
|
FX_SAFE_INT32 check_dest_row_1 = dest_row;
|
||
|
|
check_dest_row_1 += pdfium::base::checked_cast<int>(scale_y);
|
||
|
|
int dest_row_1 = check_dest_row_1.ValueOrDie();
|
||
|
|
if (dest_row_1 >= dest_bottom - 1) {
|
||
|
|
const uint8_t* scan_src =
|
||
|
|
pDeviceBitmap->GetScanline(dest_row).subspan(dest_ScanOffset).data();
|
||
|
|
while (++dest_row < dest_bottom) {
|
||
|
|
uint8_t* scan_des = pDeviceBitmap->GetWritableScanline(dest_row)
|
||
|
|
.subspan(dest_ScanOffset)
|
||
|
|
.data();
|
||
|
|
uint32_t size = m_sizeX * dest_Bpp;
|
||
|
|
memmove(scan_des, scan_src, size);
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
for (; dest_row_1 > dest_row; dest_row_1--) {
|
||
|
|
uint8_t* scan_des = pDeviceBitmap->GetWritableScanline(dest_row_1)
|
||
|
|
.subspan(dest_ScanOffset)
|
||
|
|
.data();
|
||
|
|
PixelWeight* pWeight = m_WeightVert.GetPixelWeight(dest_row_1 - dest_top);
|
||
|
|
const uint8_t* scan_src1 =
|
||
|
|
pDeviceBitmap->GetScanline(pWeight->m_SrcStart + dest_top)
|
||
|
|
.subspan(dest_ScanOffset)
|
||
|
|
.data();
|
||
|
|
const uint8_t* scan_src2 =
|
||
|
|
pDeviceBitmap->GetScanline(pWeight->m_SrcEnd + dest_top)
|
||
|
|
.subspan(dest_ScanOffset)
|
||
|
|
.data();
|
||
|
|
switch (pDeviceBitmap->GetFormat()) {
|
||
|
|
case FXDIB_Format::kInvalid:
|
||
|
|
case FXDIB_Format::k1bppMask:
|
||
|
|
case FXDIB_Format::k1bppRgb:
|
||
|
|
return;
|
||
|
|
case FXDIB_Format::k8bppMask:
|
||
|
|
case FXDIB_Format::k8bppRgb:
|
||
|
|
if (pDeviceBitmap->HasPalette())
|
||
|
|
return;
|
||
|
|
for (int dest_col = 0; dest_col < m_sizeX; dest_col++) {
|
||
|
|
uint32_t dest_g = 0;
|
||
|
|
dest_g += pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
dest_g += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::kRgb:
|
||
|
|
case FXDIB_Format::kRgb32:
|
||
|
|
for (int dest_col = 0; dest_col < m_sizeX; dest_col++) {
|
||
|
|
uint32_t dest_b = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
uint32_t dest_g = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
uint32_t dest_r = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
scan_src1 += dest_Bpp - 3;
|
||
|
|
dest_b += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
dest_g += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
dest_r += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
scan_src2 += dest_Bpp - 3;
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
scan_des += dest_Bpp - 3;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::kArgb:
|
||
|
|
for (int dest_col = 0; dest_col < m_sizeX; dest_col++) {
|
||
|
|
uint32_t dest_b = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
uint32_t dest_g = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
uint32_t dest_r = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
uint32_t dest_a = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
dest_b += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
dest_g += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
dest_r += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
dest_a += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_a);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ProgressiveDecoder::BmpDetectImageTypeInBuffer(
|
||
|
|
CFX_DIBAttribute* pAttribute) {
|
||
|
|
std::unique_ptr<ProgressiveDecoderIface::Context> pBmpContext =
|
||
|
|
BmpDecoder::StartDecode(this);
|
||
|
|
BmpDecoder::Input(pBmpContext.get(), m_pCodecMemory);
|
||
|
|
|
||
|
|
const std::vector<uint32_t>* palette;
|
||
|
|
BmpDecoder::Status read_result = BmpDecoder::ReadHeader(
|
||
|
|
pBmpContext.get(), &m_SrcWidth, &m_SrcHeight, &m_BmpIsTopBottom,
|
||
|
|
&m_SrcComponents, &m_SrcPaletteNumber, &palette, pAttribute);
|
||
|
|
while (read_result == BmpDecoder::Status::kContinue) {
|
||
|
|
FXCODEC_STATUS error_status = FXCODEC_STATUS::kError;
|
||
|
|
if (!BmpReadMoreData(pBmpContext.get(), &error_status)) {
|
||
|
|
m_status = error_status;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
read_result = BmpDecoder::ReadHeader(
|
||
|
|
pBmpContext.get(), &m_SrcWidth, &m_SrcHeight, &m_BmpIsTopBottom,
|
||
|
|
&m_SrcComponents, &m_SrcPaletteNumber, &palette, pAttribute);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (read_result != BmpDecoder::Status::kSuccess) {
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
FXDIB_Format format = FXDIB_Format::kInvalid;
|
||
|
|
switch (m_SrcComponents) {
|
||
|
|
case 1:
|
||
|
|
m_SrcFormat = FXCodec_8bppRgb;
|
||
|
|
format = FXDIB_Format::k8bppRgb;
|
||
|
|
break;
|
||
|
|
case 3:
|
||
|
|
m_SrcFormat = FXCodec_Rgb;
|
||
|
|
format = FXDIB_Format::kRgb;
|
||
|
|
break;
|
||
|
|
case 4:
|
||
|
|
m_SrcFormat = FXCodec_Rgb32;
|
||
|
|
format = FXDIB_Format::kRgb32;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Set to 0 to make CalculatePitchAndSize() calculate it.
|
||
|
|
constexpr uint32_t kNoPitch = 0;
|
||
|
|
absl::optional<CFX_DIBitmap::PitchAndSize> needed_data =
|
||
|
|
CFX_DIBitmap::CalculatePitchAndSize(m_SrcWidth, m_SrcHeight, format,
|
||
|
|
kNoPitch);
|
||
|
|
if (!needed_data.has_value()) {
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint32_t available_data = pdfium::base::checked_cast<uint32_t>(
|
||
|
|
m_pFile->GetSize() - m_offSet +
|
||
|
|
BmpDecoder::GetAvailInput(pBmpContext.get()));
|
||
|
|
if (needed_data.value().size > available_data) {
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_SrcBPC = 8;
|
||
|
|
m_clipBox = FX_RECT(0, 0, m_SrcWidth, m_SrcHeight);
|
||
|
|
m_pBmpContext = std::move(pBmpContext);
|
||
|
|
if (m_SrcPaletteNumber) {
|
||
|
|
m_SrcPalette.resize(m_SrcPaletteNumber);
|
||
|
|
memcpy(m_SrcPalette.data(), palette->data(),
|
||
|
|
m_SrcPaletteNumber * sizeof(FX_ARGB));
|
||
|
|
} else {
|
||
|
|
m_SrcPalette.clear();
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ProgressiveDecoder::BmpReadMoreData(
|
||
|
|
ProgressiveDecoderIface::Context* pContext,
|
||
|
|
FXCODEC_STATUS* err_status) {
|
||
|
|
return ReadMoreData(BmpProgressiveDecoder::GetInstance(), pContext,
|
||
|
|
err_status);
|
||
|
|
}
|
||
|
|
|
||
|
|
FXCODEC_STATUS ProgressiveDecoder::BmpStartDecode() {
|
||
|
|
GetTransMethod(m_pDeviceBitmap->GetFormat(), m_SrcFormat);
|
||
|
|
m_ScanlineSize = FxAlignToBoundary<4>(m_SrcWidth * m_SrcComponents);
|
||
|
|
m_DecodeBuf.resize(m_ScanlineSize);
|
||
|
|
FXDIB_ResampleOptions options;
|
||
|
|
options.bInterpolateBilinear = true;
|
||
|
|
m_WeightHorz.CalculateWeights(m_sizeX, 0, m_sizeX, m_clipBox.Width(), 0,
|
||
|
|
m_clipBox.Width(), options);
|
||
|
|
m_WeightVert.CalculateWeights(m_sizeY, m_clipBox.Height());
|
||
|
|
m_status = FXCODEC_STATUS::kDecodeToBeContinued;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
|
||
|
|
FXCODEC_STATUS ProgressiveDecoder::BmpContinueDecode() {
|
||
|
|
BmpDecoder::Status read_res = BmpDecoder::LoadImage(m_pBmpContext.get());
|
||
|
|
while (read_res == BmpDecoder::Status::kContinue) {
|
||
|
|
FXCODEC_STATUS error_status = FXCODEC_STATUS::kDecodeFinished;
|
||
|
|
if (!BmpReadMoreData(m_pBmpContext.get(), &error_status)) {
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = error_status;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
read_res = BmpDecoder::LoadImage(m_pBmpContext.get());
|
||
|
|
}
|
||
|
|
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = read_res == BmpDecoder::Status::kSuccess
|
||
|
|
? FXCODEC_STATUS::kDecodeFinished
|
||
|
|
: FXCODEC_STATUS::kError;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
#endif // PDF_ENABLE_XFA_BMP
|
||
|
|
|
||
|
|
#ifdef PDF_ENABLE_XFA_GIF
|
||
|
|
bool ProgressiveDecoder::GifReadMoreData(FXCODEC_STATUS* err_status) {
|
||
|
|
return ReadMoreData(GifProgressiveDecoder::GetInstance(), m_pGifContext.get(),
|
||
|
|
err_status);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ProgressiveDecoder::GifDetectImageTypeInBuffer() {
|
||
|
|
m_pGifContext = GifDecoder::StartDecode(this);
|
||
|
|
GifDecoder::Input(m_pGifContext.get(), m_pCodecMemory);
|
||
|
|
m_SrcComponents = 1;
|
||
|
|
GifDecoder::Status readResult =
|
||
|
|
GifDecoder::ReadHeader(m_pGifContext.get(), &m_SrcWidth, &m_SrcHeight,
|
||
|
|
&m_GifPltNumber, &m_pGifPalette, &m_GifBgIndex);
|
||
|
|
while (readResult == GifDecoder::Status::kUnfinished) {
|
||
|
|
FXCODEC_STATUS error_status = FXCODEC_STATUS::kError;
|
||
|
|
if (!GifReadMoreData(&error_status)) {
|
||
|
|
m_pGifContext = nullptr;
|
||
|
|
m_status = error_status;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
readResult =
|
||
|
|
GifDecoder::ReadHeader(m_pGifContext.get(), &m_SrcWidth, &m_SrcHeight,
|
||
|
|
&m_GifPltNumber, &m_pGifPalette, &m_GifBgIndex);
|
||
|
|
}
|
||
|
|
if (readResult == GifDecoder::Status::kSuccess) {
|
||
|
|
m_SrcBPC = 8;
|
||
|
|
m_clipBox = FX_RECT(0, 0, m_SrcWidth, m_SrcHeight);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
m_pGifContext = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
FXCODEC_STATUS ProgressiveDecoder::GifStartDecode() {
|
||
|
|
m_SrcFormat = FXCodec_8bppRgb;
|
||
|
|
GetTransMethod(m_pDeviceBitmap->GetFormat(), m_SrcFormat);
|
||
|
|
int scanline_size = FxAlignToBoundary<4>(m_SrcWidth);
|
||
|
|
m_DecodeBuf.resize(scanline_size);
|
||
|
|
FXDIB_ResampleOptions options;
|
||
|
|
options.bInterpolateBilinear = true;
|
||
|
|
m_WeightHorz.CalculateWeights(m_sizeX, 0, m_sizeX, m_clipBox.Width(), 0,
|
||
|
|
m_clipBox.Width(), options);
|
||
|
|
m_WeightVert.CalculateWeights(m_sizeY, m_clipBox.Height());
|
||
|
|
m_FrameCur = 0;
|
||
|
|
m_status = FXCODEC_STATUS::kDecodeToBeContinued;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
|
||
|
|
FXCODEC_STATUS ProgressiveDecoder::GifContinueDecode() {
|
||
|
|
GifDecoder::Status readRes =
|
||
|
|
GifDecoder::LoadFrame(m_pGifContext.get(), m_FrameCur);
|
||
|
|
while (readRes == GifDecoder::Status::kUnfinished) {
|
||
|
|
FXCODEC_STATUS error_status = FXCODEC_STATUS::kDecodeFinished;
|
||
|
|
if (!GifReadMoreData(&error_status)) {
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = error_status;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
readRes = GifDecoder::LoadFrame(m_pGifContext.get(), m_FrameCur);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (readRes == GifDecoder::Status::kSuccess) {
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kDecodeFinished;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
|
||
|
|
void ProgressiveDecoder::GifDoubleLineResampleVert(
|
||
|
|
const RetainPtr<CFX_DIBitmap>& pDeviceBitmap,
|
||
|
|
double scale_y,
|
||
|
|
int dest_row) {
|
||
|
|
int dest_Bpp = pDeviceBitmap->GetBPP() >> 3;
|
||
|
|
uint32_t dest_ScanOffset = m_startX * dest_Bpp;
|
||
|
|
int dest_top = m_startY;
|
||
|
|
pdfium::base::CheckedNumeric<double> scale_y2 = scale_y;
|
||
|
|
scale_y2 *= 2;
|
||
|
|
FX_SAFE_INT32 check_dest_row_1 = dest_row;
|
||
|
|
check_dest_row_1 -= scale_y2.ValueOrDie();
|
||
|
|
int dest_row_1 = check_dest_row_1.ValueOrDie();
|
||
|
|
dest_row_1 = std::max(dest_row_1, dest_top);
|
||
|
|
for (; dest_row_1 < dest_row; dest_row_1++) {
|
||
|
|
uint8_t* scan_des = pDeviceBitmap->GetWritableScanline(dest_row_1)
|
||
|
|
.subspan(dest_ScanOffset)
|
||
|
|
.data();
|
||
|
|
PixelWeight* pWeight = m_WeightVert.GetPixelWeight(dest_row_1 - dest_top);
|
||
|
|
const uint8_t* scan_src1 =
|
||
|
|
pDeviceBitmap->GetScanline(pWeight->m_SrcStart + dest_top)
|
||
|
|
.subspan(dest_ScanOffset)
|
||
|
|
.data();
|
||
|
|
const uint8_t* scan_src2 =
|
||
|
|
pDeviceBitmap->GetScanline(pWeight->m_SrcEnd + dest_top)
|
||
|
|
.subspan(dest_ScanOffset)
|
||
|
|
.data();
|
||
|
|
switch (pDeviceBitmap->GetFormat()) {
|
||
|
|
case FXDIB_Format::kInvalid:
|
||
|
|
case FXDIB_Format::k1bppMask:
|
||
|
|
case FXDIB_Format::k1bppRgb:
|
||
|
|
return;
|
||
|
|
case FXDIB_Format::k8bppMask:
|
||
|
|
case FXDIB_Format::k8bppRgb:
|
||
|
|
if (pDeviceBitmap->HasPalette())
|
||
|
|
return;
|
||
|
|
for (int dest_col = 0; dest_col < m_sizeX; dest_col++) {
|
||
|
|
uint32_t dest_g = 0;
|
||
|
|
dest_g += pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
dest_g += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::kRgb:
|
||
|
|
case FXDIB_Format::kRgb32:
|
||
|
|
for (int dest_col = 0; dest_col < m_sizeX; dest_col++) {
|
||
|
|
uint32_t dest_b = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
uint32_t dest_g = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
uint32_t dest_r = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
scan_src1 += dest_Bpp - 3;
|
||
|
|
dest_b += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
dest_g += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
dest_r += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
scan_src2 += dest_Bpp - 3;
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
scan_des += dest_Bpp - 3;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::kArgb:
|
||
|
|
for (int dest_col = 0; dest_col < m_sizeX; dest_col++) {
|
||
|
|
uint32_t dest_b = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
uint32_t dest_g = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
uint32_t dest_r = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
uint32_t dest_a = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
dest_b += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
dest_g += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
dest_r += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
dest_a += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_a);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
int dest_bottom = dest_top + m_sizeY - 1;
|
||
|
|
if (dest_row + (int)(2 * scale_y) >= dest_bottom &&
|
||
|
|
dest_row + (int)scale_y < dest_bottom) {
|
||
|
|
GifDoubleLineResampleVert(pDeviceBitmap, scale_y, dest_row + (int)scale_y);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif // PDF_ENABLE_XFA_GIF
|
||
|
|
|
||
|
|
bool ProgressiveDecoder::JpegReadMoreData(FXCODEC_STATUS* err_status) {
|
||
|
|
return ReadMoreData(JpegProgressiveDecoder::GetInstance(),
|
||
|
|
m_pJpegContext.get(), err_status);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ProgressiveDecoder::JpegDetectImageTypeInBuffer(
|
||
|
|
CFX_DIBAttribute* pAttribute) {
|
||
|
|
m_pJpegContext = JpegProgressiveDecoder::Start();
|
||
|
|
if (!m_pJpegContext) {
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
JpegProgressiveDecoder::GetInstance()->Input(m_pJpegContext.get(),
|
||
|
|
m_pCodecMemory);
|
||
|
|
|
||
|
|
// Setting jump marker before calling ReadHeader, since a longjmp to
|
||
|
|
// the marker indicates a fatal error.
|
||
|
|
if (setjmp(JpegProgressiveDecoder::GetJumpMark(m_pJpegContext.get())) == -1) {
|
||
|
|
m_pJpegContext.reset();
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t readResult = JpegProgressiveDecoder::ReadHeader(
|
||
|
|
m_pJpegContext.get(), &m_SrcWidth, &m_SrcHeight, &m_SrcComponents,
|
||
|
|
pAttribute);
|
||
|
|
while (readResult == 2) {
|
||
|
|
FXCODEC_STATUS error_status = FXCODEC_STATUS::kError;
|
||
|
|
if (!JpegReadMoreData(&error_status)) {
|
||
|
|
m_status = error_status;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
readResult = JpegProgressiveDecoder::ReadHeader(
|
||
|
|
m_pJpegContext.get(), &m_SrcWidth, &m_SrcHeight, &m_SrcComponents,
|
||
|
|
pAttribute);
|
||
|
|
}
|
||
|
|
if (!readResult) {
|
||
|
|
m_SrcBPC = 8;
|
||
|
|
m_clipBox = FX_RECT(0, 0, m_SrcWidth, m_SrcHeight);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
m_pJpegContext.reset();
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
FXCODEC_STATUS ProgressiveDecoder::JpegStartDecode(FXDIB_Format format) {
|
||
|
|
int down_scale = GetDownScale();
|
||
|
|
// Setting jump marker before calling StartScanLine, since a longjmp to
|
||
|
|
// the marker indicates a fatal error.
|
||
|
|
if (setjmp(JpegProgressiveDecoder::GetJumpMark(m_pJpegContext.get())) == -1) {
|
||
|
|
m_pJpegContext.reset();
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return FXCODEC_STATUS::kError;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool startStatus =
|
||
|
|
JpegProgressiveDecoder::StartScanline(m_pJpegContext.get(), down_scale);
|
||
|
|
while (!startStatus) {
|
||
|
|
FXCODEC_STATUS error_status = FXCODEC_STATUS::kError;
|
||
|
|
if (!JpegReadMoreData(&error_status)) {
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = error_status;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
|
||
|
|
startStatus =
|
||
|
|
JpegProgressiveDecoder::StartScanline(m_pJpegContext.get(), down_scale);
|
||
|
|
}
|
||
|
|
int scanline_size = (m_SrcWidth + down_scale - 1) / down_scale;
|
||
|
|
scanline_size = FxAlignToBoundary<4>(scanline_size * m_SrcComponents);
|
||
|
|
m_DecodeBuf.resize(scanline_size);
|
||
|
|
FXDIB_ResampleOptions options;
|
||
|
|
options.bInterpolateBilinear = true;
|
||
|
|
m_WeightHorz.CalculateWeights(m_sizeX, 0, m_sizeX, m_clipBox.Width(), 0,
|
||
|
|
m_clipBox.Width(), options);
|
||
|
|
m_WeightVert.CalculateWeights(m_sizeY, m_clipBox.Height());
|
||
|
|
switch (m_SrcComponents) {
|
||
|
|
case 1:
|
||
|
|
m_SrcFormat = FXCodec_8bppGray;
|
||
|
|
break;
|
||
|
|
case 3:
|
||
|
|
m_SrcFormat = FXCodec_Rgb;
|
||
|
|
break;
|
||
|
|
case 4:
|
||
|
|
m_SrcFormat = FXCodec_Cmyk;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
GetTransMethod(format, m_SrcFormat);
|
||
|
|
m_status = FXCODEC_STATUS::kDecodeToBeContinued;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
|
||
|
|
FXCODEC_STATUS ProgressiveDecoder::JpegContinueDecode() {
|
||
|
|
// JpegModule* pJpegModule = m_pCodecMgr->GetJpegModule();
|
||
|
|
// Setting jump marker before calling ReadScanLine, since a longjmp to
|
||
|
|
// the marker indicates a fatal error.
|
||
|
|
if (setjmp(JpegProgressiveDecoder::GetJumpMark(m_pJpegContext.get())) == -1) {
|
||
|
|
m_pJpegContext.reset();
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return FXCODEC_STATUS::kError;
|
||
|
|
}
|
||
|
|
|
||
|
|
while (true) {
|
||
|
|
bool readRes = JpegProgressiveDecoder::ReadScanline(m_pJpegContext.get(),
|
||
|
|
m_DecodeBuf.data());
|
||
|
|
while (!readRes) {
|
||
|
|
FXCODEC_STATUS error_status = FXCODEC_STATUS::kDecodeFinished;
|
||
|
|
if (!JpegReadMoreData(&error_status)) {
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = error_status;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
readRes = JpegProgressiveDecoder::ReadScanline(m_pJpegContext.get(),
|
||
|
|
m_DecodeBuf.data());
|
||
|
|
}
|
||
|
|
if (m_SrcFormat == FXCodec_Rgb) {
|
||
|
|
int src_Bpp = (m_SrcFormat & 0xff) >> 3;
|
||
|
|
RGB2BGR(m_DecodeBuf.data() + m_clipBox.left * src_Bpp, m_clipBox.Width());
|
||
|
|
}
|
||
|
|
if (m_SrcRow >= m_clipBox.bottom) {
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kDecodeFinished;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
Resample(m_pDeviceBitmap, m_SrcRow, m_DecodeBuf.data(), m_SrcFormat);
|
||
|
|
m_SrcRow++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef PDF_ENABLE_XFA_PNG
|
||
|
|
void ProgressiveDecoder::PngOneOneMapResampleHorz(
|
||
|
|
const RetainPtr<CFX_DIBitmap>& pDeviceBitmap,
|
||
|
|
int32_t dest_line,
|
||
|
|
pdfium::span<uint8_t> src_span,
|
||
|
|
FXCodec_Format src_format) {
|
||
|
|
int32_t src_Bpp = (m_SrcFormat & 0xff) >> 3;
|
||
|
|
int32_t dest_Bpp = pDeviceBitmap->GetBPP() >> 3;
|
||
|
|
int32_t src_left = m_clipBox.left;
|
||
|
|
int32_t dest_left = m_startX;
|
||
|
|
uint8_t* src_scan = src_span.subspan(src_left * src_Bpp).data();
|
||
|
|
uint8_t* dest_scan = pDeviceBitmap->GetWritableScanline(dest_line)
|
||
|
|
.subspan(dest_left * dest_Bpp)
|
||
|
|
.data();
|
||
|
|
switch (pDeviceBitmap->GetFormat()) {
|
||
|
|
case FXDIB_Format::k1bppMask:
|
||
|
|
case FXDIB_Format::k1bppRgb:
|
||
|
|
NOTREACHED_NORETURN();
|
||
|
|
case FXDIB_Format::k8bppMask:
|
||
|
|
case FXDIB_Format::k8bppRgb:
|
||
|
|
if (pDeviceBitmap->HasPalette())
|
||
|
|
return;
|
||
|
|
for (int32_t dest_col = 0; dest_col < m_sizeX; dest_col++) {
|
||
|
|
PixelWeight* pPixelWeights = m_WeightHorzOO.GetPixelWeight(dest_col);
|
||
|
|
uint32_t dest_g =
|
||
|
|
pPixelWeights->m_Weights[0] * src_scan[pPixelWeights->m_SrcStart];
|
||
|
|
dest_g +=
|
||
|
|
pPixelWeights->m_Weights[1] * src_scan[pPixelWeights->m_SrcEnd];
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::kRgb:
|
||
|
|
case FXDIB_Format::kRgb32:
|
||
|
|
for (int32_t dest_col = 0; dest_col < m_sizeX; dest_col++) {
|
||
|
|
PixelWeight* pPixelWeights = m_WeightHorzOO.GetPixelWeight(dest_col);
|
||
|
|
const uint8_t* p = src_scan + pPixelWeights->m_SrcStart * src_Bpp;
|
||
|
|
uint32_t dest_b = pPixelWeights->m_Weights[0] * (*p++);
|
||
|
|
uint32_t dest_g = pPixelWeights->m_Weights[0] * (*p++);
|
||
|
|
uint32_t dest_r = pPixelWeights->m_Weights[0] * (*p);
|
||
|
|
p = src_scan + pPixelWeights->m_SrcEnd * src_Bpp;
|
||
|
|
dest_b += pPixelWeights->m_Weights[1] * (*p++);
|
||
|
|
dest_g += pPixelWeights->m_Weights[1] * (*p++);
|
||
|
|
dest_r += pPixelWeights->m_Weights[1] * (*p);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
dest_scan += dest_Bpp - 3;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::kArgb:
|
||
|
|
for (int32_t dest_col = 0; dest_col < m_sizeX; dest_col++) {
|
||
|
|
PixelWeight* pPixelWeights = m_WeightHorzOO.GetPixelWeight(dest_col);
|
||
|
|
const uint8_t* p = src_scan + pPixelWeights->m_SrcStart * src_Bpp;
|
||
|
|
uint32_t dest_b = pPixelWeights->m_Weights[0] * (*p++);
|
||
|
|
uint32_t dest_g = pPixelWeights->m_Weights[0] * (*p++);
|
||
|
|
uint32_t dest_r = pPixelWeights->m_Weights[0] * (*p++);
|
||
|
|
uint32_t dest_a = pPixelWeights->m_Weights[0] * (*p);
|
||
|
|
p = src_scan + pPixelWeights->m_SrcEnd * src_Bpp;
|
||
|
|
dest_b += pPixelWeights->m_Weights[1] * (*p++);
|
||
|
|
dest_g += pPixelWeights->m_Weights[1] * (*p++);
|
||
|
|
dest_r += pPixelWeights->m_Weights[1] * (*p++);
|
||
|
|
dest_a += pPixelWeights->m_Weights[1] * (*p);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_a);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ProgressiveDecoder::PngDetectImageTypeInBuffer(
|
||
|
|
CFX_DIBAttribute* pAttribute) {
|
||
|
|
m_pPngContext = PngDecoder::StartDecode(this);
|
||
|
|
if (!m_pPngContext) {
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
while (PngDecoder::ContinueDecode(m_pPngContext.get(), m_pCodecMemory,
|
||
|
|
pAttribute)) {
|
||
|
|
uint32_t remain_size = static_cast<uint32_t>(m_pFile->GetSize()) - m_offSet;
|
||
|
|
uint32_t input_size = std::min<uint32_t>(remain_size, kBlockSize);
|
||
|
|
if (input_size == 0) {
|
||
|
|
m_pPngContext.reset();
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (m_pCodecMemory && input_size > m_pCodecMemory->GetSize())
|
||
|
|
m_pCodecMemory = pdfium::MakeRetain<CFX_CodecMemory>(input_size);
|
||
|
|
|
||
|
|
if (!m_pFile->ReadBlockAtOffset(
|
||
|
|
m_pCodecMemory->GetBufferSpan().first(input_size), m_offSet)) {
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
m_offSet += input_size;
|
||
|
|
}
|
||
|
|
m_pPngContext.reset();
|
||
|
|
if (m_SrcPassNumber == 0) {
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
FXCODEC_STATUS ProgressiveDecoder::PngStartDecode() {
|
||
|
|
m_pPngContext = PngDecoder::StartDecode(this);
|
||
|
|
if (!m_pPngContext) {
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
m_offSet = 0;
|
||
|
|
switch (m_pDeviceBitmap->GetFormat()) {
|
||
|
|
case FXDIB_Format::k8bppMask:
|
||
|
|
case FXDIB_Format::k8bppRgb:
|
||
|
|
m_SrcComponents = 1;
|
||
|
|
m_SrcFormat = FXCodec_8bppGray;
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::kRgb:
|
||
|
|
m_SrcComponents = 3;
|
||
|
|
m_SrcFormat = FXCodec_Rgb;
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::kRgb32:
|
||
|
|
case FXDIB_Format::kArgb:
|
||
|
|
m_SrcComponents = 4;
|
||
|
|
m_SrcFormat = FXCodec_Argb;
|
||
|
|
break;
|
||
|
|
default: {
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
GetTransMethod(m_pDeviceBitmap->GetFormat(), m_SrcFormat);
|
||
|
|
int scanline_size = FxAlignToBoundary<4>(m_SrcWidth * m_SrcComponents);
|
||
|
|
m_DecodeBuf.resize(scanline_size);
|
||
|
|
m_WeightHorzOO.CalculateWeights(m_sizeX, m_clipBox.Width());
|
||
|
|
m_WeightVert.CalculateWeights(m_sizeY, m_clipBox.Height());
|
||
|
|
m_status = FXCODEC_STATUS::kDecodeToBeContinued;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
|
||
|
|
FXCODEC_STATUS ProgressiveDecoder::PngContinueDecode() {
|
||
|
|
while (true) {
|
||
|
|
uint32_t remain_size = (uint32_t)m_pFile->GetSize() - m_offSet;
|
||
|
|
uint32_t input_size = std::min<uint32_t>(remain_size, kBlockSize);
|
||
|
|
if (input_size == 0) {
|
||
|
|
m_pPngContext.reset();
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kDecodeFinished;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
if (m_pCodecMemory && input_size > m_pCodecMemory->GetSize())
|
||
|
|
m_pCodecMemory = pdfium::MakeRetain<CFX_CodecMemory>(input_size);
|
||
|
|
|
||
|
|
bool bResult = m_pFile->ReadBlockAtOffset(
|
||
|
|
m_pCodecMemory->GetBufferSpan().first(input_size), m_offSet);
|
||
|
|
if (!bResult) {
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
m_offSet += input_size;
|
||
|
|
bResult = PngDecoder::ContinueDecode(m_pPngContext.get(), m_pCodecMemory,
|
||
|
|
nullptr);
|
||
|
|
if (!bResult) {
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif // PDF_ENABLE_XFA_PNG
|
||
|
|
|
||
|
|
#ifdef PDF_ENABLE_XFA_TIFF
|
||
|
|
bool ProgressiveDecoder::TiffDetectImageTypeFromFile(
|
||
|
|
CFX_DIBAttribute* pAttribute) {
|
||
|
|
m_pTiffContext = TiffDecoder::CreateDecoder(m_pFile);
|
||
|
|
if (!m_pTiffContext) {
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
int32_t dummy_bpc;
|
||
|
|
bool ret = TiffDecoder::LoadFrameInfo(m_pTiffContext.get(), 0, &m_SrcWidth,
|
||
|
|
&m_SrcHeight, &m_SrcComponents,
|
||
|
|
&dummy_bpc, pAttribute);
|
||
|
|
m_SrcComponents = 4;
|
||
|
|
m_clipBox = FX_RECT(0, 0, m_SrcWidth, m_SrcHeight);
|
||
|
|
if (!ret) {
|
||
|
|
m_pTiffContext.reset();
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
FXCODEC_STATUS ProgressiveDecoder::TiffContinueDecode() {
|
||
|
|
bool ret = false;
|
||
|
|
if (m_pDeviceBitmap->GetBPP() == 32 &&
|
||
|
|
m_pDeviceBitmap->GetWidth() == m_SrcWidth && m_SrcWidth == m_sizeX &&
|
||
|
|
m_pDeviceBitmap->GetHeight() == m_SrcHeight && m_SrcHeight == m_sizeY &&
|
||
|
|
m_startX == 0 && m_startY == 0 && m_clipBox.left == 0 &&
|
||
|
|
m_clipBox.top == 0 && m_clipBox.right == m_SrcWidth &&
|
||
|
|
m_clipBox.bottom == m_SrcHeight) {
|
||
|
|
ret = TiffDecoder::Decode(m_pTiffContext.get(), m_pDeviceBitmap);
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
if (!ret) {
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
m_status = FXCODEC_STATUS::kDecodeFinished;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
|
||
|
|
auto pDIBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
|
||
|
|
pDIBitmap->Create(m_SrcWidth, m_SrcHeight, FXDIB_Format::kArgb);
|
||
|
|
if (pDIBitmap->GetBuffer().empty()) {
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
ret = TiffDecoder::Decode(m_pTiffContext.get(), pDIBitmap);
|
||
|
|
if (!ret) {
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
RetainPtr<CFX_DIBitmap> pClipBitmap =
|
||
|
|
(m_clipBox.left == 0 && m_clipBox.top == 0 &&
|
||
|
|
m_clipBox.right == m_SrcWidth && m_clipBox.bottom == m_SrcHeight)
|
||
|
|
? pDIBitmap
|
||
|
|
: pDIBitmap->ClipTo(m_clipBox);
|
||
|
|
if (!pClipBitmap) {
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
RetainPtr<CFX_DIBitmap> pFormatBitmap;
|
||
|
|
switch (m_pDeviceBitmap->GetFormat()) {
|
||
|
|
case FXDIB_Format::k8bppRgb:
|
||
|
|
pFormatBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
|
||
|
|
pFormatBitmap->Create(pClipBitmap->GetWidth(), pClipBitmap->GetHeight(),
|
||
|
|
FXDIB_Format::k8bppRgb);
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::k8bppMask:
|
||
|
|
pFormatBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
|
||
|
|
pFormatBitmap->Create(pClipBitmap->GetWidth(), pClipBitmap->GetHeight(),
|
||
|
|
FXDIB_Format::k8bppMask);
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::kRgb:
|
||
|
|
pFormatBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
|
||
|
|
pFormatBitmap->Create(pClipBitmap->GetWidth(), pClipBitmap->GetHeight(),
|
||
|
|
FXDIB_Format::kRgb);
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::kRgb32:
|
||
|
|
pFormatBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
|
||
|
|
pFormatBitmap->Create(pClipBitmap->GetWidth(), pClipBitmap->GetHeight(),
|
||
|
|
FXDIB_Format::kRgb32);
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::kArgb:
|
||
|
|
pFormatBitmap = pClipBitmap;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
switch (m_pDeviceBitmap->GetFormat()) {
|
||
|
|
case FXDIB_Format::k8bppRgb:
|
||
|
|
case FXDIB_Format::k8bppMask: {
|
||
|
|
for (int32_t row = 0; row < pClipBitmap->GetHeight(); row++) {
|
||
|
|
const uint8_t* src_line = pClipBitmap->GetScanline(row).data();
|
||
|
|
uint8_t* dest_line = pFormatBitmap->GetWritableScanline(row).data();
|
||
|
|
for (int32_t col = 0; col < pClipBitmap->GetWidth(); col++) {
|
||
|
|
uint8_t _a = 255 - src_line[3];
|
||
|
|
uint8_t b = (src_line[0] * src_line[3] + 0xFF * _a) / 255;
|
||
|
|
uint8_t g = (src_line[1] * src_line[3] + 0xFF * _a) / 255;
|
||
|
|
uint8_t r = (src_line[2] * src_line[3] + 0xFF * _a) / 255;
|
||
|
|
*dest_line++ = FXRGB2GRAY(r, g, b);
|
||
|
|
src_line += 4;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} break;
|
||
|
|
case FXDIB_Format::kRgb:
|
||
|
|
case FXDIB_Format::kRgb32: {
|
||
|
|
int32_t desBpp =
|
||
|
|
(m_pDeviceBitmap->GetFormat() == FXDIB_Format::kRgb) ? 3 : 4;
|
||
|
|
for (int32_t row = 0; row < pClipBitmap->GetHeight(); row++) {
|
||
|
|
const uint8_t* src_line = pClipBitmap->GetScanline(row).data();
|
||
|
|
uint8_t* dest_line = pFormatBitmap->GetWritableScanline(row).data();
|
||
|
|
for (int32_t col = 0; col < pClipBitmap->GetWidth(); col++) {
|
||
|
|
uint8_t _a = 255 - src_line[3];
|
||
|
|
uint8_t b = (src_line[0] * src_line[3] + 0xFF * _a) / 255;
|
||
|
|
uint8_t g = (src_line[1] * src_line[3] + 0xFF * _a) / 255;
|
||
|
|
uint8_t r = (src_line[2] * src_line[3] + 0xFF * _a) / 255;
|
||
|
|
*dest_line++ = b;
|
||
|
|
*dest_line++ = g;
|
||
|
|
*dest_line++ = r;
|
||
|
|
dest_line += desBpp - 3;
|
||
|
|
src_line += 4;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} break;
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if (!pFormatBitmap) {
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
|
||
|
|
FXDIB_ResampleOptions options;
|
||
|
|
options.bInterpolateBilinear = true;
|
||
|
|
RetainPtr<CFX_DIBitmap> pStrechBitmap =
|
||
|
|
pFormatBitmap->StretchTo(m_sizeX, m_sizeY, options, nullptr);
|
||
|
|
pFormatBitmap = nullptr;
|
||
|
|
if (!pStrechBitmap) {
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
m_pDeviceBitmap->TransferBitmap(m_startX, m_startY, m_sizeX, m_sizeY,
|
||
|
|
pStrechBitmap, 0, 0);
|
||
|
|
m_pDeviceBitmap = nullptr;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kDecodeFinished;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
#endif // PDF_ENABLE_XFA_TIFF
|
||
|
|
|
||
|
|
bool ProgressiveDecoder::DetectImageType(FXCODEC_IMAGE_TYPE imageType,
|
||
|
|
CFX_DIBAttribute* pAttribute) {
|
||
|
|
#ifdef PDF_ENABLE_XFA_TIFF
|
||
|
|
if (imageType == FXCODEC_IMAGE_TIFF)
|
||
|
|
return TiffDetectImageTypeFromFile(pAttribute);
|
||
|
|
#endif // PDF_ENABLE_XFA_TIFF
|
||
|
|
|
||
|
|
size_t size = pdfium::base::checked_cast<size_t>(
|
||
|
|
std::min<FX_FILESIZE>(m_pFile->GetSize(), kBlockSize));
|
||
|
|
m_pCodecMemory = pdfium::MakeRetain<CFX_CodecMemory>(size);
|
||
|
|
m_offSet = 0;
|
||
|
|
if (!m_pFile->ReadBlockAtOffset(m_pCodecMemory->GetBufferSpan().first(size),
|
||
|
|
m_offSet)) {
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
m_offSet += size;
|
||
|
|
|
||
|
|
if (imageType == FXCODEC_IMAGE_JPG)
|
||
|
|
return JpegDetectImageTypeInBuffer(pAttribute);
|
||
|
|
|
||
|
|
#ifdef PDF_ENABLE_XFA_BMP
|
||
|
|
if (imageType == FXCODEC_IMAGE_BMP)
|
||
|
|
return BmpDetectImageTypeInBuffer(pAttribute);
|
||
|
|
#endif // PDF_ENABLE_XFA_BMP
|
||
|
|
|
||
|
|
#ifdef PDF_ENABLE_XFA_GIF
|
||
|
|
if (imageType == FXCODEC_IMAGE_GIF)
|
||
|
|
return GifDetectImageTypeInBuffer();
|
||
|
|
#endif // PDF_ENABLE_XFA_GIF
|
||
|
|
|
||
|
|
#ifdef PDF_ENABLE_XFA_PNG
|
||
|
|
if (imageType == FXCODEC_IMAGE_PNG)
|
||
|
|
return PngDetectImageTypeInBuffer(pAttribute);
|
||
|
|
#endif // PDF_ENABLE_XFA_PNG
|
||
|
|
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ProgressiveDecoder::ReadMoreData(
|
||
|
|
ProgressiveDecoderIface* pModule,
|
||
|
|
ProgressiveDecoderIface::Context* pContext,
|
||
|
|
FXCODEC_STATUS* err_status) {
|
||
|
|
// Check for EOF.
|
||
|
|
if (m_offSet >= static_cast<uint32_t>(m_pFile->GetSize()))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
// Try to get whatever remains.
|
||
|
|
uint32_t dwBytesToFetchFromFile =
|
||
|
|
pdfium::base::checked_cast<uint32_t>(m_pFile->GetSize() - m_offSet);
|
||
|
|
|
||
|
|
// Figure out if the codec stopped processing midway through the buffer.
|
||
|
|
size_t dwUnconsumed;
|
||
|
|
FX_SAFE_SIZE_T avail_input = pModule->GetAvailInput(pContext);
|
||
|
|
if (!avail_input.AssignIfValid(&dwUnconsumed))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
if (dwUnconsumed == m_pCodecMemory->GetSize()) {
|
||
|
|
// Codec couldn't make any progress against the bytes in the buffer.
|
||
|
|
// Increase the buffer size so that there might be enough contiguous
|
||
|
|
// bytes to allow whatever operation is having difficulty to succeed.
|
||
|
|
dwBytesToFetchFromFile =
|
||
|
|
std::min<uint32_t>(dwBytesToFetchFromFile, kBlockSize);
|
||
|
|
size_t dwNewSize = m_pCodecMemory->GetSize() + dwBytesToFetchFromFile;
|
||
|
|
if (!m_pCodecMemory->TryResize(dwNewSize)) {
|
||
|
|
*err_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
// TODO(crbug.com/pdfium/1904): Simplify the `CFX_CodecMemory` API so we
|
||
|
|
// don't need to do this awkward dance to free up exactly enough buffer
|
||
|
|
// space for the next read.
|
||
|
|
size_t dwConsumable = m_pCodecMemory->GetSize() - dwUnconsumed;
|
||
|
|
dwBytesToFetchFromFile = pdfium::base::checked_cast<uint32_t>(
|
||
|
|
std::min<size_t>(dwBytesToFetchFromFile, dwConsumable));
|
||
|
|
m_pCodecMemory->Consume(dwBytesToFetchFromFile);
|
||
|
|
m_pCodecMemory->Seek(dwConsumable - dwBytesToFetchFromFile);
|
||
|
|
dwUnconsumed += m_pCodecMemory->GetPosition();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Append new data past the bytes not yet processed by the codec.
|
||
|
|
if (!m_pFile->ReadBlockAtOffset(m_pCodecMemory->GetBufferSpan().subspan(
|
||
|
|
dwUnconsumed, dwBytesToFetchFromFile),
|
||
|
|
m_offSet)) {
|
||
|
|
*err_status = FXCODEC_STATUS::kError;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
m_offSet += dwBytesToFetchFromFile;
|
||
|
|
return pModule->Input(pContext, m_pCodecMemory);
|
||
|
|
}
|
||
|
|
|
||
|
|
FXCODEC_STATUS ProgressiveDecoder::LoadImageInfo(
|
||
|
|
RetainPtr<IFX_SeekableReadStream> pFile,
|
||
|
|
FXCODEC_IMAGE_TYPE imageType,
|
||
|
|
CFX_DIBAttribute* pAttribute,
|
||
|
|
bool bSkipImageTypeCheck) {
|
||
|
|
DCHECK(pAttribute);
|
||
|
|
|
||
|
|
switch (m_status) {
|
||
|
|
case FXCODEC_STATUS::kFrameReady:
|
||
|
|
case FXCODEC_STATUS::kFrameToBeContinued:
|
||
|
|
case FXCODEC_STATUS::kDecodeReady:
|
||
|
|
case FXCODEC_STATUS::kDecodeToBeContinued:
|
||
|
|
return FXCODEC_STATUS::kError;
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
m_pFile = std::move(pFile);
|
||
|
|
if (!m_pFile) {
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
m_offSet = 0;
|
||
|
|
m_SrcWidth = m_SrcHeight = 0;
|
||
|
|
m_SrcComponents = m_SrcBPC = 0;
|
||
|
|
m_clipBox = FX_RECT();
|
||
|
|
m_startX = m_startY = 0;
|
||
|
|
m_sizeX = m_sizeY = 0;
|
||
|
|
m_SrcPassNumber = 0;
|
||
|
|
if (imageType != FXCODEC_IMAGE_UNKNOWN &&
|
||
|
|
DetectImageType(imageType, pAttribute)) {
|
||
|
|
m_imageType = imageType;
|
||
|
|
m_status = FXCODEC_STATUS::kFrameReady;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
// If we got here then the image data does not match the requested decoder.
|
||
|
|
// If we're skipping the type check then bail out at this point and return
|
||
|
|
// the failed status.
|
||
|
|
if (bSkipImageTypeCheck)
|
||
|
|
return m_status;
|
||
|
|
|
||
|
|
for (int type = FXCODEC_IMAGE_UNKNOWN + 1; type < FXCODEC_IMAGE_MAX; type++) {
|
||
|
|
if (DetectImageType(static_cast<FXCODEC_IMAGE_TYPE>(type), pAttribute)) {
|
||
|
|
m_imageType = static_cast<FXCODEC_IMAGE_TYPE>(type);
|
||
|
|
m_status = FXCODEC_STATUS::kFrameReady;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
m_pFile = nullptr;
|
||
|
|
return m_status;
|
||
|
|
}
|
||
|
|
|
||
|
|
void ProgressiveDecoder::SetClipBox(FX_RECT* clip) {
|
||
|
|
if (m_status != FXCODEC_STATUS::kFrameReady)
|
||
|
|
return;
|
||
|
|
|
||
|
|
if (clip->IsEmpty()) {
|
||
|
|
m_clipBox = FX_RECT();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
clip->left = std::max(clip->left, 0);
|
||
|
|
clip->right = std::min(clip->right, m_SrcWidth);
|
||
|
|
clip->top = std::max(clip->top, 0);
|
||
|
|
clip->bottom = std::min(clip->bottom, m_SrcHeight);
|
||
|
|
if (clip->IsEmpty()) {
|
||
|
|
m_clipBox = FX_RECT();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
m_clipBox = *clip;
|
||
|
|
}
|
||
|
|
|
||
|
|
int ProgressiveDecoder::GetDownScale() {
|
||
|
|
int down_scale = 1;
|
||
|
|
int ratio_w = m_clipBox.Width() / m_sizeX;
|
||
|
|
int ratio_h = m_clipBox.Height() / m_sizeY;
|
||
|
|
int ratio = std::min(ratio_w, ratio_h);
|
||
|
|
if (ratio >= 8)
|
||
|
|
down_scale = 8;
|
||
|
|
else if (ratio >= 4)
|
||
|
|
down_scale = 4;
|
||
|
|
else if (ratio >= 2)
|
||
|
|
down_scale = 2;
|
||
|
|
|
||
|
|
m_clipBox.left /= down_scale;
|
||
|
|
m_clipBox.right /= down_scale;
|
||
|
|
m_clipBox.top /= down_scale;
|
||
|
|
m_clipBox.bottom /= down_scale;
|
||
|
|
if (m_clipBox.right == m_clipBox.left)
|
||
|
|
m_clipBox.right = m_clipBox.left + 1;
|
||
|
|
if (m_clipBox.bottom == m_clipBox.top)
|
||
|
|
m_clipBox.bottom = m_clipBox.top + 1;
|
||
|
|
return down_scale;
|
||
|
|
}
|
||
|
|
|
||
|
|
void ProgressiveDecoder::GetTransMethod(FXDIB_Format dest_format,
|
||
|
|
FXCodec_Format src_format) {
|
||
|
|
switch (dest_format) {
|
||
|
|
case FXDIB_Format::k1bppMask:
|
||
|
|
case FXDIB_Format::k1bppRgb: {
|
||
|
|
switch (src_format) {
|
||
|
|
case FXCodec_1bppGray:
|
||
|
|
m_TransMethod = 0;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
m_TransMethod = -1;
|
||
|
|
}
|
||
|
|
} break;
|
||
|
|
case FXDIB_Format::k8bppMask:
|
||
|
|
case FXDIB_Format::k8bppRgb: {
|
||
|
|
switch (src_format) {
|
||
|
|
case FXCodec_1bppGray:
|
||
|
|
m_TransMethod = 1;
|
||
|
|
break;
|
||
|
|
case FXCodec_8bppGray:
|
||
|
|
m_TransMethod = 2;
|
||
|
|
break;
|
||
|
|
case FXCodec_1bppRgb:
|
||
|
|
case FXCodec_8bppRgb:
|
||
|
|
m_TransMethod = 3;
|
||
|
|
break;
|
||
|
|
case FXCodec_Rgb:
|
||
|
|
case FXCodec_Rgb32:
|
||
|
|
case FXCodec_Argb:
|
||
|
|
m_TransMethod = 4;
|
||
|
|
break;
|
||
|
|
case FXCodec_Cmyk:
|
||
|
|
m_TransMethod = 5;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
m_TransMethod = -1;
|
||
|
|
}
|
||
|
|
} break;
|
||
|
|
case FXDIB_Format::kRgb: {
|
||
|
|
switch (src_format) {
|
||
|
|
case FXCodec_1bppGray:
|
||
|
|
m_TransMethod = 6;
|
||
|
|
break;
|
||
|
|
case FXCodec_8bppGray:
|
||
|
|
m_TransMethod = 7;
|
||
|
|
break;
|
||
|
|
case FXCodec_1bppRgb:
|
||
|
|
case FXCodec_8bppRgb:
|
||
|
|
m_TransMethod = 8;
|
||
|
|
break;
|
||
|
|
case FXCodec_Rgb:
|
||
|
|
case FXCodec_Rgb32:
|
||
|
|
case FXCodec_Argb:
|
||
|
|
m_TransMethod = 9;
|
||
|
|
break;
|
||
|
|
case FXCodec_Cmyk:
|
||
|
|
m_TransMethod = 10;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
m_TransMethod = -1;
|
||
|
|
}
|
||
|
|
} break;
|
||
|
|
case FXDIB_Format::kRgb32:
|
||
|
|
case FXDIB_Format::kArgb: {
|
||
|
|
switch (src_format) {
|
||
|
|
case FXCodec_1bppGray:
|
||
|
|
m_TransMethod = 6;
|
||
|
|
break;
|
||
|
|
case FXCodec_8bppGray:
|
||
|
|
m_TransMethod = 7;
|
||
|
|
break;
|
||
|
|
case FXCodec_1bppRgb:
|
||
|
|
case FXCodec_8bppRgb:
|
||
|
|
if (dest_format == FXDIB_Format::kArgb) {
|
||
|
|
m_TransMethod = 12;
|
||
|
|
} else {
|
||
|
|
m_TransMethod = 8;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case FXCodec_Rgb:
|
||
|
|
case FXCodec_Rgb32:
|
||
|
|
m_TransMethod = 9;
|
||
|
|
break;
|
||
|
|
case FXCodec_Cmyk:
|
||
|
|
m_TransMethod = 10;
|
||
|
|
break;
|
||
|
|
case FXCodec_Argb:
|
||
|
|
m_TransMethod = 11;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
m_TransMethod = -1;
|
||
|
|
}
|
||
|
|
} break;
|
||
|
|
default:
|
||
|
|
m_TransMethod = -1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void ProgressiveDecoder::ResampleScanline(
|
||
|
|
const RetainPtr<CFX_DIBitmap>& pDeviceBitmap,
|
||
|
|
int dest_line,
|
||
|
|
pdfium::span<uint8_t> src_span,
|
||
|
|
FXCodec_Format src_format) {
|
||
|
|
uint8_t* src_scan = src_span.data();
|
||
|
|
int src_left = m_clipBox.left;
|
||
|
|
int dest_left = m_startX;
|
||
|
|
uint8_t* dest_scan = pDeviceBitmap->GetWritableScanline(dest_line).data();
|
||
|
|
int src_bytes_per_pixel = (src_format & 0xff) / 8;
|
||
|
|
int dest_bytes_per_pixel = pDeviceBitmap->GetBPP() / 8;
|
||
|
|
src_scan += src_left * src_bytes_per_pixel;
|
||
|
|
dest_scan += dest_left * dest_bytes_per_pixel;
|
||
|
|
for (int dest_col = 0; dest_col < m_sizeX; dest_col++) {
|
||
|
|
PixelWeight* pPixelWeights = m_WeightHorz.GetPixelWeight(dest_col);
|
||
|
|
switch (m_TransMethod) {
|
||
|
|
case -1:
|
||
|
|
return;
|
||
|
|
case 0:
|
||
|
|
return;
|
||
|
|
case 1:
|
||
|
|
return;
|
||
|
|
case 2: {
|
||
|
|
uint32_t dest_g = 0;
|
||
|
|
for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
|
||
|
|
j++) {
|
||
|
|
uint32_t pixel_weight =
|
||
|
|
pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
|
||
|
|
dest_g += pixel_weight * src_scan[j];
|
||
|
|
}
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
} break;
|
||
|
|
case 3: {
|
||
|
|
uint32_t dest_r = 0;
|
||
|
|
uint32_t dest_g = 0;
|
||
|
|
uint32_t dest_b = 0;
|
||
|
|
for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
|
||
|
|
j++) {
|
||
|
|
uint32_t pixel_weight =
|
||
|
|
pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
|
||
|
|
uint32_t argb = m_SrcPalette[src_scan[j]];
|
||
|
|
dest_r += pixel_weight * FXARGB_R(argb);
|
||
|
|
dest_g += pixel_weight * FXARGB_G(argb);
|
||
|
|
dest_b += pixel_weight * FXARGB_B(argb);
|
||
|
|
}
|
||
|
|
*dest_scan++ = static_cast<uint8_t>(
|
||
|
|
FXRGB2GRAY(CStretchEngine::PixelFromFixed(dest_r),
|
||
|
|
CStretchEngine::PixelFromFixed(dest_g),
|
||
|
|
CStretchEngine::PixelFromFixed(dest_b)));
|
||
|
|
} break;
|
||
|
|
case 4: {
|
||
|
|
uint32_t dest_b = 0;
|
||
|
|
uint32_t dest_g = 0;
|
||
|
|
uint32_t dest_r = 0;
|
||
|
|
for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
|
||
|
|
j++) {
|
||
|
|
uint32_t pixel_weight =
|
||
|
|
pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
|
||
|
|
const uint8_t* src_pixel = src_scan + j * src_bytes_per_pixel;
|
||
|
|
dest_b += pixel_weight * (*src_pixel++);
|
||
|
|
dest_g += pixel_weight * (*src_pixel++);
|
||
|
|
dest_r += pixel_weight * (*src_pixel);
|
||
|
|
}
|
||
|
|
*dest_scan++ = static_cast<uint8_t>(
|
||
|
|
FXRGB2GRAY(CStretchEngine::PixelFromFixed(dest_r),
|
||
|
|
CStretchEngine::PixelFromFixed(dest_g),
|
||
|
|
CStretchEngine::PixelFromFixed(dest_b)));
|
||
|
|
} break;
|
||
|
|
case 5: {
|
||
|
|
uint32_t dest_b = 0;
|
||
|
|
uint32_t dest_g = 0;
|
||
|
|
uint32_t dest_r = 0;
|
||
|
|
for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
|
||
|
|
j++) {
|
||
|
|
uint32_t pixel_weight =
|
||
|
|
pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
|
||
|
|
const uint8_t* src_pixel = src_scan + j * src_bytes_per_pixel;
|
||
|
|
uint8_t src_b = 0;
|
||
|
|
uint8_t src_g = 0;
|
||
|
|
uint8_t src_r = 0;
|
||
|
|
std::tie(src_r, src_g, src_b) =
|
||
|
|
AdobeCMYK_to_sRGB1(255 - src_pixel[0], 255 - src_pixel[1],
|
||
|
|
255 - src_pixel[2], 255 - src_pixel[3]);
|
||
|
|
dest_b += pixel_weight * src_b;
|
||
|
|
dest_g += pixel_weight * src_g;
|
||
|
|
dest_r += pixel_weight * src_r;
|
||
|
|
}
|
||
|
|
*dest_scan++ = static_cast<uint8_t>(
|
||
|
|
FXRGB2GRAY(CStretchEngine::PixelFromFixed(dest_r),
|
||
|
|
CStretchEngine::PixelFromFixed(dest_g),
|
||
|
|
CStretchEngine::PixelFromFixed(dest_b)));
|
||
|
|
} break;
|
||
|
|
case 6:
|
||
|
|
return;
|
||
|
|
case 7: {
|
||
|
|
uint32_t dest_g = 0;
|
||
|
|
for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
|
||
|
|
j++) {
|
||
|
|
uint32_t pixel_weight =
|
||
|
|
pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
|
||
|
|
dest_g += pixel_weight * src_scan[j];
|
||
|
|
}
|
||
|
|
memset(dest_scan, CStretchEngine::PixelFromFixed(dest_g), 3);
|
||
|
|
dest_scan += dest_bytes_per_pixel;
|
||
|
|
} break;
|
||
|
|
case 8: {
|
||
|
|
uint32_t dest_r = 0;
|
||
|
|
uint32_t dest_g = 0;
|
||
|
|
uint32_t dest_b = 0;
|
||
|
|
for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
|
||
|
|
j++) {
|
||
|
|
uint32_t pixel_weight =
|
||
|
|
pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
|
||
|
|
uint32_t argb = m_SrcPalette[src_scan[j]];
|
||
|
|
dest_r += pixel_weight * FXARGB_R(argb);
|
||
|
|
dest_g += pixel_weight * FXARGB_G(argb);
|
||
|
|
dest_b += pixel_weight * FXARGB_B(argb);
|
||
|
|
}
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
dest_scan += dest_bytes_per_pixel - 3;
|
||
|
|
} break;
|
||
|
|
case 12: {
|
||
|
|
#ifdef PDF_ENABLE_XFA_BMP
|
||
|
|
if (m_pBmpContext) {
|
||
|
|
uint32_t dest_r = 0;
|
||
|
|
uint32_t dest_g = 0;
|
||
|
|
uint32_t dest_b = 0;
|
||
|
|
for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
|
||
|
|
j++) {
|
||
|
|
uint32_t pixel_weight =
|
||
|
|
pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
|
||
|
|
uint32_t argb = m_SrcPalette[src_scan[j]];
|
||
|
|
dest_r += pixel_weight * FXARGB_R(argb);
|
||
|
|
dest_g += pixel_weight * FXARGB_G(argb);
|
||
|
|
dest_b += pixel_weight * FXARGB_B(argb);
|
||
|
|
}
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
*dest_scan++ = 0xFF;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
#endif // PDF_ENABLE_XFA_BMP
|
||
|
|
uint32_t dest_a = 0;
|
||
|
|
uint32_t dest_r = 0;
|
||
|
|
uint32_t dest_g = 0;
|
||
|
|
uint32_t dest_b = 0;
|
||
|
|
for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
|
||
|
|
j++) {
|
||
|
|
uint32_t pixel_weight =
|
||
|
|
pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
|
||
|
|
unsigned long argb = m_SrcPalette[src_scan[j]];
|
||
|
|
dest_a += pixel_weight * FXARGB_A(argb);
|
||
|
|
dest_r += pixel_weight * FXARGB_R(argb);
|
||
|
|
dest_g += pixel_weight * FXARGB_G(argb);
|
||
|
|
dest_b += pixel_weight * FXARGB_B(argb);
|
||
|
|
}
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_a);
|
||
|
|
} break;
|
||
|
|
case 9: {
|
||
|
|
uint32_t dest_b = 0;
|
||
|
|
uint32_t dest_g = 0;
|
||
|
|
uint32_t dest_r = 0;
|
||
|
|
for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
|
||
|
|
j++) {
|
||
|
|
uint32_t pixel_weight =
|
||
|
|
pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
|
||
|
|
const uint8_t* src_pixel = src_scan + j * src_bytes_per_pixel;
|
||
|
|
dest_b += pixel_weight * (*src_pixel++);
|
||
|
|
dest_g += pixel_weight * (*src_pixel++);
|
||
|
|
dest_r += pixel_weight * (*src_pixel);
|
||
|
|
}
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
dest_scan += dest_bytes_per_pixel - 3;
|
||
|
|
} break;
|
||
|
|
case 10: {
|
||
|
|
uint32_t dest_b = 0;
|
||
|
|
uint32_t dest_g = 0;
|
||
|
|
uint32_t dest_r = 0;
|
||
|
|
for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
|
||
|
|
j++) {
|
||
|
|
uint32_t pixel_weight =
|
||
|
|
pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
|
||
|
|
const uint8_t* src_pixel = src_scan + j * src_bytes_per_pixel;
|
||
|
|
uint8_t src_b = 0;
|
||
|
|
uint8_t src_g = 0;
|
||
|
|
uint8_t src_r = 0;
|
||
|
|
std::tie(src_r, src_g, src_b) =
|
||
|
|
AdobeCMYK_to_sRGB1(255 - src_pixel[0], 255 - src_pixel[1],
|
||
|
|
255 - src_pixel[2], 255 - src_pixel[3]);
|
||
|
|
dest_b += pixel_weight * src_b;
|
||
|
|
dest_g += pixel_weight * src_g;
|
||
|
|
dest_r += pixel_weight * src_r;
|
||
|
|
}
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
dest_scan += dest_bytes_per_pixel - 3;
|
||
|
|
} break;
|
||
|
|
case 11: {
|
||
|
|
uint32_t dest_alpha = 0;
|
||
|
|
uint32_t dest_r = 0;
|
||
|
|
uint32_t dest_g = 0;
|
||
|
|
uint32_t dest_b = 0;
|
||
|
|
for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
|
||
|
|
j++) {
|
||
|
|
uint32_t pixel_weight =
|
||
|
|
pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
|
||
|
|
const uint8_t* src_pixel = src_scan + j * src_bytes_per_pixel;
|
||
|
|
pixel_weight = pixel_weight * src_pixel[3] / 255;
|
||
|
|
dest_b += pixel_weight * (*src_pixel++);
|
||
|
|
dest_g += pixel_weight * (*src_pixel++);
|
||
|
|
dest_r += pixel_weight * (*src_pixel);
|
||
|
|
dest_alpha += pixel_weight;
|
||
|
|
}
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
*dest_scan++ = CStretchEngine::PixelFromFixed(dest_alpha * 255);
|
||
|
|
} break;
|
||
|
|
default:
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void ProgressiveDecoder::ResampleVert(
|
||
|
|
const RetainPtr<CFX_DIBitmap>& pDeviceBitmap,
|
||
|
|
double scale_y,
|
||
|
|
int dest_row) {
|
||
|
|
int dest_Bpp = pDeviceBitmap->GetBPP() >> 3;
|
||
|
|
uint32_t dest_ScanOffset = m_startX * dest_Bpp;
|
||
|
|
int dest_top = m_startY;
|
||
|
|
FX_SAFE_INT32 check_dest_row_1 = dest_row;
|
||
|
|
check_dest_row_1 -= pdfium::base::checked_cast<int>(scale_y);
|
||
|
|
int dest_row_1 = check_dest_row_1.ValueOrDie();
|
||
|
|
if (dest_row_1 < dest_top) {
|
||
|
|
int dest_bottom = dest_top + m_sizeY;
|
||
|
|
if (dest_row + (int)scale_y >= dest_bottom - 1) {
|
||
|
|
pdfium::span<const uint8_t> scan_src =
|
||
|
|
pDeviceBitmap->GetScanline(dest_row).subspan(dest_ScanOffset,
|
||
|
|
m_sizeX * dest_Bpp);
|
||
|
|
while (++dest_row < dest_bottom) {
|
||
|
|
fxcrt::spanmove(pDeviceBitmap->GetWritableScanline(dest_row).subspan(
|
||
|
|
dest_ScanOffset),
|
||
|
|
scan_src);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
for (; dest_row_1 < dest_row; dest_row_1++) {
|
||
|
|
uint8_t* scan_des = pDeviceBitmap->GetWritableScanline(dest_row_1)
|
||
|
|
.subspan(dest_ScanOffset)
|
||
|
|
.data();
|
||
|
|
PixelWeight* pWeight = m_WeightVert.GetPixelWeight(dest_row_1 - dest_top);
|
||
|
|
const uint8_t* scan_src1 =
|
||
|
|
pDeviceBitmap->GetScanline(pWeight->m_SrcStart + dest_top)
|
||
|
|
.subspan(dest_ScanOffset)
|
||
|
|
.data();
|
||
|
|
const uint8_t* scan_src2 =
|
||
|
|
pDeviceBitmap->GetScanline(pWeight->m_SrcEnd + dest_top)
|
||
|
|
.subspan(dest_ScanOffset)
|
||
|
|
.data();
|
||
|
|
switch (pDeviceBitmap->GetFormat()) {
|
||
|
|
case FXDIB_Format::kInvalid:
|
||
|
|
case FXDIB_Format::k1bppMask:
|
||
|
|
case FXDIB_Format::k1bppRgb:
|
||
|
|
return;
|
||
|
|
case FXDIB_Format::k8bppMask:
|
||
|
|
case FXDIB_Format::k8bppRgb:
|
||
|
|
if (pDeviceBitmap->HasPalette())
|
||
|
|
return;
|
||
|
|
for (int dest_col = 0; dest_col < m_sizeX; dest_col++) {
|
||
|
|
uint32_t dest_g = 0;
|
||
|
|
dest_g += pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
dest_g += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::kRgb:
|
||
|
|
case FXDIB_Format::kRgb32:
|
||
|
|
for (int dest_col = 0; dest_col < m_sizeX; dest_col++) {
|
||
|
|
uint32_t dest_b = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
uint32_t dest_g = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
uint32_t dest_r = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
scan_src1 += dest_Bpp - 3;
|
||
|
|
dest_b += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
dest_g += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
dest_r += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
scan_src2 += dest_Bpp - 3;
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
scan_des += dest_Bpp - 3;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case FXDIB_Format::kArgb:
|
||
|
|
for (int dest_col = 0; dest_col < m_sizeX; dest_col++) {
|
||
|
|
uint32_t dest_b = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
uint32_t dest_g = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
uint32_t dest_r = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
uint32_t dest_a = pWeight->m_Weights[0] * (*scan_src1++);
|
||
|
|
dest_b += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
dest_g += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
dest_r += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
dest_a += pWeight->m_Weights[1] * (*scan_src2++);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_b);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_g);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_r);
|
||
|
|
*scan_des++ = CStretchEngine::PixelFromFixed(dest_a);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
int dest_bottom = dest_top + m_sizeY;
|
||
|
|
if (dest_row + (int)scale_y >= dest_bottom - 1) {
|
||
|
|
pdfium::span<const uint8_t> scan_src =
|
||
|
|
pDeviceBitmap->GetScanline(dest_row).subspan(dest_ScanOffset,
|
||
|
|
m_sizeX * dest_Bpp);
|
||
|
|
while (++dest_row < dest_bottom) {
|
||
|
|
fxcrt::spanmove(
|
||
|
|
pDeviceBitmap->GetWritableScanline(dest_row).subspan(dest_ScanOffset),
|
||
|
|
scan_src);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void ProgressiveDecoder::Resample(const RetainPtr<CFX_DIBitmap>& pDeviceBitmap,
|
||
|
|
int32_t src_line,
|
||
|
|
uint8_t* src_scan,
|
||
|
|
FXCodec_Format src_format) {
|
||
|
|
int src_top = m_clipBox.top;
|
||
|
|
int dest_top = m_startY;
|
||
|
|
int src_height = m_clipBox.Height();
|
||
|
|
int dest_height = m_sizeY;
|
||
|
|
if (src_line >= src_top) {
|
||
|
|
double scale_y = static_cast<double>(dest_height) / src_height;
|
||
|
|
int src_row = src_line - src_top;
|
||
|
|
int dest_row = (int)(src_row * scale_y) + dest_top;
|
||
|
|
if (dest_row >= dest_top + dest_height)
|
||
|
|
return;
|
||
|
|
|
||
|
|
ResampleScanline(pDeviceBitmap, dest_row, m_DecodeBuf, src_format);
|
||
|
|
if (scale_y > 1.0)
|
||
|
|
ResampleVert(pDeviceBitmap, scale_y, dest_row);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
std::pair<FXCODEC_STATUS, size_t> ProgressiveDecoder::GetFrames() {
|
||
|
|
if (!(m_status == FXCODEC_STATUS::kFrameReady ||
|
||
|
|
m_status == FXCODEC_STATUS::kFrameToBeContinued)) {
|
||
|
|
return {FXCODEC_STATUS::kError, 0};
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (m_imageType) {
|
||
|
|
#ifdef PDF_ENABLE_XFA_BMP
|
||
|
|
case FXCODEC_IMAGE_BMP:
|
||
|
|
#endif // PDF_ENABLE_XFA_BMP
|
||
|
|
case FXCODEC_IMAGE_JPG:
|
||
|
|
#ifdef PDF_ENABLE_XFA_PNG
|
||
|
|
case FXCODEC_IMAGE_PNG:
|
||
|
|
#endif // PDF_ENABLE_XFA_PNG
|
||
|
|
#ifdef PDF_ENABLE_XFA_TIFF
|
||
|
|
case FXCODEC_IMAGE_TIFF:
|
||
|
|
#endif // PDF_ENABLE_XFA_TIFF
|
||
|
|
m_FrameNumber = 1;
|
||
|
|
m_status = FXCODEC_STATUS::kDecodeReady;
|
||
|
|
return {m_status, 1};
|
||
|
|
#ifdef PDF_ENABLE_XFA_GIF
|
||
|
|
case FXCODEC_IMAGE_GIF: {
|
||
|
|
while (true) {
|
||
|
|
GifDecoder::Status readResult;
|
||
|
|
std::tie(readResult, m_FrameNumber) =
|
||
|
|
GifDecoder::LoadFrameInfo(m_pGifContext.get());
|
||
|
|
while (readResult == GifDecoder::Status::kUnfinished) {
|
||
|
|
FXCODEC_STATUS error_status = FXCODEC_STATUS::kError;
|
||
|
|
if (!GifReadMoreData(&error_status))
|
||
|
|
return {error_status, 0};
|
||
|
|
|
||
|
|
std::tie(readResult, m_FrameNumber) =
|
||
|
|
GifDecoder::LoadFrameInfo(m_pGifContext.get());
|
||
|
|
}
|
||
|
|
if (readResult == GifDecoder::Status::kSuccess) {
|
||
|
|
m_status = FXCODEC_STATUS::kDecodeReady;
|
||
|
|
return {m_status, m_FrameNumber};
|
||
|
|
}
|
||
|
|
m_pGifContext = nullptr;
|
||
|
|
m_status = FXCODEC_STATUS::kError;
|
||
|
|
return {m_status, 0};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif // PDF_ENABLE_XFA_GIF
|
||
|
|
default:
|
||
|
|
return {FXCODEC_STATUS::kError, 0};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
FXCODEC_STATUS ProgressiveDecoder::StartDecode(
|
||
|
|
const RetainPtr<CFX_DIBitmap>& pDIBitmap,
|
||
|
|
int start_x,
|
||
|
|
int start_y,
|
||
|
|
int size_x,
|
||
|
|
int size_y) {
|
||
|
|
if (m_status != FXCODEC_STATUS::kDecodeReady)
|
||
|
|
return FXCODEC_STATUS::kError;
|
||
|
|
|
||
|
|
if (!pDIBitmap || pDIBitmap->GetBPP() < 8 || m_FrameNumber == 0)
|
||
|
|
return FXCODEC_STATUS::kError;
|
||
|
|
|
||
|
|
m_pDeviceBitmap = pDIBitmap;
|
||
|
|
if (m_clipBox.IsEmpty())
|
||
|
|
return FXCODEC_STATUS::kError;
|
||
|
|
if (size_x <= 0 || size_x > 65535 || size_y <= 0 || size_y > 65535)
|
||
|
|
return FXCODEC_STATUS::kError;
|
||
|
|
|
||
|
|
FX_RECT device_rc =
|
||
|
|
FX_RECT(start_x, start_y, start_x + size_x, start_y + size_y);
|
||
|
|
int32_t out_range_x = device_rc.right - pDIBitmap->GetWidth();
|
||
|
|
int32_t out_range_y = device_rc.bottom - pDIBitmap->GetHeight();
|
||
|
|
device_rc.Intersect(
|
||
|
|
FX_RECT(0, 0, pDIBitmap->GetWidth(), pDIBitmap->GetHeight()));
|
||
|
|
if (device_rc.IsEmpty())
|
||
|
|
return FXCODEC_STATUS::kError;
|
||
|
|
|
||
|
|
m_startX = device_rc.left;
|
||
|
|
m_startY = device_rc.top;
|
||
|
|
m_sizeX = device_rc.Width();
|
||
|
|
m_sizeY = device_rc.Height();
|
||
|
|
m_FrameCur = 0;
|
||
|
|
if (start_x < 0 || out_range_x > 0) {
|
||
|
|
float scaleX = (float)m_clipBox.Width() / (float)size_x;
|
||
|
|
if (start_x < 0) {
|
||
|
|
m_clipBox.left -= static_cast<int32_t>(ceil((float)start_x * scaleX));
|
||
|
|
}
|
||
|
|
if (out_range_x > 0) {
|
||
|
|
m_clipBox.right -=
|
||
|
|
static_cast<int32_t>(floor((float)out_range_x * scaleX));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (start_y < 0 || out_range_y > 0) {
|
||
|
|
float scaleY = (float)m_clipBox.Height() / (float)size_y;
|
||
|
|
if (start_y < 0) {
|
||
|
|
m_clipBox.top -= static_cast<int32_t>(ceil((float)start_y * scaleY));
|
||
|
|
}
|
||
|
|
if (out_range_y > 0) {
|
||
|
|
m_clipBox.bottom -=
|
||
|
|
static_cast<int32_t>(floor((float)out_range_y * scaleY));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (m_clipBox.IsEmpty()) {
|
||
|
|
return FXCODEC_STATUS::kError;
|
||
|
|
}
|
||
|
|
switch (m_imageType) {
|
||
|
|
#ifdef PDF_ENABLE_XFA_BMP
|
||
|
|
case FXCODEC_IMAGE_BMP:
|
||
|
|
return BmpStartDecode();
|
||
|
|
#endif // PDF_ENABLE_XFA_BMP
|
||
|
|
#ifdef PDF_ENABLE_XFA_GIF
|
||
|
|
case FXCODEC_IMAGE_GIF:
|
||
|
|
return GifStartDecode();
|
||
|
|
#endif // PDF_ENABLE_XFA_GIF
|
||
|
|
case FXCODEC_IMAGE_JPG:
|
||
|
|
return JpegStartDecode(pDIBitmap->GetFormat());
|
||
|
|
#ifdef PDF_ENABLE_XFA_PNG
|
||
|
|
case FXCODEC_IMAGE_PNG:
|
||
|
|
return PngStartDecode();
|
||
|
|
#endif // PDF_ENABLE_XFA_PNG
|
||
|
|
#ifdef PDF_ENABLE_XFA_TIFF
|
||
|
|
case FXCODEC_IMAGE_TIFF:
|
||
|
|
m_status = FXCODEC_STATUS::kDecodeToBeContinued;
|
||
|
|
return m_status;
|
||
|
|
#endif // PDF_ENABLE_XFA_TIFF
|
||
|
|
default:
|
||
|
|
return FXCODEC_STATUS::kError;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
FXCODEC_STATUS ProgressiveDecoder::ContinueDecode() {
|
||
|
|
if (m_status != FXCODEC_STATUS::kDecodeToBeContinued)
|
||
|
|
return FXCODEC_STATUS::kError;
|
||
|
|
|
||
|
|
switch (m_imageType) {
|
||
|
|
case FXCODEC_IMAGE_JPG:
|
||
|
|
return JpegContinueDecode();
|
||
|
|
#ifdef PDF_ENABLE_XFA_BMP
|
||
|
|
case FXCODEC_IMAGE_BMP:
|
||
|
|
return BmpContinueDecode();
|
||
|
|
#endif // PDF_ENABLE_XFA_BMP
|
||
|
|
#ifdef PDF_ENABLE_XFA_GIF
|
||
|
|
case FXCODEC_IMAGE_GIF:
|
||
|
|
return GifContinueDecode();
|
||
|
|
#endif // PDF_ENABLE_XFA_GIF
|
||
|
|
#ifdef PDF_ENABLE_XFA_PNG
|
||
|
|
case FXCODEC_IMAGE_PNG:
|
||
|
|
return PngContinueDecode();
|
||
|
|
#endif // PDF_ENABLE_XFA_PNG
|
||
|
|
#ifdef PDF_ENABLE_XFA_TIFF
|
||
|
|
case FXCODEC_IMAGE_TIFF:
|
||
|
|
return TiffContinueDecode();
|
||
|
|
#endif // PDF_ENABLE_XFA_TIFF
|
||
|
|
default:
|
||
|
|
return FXCODEC_STATUS::kError;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace fxcodec
|