LibreOffice Module vcl (master) 1
PDFiumLibrary.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 */
10
12
13#include <cassert>
14
15#include <sal/log.hxx>
16#include <fpdf_doc.h>
17#include <fpdf_annot.h>
18#include <fpdf_edit.h>
19#include <fpdf_text.h>
20#include <fpdf_save.h>
21#include <fpdf_signature.h>
22#include <fpdf_formfill.h>
23
24#include <osl/endian.h>
25#include <vcl/bitmap.hxx>
26#include <tools/stream.hxx>
28#include <o3tl/string_view.hxx>
29
31
32using namespace com::sun::star;
33
34static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Unknown) == FPDF_PAGEOBJ_UNKNOWN,
35 "PDFPageObjectType::Unknown value mismatch");
36static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Text) == FPDF_PAGEOBJ_TEXT,
37 "PDFPageObjectType::Text value mismatch");
38static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Path) == FPDF_PAGEOBJ_PATH,
39 "PDFPageObjectType::Path value mismatch");
40static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Image) == FPDF_PAGEOBJ_IMAGE,
41 "PDFPageObjectType::Image value mismatch");
42static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Shading) == FPDF_PAGEOBJ_SHADING,
43 "PDFPageObjectType::Shading value mismatch");
44static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Form) == FPDF_PAGEOBJ_FORM,
45 "PDFPageObjectType::Form value mismatch");
46
47static_assert(static_cast<int>(vcl::pdf::PDFSegmentType::Unknown) == FPDF_SEGMENT_UNKNOWN,
48 "PDFSegmentType::Unknown value mismatch");
49static_assert(static_cast<int>(vcl::pdf::PDFSegmentType::Lineto) == FPDF_SEGMENT_LINETO,
50 "PDFSegmentType::Lineto value mismatch");
51static_assert(static_cast<int>(vcl::pdf::PDFSegmentType::Bezierto) == FPDF_SEGMENT_BEZIERTO,
52 "PDFSegmentType::Bezierto value mismatch");
53static_assert(static_cast<int>(vcl::pdf::PDFSegmentType::Moveto) == FPDF_SEGMENT_MOVETO,
54 "PDFSegmentType::Moveto value mismatch");
55
56static_assert(static_cast<int>(vcl::pdf::PDFBitmapType::Unknown) == FPDFBitmap_Unknown,
57 "PDFBitmapType::Unknown value mismatch");
58static_assert(static_cast<int>(vcl::pdf::PDFBitmapType::Gray) == FPDFBitmap_Gray,
59 "PDFBitmapType::Gray value mismatch");
60static_assert(static_cast<int>(vcl::pdf::PDFBitmapType::BGR) == FPDFBitmap_BGR,
61 "PDFBitmapType::BGR value mismatch");
62static_assert(static_cast<int>(vcl::pdf::PDFBitmapType::BGRx) == FPDFBitmap_BGRx,
63 "PDFBitmapType::BGRx value mismatch");
64static_assert(static_cast<int>(vcl::pdf::PDFBitmapType::BGRA) == FPDFBitmap_BGRA,
65 "PDFBitmapType::BGRA value mismatch");
66
67static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Unknown) == FPDF_OBJECT_UNKNOWN,
68 "PDFObjectType::Unknown value mismatch");
69static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Boolean) == FPDF_OBJECT_BOOLEAN,
70 "PDFObjectType::Boolean value mismatch");
71static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Number) == FPDF_OBJECT_NUMBER,
72 "PDFObjectType::Number value mismatch");
73static_assert(static_cast<int>(vcl::pdf::PDFObjectType::String) == FPDF_OBJECT_STRING,
74 "PDFObjectType::String value mismatch");
75static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Name) == FPDF_OBJECT_NAME,
76 "PDFObjectType::Name value mismatch");
77static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Array) == FPDF_OBJECT_ARRAY,
78 "PDFObjectType::Array value mismatch");
79static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Dictionary) == FPDF_OBJECT_DICTIONARY,
80 "PDFObjectType::Dictionary value mismatch");
81static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Stream) == FPDF_OBJECT_STREAM,
82 "PDFObjectType::Stream value mismatch");
83static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Nullobj) == FPDF_OBJECT_NULLOBJ,
84 "PDFObjectType::Nullobj value mismatch");
85static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Reference) == FPDF_OBJECT_REFERENCE,
86 "PDFObjectType::Reference value mismatch");
87
88static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::Unknown) == FPDF_TEXTRENDERMODE_UNKNOWN,
89 "PDFTextRenderMode::Unknown value mismatch");
90static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::Fill) == FPDF_TEXTRENDERMODE_FILL,
91 "PDFTextRenderMode::Fill value mismatch");
92static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::Stroke) == FPDF_TEXTRENDERMODE_STROKE,
93 "PDFTextRenderMode::Stroke value mismatch");
94static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::FillStroke)
95 == FPDF_TEXTRENDERMODE_FILL_STROKE,
96 "PDFTextRenderMode::FillStroke value mismatch");
97static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::Invisible)
98 == FPDF_TEXTRENDERMODE_INVISIBLE,
99 "PDFTextRenderMode::Invisible value mismatch");
100static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::FillClip)
101 == FPDF_TEXTRENDERMODE_FILL_CLIP,
102 "PDFTextRenderMode::FillClip value mismatch");
103static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::StrokeClip)
104 == FPDF_TEXTRENDERMODE_STROKE_CLIP,
105 "PDFTextRenderMode::StrokeClip value mismatch");
106static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::FillStrokeClip)
107 == FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP,
108 "PDFTextRenderMode::FillStrokeClip value mismatch");
109static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::Clip) == FPDF_TEXTRENDERMODE_CLIP,
110 "PDFTextRenderMode::Clip value mismatch");
111
112static_assert(static_cast<int>(vcl::pdf::PDFFillMode::None) == FPDF_FILLMODE_NONE,
113 "PDFFillMode::None value mismatch");
114static_assert(static_cast<int>(vcl::pdf::PDFFillMode::Alternate) == FPDF_FILLMODE_ALTERNATE,
115 "PDFFillMode::Alternate value mismatch");
116static_assert(static_cast<int>(vcl::pdf::PDFFillMode::Winding) == FPDF_FILLMODE_WINDING,
117 "PDFFillMode::Winding value mismatch");
118
119static_assert(static_cast<int>(vcl::pdf::PDFFindFlags::MatchCase) == FPDF_MATCHCASE,
120 "PDFFindFlags::MatchCase value mismatch");
121static_assert(static_cast<int>(vcl::pdf::PDFFindFlags::MatchWholeWord) == FPDF_MATCHWHOLEWORD,
122 "PDFFindFlags::MatchWholeWord value mismatch");
123static_assert(static_cast<int>(vcl::pdf::PDFFindFlags::Consecutive) == FPDF_CONSECUTIVE,
124 "PDFFindFlags::Consecutive value mismatch");
125
126static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Success) == FPDF_ERR_SUCCESS,
127 "PDFErrorType::Success value mismatch");
128static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Unknown) == FPDF_ERR_UNKNOWN,
129 "PDFErrorType::Unknown value mismatch");
130static_assert(static_cast<int>(vcl::pdf::PDFErrorType::File) == FPDF_ERR_FILE,
131 "PDFErrorType::File value mismatch");
132static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Format) == FPDF_ERR_FORMAT,
133 "PDFErrorType::Format value mismatch");
134static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Password) == FPDF_ERR_PASSWORD,
135 "PDFErrorType::Password value mismatch");
136static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Security) == FPDF_ERR_SECURITY,
137 "PDFErrorType::Security value mismatch");
138static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Page) == FPDF_ERR_PAGE,
139 "PDFErrorType::Page value mismatch");
140
141static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::Unknown) == FPDF_FORMFIELD_UNKNOWN,
142 "PDFFormFieldType::Unknown value mismatch");
143static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::PushButton) == FPDF_FORMFIELD_PUSHBUTTON,
144 "PDFFormFieldType::PushButton value mismatch");
145static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::CheckBox) == FPDF_FORMFIELD_CHECKBOX,
146 "PDFFormFieldType::CheckBox value mismatch");
147static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::RadioButton)
148 == FPDF_FORMFIELD_RADIOBUTTON,
149 "PDFFormFieldType::RadioButton value mismatch");
150static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::ComboBox) == FPDF_FORMFIELD_COMBOBOX,
151 "PDFFormFieldType::ComboBox value mismatch");
152static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::ListBox) == FPDF_FORMFIELD_LISTBOX,
153 "PDFFormFieldType::ListBox value mismatch");
154static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::TextField) == FPDF_FORMFIELD_TEXTFIELD,
155 "PDFFormFieldType::TextField value mismatch");
156static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::Signature) == FPDF_FORMFIELD_SIGNATURE,
157 "PDFFormFieldType::Signature value mismatch");
158
159static_assert(static_cast<int>(vcl::pdf::PDFAnnotAActionType::KeyStroke)
160 == FPDF_ANNOT_AACTION_KEY_STROKE,
161 "PDFAnnotAActionType::KeyStroke) value mismatch");
162static_assert(static_cast<int>(vcl::pdf::PDFAnnotAActionType::Format) == FPDF_ANNOT_AACTION_FORMAT,
163 "PDFAnnotAActionType::Format) value mismatch");
164static_assert(static_cast<int>(vcl::pdf::PDFAnnotAActionType::Validate)
165 == FPDF_ANNOT_AACTION_VALIDATE,
166 "PDFAnnotAActionType::Validate) value mismatch");
167static_assert(static_cast<int>(vcl::pdf::PDFAnnotAActionType::Calculate)
168 == FPDF_ANNOT_AACTION_CALCULATE,
169 "PDFAnnotAActionType::Calculate) value mismatch");
170
171namespace
172{
174struct CompatibleWriter : public FPDF_FILEWRITE
175{
176 CompatibleWriter(SvMemoryStream& rStream)
177 : m_rStream(rStream)
178 {
179 }
180
181 SvMemoryStream& m_rStream;
182};
183
184int CompatibleWriterCallback(FPDF_FILEWRITE* pFileWrite, const void* pData, unsigned long nSize)
185{
186 auto pImpl = static_cast<CompatibleWriter*>(pFileWrite);
187 pImpl->m_rStream.WriteBytes(pData, nSize);
188 return 1;
189}
190}
191
192namespace vcl::pdf
193{
194namespace
195{
196class PDFiumBitmapImpl final : public PDFiumBitmap
197{
198private:
199 FPDF_BITMAP mpBitmap;
200
201 PDFiumBitmapImpl(const PDFiumBitmapImpl&) = delete;
202 PDFiumBitmapImpl& operator=(const PDFiumBitmapImpl&) = delete;
203
204public:
205 PDFiumBitmapImpl(FPDF_BITMAP pBitmap);
206 ~PDFiumBitmapImpl() override;
207 FPDF_BITMAP getPointer() { return mpBitmap; }
208
209 void fillRect(int left, int top, int width, int height, sal_uInt32 nColor) override;
210 void renderPageBitmap(PDFiumDocument* pDoc, PDFiumPage* pPage, int nStartX, int nStartY,
211 int nSizeX, int nSizeY) override;
212 ConstScanline getBuffer() override;
213 int getStride() override;
214 int getWidth() override;
215 int getHeight() override;
216 PDFBitmapType getFormat() override;
217};
218
219class PDFiumPathSegmentImpl final : public PDFiumPathSegment
220{
221private:
222 FPDF_PATHSEGMENT mpPathSegment;
223
224 PDFiumPathSegmentImpl(const PDFiumPathSegmentImpl&) = delete;
225 PDFiumPathSegmentImpl& operator=(const PDFiumPathSegmentImpl&) = delete;
226
227public:
228 PDFiumPathSegmentImpl(FPDF_PATHSEGMENT pPathSegment);
229
230 basegfx::B2DPoint getPoint() const override;
231 bool isClosed() const override;
232 PDFSegmentType getType() const override;
233};
234
235class PDFiumAnnotationImpl final : public PDFiumAnnotation
236{
237private:
238 FPDF_ANNOTATION mpAnnotation;
239
240 PDFiumAnnotationImpl(const PDFiumAnnotationImpl&) = delete;
241 PDFiumAnnotationImpl& operator=(const PDFiumAnnotationImpl&) = delete;
242
243public:
244 PDFiumAnnotationImpl(FPDF_ANNOTATION pAnnotation);
245 ~PDFiumAnnotationImpl();
246 FPDF_ANNOTATION getPointer() { return mpAnnotation; }
247
248 PDFAnnotationSubType getSubType() override;
249 basegfx::B2DRectangle getRectangle() override;
250 bool hasKey(OString const& rKey) override;
251 PDFObjectType getValueType(OString const& rKey) override;
252 OUString getString(OString const& rKey) override;
253 std::unique_ptr<PDFiumAnnotation> getLinked(OString const& rKey) override;
254 int getObjectCount() override;
255 std::unique_ptr<PDFiumPageObject> getObject(int nIndex) override;
256 std::vector<std::vector<basegfx::B2DPoint>> getInkStrokes() override;
257 std::vector<basegfx::B2DPoint> getVertices() override;
258 Color getColor() override;
259 Color getInteriorColor() override;
260 float getBorderWidth() override;
261 basegfx::B2DSize getBorderCornerRadius() override;
262 size_t getAttachmentPointsCount() override;
263 std::vector<basegfx::B2DPoint> getAttachmentPoints(size_t nIndex) override;
264 std::vector<basegfx::B2DPoint> getLineGeometry() override;
265 PDFFormFieldType getFormFieldType(PDFiumDocument* pDoc) override;
266 float getFontSize(PDFiumDocument* pDoc) override;
267 OUString getFormFieldAlternateName(PDFiumDocument* pDoc) override;
268 int getFormFieldFlags(PDFiumDocument* pDoc) override;
269 OUString getFormAdditionalActionJavaScript(PDFiumDocument* pDoc,
270 PDFAnnotAActionType eEvent) override;
271 OUString getFormFieldValue(PDFiumDocument* pDoc) override;
272};
273
274class PDFiumPageObjectImpl final : public PDFiumPageObject
275{
276private:
277 FPDF_PAGEOBJECT mpPageObject;
278
279 PDFiumPageObjectImpl(const PDFiumPageObjectImpl&) = delete;
280 PDFiumPageObjectImpl& operator=(const PDFiumPageObjectImpl&) = delete;
281
282public:
283 PDFiumPageObjectImpl(FPDF_PAGEOBJECT pPageObject);
284
285 PDFPageObjectType getType() override;
286 OUString getText(std::unique_ptr<PDFiumTextPage> const& pTextPage) override;
287
288 int getFormObjectCount() override;
289 std::unique_ptr<PDFiumPageObject> getFormObject(int nIndex) override;
290
291 basegfx::B2DHomMatrix getMatrix() override;
292 basegfx::B2DRectangle getBounds() override;
293 double getFontSize() override;
294 OUString getFontName() override;
295 PDFTextRenderMode getTextRenderMode() override;
296 Color getFillColor() override;
297 Color getStrokeColor() override;
298 double getStrokeWidth() override;
299 // Path
300 int getPathSegmentCount() override;
301 std::unique_ptr<PDFiumPathSegment> getPathSegment(int index) override;
302 Size getImageSize(PDFiumPage& rPage) override;
303 std::unique_ptr<PDFiumBitmap> getImageBitmap() override;
304 bool getDrawMode(PDFFillMode& eFillMode, bool& bStroke) override;
305};
306
307class PDFiumSearchHandleImpl final : public PDFiumSearchHandle
308{
309private:
310 FPDF_SCHHANDLE mpSearchHandle;
311
312 PDFiumSearchHandleImpl(const PDFiumSearchHandleImpl&) = delete;
313 PDFiumSearchHandleImpl& operator=(const PDFiumSearchHandleImpl&) = delete;
314
315public:
316 PDFiumSearchHandleImpl(FPDF_SCHHANDLE pSearchHandle);
317 ~PDFiumSearchHandleImpl();
318
319 bool findNext() override;
320 bool findPrev() override;
321 int getSearchResultIndex() override;
322 int getSearchCount() override;
323};
324
325class PDFiumTextPageImpl final : public PDFiumTextPage
326{
327private:
328 FPDF_TEXTPAGE mpTextPage;
329
330 PDFiumTextPageImpl(const PDFiumTextPageImpl&) = delete;
331 PDFiumTextPageImpl& operator=(const PDFiumTextPageImpl&) = delete;
332
333public:
334 PDFiumTextPageImpl(FPDF_TEXTPAGE pTextPage);
335 ~PDFiumTextPageImpl();
336
337 FPDF_TEXTPAGE getPointer() { return mpTextPage; }
338
339 int countChars() override;
340 unsigned int getUnicode(int index) override;
341 std::unique_ptr<PDFiumSearchHandle> findStart(const OUString& rFindWhat, PDFFindFlags nFlags,
342 sal_Int32 nStartIndex) override;
343
345 basegfx::B2DRectangle getCharBox(int nIndex, double fPageHeight) override;
346};
347
348class PDFiumSignatureImpl final : public PDFiumSignature
349{
350private:
351 FPDF_SIGNATURE mpSignature;
352 PDFiumSignatureImpl(const PDFiumSignatureImpl&) = delete;
353 PDFiumSignatureImpl& operator=(const PDFiumSignatureImpl&) = delete;
354
355public:
356 PDFiumSignatureImpl(FPDF_SIGNATURE pSignature);
357
358 std::vector<int> getByteRange() override;
359 int getDocMDPPermission() override;
360 std::vector<unsigned char> getContents() override;
361 OString getSubFilter() override;
362 OUString getReason() override;
363 css::util::DateTime getTime() override;
364};
365
366class PDFiumPageImpl final : public PDFiumPage
367{
368private:
369 FPDF_PAGE mpPage;
370
371private:
372 PDFiumPageImpl(const PDFiumPageImpl&) = delete;
373 PDFiumPageImpl& operator=(const PDFiumPageImpl&) = delete;
374
375public:
376 PDFiumPageImpl(FPDF_PAGE pPage)
377 : mpPage(pPage)
378 {
379 }
380
381 ~PDFiumPageImpl() override
382 {
383 if (mpPage)
384 FPDF_ClosePage(mpPage);
385 }
386
387 FPDF_PAGE getPointer() { return mpPage; }
388
389 int getObjectCount() override;
390 std::unique_ptr<PDFiumPageObject> getObject(int nIndex) override;
391
392 int getAnnotationCount() override;
393 int getAnnotationIndex(std::unique_ptr<PDFiumAnnotation> const& rAnnotation) override;
394
395 std::unique_ptr<PDFiumAnnotation> getAnnotation(int nIndex) override;
396
397 std::unique_ptr<PDFiumTextPage> getTextPage() override;
398
399 BitmapChecksum getChecksum(int nMDPPerm) override;
400
401 double getWidth() override;
402 double getHeight() override;
403
404 bool hasTransparency() override;
405
406 bool hasLinks() override;
407
408 void onAfterLoadPage(PDFiumDocument* pDoc) override;
409};
410
412class PDFiumFormHandle final
413{
414private:
415 FPDF_FORMHANDLE mpHandle;
416
417 PDFiumFormHandle(const PDFiumFormHandle&) = delete;
418 PDFiumFormHandle& operator=(const PDFiumFormHandle&) = delete;
419
420public:
421 PDFiumFormHandle(FPDF_FORMHANDLE pHandle);
422 ~PDFiumFormHandle();
423 FPDF_FORMHANDLE getPointer();
424};
425
426class PDFiumDocumentImpl : public PDFiumDocument
427{
428private:
429 FPDF_DOCUMENT mpPdfDocument;
430 FPDF_FORMFILLINFO m_aFormCallbacks;
431 std::unique_ptr<PDFiumFormHandle> m_pFormHandle;
432
433private:
434 PDFiumDocumentImpl(const PDFiumDocumentImpl&) = delete;
435 PDFiumDocumentImpl& operator=(const PDFiumDocumentImpl&) = delete;
436
437public:
438 PDFiumDocumentImpl(FPDF_DOCUMENT pPdfDocument);
439 ~PDFiumDocumentImpl() override;
440 FPDF_FORMHANDLE getFormHandlePointer();
441
442 // Page size in points
443 basegfx::B2DSize getPageSize(int nIndex) override;
444 int getPageCount() override;
445 int getSignatureCount() override;
446 int getFileVersion() override;
447 bool saveWithVersion(SvMemoryStream& rStream, int nFileVersion) override;
448
449 std::unique_ptr<PDFiumPage> openPage(int nIndex) override;
450 std::unique_ptr<PDFiumSignature> getSignature(int nIndex) override;
451 std::vector<unsigned int> getTrailerEnds() override;
452};
453
454class PDFiumImpl : public PDFium
455{
456private:
457 PDFiumImpl(const PDFiumImpl&) = delete;
458 PDFiumImpl& operator=(const PDFiumImpl&) = delete;
459
460 OUString maLastError;
461
462public:
463 PDFiumImpl();
464 ~PDFiumImpl() override;
465
466 const OUString& getLastError() const override { return maLastError; }
467
468 std::unique_ptr<PDFiumDocument> openDocument(const void* pData, int nSize,
469 const OString& rPassword) override;
470 PDFErrorType getLastErrorCode() override;
472 std::unique_ptr<PDFiumBitmap> createBitmap(int& nWidth, int& nHeight, int nAlpha) override;
473};
474}
475
476PDFiumImpl::PDFiumImpl()
477{
478 FPDF_LIBRARY_CONFIG aConfig;
479 aConfig.version = 2;
480 aConfig.m_pUserFontPaths = nullptr;
481 aConfig.m_pIsolate = nullptr;
482 aConfig.m_v8EmbedderSlot = 0;
483 FPDF_InitLibraryWithConfig(&aConfig);
484}
485
486PDFiumImpl::~PDFiumImpl() { FPDF_DestroyLibrary(); }
487
488std::unique_ptr<PDFiumDocument> PDFiumImpl::openDocument(const void* pData, int nSize,
489 const OString& rPassword)
490{
491 maLastError = OUString();
492 std::unique_ptr<PDFiumDocument> pPDFiumDocument;
493
494 FPDF_BYTESTRING pPassword = nullptr;
495 if (!rPassword.isEmpty())
496 {
497 pPassword = rPassword.getStr();
498 }
499 FPDF_DOCUMENT pDocument = FPDF_LoadMemDocument(pData, nSize, pPassword);
500
501 if (!pDocument)
502 {
503 switch (FPDF_GetLastError())
504 {
505 case FPDF_ERR_SUCCESS:
506 maLastError = "Success";
507 break;
508 case FPDF_ERR_UNKNOWN:
509 maLastError = "Unknown error";
510 break;
511 case FPDF_ERR_FILE:
512 maLastError = "File not found";
513 break;
514 case FPDF_ERR_FORMAT:
515 maLastError = "Input is not a PDF format";
516 break;
517 case FPDF_ERR_PASSWORD:
518 maLastError = "Incorrect password or password is required";
519 break;
520 case FPDF_ERR_SECURITY:
521 maLastError = "Security error";
522 break;
523 case FPDF_ERR_PAGE:
524 maLastError = "Content error";
525 break;
526 default:
527 break;
528 }
529 }
530 else
531 {
532 pPDFiumDocument = std::make_unique<PDFiumDocumentImpl>(pDocument);
533 }
534
535 return pPDFiumDocument;
536}
537
538PDFErrorType PDFiumImpl::getLastErrorCode()
539{
540 return static_cast<PDFErrorType>(FPDF_GetLastError());
541}
542
543std::unique_ptr<PDFiumBitmap> PDFiumImpl::createBitmap(int& nWidth, int& nHeight, int nAlpha)
544{
545 std::unique_ptr<PDFiumBitmap> pPDFiumBitmap;
546
547 FPDF_BITMAP pPdfBitmap = FPDFBitmap_Create(nWidth, nHeight, nAlpha);
548 if (!pPdfBitmap)
549 {
550 int nOriginal = nHeight;
551 // PDFium cannot create big bitmaps, max 2^14 x 2^14 x 4 bytes per pixel
552 if (nHeight > 16384)
553 nHeight = 16384;
554
555 if (nWidth > 16384)
556 {
557 nWidth = 16384.0 / nOriginal * nWidth;
558 }
559
560 if (nWidth * nHeight > 16384 * 16384)
561 {
562 nOriginal = nWidth;
563 nHeight = 16384.0 / nOriginal * nHeight;
564 }
565
566 pPdfBitmap = FPDFBitmap_Create(nWidth, nHeight, nAlpha);
567 }
568
569 if (!pPdfBitmap)
570 {
571 maLastError = "Failed to create bitmap";
572 SAL_WARN("vcl.filter", "PDFiumImpl: " << getLastError());
573 }
574 else
575 {
576 pPDFiumBitmap = std::make_unique<PDFiumBitmapImpl>(pPdfBitmap);
577 }
578 return pPDFiumBitmap;
579}
580
581PDFiumSignatureImpl::PDFiumSignatureImpl(FPDF_SIGNATURE pSignature)
582 : mpSignature(pSignature)
583{
584}
585
586std::vector<int> PDFiumSignatureImpl::getByteRange()
587{
588 int nByteRangeLen = FPDFSignatureObj_GetByteRange(mpSignature, nullptr, 0);
589 std::vector<int> aByteRange(nByteRangeLen);
590 if (nByteRangeLen <= 0)
591 {
592 return aByteRange;
593 }
594
595 FPDFSignatureObj_GetByteRange(mpSignature, aByteRange.data(), aByteRange.size());
596 return aByteRange;
597}
598
599int PDFiumSignatureImpl::getDocMDPPermission()
600{
601 return FPDFSignatureObj_GetDocMDPPermission(mpSignature);
602}
603
604std::vector<unsigned char> PDFiumSignatureImpl::getContents()
605{
606 int nContentsLen = FPDFSignatureObj_GetContents(mpSignature, nullptr, 0);
607 std::vector<unsigned char> aContents(nContentsLen);
608 if (aContents.empty())
609 {
610 return aContents;
611 }
612
613 FPDFSignatureObj_GetContents(mpSignature, aContents.data(), aContents.size());
614 return aContents;
615}
616
617OString PDFiumSignatureImpl::getSubFilter()
618{
619 int nSubFilterLen = FPDFSignatureObj_GetSubFilter(mpSignature, nullptr, 0);
620 std::vector<char> aSubFilterBuf(nSubFilterLen);
621 FPDFSignatureObj_GetSubFilter(mpSignature, aSubFilterBuf.data(), aSubFilterBuf.size());
622 // Buffer is NUL-terminated.
623 OString aSubFilter(aSubFilterBuf.data(), aSubFilterBuf.size() - 1);
624 return aSubFilter;
625}
626
627OUString PDFiumSignatureImpl::getReason()
628{
629 int nReasonLen = FPDFSignatureObj_GetReason(mpSignature, nullptr, 0);
630 OUString aRet;
631 if (nReasonLen > 0)
632 {
633 std::vector<char16_t> aReasonBuf(nReasonLen);
634 FPDFSignatureObj_GetReason(mpSignature, aReasonBuf.data(), aReasonBuf.size());
635 aRet = OUString(aReasonBuf.data(), aReasonBuf.size() - 1);
636 }
637
638 return aRet;
639}
640
641util::DateTime PDFiumSignatureImpl::getTime()
642{
643 util::DateTime aRet;
644 int nTimeLen = FPDFSignatureObj_GetTime(mpSignature, nullptr, 0);
645 if (nTimeLen <= 0)
646 {
647 return aRet;
648 }
649
650 // Example: "D:20161027100104".
651 std::vector<char> aTimeBuf(nTimeLen);
652 FPDFSignatureObj_GetTime(mpSignature, aTimeBuf.data(), aTimeBuf.size());
653 OString aM(aTimeBuf.data(), aTimeBuf.size() - 1);
654 if (aM.startsWith("D:") && aM.getLength() >= 16)
655 {
656 aRet.Year = o3tl::toInt32(aM.subView(2, 4));
657 aRet.Month = o3tl::toInt32(aM.subView(6, 2));
658 aRet.Day = o3tl::toInt32(aM.subView(8, 2));
659 aRet.Hours = o3tl::toInt32(aM.subView(10, 2));
660 aRet.Minutes = o3tl::toInt32(aM.subView(12, 2));
661 aRet.Seconds = o3tl::toInt32(aM.subView(14, 2));
662 }
663 return aRet;
664}
665
666PDFiumDocumentImpl::PDFiumDocumentImpl(FPDF_DOCUMENT pPdfDocument)
667 : mpPdfDocument(pPdfDocument)
669{
670 m_aFormCallbacks.version = 1;
671 m_pFormHandle = std::make_unique<PDFiumFormHandle>(
672 FPDFDOC_InitFormFillEnvironment(pPdfDocument, &m_aFormCallbacks));
673}
674
675PDFiumDocumentImpl::~PDFiumDocumentImpl()
676{
677 m_pFormHandle.reset();
678 if (mpPdfDocument)
679 FPDF_CloseDocument(mpPdfDocument);
680}
681
682FPDF_FORMHANDLE PDFiumDocumentImpl::getFormHandlePointer() { return m_pFormHandle->getPointer(); }
683
684std::unique_ptr<PDFiumPage> PDFiumDocumentImpl::openPage(int nIndex)
685{
686 std::unique_ptr<PDFiumPage> pPDFiumPage;
687 FPDF_PAGE pPage = FPDF_LoadPage(mpPdfDocument, nIndex);
688 if (pPage)
689 {
690 pPDFiumPage = std::make_unique<PDFiumPageImpl>(pPage);
691 }
692 return pPDFiumPage;
693}
694
695std::unique_ptr<PDFiumSignature> PDFiumDocumentImpl::getSignature(int nIndex)
696{
697 std::unique_ptr<PDFiumSignature> pPDFiumSignature;
698 FPDF_SIGNATURE pSignature = FPDF_GetSignatureObject(mpPdfDocument, nIndex);
699 if (pSignature)
700 {
701 pPDFiumSignature = std::make_unique<PDFiumSignatureImpl>(pSignature);
702 }
703 return pPDFiumSignature;
704}
705
706std::vector<unsigned int> PDFiumDocumentImpl::getTrailerEnds()
707{
708 int nNumTrailers = FPDF_GetTrailerEnds(mpPdfDocument, nullptr, 0);
709 std::vector<unsigned int> aTrailerEnds(nNumTrailers);
710 FPDF_GetTrailerEnds(mpPdfDocument, aTrailerEnds.data(), aTrailerEnds.size());
711 return aTrailerEnds;
712}
713
714basegfx::B2DSize PDFiumDocumentImpl::getPageSize(int nIndex)
715{
716 basegfx::B2DSize aSize;
717 FS_SIZEF aPDFSize;
718 if (FPDF_GetPageSizeByIndexF(mpPdfDocument, nIndex, &aPDFSize))
719 {
720 aSize = basegfx::B2DSize(aPDFSize.width, aPDFSize.height);
721 }
722 return aSize;
723}
724
725int PDFiumDocumentImpl::getPageCount() { return FPDF_GetPageCount(mpPdfDocument); }
726
727int PDFiumDocumentImpl::getSignatureCount() { return FPDF_GetSignatureCount(mpPdfDocument); }
728
729int PDFiumDocumentImpl::getFileVersion()
730{
731 int nFileVersion = 0;
732 FPDF_GetFileVersion(mpPdfDocument, &nFileVersion);
733 return nFileVersion;
734}
735
736bool PDFiumDocumentImpl::saveWithVersion(SvMemoryStream& rStream, int nFileVersion)
737{
738 CompatibleWriter aWriter(rStream);
739 aWriter.version = 1;
740 aWriter.WriteBlock = &CompatibleWriterCallback;
741 if (!FPDF_SaveWithVersion(mpPdfDocument, &aWriter, 0, nFileVersion))
742 {
743 return false;
744 }
745
746 return true;
747}
748
749int PDFiumPageImpl::getObjectCount() { return FPDFPage_CountObjects(mpPage); }
750
751std::unique_ptr<PDFiumPageObject> PDFiumPageImpl::getObject(int nIndex)
752{
753 std::unique_ptr<PDFiumPageObject> pPDFiumPageObject;
754 FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(mpPage, nIndex);
755 if (pPageObject)
756 {
757 pPDFiumPageObject = std::make_unique<PDFiumPageObjectImpl>(pPageObject);
758 }
759 return pPDFiumPageObject;
760}
761
762int PDFiumPageImpl::getAnnotationCount() { return FPDFPage_GetAnnotCount(mpPage); }
763
764int PDFiumPageImpl::getAnnotationIndex(std::unique_ptr<PDFiumAnnotation> const& rAnnotation)
765{
766 auto pAnnotation = static_cast<PDFiumAnnotationImpl*>(rAnnotation.get());
767 return FPDFPage_GetAnnotIndex(mpPage, pAnnotation->getPointer());
768}
769
770std::unique_ptr<PDFiumAnnotation> PDFiumPageImpl::getAnnotation(int nIndex)
771{
772 std::unique_ptr<PDFiumAnnotation> pPDFiumAnnotation;
773 FPDF_ANNOTATION pAnnotation = FPDFPage_GetAnnot(mpPage, nIndex);
774 if (pAnnotation)
775 {
776 pPDFiumAnnotation = std::make_unique<PDFiumAnnotationImpl>(pAnnotation);
777 }
778 return pPDFiumAnnotation;
779}
780
781std::unique_ptr<PDFiumTextPage> PDFiumPageImpl::getTextPage()
782{
783 std::unique_ptr<PDFiumTextPage> pPDFiumTextPage;
784 FPDF_TEXTPAGE pTextPage = FPDFText_LoadPage(mpPage);
785 if (pTextPage)
786 {
787 pPDFiumTextPage = std::make_unique<PDFiumTextPageImpl>(pTextPage);
788 }
789 return pPDFiumTextPage;
790}
791
792bool PDFiumPageImpl::hasLinks()
793{
794 // This could be a full iterator, but at the moment we just determine if the list is empty or
795 // not.
796 int nStartPos = 0;
797 FPDF_LINK pLinkAnnot = nullptr;
798 return FPDFLink_Enumerate(mpPage, &nStartPos, &pLinkAnnot);
799}
800
801void PDFiumPageImpl::onAfterLoadPage(PDFiumDocument* pDoc)
802{
803 auto pDocImpl = static_cast<PDFiumDocumentImpl*>(pDoc);
804 FORM_OnAfterLoadPage(mpPage, pDocImpl->getFormHandlePointer());
805}
806
807PDFiumPageObjectImpl::PDFiumPageObjectImpl(FPDF_PAGEOBJECT pPageObject)
808 : mpPageObject(pPageObject)
809{
810}
811
812OUString PDFiumPageObjectImpl::getText(std::unique_ptr<PDFiumTextPage> const& rTextPage)
813{
814 OUString sReturnText;
815
816 auto pTextPage = static_cast<PDFiumTextPageImpl*>(rTextPage.get());
817 int nBytes = FPDFTextObj_GetText(mpPageObject, pTextPage->getPointer(), nullptr, 0);
818 assert(nBytes % 2 == 0);
819 nBytes /= 2;
820
821 std::unique_ptr<sal_Unicode[]> pText(new sal_Unicode[nBytes]);
822
823 int nActualBytes = FPDFTextObj_GetText(mpPageObject, pTextPage->getPointer(),
824 reinterpret_cast<FPDF_WCHAR*>(pText.get()), nBytes * 2);
825 assert(nActualBytes % 2 == 0);
826 nActualBytes /= 2;
827 if (nActualBytes > 1)
828 {
829#if defined OSL_BIGENDIAN
830 // The data returned by FPDFTextObj_GetText is documented to always be UTF-16LE:
831 for (int i = 0; i != nActualBytes; ++i)
832 {
833 pText[i] = OSL_SWAPWORD(pText[i]);
834 }
835#endif
836 sReturnText = OUString(pText.get());
837 }
838
839 return sReturnText;
840}
841
842PDFPageObjectType PDFiumPageObjectImpl::getType()
843{
844 return static_cast<PDFPageObjectType>(FPDFPageObj_GetType(mpPageObject));
845}
846
847int PDFiumPageObjectImpl::getFormObjectCount() { return FPDFFormObj_CountObjects(mpPageObject); }
848
849std::unique_ptr<PDFiumPageObject> PDFiumPageObjectImpl::getFormObject(int nIndex)
850{
851 std::unique_ptr<PDFiumPageObject> pPDFiumFormObject;
852 FPDF_PAGEOBJECT pFormObject = FPDFFormObj_GetObject(mpPageObject, nIndex);
853 if (pFormObject)
854 {
855 pPDFiumFormObject = std::make_unique<PDFiumPageObjectImpl>(pFormObject);
856 }
857 return pPDFiumFormObject;
858}
859
860basegfx::B2DHomMatrix PDFiumPageObjectImpl::getMatrix()
861{
862 basegfx::B2DHomMatrix aB2DMatrix;
863 FS_MATRIX matrix;
864 if (FPDFPageObj_GetMatrix(mpPageObject, &matrix))
866 matrix.f);
867 return aB2DMatrix;
868}
869
870basegfx::B2DRectangle PDFiumPageObjectImpl::getBounds()
871{
872 basegfx::B2DRectangle aB2DRectangle;
873
874 float left = 0;
875 float bottom = 0;
876 float right = 0;
877 float top = 0;
878 if (FPDFPageObj_GetBounds(mpPageObject, &left, &bottom, &right, &top))
879 {
880 aB2DRectangle = basegfx::B2DRectangle(left, top, right, bottom);
881 }
882 return aB2DRectangle;
883}
884
885double PDFiumPageObjectImpl::getFontSize()
886{
887 float nSize{};
888 FPDFTextObj_GetFontSize(mpPageObject, &nSize);
889 return nSize;
890}
891
892OUString PDFiumPageObjectImpl::getFontName()
893{
894 OUString sFontName;
895 const int nFontName = 80 + 1;
896 std::unique_ptr<char[]> pFontName(new char[nFontName]); // + terminating null
897 FPDF_FONT pFontObject = FPDFTextObj_GetFont(mpPageObject);
898 int nFontNameChars = FPDFFont_GetFontName(pFontObject, pFontName.get(), nFontName);
899 if (nFontName >= nFontNameChars)
900 {
901 sFontName = OUString::createFromAscii(pFontName.get());
902 }
903 return sFontName;
904}
905
906PDFTextRenderMode PDFiumPageObjectImpl::getTextRenderMode()
907{
908 return static_cast<PDFTextRenderMode>(FPDFTextObj_GetTextRenderMode(mpPageObject));
909}
910
911Color PDFiumPageObjectImpl::getFillColor()
912{
913 Color aColor = COL_TRANSPARENT;
914 unsigned int nR, nG, nB, nA;
915 if (FPDFPageObj_GetFillColor(mpPageObject, &nR, &nG, &nB, &nA))
916 {
917 aColor = Color(ColorAlpha, nA, nR, nG, nB);
918 }
919 return aColor;
920}
921
922Color PDFiumPageObjectImpl::getStrokeColor()
923{
924 Color aColor = COL_TRANSPARENT;
925 unsigned int nR, nG, nB, nA;
926 if (FPDFPageObj_GetStrokeColor(mpPageObject, &nR, &nG, &nB, &nA))
927 {
928 aColor = Color(ColorAlpha, nA, nR, nG, nB);
929 }
930 return aColor;
931}
932
933double PDFiumPageObjectImpl::getStrokeWidth()
934{
935 float fWidth = 1;
936 FPDFPageObj_GetStrokeWidth(mpPageObject, &fWidth);
937 return fWidth;
938}
939
940int PDFiumPageObjectImpl::getPathSegmentCount() { return FPDFPath_CountSegments(mpPageObject); }
941
942std::unique_ptr<PDFiumPathSegment> PDFiumPageObjectImpl::getPathSegment(int index)
943{
944 std::unique_ptr<PDFiumPathSegment> pPDFiumPathSegment;
945 FPDF_PATHSEGMENT pPathSegment = FPDFPath_GetPathSegment(mpPageObject, index);
946 if (pPathSegment)
947 {
948 pPDFiumPathSegment = std::make_unique<PDFiumPathSegmentImpl>(pPathSegment);
949 }
950 return pPDFiumPathSegment;
951}
952
953Size PDFiumPageObjectImpl::getImageSize(PDFiumPage& rPage)
954{
955 FPDF_IMAGEOBJ_METADATA aMeta;
956 auto& rPageImpl = static_cast<PDFiumPageImpl&>(rPage);
957 FPDFImageObj_GetImageMetadata(mpPageObject, rPageImpl.getPointer(), &aMeta);
958 return Size(aMeta.width, aMeta.height);
959}
960
961std::unique_ptr<PDFiumBitmap> PDFiumPageObjectImpl::getImageBitmap()
962{
963 std::unique_ptr<PDFiumBitmap> pPDFiumBitmap;
964 FPDF_BITMAP pBitmap = FPDFImageObj_GetBitmap(mpPageObject);
965 if (pBitmap)
966 {
967 pPDFiumBitmap = std::make_unique<PDFiumBitmapImpl>(pBitmap);
968 }
969 return pPDFiumBitmap;
970}
971
972bool PDFiumPageObjectImpl::getDrawMode(PDFFillMode& rFillMode, bool& rStroke)
973{
974 auto nFillMode = static_cast<int>(rFillMode);
975 auto bStroke = static_cast<FPDF_BOOL>(rStroke);
976 bool bRet = FPDFPath_GetDrawMode(mpPageObject, &nFillMode, &bStroke);
977 rFillMode = static_cast<PDFFillMode>(nFillMode);
978 rStroke = static_cast<bool>(bStroke);
979 return bRet;
980}
981
982BitmapChecksum PDFiumPageImpl::getChecksum(int nMDPPerm)
983{
984 int nPageWidth = getWidth();
985 int nPageHeight = getHeight();
986 std::unique_ptr<PDFiumBitmap> pPdfBitmap
987 = PDFiumLibrary::get()->createBitmap(nPageWidth, nPageHeight, /*nAlpha=*/1);
988 if (!pPdfBitmap)
989 return 0;
990
991 PDFiumBitmapImpl* pBitmapImpl = static_cast<PDFiumBitmapImpl*>(pPdfBitmap.get());
992
993 int nFlags = 0;
994 if (nMDPPerm != 3)
995 {
996 // Annotations/commenting should affect the checksum, signature verification wants this.
997 nFlags = FPDF_ANNOT;
998 }
999 FPDF_RenderPageBitmap(pBitmapImpl->getPointer(), mpPage, /*start_x=*/0, /*start_y=*/0,
1000 nPageWidth, nPageHeight,
1001 /*rotate=*/0, nFlags);
1002 Bitmap aBitmap(Size(nPageWidth, nPageHeight), vcl::PixelFormat::N24_BPP);
1003 {
1004 BitmapScopedWriteAccess pWriteAccess(aBitmap);
1005 const auto pPdfBuffer
1006 = static_cast<ConstScanline>(FPDFBitmap_GetBuffer(pBitmapImpl->getPointer()));
1007 const int nStride = FPDFBitmap_GetStride(pBitmapImpl->getPointer());
1008 for (int nRow = 0; nRow < nPageHeight; ++nRow)
1009 {
1010 ConstScanline pPdfLine = pPdfBuffer + (nStride * nRow);
1011 pWriteAccess->CopyScanline(nRow, pPdfLine, ScanlineFormat::N32BitTcBgra, nStride);
1012 }
1013 }
1014 return aBitmap.GetChecksum();
1015}
1016
1017double PDFiumPageImpl::getWidth() { return FPDF_GetPageWidth(mpPage); }
1018
1019double PDFiumPageImpl::getHeight() { return FPDF_GetPageHeight(mpPage); }
1020
1021bool PDFiumPageImpl::hasTransparency() { return FPDFPage_HasTransparency(mpPage); }
1022
1023PDFiumPathSegmentImpl::PDFiumPathSegmentImpl(FPDF_PATHSEGMENT pPathSegment)
1024 : mpPathSegment(pPathSegment)
1025{
1026}
1027
1028basegfx::B2DPoint PDFiumPathSegmentImpl::getPoint() const
1029{
1030 basegfx::B2DPoint aPoint;
1031 float fx, fy;
1032 if (FPDFPathSegment_GetPoint(mpPathSegment, &fx, &fy))
1033 aPoint = basegfx::B2DPoint(fx, fy);
1034 return aPoint;
1035}
1036
1037bool PDFiumPathSegmentImpl::isClosed() const { return FPDFPathSegment_GetClose(mpPathSegment); }
1038
1039PDFSegmentType PDFiumPathSegmentImpl::getType() const
1040{
1041 return static_cast<PDFSegmentType>(FPDFPathSegment_GetType(mpPathSegment));
1042}
1043
1044PDFiumFormHandle::PDFiumFormHandle(FPDF_FORMHANDLE pHandle)
1045 : mpHandle(pHandle)
1046{
1047}
1048
1049PDFiumFormHandle::~PDFiumFormHandle() { FPDFDOC_ExitFormFillEnvironment(mpHandle); }
1050
1051FPDF_FORMHANDLE PDFiumFormHandle::getPointer() { return mpHandle; }
1052
1053PDFiumBitmapImpl::PDFiumBitmapImpl(FPDF_BITMAP pBitmap)
1054 : mpBitmap(pBitmap)
1055{
1056}
1057
1058PDFiumBitmapImpl::~PDFiumBitmapImpl()
1059{
1060 if (mpBitmap)
1061 {
1062 FPDFBitmap_Destroy(mpBitmap);
1063 }
1064}
1065
1066void PDFiumBitmapImpl::fillRect(int left, int top, int width, int height, sal_uInt32 nColor)
1067{
1068 FPDFBitmap_FillRect(mpBitmap, left, top, width, height, nColor);
1069}
1070
1071void PDFiumBitmapImpl::renderPageBitmap(PDFiumDocument* pDoc, PDFiumPage* pPage, int nStartX,
1072 int nStartY, int nSizeX, int nSizeY)
1073{
1074 auto pPageImpl = static_cast<PDFiumPageImpl*>(pPage);
1075 FPDF_RenderPageBitmap(mpBitmap, pPageImpl->getPointer(), nStartX, nStartY, nSizeX, nSizeY,
1076 /*rotate=*/0, /*flags=*/0);
1077
1078 // Render widget annotations for FormFields.
1079 auto pDocImpl = static_cast<PDFiumDocumentImpl*>(pDoc);
1080 FPDF_FFLDraw(pDocImpl->getFormHandlePointer(), mpBitmap, pPageImpl->getPointer(), nStartX,
1081 nStartY, nSizeX, nSizeY, /*rotate=*/0, /*flags=*/0);
1082}
1083
1084ConstScanline PDFiumBitmapImpl::getBuffer()
1085{
1086 return static_cast<ConstScanline>(FPDFBitmap_GetBuffer(mpBitmap));
1087}
1088
1089int PDFiumBitmapImpl::getStride() { return FPDFBitmap_GetStride(mpBitmap); }
1090
1091int PDFiumBitmapImpl::getWidth() { return FPDFBitmap_GetWidth(mpBitmap); }
1092
1093int PDFiumBitmapImpl::getHeight() { return FPDFBitmap_GetHeight(mpBitmap); }
1094
1095PDFBitmapType PDFiumBitmapImpl::getFormat()
1096{
1097 return static_cast<PDFBitmapType>(FPDFBitmap_GetFormat(mpBitmap));
1098}
1099
1100PDFiumAnnotationImpl::PDFiumAnnotationImpl(FPDF_ANNOTATION pAnnotation)
1101 : mpAnnotation(pAnnotation)
1102{
1103}
1104
1105PDFiumAnnotationImpl::~PDFiumAnnotationImpl()
1106{
1107 if (mpAnnotation)
1108 FPDFPage_CloseAnnot(mpAnnotation);
1109}
1110
1111PDFAnnotationSubType PDFiumAnnotationImpl::getSubType()
1112{
1113 return PDFAnnotationSubType(FPDFAnnot_GetSubtype(mpAnnotation));
1114}
1115
1116basegfx::B2DRectangle PDFiumAnnotationImpl::getRectangle()
1117{
1118 basegfx::B2DRectangle aB2DRectangle;
1119 FS_RECTF aRect;
1120 if (FPDFAnnot_GetRect(mpAnnotation, &aRect))
1121 {
1122 aB2DRectangle = basegfx::B2DRectangle(aRect.left, aRect.top, aRect.right, aRect.bottom);
1123 }
1124 return aB2DRectangle;
1125}
1126
1128{
1129 unsigned int nR, nG, nB, nA;
1130 if (FPDFAnnot_GetColor(mpAnnotation, FPDFANNOT_COLORTYPE_Color, &nR, &nG, &nB, &nA))
1131 {
1132 return Color(ColorAlpha, nA, nR, nG, nB);
1133 }
1134 // FPDFAnnot_GetColor can return false if there is an appearance stream
1135 // So we search for a color with getStrokeColor
1136 for (int i = 0; i < getObjectCount(); ++i)
1137 {
1138 if (getObject(i)->getType() == PDFPageObjectType::Path)
1139 return getObject(i)->getStrokeColor();
1140 }
1141 return COL_TRANSPARENT;
1142}
1143
1144Color PDFiumAnnotationImpl::getInteriorColor()
1145{
1146 unsigned int nR, nG, nB, nA;
1147 if (FPDFAnnot_GetColor(mpAnnotation, FPDFANNOT_COLORTYPE_InteriorColor, &nR, &nG, &nB, &nA))
1148 {
1149 return Color(ColorAlpha, nA, nR, nG, nB);
1150 }
1151 // FPDFAnnot_GetColor can return false if there is an appearance stream
1152 // So we search for a color with getFillColor
1153 for (int i = 0; i < getObjectCount(); ++i)
1154 {
1155 if (getObject(i)->getType() == PDFPageObjectType::Path)
1156 return getObject(i)->getFillColor();
1157 }
1158 return COL_TRANSPARENT;
1159}
1160
1161size_t PDFiumAnnotationImpl::getAttachmentPointsCount()
1162{
1163 return FPDFAnnot_CountAttachmentPoints(mpAnnotation);
1164}
1165
1166std::vector<basegfx::B2DPoint> PDFiumAnnotationImpl::getAttachmentPoints(size_t nIndex)
1167{
1168 std::vector<basegfx::B2DPoint> aQuads;
1169
1170 FS_QUADPOINTSF aQuadpoints;
1171 if (FPDFAnnot_GetAttachmentPoints(mpAnnotation, nIndex, &aQuadpoints))
1172 {
1173 aQuads.emplace_back(aQuadpoints.x1, aQuadpoints.y1);
1174 aQuads.emplace_back(aQuadpoints.x2, aQuadpoints.y2);
1175 aQuads.emplace_back(aQuadpoints.x3, aQuadpoints.y3);
1176 aQuads.emplace_back(aQuadpoints.x4, aQuadpoints.y4);
1177 }
1178 return aQuads;
1179}
1180
1181std::vector<basegfx::B2DPoint> PDFiumAnnotationImpl::getLineGeometry()
1182{
1183 std::vector<basegfx::B2DPoint> aLine;
1184 FS_POINTF aStart;
1185 FS_POINTF aEnd;
1186 if (FPDFAnnot_GetLine(mpAnnotation, &aStart, &aEnd))
1187 {
1188 aLine.emplace_back(aStart.x, aStart.y);
1189 aLine.emplace_back(aEnd.x, aEnd.y);
1190 }
1191 return aLine;
1192}
1193
1194PDFFormFieldType PDFiumAnnotationImpl::getFormFieldType(PDFiumDocument* pDoc)
1195{
1196 auto pDocImpl = static_cast<PDFiumDocumentImpl*>(pDoc);
1197 return PDFFormFieldType(
1198 FPDFAnnot_GetFormFieldType(pDocImpl->getFormHandlePointer(), mpAnnotation));
1199}
1200
1201int PDFiumAnnotationImpl::getFormFieldFlags(PDFiumDocument* pDoc)
1202{
1203 auto pDocImpl = static_cast<PDFiumDocumentImpl*>(pDoc);
1204 return FPDFAnnot_GetFormFieldFlags(pDocImpl->getFormHandlePointer(), mpAnnotation);
1205}
1206
1207float PDFiumAnnotationImpl::getFontSize(PDFiumDocument* pDoc)
1208{
1209 auto pDocImpl = static_cast<PDFiumDocumentImpl*>(pDoc);
1210 float fRet{};
1211 if (!FPDFAnnot_GetFontSize(pDocImpl->getFormHandlePointer(), mpAnnotation, &fRet))
1212 {
1213 return 0.0f;
1214 }
1215
1216 return fRet;
1217}
1218
1219OUString PDFiumAnnotationImpl::getFormFieldAlternateName(PDFiumDocument* pDoc)
1220{
1221 auto pDocImpl = static_cast<PDFiumDocumentImpl*>(pDoc);
1222 OUString aString;
1223 unsigned long nSize = FPDFAnnot_GetFormFieldAlternateName(pDocImpl->getFormHandlePointer(),
1224 mpAnnotation, nullptr, 0);
1225 assert(nSize % 2 == 0);
1226 nSize /= 2;
1227 if (nSize > 1)
1228 {
1229 std::unique_ptr<sal_Unicode[]> pText(new sal_Unicode[nSize]);
1230 unsigned long nStringSize = FPDFAnnot_GetFormFieldAlternateName(
1231 pDocImpl->getFormHandlePointer(), mpAnnotation,
1232 reinterpret_cast<FPDF_WCHAR*>(pText.get()), nSize * 2);
1233 assert(nStringSize % 2 == 0);
1234 nStringSize /= 2;
1235 if (nStringSize > 0)
1236 {
1237#if defined OSL_BIGENDIAN
1238 for (unsigned long i = 0; i != nStringSize; ++i)
1239 {
1240 pText[i] = OSL_SWAPWORD(pText[i]);
1241 }
1242#endif
1243 aString = OUString(pText.get());
1244 }
1245 }
1246 return aString;
1247}
1248
1249OUString PDFiumAnnotationImpl::getFormFieldValue(PDFiumDocument* pDoc)
1250{
1251 auto pDocImpl = static_cast<PDFiumDocumentImpl*>(pDoc);
1252 OUString aString;
1253 unsigned long nSize
1254 = FPDFAnnot_GetFormFieldValue(pDocImpl->getFormHandlePointer(), mpAnnotation, nullptr, 0);
1255 assert(nSize % 2 == 0);
1256 nSize /= 2;
1257 if (nSize > 1)
1258 {
1259 std::unique_ptr<sal_Unicode[]> pText(new sal_Unicode[nSize]);
1260 unsigned long nStringSize
1261 = FPDFAnnot_GetFormFieldValue(pDocImpl->getFormHandlePointer(), mpAnnotation,
1262 reinterpret_cast<FPDF_WCHAR*>(pText.get()), nSize * 2);
1263 assert(nStringSize % 2 == 0);
1264 nStringSize /= 2;
1265 if (nStringSize > 0)
1266 {
1267#if defined OSL_BIGENDIAN
1268 for (unsigned long i = 0; i != nStringSize; ++i)
1269 {
1270 pText[i] = OSL_SWAPWORD(pText[i]);
1271 }
1272#endif
1273 aString = OUString(pText.get());
1274 }
1275 }
1276 return aString;
1277}
1278
1279OUString PDFiumAnnotationImpl::getFormAdditionalActionJavaScript(PDFiumDocument* pDoc,
1280 PDFAnnotAActionType eEvent)
1281{
1282 auto pDocImpl = static_cast<PDFiumDocumentImpl*>(pDoc);
1283 OUString aString;
1284 unsigned long nSize = FPDFAnnot_GetFormAdditionalActionJavaScript(
1285 pDocImpl->getFormHandlePointer(), mpAnnotation, static_cast<int>(eEvent), nullptr, 0);
1286 assert(nSize % 2 == 0);
1287 nSize /= 2;
1288 if (nSize > 1)
1289 {
1290 std::unique_ptr<sal_Unicode[]> pText(new sal_Unicode[nSize]);
1291 unsigned long nStringSize = FPDFAnnot_GetFormAdditionalActionJavaScript(
1292 pDocImpl->getFormHandlePointer(), mpAnnotation, static_cast<int>(eEvent),
1293 reinterpret_cast<FPDF_WCHAR*>(pText.get()), nSize * 2);
1294 assert(nStringSize % 2 == 0);
1295 nStringSize /= 2;
1296 if (nStringSize > 0)
1297 {
1298#if defined OSL_BIGENDIAN
1299 for (unsigned long i = 0; i != nStringSize; ++i)
1300 {
1301 pText[i] = OSL_SWAPWORD(pText[i]);
1302 }
1303#endif
1304 aString = OUString(pText.get());
1305 }
1306 }
1307 return aString;
1308}
1309
1310namespace
1311{
1312bool getBorderProperties(FPDF_ANNOTATION mpAnnotation, float& rHorizontalCornerRadius,
1313 float& rVerticalCornerRadius, float& rBorderWidth)
1314{
1315 float fHoriRadius = 0.0f;
1316 float fVertRadius = 0.0f;
1317 float fWidth = 0.0f;
1318
1319 if (!FPDFAnnot_GetBorder(mpAnnotation, &fHoriRadius, &fVertRadius, &fWidth))
1320 return false;
1321
1322 rHorizontalCornerRadius = fHoriRadius;
1323 rVerticalCornerRadius = fVertRadius;
1324 rBorderWidth = fWidth;
1325 return true;
1326}
1327}
1328
1329float PDFiumAnnotationImpl::getBorderWidth()
1330{
1331 float fHorizontalCornerRadius;
1332 float fVerticalCornerRadius;
1333 float fBorderWidth;
1334
1335 if (!getBorderProperties(mpAnnotation, fHorizontalCornerRadius, fVerticalCornerRadius,
1336 fBorderWidth))
1337 return 0.0f;
1338 return fBorderWidth;
1339}
1340
1341basegfx::B2DSize PDFiumAnnotationImpl::getBorderCornerRadius()
1342{
1343 float fHorizontalCornerRadius;
1344 float fVerticalCornerRadius;
1345 float fBorderWidth;
1346
1347 if (!getBorderProperties(mpAnnotation, fHorizontalCornerRadius, fVerticalCornerRadius,
1348 fBorderWidth))
1349 return basegfx::B2DSize(0.0, 0.0);
1350 return basegfx::B2DSize(fHorizontalCornerRadius, fVerticalCornerRadius);
1351}
1352
1353bool PDFiumAnnotationImpl::hasKey(OString const& rKey)
1354{
1355 return FPDFAnnot_HasKey(mpAnnotation, rKey.getStr());
1356}
1357
1358PDFObjectType PDFiumAnnotationImpl::getValueType(OString const& rKey)
1359{
1360 return static_cast<PDFObjectType>(FPDFAnnot_GetValueType(mpAnnotation, rKey.getStr()));
1361}
1362
1363OUString PDFiumAnnotationImpl::getString(OString const& rKey)
1364{
1365 OUString rString;
1366 unsigned long nSize = FPDFAnnot_GetStringValue(mpAnnotation, rKey.getStr(), nullptr, 0);
1367 assert(nSize % 2 == 0);
1368 nSize /= 2;
1369 if (nSize > 1)
1370 {
1371 std::unique_ptr<sal_Unicode[]> pText(new sal_Unicode[nSize]);
1372 unsigned long nStringSize = FPDFAnnot_GetStringValue(
1373 mpAnnotation, rKey.getStr(), reinterpret_cast<FPDF_WCHAR*>(pText.get()), nSize * 2);
1374 assert(nStringSize % 2 == 0);
1375 nStringSize /= 2;
1376 if (nStringSize > 0)
1377 {
1378#if defined OSL_BIGENDIAN
1379 // The data returned by FPDFAnnot_GetStringValue is documented to always be UTF-16LE:
1380 for (unsigned long i = 0; i != nStringSize; ++i)
1381 {
1382 pText[i] = OSL_SWAPWORD(pText[i]);
1383 }
1384#endif
1385 rString = OUString(pText.get());
1386 }
1387 }
1388 return rString;
1389}
1390
1391std::vector<std::vector<basegfx::B2DPoint>> PDFiumAnnotationImpl::getInkStrokes()
1392{
1393 std::vector<std::vector<basegfx::B2DPoint>> aB2DPointList;
1394 int nInkStrokes = FPDFAnnot_GetInkListCount(mpAnnotation);
1395 for (int i = 0; i < nInkStrokes; i++)
1396 {
1397 std::vector<basegfx::B2DPoint> aB2DPoints;
1398 int nPoints = FPDFAnnot_GetInkListPath(mpAnnotation, i, nullptr, 0);
1399 if (nPoints)
1400 {
1401 std::vector<FS_POINTF> aPoints(nPoints);
1402 if (FPDFAnnot_GetInkListPath(mpAnnotation, i, aPoints.data(), aPoints.size()))
1403 {
1404 for (auto const& rPoint : aPoints)
1405 {
1406 aB2DPoints.emplace_back(rPoint.x, rPoint.y);
1407 }
1408 aB2DPointList.push_back(aB2DPoints);
1409 }
1410 }
1411 }
1412 return aB2DPointList;
1413}
1414
1415std::vector<basegfx::B2DPoint> PDFiumAnnotationImpl::getVertices()
1416{
1417 std::vector<basegfx::B2DPoint> aB2DPoints;
1418 int nPoints = FPDFAnnot_GetVertices(mpAnnotation, nullptr, 0);
1419 if (nPoints)
1420 {
1421 std::vector<FS_POINTF> aPoints(nPoints);
1422 if (FPDFAnnot_GetVertices(mpAnnotation, aPoints.data(), aPoints.size()))
1423 {
1424 for (auto const& rPoint : aPoints)
1425 aB2DPoints.emplace_back(rPoint.x, rPoint.y);
1426 }
1427 }
1428 return aB2DPoints;
1429}
1430
1431std::unique_ptr<PDFiumAnnotation> PDFiumAnnotationImpl::getLinked(OString const& rKey)
1432{
1433 std::unique_ptr<PDFiumAnnotation> pPDFiumAnnotation;
1434 FPDF_ANNOTATION pAnnotation = FPDFAnnot_GetLinkedAnnot(mpAnnotation, rKey.getStr());
1435 if (pAnnotation)
1436 {
1437 pPDFiumAnnotation = std::make_unique<PDFiumAnnotationImpl>(pAnnotation);
1438 }
1439 return pPDFiumAnnotation;
1440}
1441
1442int PDFiumAnnotationImpl::getObjectCount() { return FPDFAnnot_GetObjectCount(mpAnnotation); }
1443
1444std::unique_ptr<PDFiumPageObject> PDFiumAnnotationImpl::getObject(int nIndex)
1445{
1446 std::unique_ptr<PDFiumPageObject> pPDFiumPageObject;
1447 FPDF_PAGEOBJECT pPageObject = FPDFAnnot_GetObject(mpAnnotation, nIndex);
1448 if (pPageObject)
1449 {
1450 pPDFiumPageObject = std::make_unique<PDFiumPageObjectImpl>(pPageObject);
1451 }
1452 return pPDFiumPageObject;
1453}
1454
1455PDFiumTextPageImpl::PDFiumTextPageImpl(FPDF_TEXTPAGE pTextPage)
1456 : mpTextPage(pTextPage)
1457{
1458}
1459
1460PDFiumTextPageImpl::~PDFiumTextPageImpl()
1461{
1462 if (mpTextPage)
1463 FPDFText_ClosePage(mpTextPage);
1464}
1465
1466int PDFiumTextPageImpl::countChars() { return FPDFText_CountChars(mpTextPage); }
1467
1468basegfx::B2DRectangle PDFiumTextPageImpl::getCharBox(int nIndex, double fPageHeight)
1469{
1470 double left = 0.0;
1471 double right = 0.0;
1472 double bottom = 0.0;
1473 double top = 0.0;
1474
1475 if (FPDFText_GetCharBox(mpTextPage, nIndex, &left, &right, &bottom, &top))
1476 {
1477 left = convertPointToMm100(left);
1478 right = convertPointToMm100(right);
1479 top = fPageHeight - convertPointToMm100(top);
1480 bottom = fPageHeight - convertPointToMm100(bottom);
1481
1482 return basegfx::B2DRectangle(left, bottom, right, top);
1483 }
1484
1485 return basegfx::B2DRectangle();
1486}
1487
1488unsigned int PDFiumTextPageImpl::getUnicode(int index)
1489{
1490 return FPDFText_GetUnicode(mpTextPage, index);
1491}
1492
1493std::unique_ptr<PDFiumSearchHandle>
1494PDFiumTextPageImpl::findStart(const OUString& rFindWhat, PDFFindFlags nFlags, sal_Int32 nStartIndex)
1495{
1496 FPDF_WIDESTRING pFindWhat = reinterpret_cast<FPDF_WIDESTRING>(rFindWhat.getStr());
1497 return std::make_unique<vcl::pdf::PDFiumSearchHandleImpl>(
1498 FPDFText_FindStart(mpTextPage, pFindWhat, static_cast<sal_uInt32>(nFlags), nStartIndex));
1499}
1500
1501PDFiumSearchHandleImpl::PDFiumSearchHandleImpl(FPDF_SCHHANDLE pSearchHandle)
1502 : mpSearchHandle(pSearchHandle)
1503{
1504}
1505
1506PDFiumSearchHandleImpl::~PDFiumSearchHandleImpl()
1507{
1508 if (mpSearchHandle)
1509 FPDFText_FindClose(mpSearchHandle);
1510}
1511
1512bool PDFiumSearchHandleImpl::findNext() { return FPDFText_FindNext(mpSearchHandle); }
1513
1514bool PDFiumSearchHandleImpl::findPrev() { return FPDFText_FindPrev(mpSearchHandle); }
1515
1516int PDFiumSearchHandleImpl::getSearchResultIndex()
1517{
1518 return FPDFText_GetSchResultIndex(mpSearchHandle);
1519}
1520
1521int PDFiumSearchHandleImpl::getSearchCount() { return FPDFText_GetSchCount(mpSearchHandle); }
1522
1523std::shared_ptr<PDFium>& PDFiumLibrary::get()
1524{
1525 static std::shared_ptr<PDFium> pInstance = std::make_shared<PDFiumImpl>();
1526 return pInstance;
1527}
1528
1529} // end vcl::pdf
1530
1531/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
FPDF_DOCUMENT mpPdfDocument
FPDF_ANNOTATION mpAnnotation
FPDF_FORMHANDLE mpHandle
FPDF_TEXTPAGE mpTextPage
FPDF_SIGNATURE mpSignature
FPDF_PAGEOBJECT mpPageObject
FPDF_PATHSEGMENT mpPathSegment
std::unique_ptr< PDFiumFormHandle > m_pFormHandle
OUString maLastError
FPDF_SCHHANDLE mpSearchHandle
FPDF_PAGE mpPage
FPDF_FORMFILLINFO m_aFormCallbacks
FPDF_BITMAP mpBitmap
const sal_uInt8 * ConstScanline
Definition: Scanline.hxx:27
constexpr auto convertPointToMm100(N n)
static BitmapColor getColor(const BitmapReadAccess *pReadAcc, tools::Long nZ)
sal_uInt64 BitmapChecksum
Definition: checksum.hxx:30
std::size_t WriteBytes(const void *pData, std::size_t nSize)
static B2DHomMatrix abcdef(double da, double db, double dc, double dd, double de, double df)
This template handles BitmapAccess the RAII way.
constexpr ::Color COL_TRANSPARENT(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
OString right
OString top
OString bottom
#define SAL_WARN(area, stream)
B2DRange B2DRectangle
OUString getString(const Any &_rAny)
double matrix[4][4]
int i
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
sal_Int32 getPageCount(const uno::Reference< frame::XModel > &xModel)
void fillRect(const ::cppcanvas::CanvasSharedPtr &rCanvas, const ::basegfx::B2DRectangle &rRect, ::cppcanvas::IntSRGBA aFillColor)
bool getType(BSTR name, Type &type)
sal_uInt16 sal_Unicode
sal_uInt64 left