1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <test/unoapi_test.hxx>
12 #include <comphelper/scopeguard.hxx>
13 #include <comphelper/propertysequence.hxx>
15 #include <unotools/tempfile.hxx>
16 #include <unotools/mediadescriptor.hxx>
17 #include <svx/svdograf.hxx>
18 #include <editeng/outlobj.hxx>
19 #include <editeng/editobj.hxx>
20 #include <vcl/filter/PDFiumLibrary.hxx>
21 #include <vcl/pdf/PDFAnnotationSubType.hxx>
23 #include <DrawDocShell.hxx>
24 #include <ViewShell.hxx>
26 #include <unomodel.hxx>
35 EnvVarGuard(const char* var
, const char* val
)
37 if (getenv(var
) == nullptr)
46 SetEnv(sVar
, nullptr);
50 static void SetEnv(const char* var
, const char* val
)
58 setenv(var
, val
, false);
64 const char* sVar
= nullptr;
68 class SdrPdfImportTest
: public UnoApiTest
72 : UnoApiTest("/sd/qa/unit/data/")
77 // Load the PDF in Draw, which will load the PDF as an Graphic, then
78 // mark the graphic object and trigger "break" function. This should
79 // convert the PDF content into objects/shapes.
80 CPPUNIT_TEST_FIXTURE(SdrPdfImportTest
, testImportSimpleText
)
82 auto pPdfium
= vcl::pdf::PDFiumLibrary::get();
88 // We need to enable PDFium import (and make sure to disable after the test)
89 EnvVarGuard
UsePDFiumGuard("LO_IMPORT_USE_PDFIUM", "1");
91 loadFromURL(u
"SimplePDF.pdf");
92 auto pImpressDocument
= dynamic_cast<SdXImpressDocument
*>(mxComponent
.get());
93 sd::ViewShell
* pViewShell
= pImpressDocument
->GetDocShell()->GetViewShell();
94 CPPUNIT_ASSERT(pViewShell
);
96 // Get the first page - there should be only one.
97 SdPage
* pPage
= pViewShell
->GetActualPage();
98 CPPUNIT_ASSERT(pPage
);
100 // Check there is one object on the page only
101 CPPUNIT_ASSERT_EQUAL(size_t(1), pPage
->GetObjCount());
103 // Get the first object - there should be only one.
104 SdrObject
* pObject
= pPage
->GetObj(0);
105 CPPUNIT_ASSERT(pObject
);
107 // Check the object is a graphic object
108 SdrGrafObj
* pGraphicObject
= dynamic_cast<SdrGrafObj
*>(pObject
);
109 CPPUNIT_ASSERT(pGraphicObject
);
110 // Check the graphic is a vector graphic and that it is PDF
111 Graphic aGraphic
= pGraphicObject
->GetGraphic();
112 auto const& pVectorGraphicData
= aGraphic
.getVectorGraphicData();
113 CPPUNIT_ASSERT(pVectorGraphicData
);
114 CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf
, pVectorGraphicData
->getType());
117 SdrView
* pView
= pViewShell
->GetView();
118 pView
->MarkObj(pObject
, pView
->GetSdrPageView());
120 // Execute the break operation - to turn the PDF into shapes/objects
121 pViewShell
->GetDrawView()->DoImportMarkedMtf();
123 // Check there is one object on the page only
124 CPPUNIT_ASSERT_EQUAL(size_t(1), pPage
->GetObjCount());
127 SdrObject
* pImportedObject
= pPage
->GetObj(0);
128 CPPUNIT_ASSERT(pImportedObject
);
130 // Check the object position
131 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(2011, 2102), Size(2106 + 1, 298 + 1)),
132 pImportedObject
->GetLogicRect());
134 // Object should be a text object containing one paragraph with
135 // content "This is PDF!"
137 SdrTextObj
* pTextObject
= DynCastSdrTextObj(pImportedObject
);
138 CPPUNIT_ASSERT(pTextObject
);
139 OutlinerParaObject
* pOutlinerParagraphObject
= pTextObject
->GetOutlinerParaObject();
140 const EditTextObject
& aEdit
= pOutlinerParagraphObject
->GetTextObject();
141 OUString sText
= aEdit
.GetText(0);
142 CPPUNIT_ASSERT_EQUAL(OUString("This is PDF!"), sText
);
145 CPPUNIT_TEST_FIXTURE(SdrPdfImportTest
, testAnnotationsImportExport
)
147 auto pPdfium
= vcl::pdf::PDFiumLibrary::get();
153 // We need to enable PDFium import (and make sure to disable after the test)
154 EnvVarGuard
UsePDFiumGuard("LO_IMPORT_USE_PDFIUM", "1");
156 EnvVarGuard
DisablePDFCompressionGuard("VCL_DEBUG_DISABLE_PDFCOMPRESSION", "1");
158 auto pPdfiumLibrary
= vcl::pdf::PDFiumLibrary::get();
160 loadFromURL(u
"PdfWithAnnotation.pdf");
161 auto pImpressDocument
= dynamic_cast<SdXImpressDocument
*>(mxComponent
.get());
162 sd::ViewShell
* pViewShell
= pImpressDocument
->GetDocShell()->GetViewShell();
163 CPPUNIT_ASSERT(pViewShell
);
165 BinaryDataContainer aContainer
;
168 // Get the first page - there should be only one.
169 SdPage
* pPage
= pViewShell
->GetActualPage();
170 CPPUNIT_ASSERT(pPage
);
172 // Check the number of annotations
173 CPPUNIT_ASSERT_EQUAL(size_t(1), pPage
->getAnnotations().size());
175 // Get the first object - there should be only one.
176 SdrObject
* pObject
= pPage
->GetObj(0);
177 CPPUNIT_ASSERT(pObject
);
179 // Check the object is a graphic object
180 SdrGrafObj
* pGraphicObject
= dynamic_cast<SdrGrafObj
*>(pObject
);
181 CPPUNIT_ASSERT(pGraphicObject
);
183 // Check the graphic is a vector graphic and that it is PDF
184 Graphic aGraphic
= pGraphicObject
->GetGraphic();
185 auto const& pVectorGraphicData
= aGraphic
.getVectorGraphicData();
186 CPPUNIT_ASSERT(pVectorGraphicData
);
187 CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf
, pVectorGraphicData
->getType());
190 aContainer
= pVectorGraphicData
->getBinaryDataContainer();
193 { // check graphic PDF has annotations
195 CPPUNIT_ASSERT_EQUAL(false, aContainer
.isEmpty());
198 = pPdfiumLibrary
->openDocument(aContainer
.getData(), aContainer
.getSize(), OString());
199 auto pPDFPage
= pPDFDocument
->openPage(0);
201 CPPUNIT_ASSERT_EQUAL(2, pPDFPage
->getAnnotationCount());
203 auto pPDFAnnotation1
= pPDFPage
->getAnnotation(0);
204 CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Text
,
205 pPDFAnnotation1
->getSubType()); // Text annotation
207 auto pPDFAnnotation2
= pPDFPage
->getAnnotation(1);
208 CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Popup
,
209 pPDFAnnotation2
->getSubType()); // Pop-up annotation
212 { // save as PDF and check annotations
213 uno::Reference
<frame::XStorable
> xStorable(mxComponent
, uno::UNO_QUERY
);
214 utl::MediaDescriptor aMediaDescriptor
;
215 aMediaDescriptor
["FilterName"] <<= OUString("writer_pdf_Export");
216 uno::Sequence
<beans::PropertyValue
> aFilterData(
217 comphelper::InitPropertySequence({ { "ExportBookmarks", uno::Any(true) } }));
218 aMediaDescriptor
["FilterData"] <<= aFilterData
;
219 xStorable
->storeToURL(maTempFile
.GetURL(), aMediaDescriptor
.getAsConstPropertyValueList());
221 // Check PDF for annotations
222 auto pPDFDocument
= parsePDFExport();
223 CPPUNIT_ASSERT(pPDFDocument
);
224 CPPUNIT_ASSERT_EQUAL(1, pPDFDocument
->getPageCount());
226 auto pPDFPage
= pPDFDocument
->openPage(0);
227 CPPUNIT_ASSERT(pPDFPage
);
229 CPPUNIT_ASSERT_EQUAL(2, pPDFPage
->getAnnotationCount());
231 auto pPDFAnnotation1
= pPDFPage
->getAnnotation(0);
232 CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Text
,
233 pPDFAnnotation1
->getSubType()); // Text annotation
235 auto pPDFAnnotation2
= pPDFPage
->getAnnotation(1);
236 CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Popup
,
237 pPDFAnnotation2
->getSubType()); // Pop-up annotation
239 // Load document again
240 mxComponent
= loadFromDesktop(maTempFile
.GetURL());
241 auto pNewImpressDocument
= dynamic_cast<SdXImpressDocument
*>(mxComponent
.get());
242 sd::ViewShell
* pNewViewShell
= pNewImpressDocument
->GetDocShell()->GetViewShell();
243 CPPUNIT_ASSERT(pNewViewShell
);
245 SdPage
* pPage
= pNewViewShell
->GetActualPage();
246 CPPUNIT_ASSERT(pPage
);
248 // We expect only 1 annotation in the document because the PDF
249 // annotations are dependent on each-other:
250 // parent annotation "Text" and the child annotation "Pop-up"
252 CPPUNIT_ASSERT_EQUAL(size_t(1), pPage
->getAnnotations().size());
255 auto xAnnotation
= pPage
->getAnnotations().at(0);
257 CPPUNIT_ASSERT_DOUBLES_EQUAL(90.33, xAnnotation
->getPosition().X
, 1E-3);
258 CPPUNIT_ASSERT_DOUBLES_EQUAL(12.07, xAnnotation
->getPosition().Y
, 1E-3);
260 CPPUNIT_ASSERT_EQUAL(OUString("TheAuthor"), xAnnotation
->getAuthor());
261 CPPUNIT_ASSERT_EQUAL(OUString(), xAnnotation
->getInitials());
263 auto xText
= xAnnotation
->getTextRange();
265 CPPUNIT_ASSERT_EQUAL(OUString("This is the annotation text!"), xText
->getString());
267 auto aDateTime
= xAnnotation
->getDateTime();
268 CPPUNIT_ASSERT_EQUAL(sal_Int16(2020), aDateTime
.Year
);
269 CPPUNIT_ASSERT_EQUAL(sal_uInt16(6), aDateTime
.Month
);
270 CPPUNIT_ASSERT_EQUAL(sal_uInt16(18), aDateTime
.Day
);
271 CPPUNIT_ASSERT_EQUAL(sal_uInt16(12), aDateTime
.Hours
);
272 CPPUNIT_ASSERT_EQUAL(sal_uInt16(11), aDateTime
.Minutes
);
273 CPPUNIT_ASSERT_EQUAL(sal_uInt16(53), aDateTime
.Seconds
);
274 CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), aDateTime
.NanoSeconds
);
275 CPPUNIT_ASSERT_EQUAL(false, bool(aDateTime
.IsUTC
));
279 CPPUNIT_PLUGIN_IMPLEMENT();
281 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */