7#include "core/fpdfapi/render/cpdf_imagerenderer.h"
15#include "build/build_config.h"
16#include "core/fpdfapi/page/cpdf_dib.h"
17#include "core/fpdfapi/page/cpdf_docpagedata.h"
18#include "core/fpdfapi/page/cpdf_image.h"
19#include "core/fpdfapi/page/cpdf_imageloader.h"
20#include "core/fpdfapi/page/cpdf_imageobject.h"
21#include "core/fpdfapi/page/cpdf_occontext.h"
22#include "core/fpdfapi/page/cpdf_page.h"
23#include "core/fpdfapi/page/cpdf_pageimagecache.h"
24#include "core/fpdfapi/page/cpdf_pageobject.h"
25#include "core/fpdfapi/page/cpdf_shadingpattern.h"
26#include "core/fpdfapi/page/cpdf_tilingpattern.h"
27#include "core/fpdfapi/page/cpdf_transferfunc.h"
28#include "core/fpdfapi/parser/cpdf_dictionary.h"
29#include "core/fpdfapi/parser/cpdf_document.h"
30#include "core/fpdfapi/parser/cpdf_stream.h"
31#include "core/fpdfapi/parser/fpdf_parser_decode.h"
32#include "core/fpdfapi/render/cpdf_rendercontext.h"
33#include "core/fpdfapi/render/cpdf_renderstatus.h"
34#include "core/fxcrt/check.h"
35#include "core/fxcrt/fx_safe_types.h"
36#include "core/fxcrt/maybe_owned.h"
37#include "core/fxcrt/zip.h"
38#include "core/fxge/agg/cfx_agg_imagerenderer.h"
39#include "core/fxge/cfx_defaultrenderdevice.h"
40#include "core/fxge/cfx_fillrenderoptions.h"
41#include "core/fxge/cfx_path.h"
42#include "core/fxge/dib/cfx_dibbase.h"
43#include "core/fxge/dib/cfx_dibitmap.h"
44#include "core/fxge/dib/cfx_imagestretcher.h"
47#include "core/fxge/dib/cfx_imagetransformer.h"
52bool IsImageValueTooBig(
int val) {
55 constexpr int kLimit = 256 * 1024 * 1024;
57 safe_val = safe_val.Abs();
58 return safe_val.ValueOrDefault(kLimit) >= kLimit;
70 if (!GetUnitRect().has_value())
73 if (!m_pLoader->Start(
74 m_pImageObject, m_pRenderStatus->GetContext()->GetPageCache(),
75 m_pRenderStatus->GetFormResource(),
76 m_pRenderStatus->GetPageResource(), m_bStdCS,
77 m_pRenderStatus->GetGroupFamily(), m_pRenderStatus->GetLoadMask(),
78 {m_pRenderStatus->GetRenderDevice()->GetWidth(),
79 m_pRenderStatus->GetRenderDevice()->GetHeight()})) {
82 m_Mode = Mode::kDefault;
87 if (!m_pLoader->GetBitmap())
92 m_pDIBBase = m_pLoader->GetBitmap();
93 if (GetRenderOptions().ColorModeIs(CPDF_RenderOptions::kAlpha) &&
94 !m_pLoader->GetMask()) {
95 return StartBitmapAlpha();
99 if (!state.GetTransferFunc())
100 state.SetTransferFunc(m_pRenderStatus->GetTransferFunc(std::move(pTR)));
102 if (state.GetTransferFunc() && !state.GetTransferFunc()->GetIdentity())
103 m_pDIBBase = m_pLoader->TranslateImage(state.GetTransferFunc());
106 m_bPatternColor =
false;
107 m_pPattern =
nullptr;
108 if (m_pDIBBase->IsMaskFormat()) {
109 const CPDF_Color* pColor = m_pImageObject->color_state().GetFillColor();
111 m_pPattern = pColor->GetPattern();
113 m_bPatternColor =
true;
115 m_FillArgb = m_pRenderStatus->GetFillArgb(m_pImageObject);
117 RetainPtr<CFX_DIBitmap> pClone = m_pDIBBase->Realize();
121 pClone->ConvertColorScale(0xffffff, 0);
129 if (m_pRenderStatus->GetRenderDevice()->GetDeviceType() ==
130 DeviceType::kPrinter) {
137 else if (m_pImageObject->GetImage()->IsInterpol())
140 if (m_pLoader->GetMask())
141 return DrawMaskedImage();
144 return DrawPatternImage();
149 return StartDIBBase();
152 CPDF_Page* pPage =
nullptr;
153 if (
auto* pPageCache = m_pRenderStatus->GetContext()->GetPageCache()) {
154 pPage = pPageCache->GetPage();
157 pDocument = m_pImageObject->GetImage()->GetDocument();
160 pPage ? pPage->GetPageResources() :
nullptr;
162 m_pImageObject->GetImage()->GetStream()->GetDict();
164 pStreamDict->GetDirectObjectFor(
"ColorSpace");
167 pData->GetColorSpace(pCSObj.Get(), pPageResources);
176 return StartDIBBase();
184 m_pImageObject = pImageObject;
186 m_mtObj2Device
= mtObj2Device;
191 m_ImageMatrix = m_pImageObject->matrix() * mtObj2Device;
192 if (StartLoadDIBBase())
195 return StartRenderDIBBase();
203 m_pDIBBase = std::move(pDIBBase);
204 m_FillArgb = bitmap_argb;
206 m_ImageMatrix
= mtImage2Device;
207 m_ResampleOptions = options;
210 return StartDIBBase();
214bool CPDF_ImageRenderer::IsPrinting()
const {
215 if (!m_pRenderStatus->IsPrint()) {
221 !(m_pRenderStatus->GetRenderDevice()->GetRenderCaps() & FXRC_BLEND_MODE));
225void CPDF_ImageRenderer::HandleFilters() {
226 std::optional<DecoderArray> decoder_array =
227 GetDecoderArray(m_pImageObject->GetImage()->GetStream()->GetDict());
228 if (!decoder_array.has_value()) {
232 for (
const auto& decoder : decoder_array.value()) {
233 if (decoder.first ==
"DCTDecode" || decoder.first ==
"JPXDecode") {
234 m_ResampleOptions.bLossy =
true;
243 rect.Intersect(m_pRenderStatus->GetRenderDevice()->GetClipBox());
254 CFX_DefaultRenderDevice& bitmap_device,
258 auto mask_bitmap =
pdfium::MakeRetain<CFX_DIBitmap>();
267 CFX_DefaultRenderDevice mask_device;
271 mask_status.SetDropObjects(m_pRenderStatus->GetDropObjects());
276 if (mask_renderer.Start(
std::move(pDIBBase), 0xffffffff, mtNewMatrix,
277 m_ResampleOptions,
true)) {
280 if (m_pLoader->MatteColor() != 0xffffffff) {
281 const int matte_r =
FXARGB_R(m_pLoader->MatteColor());
282 const int matte_g =
FXARGB_G(m_pLoader->MatteColor());
283 const int matte_b =
FXARGB_B(m_pLoader->MatteColor());
284 RetainPtr<CFX_DIBitmap> dest_bitmap = bitmap_device.GetBitmap();
285 for (
int row = 0; row < rect
.Height(); row++) {
286 auto mask_scan = mask_bitmap->GetScanline(row).first(rect
.Width());
289 for (
auto [mask_ref, dest_ref] : fxcrt::Zip(mask_scan, dest_scan)) {
293 int orig_b = (dest_ref.blue - matte_b) * 255 / mask_ref + matte_b;
294 int orig_g = (dest_ref.green - matte_g) * 255 / mask_ref + matte_g;
295 int orig_r = (dest_ref.red - matte_r) * 255 / mask_ref + matte_r;
296 dest_ref.blue = std::clamp(orig_b, 0, 255);
297 dest_ref.green = std::clamp(orig_g, 0, 255);
298 dest_ref.red = std::clamp(orig_r, 0, 255);
303 CHECK(!mask_bitmap->HasPalette());
309 return m_pRenderStatus->GetRenderOptions();
325 CFX_DefaultRenderDevice bitmap_device;
333 bitmap_status.SetDropObjects(m_pRenderStatus->GetDropObjects());
339 if (CPDF_TilingPattern* pTilingPattern = m_pPattern->AsTilingPattern()) {
340 bitmap_status.DrawTilingPattern(pTilingPattern, m_pImageObject,
341 pattern_matrix,
false);
342 }
else if (CPDF_ShadingPattern* pShadingPattern =
343 m_pPattern->AsShadingPattern()) {
344 bitmap_status.DrawShadingPattern(pShadingPattern, m_pImageObject,
345 pattern_matrix,
false);
348 RetainPtr<
const CFX_DIBitmap> mask_bitmap =
349 CalculateDrawImage(bitmap_device, m_pDIBBase, new_matrix, rect);
354 bitmap_device.GetBitmap()->MultiplyAlphaMask(
std::move(mask_bitmap));
355 m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend(
356 bitmap_device.GetBitmap(), rect.left, rect.top, m_BlendType);
373 CFX_DefaultRenderDevice bitmap_device;
380 bitmap_status.SetDropObjects(m_pRenderStatus->GetDropObjects());
384 if (bitmap_renderer.Start(m_pDIBBase, 0, new_matrix, m_ResampleOptions,
388 RetainPtr<
const CFX_DIBitmap> mask_bitmap =
389 CalculateDrawImage(bitmap_device, m_pLoader->GetMask(), new_matrix, rect);
394#if defined(PDF_USE_SKIA)
395 if (CFX_DefaultRenderDevice::UseSkiaRenderer() &&
396 m_pRenderStatus->GetRenderDevice()->SetBitsWithMask(
397 bitmap_device.GetBitmap(), mask_bitmap, rect.left, rect.top, m_Alpha,
402 bitmap_device.GetBitmap()->MultiplyAlphaMask(
std::move(mask_bitmap));
403 bitmap_device.GetBitmap()->MultiplyAlpha(m_Alpha);
404 m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend(
405 bitmap_device.GetBitmap(), rect.left, rect.top, m_BlendType);
410 if (m_pDIBBase->GetBPP() > 1) {
411 FX_SAFE_SIZE_T image_size = m_pDIBBase->GetBPP();
413 image_size *= m_pDIBBase->GetWidth();
414 image_size *= m_pDIBBase->GetHeight();
415 if (!image_size.IsValid())
418 if (image_size.ValueOrDie() > kHugeImageSize &&
424 m_pRenderStatus->GetRenderDevice()->StartDIBitsWithBlend(
425 m_pDIBBase, m_Alpha, m_FillArgb, m_ImageMatrix, m_ResampleOptions,
428 m_DeviceHandle = std::move(result.agg_image_renderer);
429 if (m_DeviceHandle) {
430 m_Mode = Mode::kBlend;
437 if (result.result == RenderDeviceDriverIface::Result::kNotSupported) {
438 return StartDIBBaseFallback();
448bool CPDF_ImageRenderer::StartDIBBaseFallback() {
449 if ((fabs(m_ImageMatrix.b) >= 0.5f || m_ImageMatrix.a == 0) ||
450 (fabs(m_ImageMatrix.c) >= 0.5f || m_ImageMatrix.d == 0)) {
456 std::optional<FX_RECT> image_rect = GetUnitRect();
457 if (!image_rect.has_value())
460 FX_RECT clip_box = m_pRenderStatus->GetRenderDevice()->GetClipBox();
461 clip_box.Intersect(image_rect.value());
462 m_Mode = Mode::kTransform;
463 m_pTransformer = std::make_unique<CFX_ImageTransformer>(
464 m_pDIBBase, m_ImageMatrix, m_ResampleOptions, &clip_box);
468 std::optional<FX_RECT> image_rect = GetUnitRect();
469 if (!image_rect.has_value())
476 if (!GetDimensionsFromUnitRect(image_rect.value(), &dest_left, &dest_top,
477 &dest_width, &dest_height)) {
481 if (m_pDIBBase->IsOpaqueImage() && m_Alpha == 1.0f) {
482 if (m_pRenderStatus->GetRenderDevice()->StretchDIBitsWithFlagsAndBlend(
483 m_pDIBBase, dest_left, dest_top, dest_width, dest_height,
484 m_ResampleOptions, m_BlendType)) {
488 if (m_pDIBBase->IsMaskFormat()) {
489 if (m_Alpha != 1.0f) {
490 m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, FXSYS_roundf(m_Alpha * 255));
492 if (m_pRenderStatus->GetRenderDevice()->StretchBitMaskWithFlags(
493 m_pDIBBase, dest_left, dest_top, dest_width, dest_height,
494 m_FillArgb, m_ResampleOptions)) {
504 FX_RECT clip_box = m_pRenderStatus->GetRenderDevice()->GetClipBox();
505 FX_RECT dest_rect = clip_box;
506 dest_rect.Intersect(image_rect.value());
508 dest_rect.left - image_rect->left, dest_rect.top - image_rect->top,
509 dest_rect.right - image_rect->left, dest_rect.bottom - image_rect->top);
510 RetainPtr<CFX_DIBitmap> stretched = m_pDIBBase->StretchTo(
511 dest_width, dest_height, m_ResampleOptions, &dest_clip);
513 m_pRenderStatus->CompositeDIBitmap(std::move(stretched), dest_rect.left,
514 dest_rect.top, m_FillArgb, m_Alpha,
515 m_BlendType, CPDF_Transparency());
522 if (m_pDIBBase->IsOpaqueImage()) {
527 uint32_t fill_color =
529 m_pRenderStatus->GetRenderDevice()->DrawPath(
530 path,
nullptr,
nullptr, fill_color, 0,
531 CFX_FillRenderOptions::WindingOptions());
536 m_pDIBBase->IsMaskFormat() ? m_pDIBBase : m_pDIBBase->CloneAlphaMask();
537 if (fabs(m_ImageMatrix
.b) >= 0.5f || fabs(m_ImageMatrix
.c) >= 0.5f) {
540 alpha_mask = alpha_mask->TransformTo(m_ImageMatrix, &left, &top);
546 m_pRenderStatus->GetRenderDevice()->SetBitMask(
547 std::move(alpha_mask), left, top,
548 ArgbEncode(0xff, bitmap_alpha, bitmap_alpha, bitmap_alpha));
552 std::optional<
FX_RECT> image_rect = GetUnitRect();
553 if (!image_rect.has_value())
560 if (!GetDimensionsFromUnitRect(image_rect.value(), &left, &top, &dest_width,
566 m_pRenderStatus->GetRenderDevice()->StretchBitMask(
567 std::move(alpha_mask), left, top, dest_width, dest_height,
568 ArgbEncode(0xff, bitmap_alpha, bitmap_alpha, bitmap_alpha));
577 return ContinueDefault(pPause);
579 return ContinueBlend(pPause);
581 case Mode::kTransform:
582 return ContinueTransform(pPause);
588 if (m_pLoader->Continue(pPause))
591 if (!StartRenderDIBBase())
594 if (m_Mode == Mode::kDefault)
601 return m_pRenderStatus->GetRenderDevice()->ContinueDIBits(
602 m_DeviceHandle.get(), pPause);
606bool CPDF_ImageRenderer::ContinueTransform(PauseIndicatorIface* pPause) {
607 if (m_pTransformer->Continue(pPause))
610 RetainPtr<CFX_DIBitmap> bitmap = m_pTransformer->DetachBitmap();
615 if (bitmap->IsMaskFormat()) {
616 if (m_Alpha != 1.0f) {
617 m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, FXSYS_roundf(m_Alpha * 255));
619 m_Result = m_pRenderStatus->GetRenderDevice()->SetBitMask(
620 std::move(bitmap), m_pTransformer->result().left,
621 m_pTransformer->result().top, m_FillArgb);
623 bitmap->MultiplyAlpha(m_Alpha);
624 m_Result = m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend(
625 std::move(bitmap), m_pTransformer->result().left,
626 m_pTransformer->result().top, m_BlendType);
649 if (IsImageValueTooBig(dest_width) || IsImageValueTooBig(dest_height))
652 if (m_ImageMatrix
.a < 0)
653 dest_width = -dest_width;
655 if (m_ImageMatrix
.d > 0)
656 dest_height = -dest_height;
658 int dest_left = dest_width > 0 ? rect
.left : rect
.right;
659 int dest_top = dest_height > 0 ? rect
.top : rect
.bottom;
660 if (IsImageValueTooBig(dest_left) || IsImageValueTooBig(dest_top))
666 *height = dest_height;
bool Attach(RetainPtr< CFX_DIBitmap > pBitmap)
bool Create(int width, int height, FXDIB_Format format)
void Clear(uint32_t color)
FX_RECT GetOuterRect() const
CFX_Matrix & operator=(const CFX_Matrix &other)=default
void Translate(int32_t x, int32_t y)
CFX_FloatRect GetUnitRect() const
void Transform(const CFX_Matrix &matrix)
void AppendRect(float left, float bottom, float right, float top)
std::map< ByteString, RetainPtr< CPDF_Object >, std::less<> > DictMap
static CPDF_DocPageData * FromDocument(const CPDF_Document *pDoc)
float GetStrokeAlpha() const
float GetFillAlpha() const
BlendMode GetBlendType() const
CPDF_ImageRenderer(CPDF_RenderStatus *pStatus)
bool Start(RetainPtr< CFX_DIBBase > pDIBBase, FX_ARGB bitmap_argb, const CFX_Matrix &mtImage2Device, const FXDIB_ResampleOptions &options, bool bStdCS)
bool Start(CPDF_ImageObject *pImageObject, const CFX_Matrix &mtObj2Device, bool bStdCS)
bool Continue(PauseIndicatorIface *pPause)
CPDF_Document * GetDocument() const override
const Options & GetOptions() const
bool CheckOCGDictVisible(const CPDF_Dictionary *pOC) const
bool ColorModeIs(Type mode) const
void SetOptions(const CPDF_RenderOptions &options)
void SetStdCS(bool bStdCS)
void Initialize(const CPDF_RenderStatus *pParentStatus, const CPDF_GraphicStates *pInitialStates)
constexpr FX_ARGB ArgbEncode(uint32_t a, uint32_t r, uint32_t g, uint32_t b)
pdfium::CheckedNumeric< int32_t > FX_SAFE_INT32
int FXSYS_roundf(float f)
bool bInterpolateBilinear