7#include "core/fpdfapi/render/cpdf_imagerenderer.h"
15#include "core/fpdfapi/page/cpdf_dib.h"
16#include "core/fpdfapi/page/cpdf_docpagedata.h"
17#include "core/fpdfapi/page/cpdf_image.h"
18#include "core/fpdfapi/page/cpdf_imageloader.h"
19#include "core/fpdfapi/page/cpdf_imageobject.h"
20#include "core/fpdfapi/page/cpdf_occontext.h"
21#include "core/fpdfapi/page/cpdf_page.h"
22#include "core/fpdfapi/page/cpdf_pageimagecache.h"
23#include "core/fpdfapi/page/cpdf_pageobject.h"
24#include "core/fpdfapi/page/cpdf_shadingpattern.h"
25#include "core/fpdfapi/page/cpdf_tilingpattern.h"
26#include "core/fpdfapi/page/cpdf_transferfunc.h"
27#include "core/fpdfapi/parser/cpdf_dictionary.h"
28#include "core/fpdfapi/parser/cpdf_document.h"
29#include "core/fpdfapi/parser/cpdf_stream.h"
30#include "core/fpdfapi/parser/fpdf_parser_decode.h"
31#include "core/fpdfapi/render/cpdf_rendercontext.h"
32#include "core/fpdfapi/render/cpdf_renderstatus.h"
33#include "core/fxcrt/fx_safe_types.h"
34#include "core/fxcrt/maybe_owned.h"
35#include "core/fxge/cfx_defaultrenderdevice.h"
36#include "core/fxge/cfx_fillrenderoptions.h"
37#include "core/fxge/cfx_path.h"
38#include "core/fxge/dib/cfx_dibbase.h"
39#include "core/fxge/dib/cfx_dibitmap.h"
40#include "core/fxge/dib/cfx_imagestretcher.h"
41#include "core/fxge/dib/cfx_imagetransformer.h"
42#include "third_party/base/check.h"
46bool IsImageValueTooBig(
int val) {
49 constexpr int kLimit = 256 * 1024 * 1024;
50 FX_SAFE_INT32 safe_val = val;
51 safe_val = safe_val.Abs();
52 return safe_val.ValueOrDefault(kLimit) >= kLimit;
64 if (!GetUnitRect().has_value())
67 if (!m_pLoader->Start(
68 m_pImageObject, m_pRenderStatus->GetContext()->GetPageCache(),
69 m_pRenderStatus->GetFormResource(),
70 m_pRenderStatus->GetPageResource(), m_bStdCS,
71 m_pRenderStatus->GetGroupFamily(), m_pRenderStatus->GetLoadMask(),
72 {m_pRenderStatus->GetRenderDevice()->GetWidth(),
73 m_pRenderStatus->GetRenderDevice()->GetHeight()})) {
76 m_Mode = Mode::kDefault;
81 if (!m_pLoader->GetBitmap())
86 m_pDIBBase = m_pLoader->GetBitmap();
87 if (GetRenderOptions().ColorModeIs(CPDF_RenderOptions::kAlpha) &&
88 !m_pLoader->GetMask()) {
89 return StartBitmapAlpha();
93 if (!state.GetTransferFunc())
94 state.SetTransferFunc(m_pRenderStatus->GetTransferFunc(std::move(pTR)));
96 if (state.GetTransferFunc() && !state.GetTransferFunc()->GetIdentity())
97 m_pDIBBase = m_pLoader->TranslateImage(state.GetTransferFunc());
100 m_bPatternColor =
false;
101 m_pPattern =
nullptr;
102 if (m_pDIBBase->IsMaskFormat()) {
103 const CPDF_Color* pColor = m_pImageObject->color_state().GetFillColor();
105 m_pPattern = pColor->GetPattern();
107 m_bPatternColor =
true;
109 m_FillArgb = m_pRenderStatus->GetFillArgb(m_pImageObject);
111 RetainPtr<CFX_DIBitmap> pClone = m_pDIBBase->Realize();
115 pClone->ConvertColorScale(0xffffff, 0);
122 if (m_pRenderStatus->GetRenderDevice()->GetDeviceType() !=
123 DeviceType::kDisplay) {
129 else if (m_pImageObject->GetImage()->IsInterpol())
132 if (m_pLoader->GetMask())
133 return DrawMaskedImage();
136 return DrawPatternImage();
141 return StartDIBBase();
144 CPDF_Page* pPage =
nullptr;
145 if (
auto* pPageCache = m_pRenderStatus->GetContext()->GetPageCache()) {
146 pPage = pPageCache->GetPage();
149 pDocument = m_pImageObject->GetImage()->GetDocument();
151 RetainPtr<
const CPDF_Dictionary> pPageResources =
152 pPage ? pPage->GetPageResources() :
nullptr;
153 RetainPtr<
const CPDF_Dictionary> pStreamDict =
154 m_pImageObject->GetImage()->GetStream()->GetDict();
156 pStreamDict->GetDirectObjectFor(
"ColorSpace");
159 pData->GetColorSpace(pCSObj.Get(), pPageResources);
168 return StartDIBBase();
175 DCHECK(pImageObject);
177 m_pImageObject = pImageObject;
178 m_BlendType = blendType;
179 m_mtObj2Device
= mtObj2Device;
180 RetainPtr<
const CPDF_Dictionary> pOC = m_pImageObject->GetImage()->GetOC();
184 m_ImageMatrix = m_pImageObject->matrix() * mtObj2Device;
185 if (StartLoadDIBBase())
188 return StartRenderDIBBase();
196 m_pDIBBase = std::move(pDIBBase);
197 m_FillArgb = bitmap_argb;
199 m_ImageMatrix
= mtImage2Device;
200 m_ResampleOptions = options;
203 return StartDIBBase();
207 return m_pRenderStatus->IsPrint() &&
208 !(m_pRenderStatus->GetRenderDevice()->GetRenderCaps() &
214 rect.Intersect(m_pRenderStatus->GetRenderDevice()->GetClipBox());
225 CFX_DefaultRenderDevice* pBitmapDevice1,
226 CFX_DefaultRenderDevice* pBitmapDevice2,
232 bitmap_render.SetDropObjects(m_pRenderStatus->GetDropObjects());
237 if (image_render.Start(
std::move(pDIBBase), 0xffffffff, mtNewMatrix,
238 m_ResampleOptions,
true)) {
241 if (m_pLoader->MatteColor() == 0xffffffff)
243 int matte_r =
FXARGB_R(m_pLoader->MatteColor());
244 int matte_g =
FXARGB_G(m_pLoader->MatteColor());
245 int matte_b =
FXARGB_B(m_pLoader->MatteColor());
246 for (
int row = 0; row < rect
.Height(); row++) {
248 pBitmapDevice1->GetBitmap()->GetWritableScanline(row).data();
249 const uint8_t* mask_scan =
250 pBitmapDevice2->GetBitmap()->GetScanline(row).data();
251 for (
int col = 0; col < rect
.Width(); col++) {
252 int alpha = *mask_scan++;
257 int orig = (*dest_scan - matte_b) * 255 / alpha + matte_b;
258 *dest_scan++ =
std::clamp(orig, 0, 255);
259 orig = (*dest_scan - matte_g) * 255 / alpha + matte_g;
260 *dest_scan++ =
std::clamp(orig, 0, 255);
261 orig = (*dest_scan - matte_r) * 255 / alpha + matte_r;
262 *dest_scan++ =
std::clamp(orig, 0, 255);
269 return m_pRenderStatus->GetRenderOptions();
283 CFX_DefaultRenderDevice bitmap_device1;
292 bitmap_render.SetDropObjects(m_pRenderStatus->GetDropObjects());
298 static_cast<
float>(-rect
.top)
);
299 if (CPDF_TilingPattern* pTilingPattern = m_pPattern->AsTilingPattern()) {
300 bitmap_render.DrawTilingPattern(pTilingPattern, m_pImageObject,
301 patternDevice,
false);
302 }
else if (CPDF_ShadingPattern* pShadingPattern =
303 m_pPattern->AsShadingPattern()) {
304 bitmap_render.DrawShadingPattern(pShadingPattern, m_pImageObject,
305 patternDevice,
false);
308 CFX_DefaultRenderDevice bitmap_device2;
313 CalculateDrawImage(&bitmap_device1, &bitmap_device2, m_pDIBBase, new_matrix,
316 bitmap_device1.GetBitmap()->MultiplyAlphaMask(bitmap_device2.GetBitmap());
317 m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend(
318 bitmap_device1.GetBitmap(), rect.left, rect.top, m_BlendType);
333 CFX_DefaultRenderDevice bitmap_device1;
341 bitmap_render.SetDropObjects(m_pRenderStatus->GetDropObjects());
345 if (image_render.Start(m_pDIBBase, 0, new_matrix, m_ResampleOptions,
true)) {
348 CFX_DefaultRenderDevice bitmap_device2;
353 CalculateDrawImage(&bitmap_device1, &bitmap_device2, m_pLoader->GetMask(),
355 DCHECK(!bitmap_device2.GetBitmap()->HasPalette());
357#if defined(PDF_USE_SKIA)
358 if (CFX_DefaultRenderDevice::UseSkiaRenderer() &&
359 m_pRenderStatus->GetRenderDevice()->SetBitsWithMask(
360 bitmap_device1.GetBitmap(), bitmap_device2.GetBitmap(), rect.left,
361 rect.top, m_Alpha, m_BlendType)) {
365 bitmap_device1.GetBitmap()->MultiplyAlphaMask(bitmap_device2.GetBitmap());
366 bitmap_device1.GetBitmap()->MultiplyAlpha(m_Alpha);
367 m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend(
368 bitmap_device1.GetBitmap(), rect.left, rect.top, m_BlendType);
373 if (m_pDIBBase->GetBPP() > 1) {
374 FX_SAFE_SIZE_T image_size = m_pDIBBase->GetBPP();
376 image_size *= m_pDIBBase->GetWidth();
377 image_size *= m_pDIBBase->GetHeight();
378 if (!image_size.IsValid())
381 if (image_size.ValueOrDie() > kHugeImageSize &&
386 if (m_pRenderStatus->GetRenderDevice()->StartDIBitsWithBlend(
387 m_pDIBBase, m_Alpha, m_FillArgb, m_ImageMatrix, m_ResampleOptions,
388 &m_DeviceHandle, m_BlendType)) {
389 if (m_DeviceHandle) {
390 m_Mode = Mode::kBlend;
396 if ((fabs(m_ImageMatrix
.b) >= 0.5f || m_ImageMatrix
.a == 0) ||
397 (fabs(m_ImageMatrix
.c) >= 0.5f || m_ImageMatrix
.d == 0)) {
403 absl::optional<FX_RECT> image_rect = GetUnitRect();
404 if (!image_rect.has_value())
407 FX_RECT clip_box = m_pRenderStatus->GetRenderDevice()->GetClipBox();
408 clip_box.Intersect(image_rect.value());
409 m_Mode = Mode::kTransform;
410 m_pTransformer = std::make_unique<CFX_ImageTransformer>(
411 m_pDIBBase, m_ImageMatrix, m_ResampleOptions, &clip_box);
415 absl::optional<FX_RECT> image_rect = GetUnitRect();
416 if (!image_rect.has_value())
423 if (!GetDimensionsFromUnitRect(image_rect.value(), &dest_left, &dest_top,
424 &dest_width, &dest_height)) {
428 if (m_pDIBBase->IsOpaqueImage() && m_Alpha == 1.0f) {
429 if (m_pRenderStatus->GetRenderDevice()->StretchDIBitsWithFlagsAndBlend(
430 m_pDIBBase, dest_left, dest_top, dest_width, dest_height,
431 m_ResampleOptions, m_BlendType)) {
435 if (m_pDIBBase->IsMaskFormat()) {
436 if (m_Alpha != 1.0f) {
439 if (m_pRenderStatus->GetRenderDevice()->StretchBitMaskWithFlags(
440 m_pDIBBase, dest_left, dest_top, dest_width, dest_height,
441 m_FillArgb, m_ResampleOptions)) {
450 FX_RECT clip_box = m_pRenderStatus->GetRenderDevice()->GetClipBox();
452 dest_rect.Intersect(image_rect.value());
454 dest_rect.left - image_rect->left, dest_rect.top - image_rect->top,
455 dest_rect.right - image_rect->left, dest_rect.bottom - image_rect->top);
456 RetainPtr<CFX_DIBitmap> pStretched = m_pDIBBase->StretchTo(
457 dest_width, dest_height, m_ResampleOptions, &dest_clip);
459 m_pRenderStatus->CompositeDIBitmap(pStretched, dest_rect.left,
460 dest_rect.top, m_FillArgb, m_Alpha,
461 m_BlendType, CPDF_Transparency());
467 if (m_pDIBBase->IsOpaqueImage()) {
472 uint32_t fill_color =
474 m_pRenderStatus->GetRenderDevice()->DrawPath(
475 path,
nullptr,
nullptr, fill_color, 0,
476 CFX_FillRenderOptions::WindingOptions());
481 m_pDIBBase->IsMaskFormat() ? m_pDIBBase : m_pDIBBase->CloneAlphaMask();
482 if (fabs(m_ImageMatrix
.b) >= 0.5f || fabs(m_ImageMatrix
.c) >= 0.5f) {
485 alpha_mask = alpha_mask->TransformTo(m_ImageMatrix, &left, &top);
491 m_pRenderStatus->GetRenderDevice()->SetBitMask(
492 std::move(alpha_mask), left, top,
493 ArgbEncode(0xff, bitmap_alpha, bitmap_alpha, bitmap_alpha));
497 absl::optional<FX_RECT> image_rect = GetUnitRect();
498 if (!image_rect.has_value())
505 if (!GetDimensionsFromUnitRect(image_rect.value(), &left, &top, &dest_width,
511 m_pRenderStatus->GetRenderDevice()->StretchBitMask(
512 std::move(alpha_mask), left, top, dest_width, dest_height,
513 ArgbEncode(0xff, bitmap_alpha, bitmap_alpha, bitmap_alpha));
522 return ContinueDefault(pPause);
524 return ContinueBlend(pPause);
525 case Mode::kTransform:
526 return ContinueTransform(pPause);
531 if (m_pLoader->Continue(pPause))
534 if (!StartRenderDIBBase())
537 if (m_Mode == Mode::kDefault)
544 return m_pRenderStatus->GetRenderDevice()->ContinueDIBits(
545 m_DeviceHandle.get(), pPause);
549 if (m_pTransformer->Continue(pPause))
552 RetainPtr<CFX_DIBitmap> pBitmap = m_pTransformer->DetachBitmap();
556 if (pBitmap->IsMaskFormat()) {
557 if (m_Alpha != 1.0f) {
560 m_Result = m_pRenderStatus->GetRenderDevice()->SetBitMask(
561 pBitmap, m_pTransformer->result().left, m_pTransformer->result().top,
564 pBitmap->MultiplyAlpha(m_Alpha);
565 m_Result = m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend(
566 pBitmap, m_pTransformer->result().left, m_pTransformer->result().top,
573 absl::optional<DecoderArray> decoder_array =
574 GetDecoderArray(m_pImageObject->GetImage()->GetStream()->GetDict());
575 if (!decoder_array.has_value())
578 for (
const auto& decoder : decoder_array.value()) {
579 if (decoder.first ==
"DCTDecode" || decoder.first ==
"JPXDecode") {
580 m_ResampleOptions.bLossy =
true;
589 if (!image_rect.Valid())
590 return absl::nullopt;
599 DCHECK(rect.Valid());
603 if (IsImageValueTooBig(dest_width) || IsImageValueTooBig(dest_height))
606 if (m_ImageMatrix
.a < 0)
607 dest_width = -dest_width;
609 if (m_ImageMatrix
.d > 0)
610 dest_height = -dest_height;
612 int dest_left = dest_width > 0 ? rect
.left : rect
.right;
613 int dest_top = dest_height > 0 ? rect
.top : rect
.bottom;
614 if (IsImageValueTooBig(dest_left) || IsImageValueTooBig(dest_top))
620 *height = dest_height;
bool Create(int width, int height, FXDIB_Format format, RetainPtr< CFX_DIBitmap > pBackdropBitmap)
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 Translate(float x, float y)
void Transform(const CFX_Matrix &matrix)
void AppendRect(float left, float bottom, float right, float top)
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 Continue(PauseIndicatorIface *pPause)
bool Start(CPDF_ImageObject *pImageObject, const CFX_Matrix &mtObj2Device, bool bStdCS, BlendMode blendType)
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)
#define FXARGB_MUL_ALPHA(argb, alpha)
constexpr FX_ARGB ArgbEncode(uint32_t a, uint32_t r, uint32_t g, uint32_t b)
int FXSYS_roundf(float f)
bool bInterpolateBilinear