Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
fpdf_editimg.cpp
Go to the documentation of this file.
1// Copyright 2014 The PDFium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "public/fpdf_edit.h"
8
9#include <memory>
10#include <utility>
11
12#include "core/fpdfapi/page/cpdf_dib.h"
13#include "core/fpdfapi/page/cpdf_image.h"
14#include "core/fpdfapi/page/cpdf_imageobject.h"
15#include "core/fpdfapi/page/cpdf_page.h"
16#include "core/fpdfapi/page/cpdf_pageobject.h"
17#include "core/fpdfapi/parser/cpdf_array.h"
18#include "core/fpdfapi/parser/cpdf_dictionary.h"
19#include "core/fpdfapi/parser/cpdf_name.h"
20#include "core/fpdfapi/parser/cpdf_stream.h"
21#include "core/fpdfapi/parser/cpdf_stream_acc.h"
22#include "core/fpdfapi/render/cpdf_imagerenderer.h"
23#include "core/fpdfapi/render/cpdf_rendercontext.h"
24#include "core/fpdfapi/render/cpdf_renderstatus.h"
25#include "core/fxcrt/stl_util.h"
26#include "core/fxge/cfx_defaultrenderdevice.h"
27#include "core/fxge/dib/cfx_dibitmap.h"
28#include "fpdfsdk/cpdfsdk_customaccess.h"
29#include "fpdfsdk/cpdfsdk_helpers.h"
30#include "third_party/base/notreached.h"
31
32namespace {
33
34// These checks ensure the consistency of colorspace values across core/ and
35// public/.
36static_assert(static_cast<int>(CPDF_ColorSpace::Family::kDeviceGray) ==
38 "kDeviceGray value mismatch");
39static_assert(static_cast<int>(CPDF_ColorSpace::Family::kDeviceRGB) ==
41 "kDeviceRGB value mismatch");
42static_assert(static_cast<int>(CPDF_ColorSpace::Family::kDeviceCMYK) ==
44 "kDeviceCMYK value mismatch");
45static_assert(static_cast<int>(CPDF_ColorSpace::Family::kCalGray) ==
47 "kCalGray value mismatch");
48static_assert(static_cast<int>(CPDF_ColorSpace::Family::kCalRGB) ==
50 "kCalRGB value mismatch");
51static_assert(static_cast<int>(CPDF_ColorSpace::Family::kLab) ==
53 "kLab value mismatch");
54static_assert(static_cast<int>(CPDF_ColorSpace::Family::kICCBased) ==
56 "kICCBased value mismatch");
57static_assert(static_cast<int>(CPDF_ColorSpace::Family::kSeparation) ==
59 "kSeparation value mismatch");
60static_assert(static_cast<int>(CPDF_ColorSpace::Family::kDeviceN) ==
62 "kDeviceN value mismatch");
63static_assert(static_cast<int>(CPDF_ColorSpace::Family::kIndexed) ==
65 "kIndexed value mismatch");
66static_assert(static_cast<int>(CPDF_ColorSpace::Family::kPattern) ==
68 "kPattern value mismatch");
69
70RetainPtr<IFX_SeekableReadStream> MakeSeekableReadStream(
71 FPDF_FILEACCESS* pFileAccess) {
72 return pdfium::MakeRetain<CPDFSDK_CustomAccess>(pFileAccess);
73}
74
75CPDF_ImageObject* CPDFImageObjectFromFPDFPageObject(
76 FPDF_PAGEOBJECT image_object) {
77 CPDF_PageObject* pPageObject = CPDFPageObjectFromFPDFPageObject(image_object);
78 return pPageObject ? pPageObject->AsImage() : nullptr;
79}
80
81bool LoadJpegHelper(FPDF_PAGE* pages,
82 int count,
83 FPDF_PAGEOBJECT image_object,
84 FPDF_FILEACCESS* file_access,
85 bool inline_jpeg) {
86 CPDF_ImageObject* pImgObj = CPDFImageObjectFromFPDFPageObject(image_object);
87 if (!pImgObj)
88 return false;
89
90 if (!file_access)
91 return false;
92
93 if (pages) {
94 for (int index = 0; index < count; index++) {
95 CPDF_Page* pPage = CPDFPageFromFPDFPage(pages[index]);
96 if (pPage)
97 pImgObj->GetImage()->ResetCache(pPage);
98 }
99 }
100
101 RetainPtr<IFX_SeekableReadStream> pFile = MakeSeekableReadStream(file_access);
102 if (inline_jpeg)
103 pImgObj->GetImage()->SetJpegImageInline(std::move(pFile));
104 else
105 pImgObj->GetImage()->SetJpegImage(std::move(pFile));
106
107 pImgObj->SetDirty(true);
108 return true;
109}
110
111} // namespace
112
113FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
114FPDFPageObj_NewImageObj(FPDF_DOCUMENT document) {
116 if (!pDoc)
117 return nullptr;
118
119 auto pImageObj = std::make_unique<CPDF_ImageObject>();
120 pImageObj->SetImage(pdfium::MakeRetain<CPDF_Image>(pDoc));
121
122 // Caller takes ownership.
123 return FPDFPageObjectFromCPDFPageObject(pImageObj.release());
124}
125
128 int count,
129 FPDF_PAGEOBJECT image_object,
130 FPDF_FILEACCESS* file_access) {
131 return LoadJpegHelper(pages, count, image_object, file_access, false);
132}
133
136 int count,
137 FPDF_PAGEOBJECT image_object,
138 FPDF_FILEACCESS* file_access) {
139 return LoadJpegHelper(pages, count, image_object, file_access, true);
140}
141
143FPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object,
144 double a,
145 double b,
146 double c,
147 double d,
148 double e,
149 double f) {
150 CPDF_ImageObject* pImgObj = CPDFImageObjectFromFPDFPageObject(image_object);
151 if (!pImgObj)
152 return false;
153
155 static_cast<float>(a), static_cast<float>(b), static_cast<float>(c),
156 static_cast<float>(d), static_cast<float>(e), static_cast<float>(f)));
157 pImgObj->SetDirty(true);
158 return true;
159}
160
162FPDFImageObj_SetBitmap(FPDF_PAGE* pages,
163 int count,
164 FPDF_PAGEOBJECT image_object,
165 FPDF_BITMAP bitmap) {
166 CPDF_ImageObject* pImgObj = CPDFImageObjectFromFPDFPageObject(image_object);
167 if (!pImgObj)
168 return false;
169
170 if (!bitmap)
171 return false;
172
173 if (pages) {
174 for (int index = 0; index < count; index++) {
175 CPDF_Page* pPage = CPDFPageFromFPDFPage(pages[index]);
176 if (pPage)
177 pImgObj->GetImage()->ResetCache(pPage);
178 }
179 }
180
181 RetainPtr<CFX_DIBitmap> holder(CFXDIBitmapFromFPDFBitmap(bitmap));
182 pImgObj->GetImage()->SetImage(holder);
183 pImgObj->CalcBoundingBox();
184 pImgObj->SetDirty(true);
185 return true;
186}
187
188FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV
189FPDFImageObj_GetBitmap(FPDF_PAGEOBJECT image_object) {
190 CPDF_ImageObject* pImgObj = CPDFImageObjectFromFPDFPageObject(image_object);
191 if (!pImgObj)
192 return nullptr;
193
194 RetainPtr<CPDF_Image> pImg = pImgObj->GetImage();
195 if (!pImg)
196 return nullptr;
197
198 RetainPtr<CFX_DIBBase> pSource = pImg->LoadDIBBase();
199 if (!pSource)
200 return nullptr;
201
202 // If the source image has a representation of 1 bit per pixel, or if the
203 // source image has a color palette, convert it to a representation that does
204 // not have a color palette, as there is no public API to access the palette.
205 //
206 // Otherwise, convert the source image to a bitmap directly,
207 // retaining its color representation.
208 //
209 // Only return FPDF_BITMAPs in formats that FPDFBitmap_CreateEx() would
210 // return.
211 enum class ConversionOp {
212 kRealize,
213 kConvertTo8bppRgb,
214 kConvertToRgb,
215 };
216
217 ConversionOp op;
218 switch (pSource->GetFormat()) {
221 // Masks do not have palettes, so they can be safely converted to
222 // `FXDIB_Format::k8bppRgb`.
223 CHECK(!pSource->HasPalette());
224 op = ConversionOp::kConvertTo8bppRgb;
225 break;
227 // If there is a palette, then convert to `FXDIB_Format::kRgb` to avoid
228 // creating a bitmap with a palette.
229 op = pSource->HasPalette() ? ConversionOp::kConvertToRgb
230 : ConversionOp::kConvertTo8bppRgb;
231 break;
233 // If there is a palette, then convert to `FXDIB_Format::kRgb` to avoid
234 // creating a bitmap with a palette.
235 op = pSource->HasPalette() ? ConversionOp::kConvertToRgb
236 : ConversionOp::kRealize;
237 break;
238
242 CHECK(!pSource->HasPalette());
243 op = ConversionOp::kRealize;
244 break;
245
247 NOTREACHED_NORETURN();
248 }
249 }
250
251 RetainPtr<CFX_DIBitmap> pBitmap;
252 switch (op) {
253 case ConversionOp::kRealize:
254 pBitmap = pSource->Realize();
255 break;
256 case ConversionOp::kConvertTo8bppRgb:
257 pBitmap = pSource->ConvertTo(FXDIB_Format::k8bppRgb);
258 break;
259 case ConversionOp::kConvertToRgb:
260 pBitmap = pSource->ConvertTo(FXDIB_Format::kRgb);
261 break;
262 }
263 if (pBitmap) {
264 CHECK(!pBitmap->HasPalette());
265 }
266
267 return FPDFBitmapFromCFXDIBitmap(pBitmap.Leak());
268}
269
270FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV
271FPDFImageObj_GetRenderedBitmap(FPDF_DOCUMENT document,
272 FPDF_PAGE page,
273 FPDF_PAGEOBJECT image_object) {
275 if (!doc)
276 return nullptr;
277
278 CPDF_Page* optional_page = CPDFPageFromFPDFPage(page);
279 if (optional_page && optional_page->GetDocument() != doc)
280 return nullptr;
281
282 CPDF_ImageObject* image = CPDFImageObjectFromFPDFPageObject(image_object);
283 if (!image)
284 return nullptr;
285
286 // Create |result_bitmap|.
287 const CFX_Matrix& image_matrix = image->matrix();
288 int output_width = image_matrix.a;
289 int output_height = image_matrix.d;
290 auto result_bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
291 if (!result_bitmap->Create(output_width, output_height, FXDIB_Format::kArgb))
292 return nullptr;
293
294 // Set up all the rendering code.
295 RetainPtr<CPDF_Dictionary> page_resources =
296 optional_page ? optional_page->GetMutablePageResources() : nullptr;
297 CPDF_RenderContext context(doc, std::move(page_resources),
298 /*pPageCache=*/nullptr);
299 CFX_DefaultRenderDevice device;
300 device.Attach(result_bitmap);
301 CPDF_RenderStatus status(&context, &device);
302 CPDF_ImageRenderer renderer(&status);
303
304 // Need to first flip the image, as expected by |renderer|.
305 CFX_Matrix render_matrix(1, 0, 0, -1, 0, output_height);
306
307 // Then take |image_matrix|'s offset into account.
308 render_matrix.Translate(-image_matrix.e, image_matrix.f);
309
310 // Do the actual rendering.
311 bool should_continue = renderer.Start(image, render_matrix,
312 /*bStdCS=*/false, BlendMode::kNormal);
313 while (should_continue)
314 should_continue = renderer.Continue(/*pPause=*/nullptr);
315
316 if (!renderer.GetResult())
317 return nullptr;
318
319#if defined(PDF_USE_SKIA)
320 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
321 result_bitmap->UnPreMultiply();
322 }
323#endif
324
325 // Caller takes ownership.
326 return FPDFBitmapFromCFXDIBitmap(result_bitmap.Leak());
327}
328
329FPDF_EXPORT unsigned long FPDF_CALLCONV
330FPDFImageObj_GetImageDataDecoded(FPDF_PAGEOBJECT image_object,
331 void* buffer,
332 unsigned long buflen) {
333 CPDF_ImageObject* pImgObj = CPDFImageObjectFromFPDFPageObject(image_object);
334 if (!pImgObj)
335 return 0;
336
337 RetainPtr<CPDF_Image> pImg = pImgObj->GetImage();
338 if (!pImg)
339 return 0;
340
341 RetainPtr<const CPDF_Stream> pImgStream = pImg->GetStream();
342 if (!pImgStream)
343 return 0;
344
345 return DecodeStreamMaybeCopyAndReturnLength(
346 std::move(pImgStream),
347 {static_cast<uint8_t*>(buffer), static_cast<size_t>(buflen)});
348}
349
350FPDF_EXPORT unsigned long FPDF_CALLCONV
351FPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object,
352 void* buffer,
353 unsigned long buflen) {
354 CPDF_ImageObject* pImgObj = CPDFImageObjectFromFPDFPageObject(image_object);
355 if (!pImgObj)
356 return 0;
357
358 RetainPtr<CPDF_Image> pImg = pImgObj->GetImage();
359 if (!pImg)
360 return 0;
361
362 RetainPtr<const CPDF_Stream> pImgStream = pImg->GetStream();
363 if (!pImgStream)
364 return 0;
365
366 return GetRawStreamMaybeCopyAndReturnLength(
367 std::move(pImgStream),
368 {static_cast<uint8_t*>(buffer), static_cast<size_t>(buflen)});
369}
370
372FPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object) {
373 CPDF_ImageObject* pImgObj = CPDFImageObjectFromFPDFPageObject(image_object);
374 if (!pImgObj)
375 return 0;
376
377 RetainPtr<CPDF_Image> pImg = pImgObj->GetImage();
378 if (!pImg)
379 return 0;
380
381 RetainPtr<const CPDF_Dictionary> pDict = pImg->GetDict();
382 if (!pDict)
383 return 0;
384
385 RetainPtr<const CPDF_Object> pFilter = pDict->GetDirectObjectFor("Filter");
386 if (!pFilter)
387 return 0;
388
389 if (pFilter->IsArray())
390 return fxcrt::CollectionSize<int>(*pFilter->AsArray());
391
392 if (pFilter->IsName())
393 return 1;
394
395 return 0;
396}
397
398FPDF_EXPORT unsigned long FPDF_CALLCONV
399FPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object,
400 int index,
401 void* buffer,
402 unsigned long buflen) {
403 if (index < 0 || index >= FPDFImageObj_GetImageFilterCount(image_object))
404 return 0;
405
407 RetainPtr<const CPDF_Dictionary> pDict =
408 pObj->AsImage()->GetImage()->GetDict();
409 RetainPtr<const CPDF_Object> pFilter = pDict->GetDirectObjectFor("Filter");
410 ByteString bsFilter = pFilter->IsName()
411 ? pFilter->AsName()->GetString()
412 : pFilter->AsArray()->GetByteStringAt(index);
413
414 return NulTerminateMaybeCopyAndReturnLength(bsFilter, buffer, buflen);
415}
416
418FPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object,
419 FPDF_PAGE page,
420 FPDF_IMAGEOBJ_METADATA* metadata) {
421 CPDF_ImageObject* pImgObj = CPDFImageObjectFromFPDFPageObject(image_object);
422 if (!pImgObj || !metadata)
423 return false;
424
425 RetainPtr<CPDF_Image> pImg = pImgObj->GetImage();
426 if (!pImg)
427 return false;
428
429 metadata->marked_content_id =
430 pImgObj->GetContentMarks()->GetMarkedContentID();
431
432 const int nPixelWidth = pImg->GetPixelWidth();
433 const int nPixelHeight = pImg->GetPixelHeight();
434 metadata->width = nPixelWidth;
435 metadata->height = nPixelHeight;
436
437 const float nWidth = pImgObj->GetRect().Width();
438 const float nHeight = pImgObj->GetRect().Height();
439 constexpr int nPointsPerInch = 72;
440 if (nWidth != 0 && nHeight != 0) {
441 metadata->horizontal_dpi = nPixelWidth / nWidth * nPointsPerInch;
442 metadata->vertical_dpi = nPixelHeight / nHeight * nPointsPerInch;
443 }
444
445 metadata->bits_per_pixel = 0;
447
448 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
449 if (!pPage || !pPage->GetDocument() || !pImg->GetStream())
450 return true;
451
452 // A cross-document image may have come from the embedder.
453 if (pPage->GetDocument() != pImg->GetDocument())
454 return false;
455
456 RetainPtr<CPDF_DIB> pSource = pImg->CreateNewDIB();
457 CPDF_DIB::LoadState ret = pSource->StartLoadDIBBase(
458 false, nullptr, pPage->GetPageResources().Get(), false,
459 CPDF_ColorSpace::Family::kUnknown, false, {0, 0});
460 if (ret == CPDF_DIB::LoadState::kFail)
461 return true;
462
463 metadata->bits_per_pixel = pSource->GetBPP();
464 if (pSource->GetColorSpace()) {
465 metadata->colorspace =
466 static_cast<int>(pSource->GetColorSpace()->GetFamily());
467 }
468 return true;
469}
470
472FPDFImageObj_GetImagePixelSize(FPDF_PAGEOBJECT image_object,
473 unsigned int* width,
474 unsigned int* height) {
475 CPDF_ImageObject* pImgObj = CPDFImageObjectFromFPDFPageObject(image_object);
476 if (!pImgObj || !width || !height) {
477 return false;
478 }
479
480 RetainPtr<CPDF_Image> pImg = pImgObj->GetImage();
481 if (!pImg) {
482 return false;
483 }
484
485 *width = pImg->GetPixelWidth();
486 *height = pImg->GetPixelHeight();
487 return true;
488}
bool Attach(RetainPtr< CFX_DIBitmap > pBitmap)
CFX_Matrix(float a1, float b1, float c1, float d1, float e1, float f1)
void Translate(float x, float y)
void SetImageMatrix(const CFX_Matrix &matrix)
const CFX_Matrix & matrix() const
CPDF_ImageRenderer(CPDF_RenderStatus *pStatus)
bool Continue(PauseIndicatorIface *pPause)
bool Start(CPDF_ImageObject *pImageObject, const CFX_Matrix &mtObj2Device, bool bStdCS, BlendMode blendType)
void SetDirty(bool value)
const CFX_FloatRect & GetRect() const
virtual CPDF_ImageObject * AsImage()
CPDF_Document * GetDocument() const override
Definition cpdf_page.cpp:51
unsigned long NulTerminateMaybeCopyAndReturnLength(const ByteString &text, void *buffer, unsigned long buflen)
CPDF_Page * CPDFPageFromFPDFPage(FPDF_PAGE page)
CPDF_Document * CPDFDocumentFromFPDFDocument(FPDF_DOCUMENT doc)
CPDF_PageObject * CPDFPageObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_SetBitmap(FPDF_PAGE *pages, int count, FPDF_PAGEOBJECT image_object, FPDF_BITMAP bitmap)
#define FPDF_COLORSPACE_UNKNOWN
Definition fpdf_edit.h:24
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_LoadJpegFile(FPDF_PAGE *pages, int count, FPDF_PAGEOBJECT image_object, FPDF_FILEACCESS *file_access)
#define FPDF_COLORSPACE_DEVICECMYK
Definition fpdf_edit.h:27
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object, FPDF_PAGE page, FPDF_IMAGEOBJ_METADATA *metadata)
#define FPDF_COLORSPACE_CALGRAY
Definition fpdf_edit.h:28
FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFImageObj_GetRenderedBitmap(FPDF_DOCUMENT document, FPDF_PAGE page, FPDF_PAGEOBJECT image_object)
#define FPDF_COLORSPACE_DEVICEN
Definition fpdf_edit.h:33
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object, void *buffer, unsigned long buflen)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object, int index, void *buffer, unsigned long buflen)
FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFImageObj_GetBitmap(FPDF_PAGEOBJECT image_object)
#define FPDF_COLORSPACE_DEVICEGRAY
Definition fpdf_edit.h:25
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object, double a, double b, double c, double d, double e, double f)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_LoadJpegFileInline(FPDF_PAGE *pages, int count, FPDF_PAGEOBJECT image_object, FPDF_FILEACCESS *file_access)
FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_NewImageObj(FPDF_DOCUMENT document)
#define FPDF_COLORSPACE_PATTERN
Definition fpdf_edit.h:35
FPDF_EXPORT int FPDF_CALLCONV FPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object)
#define FPDF_COLORSPACE_SEPARATION
Definition fpdf_edit.h:32
#define FPDF_COLORSPACE_LAB
Definition fpdf_edit.h:30
#define FPDF_COLORSPACE_INDEXED
Definition fpdf_edit.h:34
#define FPDF_COLORSPACE_CALRGB
Definition fpdf_edit.h:29
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetImagePixelSize(FPDF_PAGEOBJECT image_object, unsigned int *width, unsigned int *height)
#define FPDF_COLORSPACE_ICCBASED
Definition fpdf_edit.h:31
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageDataDecoded(FPDF_PAGEOBJECT image_object, void *buffer, unsigned long buflen)
#define FPDF_COLORSPACE_DEVICERGB
Definition fpdf_edit.h:26
#define FPDF_CALLCONV
Definition fpdfview.h:227
#define FPDF_EXPORT
Definition fpdfview.h:221
BlendMode
Definition fx_dib.h:49
FXDIB_Format
Definition fx_dib.h:19
#define CHECK(cvref)
unsigned int bits_per_pixel
Definition fpdf_edit.h:87
unsigned int height
Definition fpdf_edit.h:81
unsigned int width
Definition fpdf_edit.h:79