2017-02-24 13:46:52 +01:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
|
|
/*
|
|
|
|
* This file is part of the LibreOffice project.
|
|
|
|
*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
*/
|
|
|
|
|
2017-02-25 17:06:31 +01:00
|
|
|
#include <config_features.h>
|
|
|
|
|
2017-02-24 13:46:52 +01:00
|
|
|
#include <com/sun/star/frame/Desktop.hpp>
|
|
|
|
#include <com/sun/star/frame/XStorable.hpp>
|
2017-05-22 21:41:31 +02:00
|
|
|
#include <com/sun/star/view/XPrintable.hpp>
|
2017-02-24 13:46:52 +01:00
|
|
|
|
|
|
|
#include <comphelper/processfactory.hxx>
|
2017-03-29 09:47:09 +02:00
|
|
|
#include <comphelper/propertyvalue.hxx>
|
2017-05-22 21:41:31 +02:00
|
|
|
#include <comphelper/propertysequence.hxx>
|
2017-02-24 13:46:52 +01:00
|
|
|
#include <cppuhelper/implbase.hxx>
|
|
|
|
#include <test/bootstrapfixture.hxx>
|
|
|
|
#include <unotest/macros_test.hxx>
|
|
|
|
#include <unotools/mediadescriptor.hxx>
|
|
|
|
#include <unotools/tempfile.hxx>
|
2017-03-21 18:03:21 +01:00
|
|
|
#include <vcl/filter/pdfdocument.hxx>
|
2017-02-24 17:14:23 +01:00
|
|
|
#include <tools/zcodec.hxx>
|
2017-05-04 09:04:04 +02:00
|
|
|
#if HAVE_FEATURE_PDFIUM
|
|
|
|
#include <fpdf_edit.h>
|
|
|
|
#include <fpdfview.h>
|
|
|
|
#endif
|
2017-02-24 13:46:52 +01:00
|
|
|
|
|
|
|
using namespace ::com::sun::star;
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
|
|
|
/// Tests the PDF export filter.
|
|
|
|
class PdfExportTest : public test::BootstrapFixture, public unotest::MacrosTest
|
|
|
|
{
|
|
|
|
uno::Reference<uno::XComponentContext> mxComponentContext;
|
|
|
|
uno::Reference<lang::XComponent> mxComponent;
|
2017-05-22 21:41:31 +02:00
|
|
|
#if HAVE_FEATURE_PDFIUM
|
|
|
|
FPDF_PAGE mpPdfPage = nullptr;
|
|
|
|
FPDF_DOCUMENT mpPdfDocument = nullptr;
|
|
|
|
#endif
|
2017-02-24 13:46:52 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
virtual void setUp() override;
|
|
|
|
virtual void tearDown() override;
|
2017-02-25 17:06:31 +01:00
|
|
|
#if HAVE_FEATURE_PDFIUM
|
2017-04-07 12:27:40 +02:00
|
|
|
void load(const OUString& rFile, vcl::filter::PDFDocument& rDocument);
|
2017-02-24 13:46:52 +01:00
|
|
|
/// Tests that a pdf image is roundtripped back to PDF as a vector format.
|
|
|
|
void testTdf106059();
|
2017-02-24 17:14:23 +01:00
|
|
|
/// Tests that text highlight from Impress is not lost.
|
|
|
|
void testTdf105461();
|
2017-05-22 21:41:31 +02:00
|
|
|
void testTdf107868();
|
2017-02-27 14:29:03 +01:00
|
|
|
/// Tests that embedded video from Impress is not exported as a linked one.
|
|
|
|
void testTdf105093();
|
2017-02-27 16:38:54 +01:00
|
|
|
/// Tests export of non-PDF images.
|
|
|
|
void testTdf106206();
|
2017-03-30 17:04:19 +02:00
|
|
|
/// Tests export of PDF images without reference XObjects.
|
|
|
|
void testTdf106693();
|
2017-04-05 15:35:13 +02:00
|
|
|
void testTdf106972();
|
2017-04-05 17:31:47 +02:00
|
|
|
void testTdf106972Pdf17();
|
2017-04-07 12:27:40 +02:00
|
|
|
void testTdf107013();
|
2017-04-07 18:19:41 +02:00
|
|
|
void testTdf107018();
|
2017-04-11 12:42:23 +02:00
|
|
|
void testTdf107089();
|
2017-06-05 13:21:46 +03:00
|
|
|
void testTdf99680();
|
2017-06-12 14:14:13 +03:00
|
|
|
void testTdf99680_2();
|
2017-09-11 22:38:49 +02:00
|
|
|
void testTdf108963();
|
2017-02-25 17:06:31 +01:00
|
|
|
#endif
|
2017-02-24 13:46:52 +01:00
|
|
|
|
|
|
|
CPPUNIT_TEST_SUITE(PdfExportTest);
|
2017-02-25 17:06:31 +01:00
|
|
|
#if HAVE_FEATURE_PDFIUM
|
2017-02-24 13:46:52 +01:00
|
|
|
CPPUNIT_TEST(testTdf106059);
|
2017-02-24 17:14:23 +01:00
|
|
|
CPPUNIT_TEST(testTdf105461);
|
2017-05-22 21:41:31 +02:00
|
|
|
CPPUNIT_TEST(testTdf107868);
|
2017-02-27 14:29:03 +01:00
|
|
|
CPPUNIT_TEST(testTdf105093);
|
2017-02-27 16:38:54 +01:00
|
|
|
CPPUNIT_TEST(testTdf106206);
|
2017-03-30 17:04:19 +02:00
|
|
|
CPPUNIT_TEST(testTdf106693);
|
2017-04-05 15:35:13 +02:00
|
|
|
CPPUNIT_TEST(testTdf106972);
|
2017-04-05 17:31:47 +02:00
|
|
|
CPPUNIT_TEST(testTdf106972Pdf17);
|
2017-04-07 12:27:40 +02:00
|
|
|
CPPUNIT_TEST(testTdf107013);
|
2017-04-07 18:19:41 +02:00
|
|
|
CPPUNIT_TEST(testTdf107018);
|
2017-04-11 12:42:23 +02:00
|
|
|
CPPUNIT_TEST(testTdf107089);
|
2017-06-05 13:21:46 +03:00
|
|
|
CPPUNIT_TEST(testTdf99680);
|
2017-06-12 14:14:13 +03:00
|
|
|
CPPUNIT_TEST(testTdf99680_2);
|
2017-09-11 22:38:49 +02:00
|
|
|
CPPUNIT_TEST(testTdf108963);
|
2017-02-25 17:06:31 +01:00
|
|
|
#endif
|
2017-02-24 13:46:52 +01:00
|
|
|
CPPUNIT_TEST_SUITE_END();
|
|
|
|
};
|
|
|
|
|
|
|
|
void PdfExportTest::setUp()
|
|
|
|
{
|
|
|
|
test::BootstrapFixture::setUp();
|
|
|
|
|
|
|
|
mxComponentContext.set(comphelper::getComponentContext(getMultiServiceFactory()));
|
|
|
|
mxDesktop.set(frame::Desktop::create(mxComponentContext));
|
2017-05-22 21:41:31 +02:00
|
|
|
|
|
|
|
#if HAVE_FEATURE_PDFIUM
|
|
|
|
FPDF_LIBRARY_CONFIG config;
|
|
|
|
config.version = 2;
|
|
|
|
config.m_pUserFontPaths = nullptr;
|
|
|
|
config.m_pIsolate = nullptr;
|
|
|
|
config.m_v8EmbedderSlot = 0;
|
|
|
|
FPDF_InitLibraryWithConfig(&config);
|
|
|
|
#endif
|
2017-02-24 13:46:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void PdfExportTest::tearDown()
|
|
|
|
{
|
2017-05-22 21:41:31 +02:00
|
|
|
#if HAVE_FEATURE_PDFIUM
|
|
|
|
FPDF_ClosePage(mpPdfPage);
|
|
|
|
FPDF_CloseDocument(mpPdfDocument);
|
|
|
|
FPDF_DestroyLibrary();
|
|
|
|
#endif
|
|
|
|
|
2017-02-24 13:46:52 +01:00
|
|
|
if (mxComponent.is())
|
|
|
|
mxComponent->dispose();
|
|
|
|
|
|
|
|
test::BootstrapFixture::tearDown();
|
|
|
|
}
|
|
|
|
|
2017-02-25 17:06:31 +01:00
|
|
|
#if HAVE_FEATURE_PDFIUM
|
2017-04-07 12:27:40 +02:00
|
|
|
|
2017-08-23 18:11:38 +02:00
|
|
|
char const DATA_DIRECTORY[] = "/vcl/qa/cppunit/pdfexport/data/";
|
2017-08-18 16:26:34 +01:00
|
|
|
|
2017-04-07 12:27:40 +02:00
|
|
|
void PdfExportTest::load(const OUString& rFile, vcl::filter::PDFDocument& rDocument)
|
|
|
|
{
|
|
|
|
// Import the bugdoc and export as PDF.
|
|
|
|
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + rFile;
|
|
|
|
mxComponent = loadFromDesktop(aURL);
|
|
|
|
CPPUNIT_ASSERT(mxComponent.is());
|
|
|
|
|
|
|
|
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
|
|
|
|
utl::TempFile aTempFile;
|
|
|
|
aTempFile.EnableKillingFile();
|
|
|
|
utl::MediaDescriptor aMediaDescriptor;
|
|
|
|
aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
|
|
|
|
xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
|
|
|
|
|
|
|
|
// Parse the export result.
|
|
|
|
SvFileStream aStream(aTempFile.GetURL(), StreamMode::READ);
|
|
|
|
CPPUNIT_ASSERT(rDocument.Read(aStream));
|
|
|
|
}
|
|
|
|
|
2017-02-24 13:46:52 +01:00
|
|
|
void PdfExportTest::testTdf106059()
|
|
|
|
{
|
|
|
|
// Import the bugdoc and export as PDF.
|
|
|
|
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf106059.odt";
|
|
|
|
mxComponent = loadFromDesktop(aURL);
|
|
|
|
CPPUNIT_ASSERT(mxComponent.is());
|
|
|
|
|
|
|
|
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
|
|
|
|
utl::TempFile aTempFile;
|
|
|
|
aTempFile.EnableKillingFile();
|
|
|
|
utl::MediaDescriptor aMediaDescriptor;
|
|
|
|
aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
|
2017-03-29 09:47:09 +02:00
|
|
|
// Explicitly enable the usage of the reference XObject markup.
|
2017-06-09 13:43:00 +02:00
|
|
|
uno::Sequence<beans::PropertyValue> aFilterData( comphelper::InitPropertySequence({
|
|
|
|
{"UseReferenceXObject", uno::Any(true) }
|
|
|
|
}));
|
2017-03-29 09:47:09 +02:00
|
|
|
aMediaDescriptor["FilterData"] <<= aFilterData;
|
2017-02-24 13:46:52 +01:00
|
|
|
xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
|
|
|
|
|
|
|
|
// Parse the export result.
|
2017-03-21 18:03:21 +01:00
|
|
|
vcl::filter::PDFDocument aDocument;
|
2017-02-24 13:46:52 +01:00
|
|
|
SvFileStream aStream(aTempFile.GetURL(), StreamMode::READ);
|
|
|
|
CPPUNIT_ASSERT(aDocument.Read(aStream));
|
|
|
|
|
|
|
|
// Assert that the XObject in the page resources dictionary is a reference XObject.
|
2017-03-21 18:03:21 +01:00
|
|
|
std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
|
2017-02-24 13:46:52 +01:00
|
|
|
// The document has one page.
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size());
|
2017-03-21 18:03:21 +01:00
|
|
|
vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources");
|
2017-02-24 13:46:52 +01:00
|
|
|
CPPUNIT_ASSERT(pResources);
|
2017-03-21 18:03:21 +01:00
|
|
|
auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject"));
|
2017-02-24 13:46:52 +01:00
|
|
|
CPPUNIT_ASSERT(pXObjects);
|
|
|
|
// The page has one image.
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size());
|
2017-03-21 18:03:21 +01:00
|
|
|
vcl::filter::PDFObjectElement* pReferenceXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first);
|
2017-02-24 13:46:52 +01:00
|
|
|
CPPUNIT_ASSERT(pReferenceXObject);
|
|
|
|
// The image is a reference XObject.
|
|
|
|
// This dictionary key was missing, so the XObject wasn't a reference one.
|
|
|
|
CPPUNIT_ASSERT(pReferenceXObject->Lookup("Ref"));
|
|
|
|
}
|
2017-02-24 17:14:23 +01:00
|
|
|
|
2017-03-30 17:04:19 +02:00
|
|
|
void PdfExportTest::testTdf106693()
|
|
|
|
{
|
|
|
|
vcl::filter::PDFDocument aDocument;
|
2017-04-07 12:27:40 +02:00
|
|
|
load("tdf106693.odt", aDocument);
|
2017-03-30 17:04:19 +02:00
|
|
|
|
|
|
|
// Assert that the XObject in the page resources dictionary is a form XObject.
|
|
|
|
std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
|
|
|
|
// The document has one page.
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size());
|
|
|
|
vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources");
|
|
|
|
CPPUNIT_ASSERT(pResources);
|
|
|
|
auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject"));
|
|
|
|
CPPUNIT_ASSERT(pXObjects);
|
|
|
|
// The page has one image.
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size());
|
|
|
|
vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first);
|
|
|
|
CPPUNIT_ASSERT(pXObject);
|
|
|
|
// The image is a form XObject.
|
|
|
|
auto pSubtype = dynamic_cast<vcl::filter::PDFNameElement*>(pXObject->Lookup("Subtype"));
|
|
|
|
CPPUNIT_ASSERT(pSubtype);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype->GetValue());
|
|
|
|
// This failed: UseReferenceXObject was ignored and Ref was always created.
|
|
|
|
CPPUNIT_ASSERT(!pXObject->Lookup("Ref"));
|
|
|
|
|
|
|
|
// Assert that the form object refers to an inner form object, not a
|
|
|
|
// bitmap.
|
|
|
|
auto pInnerResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject->Lookup("Resources"));
|
|
|
|
CPPUNIT_ASSERT(pInnerResources);
|
|
|
|
auto pInnerXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pInnerResources->LookupElement("XObject"));
|
|
|
|
CPPUNIT_ASSERT(pInnerXObjects);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pInnerXObjects->GetItems().size());
|
|
|
|
vcl::filter::PDFObjectElement* pInnerXObject = pInnerXObjects->LookupObject(pInnerXObjects->GetItems().begin()->first);
|
|
|
|
CPPUNIT_ASSERT(pInnerXObject);
|
|
|
|
auto pInnerSubtype = dynamic_cast<vcl::filter::PDFNameElement*>(pInnerXObject->Lookup("Subtype"));
|
|
|
|
CPPUNIT_ASSERT(pInnerSubtype);
|
|
|
|
// This failed: this was Image (bitmap), not Form (vector).
|
|
|
|
CPPUNIT_ASSERT_EQUAL(OString("Form"), pInnerSubtype->GetValue());
|
|
|
|
}
|
|
|
|
|
2017-02-24 17:14:23 +01:00
|
|
|
void PdfExportTest::testTdf105461()
|
|
|
|
{
|
2017-05-04 09:04:04 +02:00
|
|
|
// Import the bugdoc and export as PDF.
|
|
|
|
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf105461.odp";
|
|
|
|
mxComponent = loadFromDesktop(aURL);
|
|
|
|
CPPUNIT_ASSERT(mxComponent.is());
|
|
|
|
|
|
|
|
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
|
|
|
|
utl::TempFile aTempFile;
|
|
|
|
aTempFile.EnableKillingFile();
|
|
|
|
utl::MediaDescriptor aMediaDescriptor;
|
|
|
|
aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
|
|
|
|
xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
|
2017-02-24 17:14:23 +01:00
|
|
|
|
2017-05-04 09:04:04 +02:00
|
|
|
// Parse the export result with pdfium.
|
|
|
|
SvFileStream aFile(aTempFile.GetURL(), StreamMode::READ);
|
|
|
|
SvMemoryStream aMemory;
|
|
|
|
aMemory.WriteStream(aFile);
|
2017-05-22 21:41:31 +02:00
|
|
|
mpPdfDocument = FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr);
|
|
|
|
CPPUNIT_ASSERT(mpPdfDocument);
|
2017-05-04 09:04:04 +02:00
|
|
|
|
|
|
|
// The document has one page.
|
2017-05-22 21:41:31 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(mpPdfDocument));
|
|
|
|
mpPdfPage = FPDF_LoadPage(mpPdfDocument, /*page_index=*/0);
|
|
|
|
CPPUNIT_ASSERT(mpPdfPage);
|
2017-02-24 17:14:23 +01:00
|
|
|
|
|
|
|
// Make sure there is a filled rectangle inside.
|
2017-10-19 09:08:32 +02:00
|
|
|
int nPageObjectCount = FPDFPage_CountObjects(mpPdfPage);
|
2017-05-04 09:04:04 +02:00
|
|
|
int nYellowPathCount = 0;
|
|
|
|
for (int i = 0; i < nPageObjectCount; ++i)
|
|
|
|
{
|
2017-05-22 21:41:31 +02:00
|
|
|
FPDF_PAGEOBJECT pPdfPageObject = FPDFPage_GetObject(mpPdfPage, i);
|
2017-05-04 09:04:04 +02:00
|
|
|
if (FPDFPageObj_GetType(pPdfPageObject) != FPDF_PAGEOBJ_PATH)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
unsigned int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 0;
|
|
|
|
FPDFPath_GetFillColor(pPdfPageObject, &nRed, &nGreen, &nBlue, &nAlpha);
|
|
|
|
if (RGB_COLORDATA(nRed, nGreen, nBlue) == COL_YELLOW)
|
|
|
|
++nYellowPathCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This was 0, the page contained no yellow paths.
|
|
|
|
CPPUNIT_ASSERT_EQUAL(1, nYellowPathCount);
|
2017-05-22 21:41:31 +02:00
|
|
|
}
|
2017-05-04 09:04:04 +02:00
|
|
|
|
2017-05-22 21:41:31 +02:00
|
|
|
void PdfExportTest::testTdf107868()
|
|
|
|
{
|
2017-05-24 09:34:09 +03:00
|
|
|
// FIXME: Why does this fail on macOS?
|
2017-05-24 20:14:35 +08:00
|
|
|
// FIXME: Why does this fail when building 64bit?
|
|
|
|
#if !defined MACOSX && !defined _WIN64
|
2017-05-22 21:41:31 +02:00
|
|
|
// Import the bugdoc and print to PDF.
|
|
|
|
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf107868.odt";
|
|
|
|
mxComponent = loadFromDesktop(aURL);
|
|
|
|
CPPUNIT_ASSERT(mxComponent.is());
|
|
|
|
|
|
|
|
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
|
|
|
|
utl::TempFile aTempFile;
|
|
|
|
aTempFile.EnableKillingFile();
|
|
|
|
uno::Reference<view::XPrintable> xPrintable(mxComponent, uno::UNO_QUERY);
|
|
|
|
CPPUNIT_ASSERT(xPrintable.is());
|
|
|
|
uno::Sequence<beans::PropertyValue> aOptions(comphelper::InitPropertySequence(
|
|
|
|
{
|
|
|
|
{"FileName", uno::makeAny(aTempFile.GetURL())},
|
|
|
|
{"Wait", uno::makeAny(true)}
|
|
|
|
}));
|
|
|
|
xPrintable->print(aOptions);
|
|
|
|
|
|
|
|
// Parse the export result with pdfium.
|
|
|
|
SvFileStream aFile(aTempFile.GetURL(), StreamMode::READ);
|
|
|
|
SvMemoryStream aMemory;
|
|
|
|
aMemory.WriteStream(aFile);
|
|
|
|
mpPdfDocument = FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr);
|
|
|
|
if (!mpPdfDocument)
|
|
|
|
// Printing to PDF failed in a non-interesting way, e.g. CUPS is not
|
|
|
|
// running, there is no printer defined, etc.
|
|
|
|
return;
|
|
|
|
|
|
|
|
// The document has one page.
|
|
|
|
CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(mpPdfDocument));
|
|
|
|
mpPdfPage = FPDF_LoadPage(mpPdfDocument, /*page_index=*/0);
|
|
|
|
CPPUNIT_ASSERT(mpPdfPage);
|
|
|
|
|
|
|
|
// Make sure there is no filled rectangle inside.
|
2017-10-19 09:08:32 +02:00
|
|
|
int nPageObjectCount = FPDFPage_CountObjects(mpPdfPage);
|
2017-05-22 21:41:31 +02:00
|
|
|
int nWhitePathCount = 0;
|
|
|
|
for (int i = 0; i < nPageObjectCount; ++i)
|
|
|
|
{
|
|
|
|
FPDF_PAGEOBJECT pPdfPageObject = FPDFPage_GetObject(mpPdfPage, i);
|
|
|
|
if (FPDFPageObj_GetType(pPdfPageObject) != FPDF_PAGEOBJ_PATH)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
unsigned int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 0;
|
|
|
|
FPDFPath_GetFillColor(pPdfPageObject, &nRed, &nGreen, &nBlue, &nAlpha);
|
|
|
|
if (RGB_COLORDATA(nRed, nGreen, nBlue) == COL_WHITE)
|
|
|
|
++nWhitePathCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This was 4, the page contained 4 white paths at problematic positions.
|
|
|
|
CPPUNIT_ASSERT_EQUAL(0, nWhitePathCount);
|
|
|
|
#endif
|
2017-02-24 17:14:23 +01:00
|
|
|
}
|
2017-02-27 14:29:03 +01:00
|
|
|
|
|
|
|
void PdfExportTest::testTdf105093()
|
|
|
|
{
|
2017-03-21 18:03:21 +01:00
|
|
|
vcl::filter::PDFDocument aDocument;
|
2017-04-07 12:27:40 +02:00
|
|
|
load("tdf105093.odp", aDocument);
|
2017-02-27 14:29:03 +01:00
|
|
|
|
|
|
|
// The document has one page.
|
2017-03-21 18:03:21 +01:00
|
|
|
std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
|
2017-02-27 14:29:03 +01:00
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size());
|
|
|
|
|
|
|
|
// Get page annotations.
|
2017-03-21 18:03:21 +01:00
|
|
|
auto pAnnots = dynamic_cast<vcl::filter::PDFArrayElement*>(aPages[0]->Lookup("Annots"));
|
2017-02-27 14:29:03 +01:00
|
|
|
CPPUNIT_ASSERT(pAnnots);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pAnnots->GetElements().size());
|
2017-03-21 18:03:21 +01:00
|
|
|
auto pAnnotReference = dynamic_cast<vcl::filter::PDFReferenceElement*>(pAnnots->GetElements()[0]);
|
2017-02-27 14:29:03 +01:00
|
|
|
CPPUNIT_ASSERT(pAnnotReference);
|
2017-03-21 18:03:21 +01:00
|
|
|
vcl::filter::PDFObjectElement* pAnnot = pAnnotReference->LookupObject();
|
2017-02-27 14:29:03 +01:00
|
|
|
CPPUNIT_ASSERT(pAnnot);
|
2017-03-21 18:03:21 +01:00
|
|
|
CPPUNIT_ASSERT_EQUAL(OString("Annot"), static_cast<vcl::filter::PDFNameElement*>(pAnnot->Lookup("Type"))->GetValue());
|
2017-02-27 14:29:03 +01:00
|
|
|
|
|
|
|
// Get the Action -> Rendition -> MediaClip -> FileSpec.
|
2017-03-21 18:03:21 +01:00
|
|
|
auto pAction = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pAnnot->Lookup("A"));
|
2017-02-27 14:29:03 +01:00
|
|
|
CPPUNIT_ASSERT(pAction);
|
2017-03-21 18:03:21 +01:00
|
|
|
auto pRendition = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pAction->LookupElement("R"));
|
2017-02-27 14:29:03 +01:00
|
|
|
CPPUNIT_ASSERT(pRendition);
|
2017-03-21 18:03:21 +01:00
|
|
|
auto pMediaClip = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pRendition->LookupElement("C"));
|
2017-02-27 14:29:03 +01:00
|
|
|
CPPUNIT_ASSERT(pMediaClip);
|
2017-03-21 18:03:21 +01:00
|
|
|
auto pFileSpec = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pMediaClip->LookupElement("D"));
|
2017-02-27 14:29:03 +01:00
|
|
|
CPPUNIT_ASSERT(pFileSpec);
|
|
|
|
// Make sure the filespec refers to an embedded file.
|
|
|
|
// This key was missing, the embedded video was handled as a linked one.
|
|
|
|
CPPUNIT_ASSERT(pFileSpec->LookupElement("EF"));
|
|
|
|
}
|
2017-02-27 16:38:54 +01:00
|
|
|
|
|
|
|
void PdfExportTest::testTdf106206()
|
|
|
|
{
|
|
|
|
// Import the bugdoc and export as PDF.
|
|
|
|
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf106206.odt";
|
|
|
|
mxComponent = loadFromDesktop(aURL);
|
|
|
|
CPPUNIT_ASSERT(mxComponent.is());
|
|
|
|
|
|
|
|
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
|
|
|
|
utl::TempFile aTempFile;
|
|
|
|
aTempFile.EnableKillingFile();
|
|
|
|
utl::MediaDescriptor aMediaDescriptor;
|
|
|
|
aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
|
|
|
|
xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
|
|
|
|
|
|
|
|
// Parse the export result.
|
2017-03-21 18:03:21 +01:00
|
|
|
vcl::filter::PDFDocument aDocument;
|
2017-02-27 16:38:54 +01:00
|
|
|
SvFileStream aStream(aTempFile.GetURL(), StreamMode::READ);
|
|
|
|
CPPUNIT_ASSERT(aDocument.Read(aStream));
|
|
|
|
|
|
|
|
// The document has one page.
|
2017-03-21 18:03:21 +01:00
|
|
|
std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
|
2017-02-27 16:38:54 +01:00
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size());
|
|
|
|
|
|
|
|
// The page has a stream.
|
2017-03-21 18:03:21 +01:00
|
|
|
vcl::filter::PDFObjectElement* pContents = aPages[0]->LookupObject("Contents");
|
2017-02-27 16:38:54 +01:00
|
|
|
CPPUNIT_ASSERT(pContents);
|
2017-03-21 18:03:21 +01:00
|
|
|
vcl::filter::PDFStreamElement* pStream = pContents->GetStream();
|
2017-02-27 16:38:54 +01:00
|
|
|
CPPUNIT_ASSERT(pStream);
|
|
|
|
SvMemoryStream& rObjectStream = pStream->GetMemory();
|
|
|
|
// Uncompress it.
|
|
|
|
SvMemoryStream aUncompressed;
|
|
|
|
ZCodec aZCodec;
|
|
|
|
aZCodec.BeginCompression();
|
|
|
|
rObjectStream.Seek(0);
|
|
|
|
aZCodec.Decompress(rObjectStream, aUncompressed);
|
|
|
|
CPPUNIT_ASSERT(aZCodec.EndCompression());
|
|
|
|
|
|
|
|
// Make sure there is an image reference there.
|
|
|
|
OString aImage("/Im");
|
|
|
|
auto pStart = static_cast<const char*>(aUncompressed.GetData());
|
|
|
|
const char* pEnd = pStart + aUncompressed.GetSize();
|
|
|
|
auto it = std::search(pStart, pEnd, aImage.getStr(), aImage.getStr() + aImage.getLength());
|
|
|
|
CPPUNIT_ASSERT(it != pEnd);
|
|
|
|
|
|
|
|
// And also that it's not an invalid one.
|
|
|
|
OString aInvalidImage("/Im0");
|
|
|
|
it = std::search(pStart, pEnd, aInvalidImage.getStr(), aInvalidImage.getStr() + aInvalidImage.getLength());
|
|
|
|
// This failed, object #0 was referenced.
|
|
|
|
CPPUNIT_ASSERT(bool(it == pEnd));
|
|
|
|
}
|
2017-04-05 15:35:13 +02:00
|
|
|
|
|
|
|
void PdfExportTest::testTdf106972()
|
|
|
|
{
|
|
|
|
// Import the bugdoc and export as PDF.
|
|
|
|
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf106972.odt";
|
|
|
|
mxComponent = loadFromDesktop(aURL);
|
|
|
|
CPPUNIT_ASSERT(mxComponent.is());
|
|
|
|
|
|
|
|
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
|
|
|
|
utl::TempFile aTempFile;
|
|
|
|
aTempFile.EnableKillingFile();
|
|
|
|
utl::MediaDescriptor aMediaDescriptor;
|
|
|
|
aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
|
|
|
|
xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
|
|
|
|
|
|
|
|
// Parse the export result.
|
|
|
|
vcl::filter::PDFDocument aDocument;
|
|
|
|
SvFileStream aStream(aTempFile.GetURL(), StreamMode::READ);
|
|
|
|
CPPUNIT_ASSERT(aDocument.Read(aStream));
|
|
|
|
|
|
|
|
// Get access to the only form object on the only page.
|
|
|
|
std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size());
|
|
|
|
vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources");
|
|
|
|
CPPUNIT_ASSERT(pResources);
|
|
|
|
auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject"));
|
|
|
|
CPPUNIT_ASSERT(pXObjects);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size());
|
|
|
|
vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first);
|
|
|
|
CPPUNIT_ASSERT(pXObject);
|
|
|
|
|
|
|
|
// Get access to the only image inside the form object.
|
|
|
|
auto pFormResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject->Lookup("Resources"));
|
|
|
|
CPPUNIT_ASSERT(pFormResources);
|
|
|
|
auto pImages = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pFormResources->LookupElement("XObject"));
|
|
|
|
CPPUNIT_ASSERT(pImages);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pImages->GetItems().size());
|
|
|
|
vcl::filter::PDFObjectElement* pImage = pImages->LookupObject(pImages->GetItems().begin()->first);
|
|
|
|
CPPUNIT_ASSERT(pImage);
|
|
|
|
|
|
|
|
// Assert resources of the image.
|
|
|
|
auto pImageResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pImage->Lookup("Resources"));
|
|
|
|
CPPUNIT_ASSERT(pImageResources);
|
|
|
|
// This failed: the PDF image had no Font resource.
|
|
|
|
CPPUNIT_ASSERT(pImageResources->LookupElement("Font"));
|
|
|
|
}
|
2017-04-05 17:31:47 +02:00
|
|
|
|
|
|
|
void PdfExportTest::testTdf106972Pdf17()
|
|
|
|
{
|
|
|
|
// Import the bugdoc and export as PDF.
|
|
|
|
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf106972-pdf17.odt";
|
|
|
|
mxComponent = loadFromDesktop(aURL);
|
|
|
|
CPPUNIT_ASSERT(mxComponent.is());
|
|
|
|
|
|
|
|
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
|
|
|
|
utl::TempFile aTempFile;
|
|
|
|
aTempFile.EnableKillingFile();
|
|
|
|
utl::MediaDescriptor aMediaDescriptor;
|
|
|
|
aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
|
|
|
|
xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
|
|
|
|
|
|
|
|
// Parse the export result.
|
|
|
|
vcl::filter::PDFDocument aDocument;
|
|
|
|
SvFileStream aStream(aTempFile.GetURL(), StreamMode::READ);
|
|
|
|
CPPUNIT_ASSERT(aDocument.Read(aStream));
|
|
|
|
|
|
|
|
// Get access to the only image on the only page.
|
|
|
|
std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size());
|
|
|
|
vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources");
|
|
|
|
CPPUNIT_ASSERT(pResources);
|
|
|
|
auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject"));
|
|
|
|
CPPUNIT_ASSERT(pXObjects);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size());
|
|
|
|
vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first);
|
|
|
|
CPPUNIT_ASSERT(pXObject);
|
|
|
|
|
2017-04-11 16:50:53 +02:00
|
|
|
// Assert that we now attempt to preserve the original PDF data, even if
|
|
|
|
// the original input was PDF >= 1.4.
|
|
|
|
CPPUNIT_ASSERT(pXObject->Lookup("Resources"));
|
2017-04-05 17:31:47 +02:00
|
|
|
}
|
2017-04-07 12:27:40 +02:00
|
|
|
|
|
|
|
void PdfExportTest::testTdf107013()
|
|
|
|
{
|
|
|
|
vcl::filter::PDFDocument aDocument;
|
|
|
|
load("tdf107013.odt", aDocument);
|
|
|
|
|
|
|
|
// Get access to the only image on the only page.
|
|
|
|
std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size());
|
|
|
|
vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources");
|
|
|
|
CPPUNIT_ASSERT(pResources);
|
|
|
|
auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject"));
|
|
|
|
CPPUNIT_ASSERT(pXObjects);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size());
|
|
|
|
vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first);
|
|
|
|
// This failed, the reference to the image was created, but not the image.
|
|
|
|
CPPUNIT_ASSERT(pXObject);
|
|
|
|
}
|
2017-04-07 18:19:41 +02:00
|
|
|
|
|
|
|
void PdfExportTest::testTdf107018()
|
|
|
|
{
|
|
|
|
vcl::filter::PDFDocument aDocument;
|
|
|
|
load("tdf107018.odt", aDocument);
|
|
|
|
|
|
|
|
// Get access to the only image on the only page.
|
|
|
|
std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size());
|
|
|
|
vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources");
|
|
|
|
CPPUNIT_ASSERT(pResources);
|
|
|
|
auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject"));
|
|
|
|
CPPUNIT_ASSERT(pXObjects);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size());
|
|
|
|
vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first);
|
|
|
|
CPPUNIT_ASSERT(pXObject);
|
|
|
|
|
|
|
|
// Get access to the form object inside the image.
|
|
|
|
auto pXObjectResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject->Lookup("Resources"));
|
|
|
|
CPPUNIT_ASSERT(pXObjectResources);
|
|
|
|
auto pXObjectForms = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObjectResources->LookupElement("XObject"));
|
|
|
|
CPPUNIT_ASSERT(pXObjectForms);
|
|
|
|
vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first);
|
|
|
|
CPPUNIT_ASSERT(pForm);
|
|
|
|
|
|
|
|
// Get access to Resources -> Font -> F1 of the form.
|
|
|
|
auto pFormResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pForm->Lookup("Resources"));
|
|
|
|
CPPUNIT_ASSERT(pFormResources);
|
|
|
|
auto pFonts = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pFormResources->LookupElement("Font"));
|
|
|
|
CPPUNIT_ASSERT(pFonts);
|
|
|
|
auto pF1Ref = dynamic_cast<vcl::filter::PDFReferenceElement*>(pFonts->LookupElement("F1"));
|
|
|
|
CPPUNIT_ASSERT(pF1Ref);
|
|
|
|
vcl::filter::PDFObjectElement* pF1 = pF1Ref->LookupObject();
|
|
|
|
CPPUNIT_ASSERT(pF1);
|
|
|
|
|
|
|
|
// Check that Foo -> Bar of the font is of type Pages.
|
|
|
|
auto pFontFoo = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pF1->Lookup("Foo"));
|
|
|
|
CPPUNIT_ASSERT(pFontFoo);
|
|
|
|
auto pBar = dynamic_cast<vcl::filter::PDFReferenceElement*>(pFontFoo->LookupElement("Bar"));
|
|
|
|
CPPUNIT_ASSERT(pBar);
|
|
|
|
vcl::filter::PDFObjectElement* pObject = pBar->LookupObject();
|
|
|
|
CPPUNIT_ASSERT(pObject);
|
|
|
|
auto pName = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("Type"));
|
|
|
|
CPPUNIT_ASSERT(pName);
|
|
|
|
// This was "XObject", reference in a nested dictionary wasn't updated when
|
|
|
|
// copying the page stream of a PDF image.
|
|
|
|
CPPUNIT_ASSERT_EQUAL(OString("Pages"), pName->GetValue());
|
|
|
|
}
|
2017-04-11 12:42:23 +02:00
|
|
|
|
|
|
|
void PdfExportTest::testTdf107089()
|
|
|
|
{
|
|
|
|
vcl::filter::PDFDocument aDocument;
|
|
|
|
load("tdf107089.odt", aDocument);
|
|
|
|
|
|
|
|
// Get access to the only image on the only page.
|
|
|
|
std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size());
|
|
|
|
vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources");
|
|
|
|
CPPUNIT_ASSERT(pResources);
|
|
|
|
auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject"));
|
|
|
|
CPPUNIT_ASSERT(pXObjects);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size());
|
|
|
|
vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first);
|
|
|
|
CPPUNIT_ASSERT(pXObject);
|
|
|
|
|
|
|
|
// Get access to the form object inside the image.
|
|
|
|
auto pXObjectResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject->Lookup("Resources"));
|
|
|
|
CPPUNIT_ASSERT(pXObjectResources);
|
|
|
|
auto pXObjectForms = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObjectResources->LookupElement("XObject"));
|
|
|
|
CPPUNIT_ASSERT(pXObjectForms);
|
|
|
|
vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first);
|
|
|
|
CPPUNIT_ASSERT(pForm);
|
|
|
|
|
|
|
|
// Make sure 'Hello' is part of the form object's stream.
|
|
|
|
vcl::filter::PDFStreamElement* pStream = pForm->GetStream();
|
|
|
|
CPPUNIT_ASSERT(pStream);
|
2017-04-11 17:39:10 +02:00
|
|
|
SvMemoryStream aObjectStream;
|
|
|
|
ZCodec aZCodec;
|
|
|
|
aZCodec.BeginCompression();
|
|
|
|
pStream->GetMemory().Seek(0);
|
|
|
|
aZCodec.Decompress(pStream->GetMemory(), aObjectStream);
|
|
|
|
CPPUNIT_ASSERT(aZCodec.EndCompression());
|
|
|
|
aObjectStream.Seek(0);
|
2017-04-11 12:42:23 +02:00
|
|
|
OString aHello("Hello");
|
2017-04-11 17:39:10 +02:00
|
|
|
auto pStart = static_cast<const char*>(aObjectStream.GetData());
|
|
|
|
const char* pEnd = pStart + aObjectStream.GetSize();
|
2017-04-11 12:42:23 +02:00
|
|
|
auto it = std::search(pStart, pEnd, aHello.getStr(), aHello.getStr() + aHello.getLength());
|
|
|
|
// This failed, 'Hello' was part only a mixed compressed/uncompressed stream, i.e. garbage.
|
|
|
|
CPPUNIT_ASSERT(it != pEnd);
|
|
|
|
}
|
2017-06-05 13:21:46 +03:00
|
|
|
|
|
|
|
void PdfExportTest::testTdf99680()
|
|
|
|
{
|
|
|
|
vcl::filter::PDFDocument aDocument;
|
|
|
|
load("tdf99680.odt", aDocument);
|
|
|
|
|
|
|
|
// The document has one page.
|
|
|
|
std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size());
|
|
|
|
|
|
|
|
// The page 1 has a stream.
|
|
|
|
vcl::filter::PDFObjectElement* pContents = aPages[0]->LookupObject("Contents");
|
|
|
|
CPPUNIT_ASSERT(pContents);
|
|
|
|
vcl::filter::PDFStreamElement* pStream = pContents->GetStream();
|
|
|
|
CPPUNIT_ASSERT(pStream);
|
|
|
|
SvMemoryStream& rObjectStream = pStream->GetMemory();
|
|
|
|
|
|
|
|
// Uncompress it.
|
|
|
|
SvMemoryStream aUncompressed;
|
|
|
|
ZCodec aZCodec;
|
|
|
|
aZCodec.BeginCompression();
|
|
|
|
rObjectStream.Seek(0);
|
|
|
|
aZCodec.Decompress(rObjectStream, aUncompressed);
|
|
|
|
CPPUNIT_ASSERT(aZCodec.EndCompression());
|
|
|
|
|
|
|
|
// Make sure there are no empty clipping regions.
|
2017-06-09 12:53:51 +02:00
|
|
|
OString aEmptyRegion("0 0 m h W* n");
|
2017-06-05 13:21:46 +03:00
|
|
|
auto pStart = static_cast<const char*>(aUncompressed.GetData());
|
|
|
|
const char* pEnd = pStart + aUncompressed.GetSize();
|
2017-06-09 12:53:51 +02:00
|
|
|
auto it = std::search(pStart, pEnd, aEmptyRegion.getStr(), aEmptyRegion.getStr() + aEmptyRegion.getLength());
|
2017-06-05 13:21:46 +03:00
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Empty clipping region detected!", it, pEnd);
|
2017-06-12 14:14:13 +03:00
|
|
|
|
|
|
|
// Count save graphic state (q) and restore (Q) operators
|
|
|
|
// and ensure their amount is equal
|
|
|
|
size_t nSaveCount = std::count(pStart, pEnd, 'q');
|
|
|
|
size_t nRestoreCount = std::count(pStart, pEnd, 'Q');
|
2017-06-15 22:24:55 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Save/restore graphic state operators count mismatch!", nSaveCount, nRestoreCount);
|
2017-06-12 14:14:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void PdfExportTest::testTdf99680_2()
|
|
|
|
{
|
|
|
|
vcl::filter::PDFDocument aDocument;
|
|
|
|
load("tdf99680-2.odt", aDocument);
|
|
|
|
|
|
|
|
// For each document page
|
|
|
|
std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aPages.size());
|
|
|
|
for (size_t nPageNr = 0; nPageNr < aPages.size(); nPageNr++)
|
|
|
|
{
|
|
|
|
// Get page contents and stream.
|
|
|
|
vcl::filter::PDFObjectElement* pContents = aPages[nPageNr]->LookupObject("Contents");
|
|
|
|
CPPUNIT_ASSERT(pContents);
|
|
|
|
vcl::filter::PDFStreamElement* pStream = pContents->GetStream();
|
|
|
|
CPPUNIT_ASSERT(pStream);
|
|
|
|
SvMemoryStream& rObjectStream = pStream->GetMemory();
|
|
|
|
|
|
|
|
// Uncompress the stream.
|
|
|
|
SvMemoryStream aUncompressed;
|
|
|
|
ZCodec aZCodec;
|
|
|
|
aZCodec.BeginCompression();
|
|
|
|
rObjectStream.Seek(0);
|
|
|
|
aZCodec.Decompress(rObjectStream, aUncompressed);
|
|
|
|
CPPUNIT_ASSERT(aZCodec.EndCompression());
|
|
|
|
|
|
|
|
// Make sure there are no empty clipping regions.
|
|
|
|
OString aEmptyRegion("0 0 m h W* n");
|
|
|
|
auto pStart = static_cast<const char*>(aUncompressed.GetData());
|
|
|
|
const char* pEnd = pStart + aUncompressed.GetSize();
|
|
|
|
auto it = std::search(pStart, pEnd, aEmptyRegion.getStr(), aEmptyRegion.getStr() + aEmptyRegion.getLength());
|
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Empty clipping region detected!", it, pEnd);
|
|
|
|
|
|
|
|
// Count save graphic state (q) and restore (Q) operators
|
|
|
|
// and ensure their amount is equal
|
|
|
|
size_t nSaveCount = std::count(pStart, pEnd, 'q');
|
|
|
|
size_t nRestoreCount = std::count(pStart, pEnd, 'Q');
|
2017-06-15 22:24:55 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("Save/restore graphic state operators count mismatch!", nSaveCount, nRestoreCount);
|
2017-06-12 14:14:13 +03:00
|
|
|
}
|
2017-06-05 13:21:46 +03:00
|
|
|
}
|
|
|
|
|
2017-09-11 22:38:49 +02:00
|
|
|
void PdfExportTest::testTdf108963()
|
|
|
|
{
|
|
|
|
// Import the bugdoc and export as PDF.
|
|
|
|
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf108963.odp";
|
|
|
|
mxComponent = loadFromDesktop(aURL);
|
|
|
|
CPPUNIT_ASSERT(mxComponent.is());
|
|
|
|
|
|
|
|
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
|
|
|
|
utl::TempFile aTempFile;
|
|
|
|
aTempFile.EnableKillingFile();
|
|
|
|
utl::MediaDescriptor aMediaDescriptor;
|
|
|
|
aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
|
|
|
|
xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
|
|
|
|
|
|
|
|
// Parse the export result with pdfium.
|
|
|
|
SvFileStream aFile(aTempFile.GetURL(), StreamMode::READ);
|
|
|
|
SvMemoryStream aMemory;
|
|
|
|
aMemory.WriteStream(aFile);
|
|
|
|
mpPdfDocument = FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr);
|
|
|
|
CPPUNIT_ASSERT(mpPdfDocument);
|
|
|
|
|
|
|
|
// The document has one page.
|
|
|
|
CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(mpPdfDocument));
|
|
|
|
mpPdfPage = FPDF_LoadPage(mpPdfDocument, /*page_index=*/0);
|
|
|
|
CPPUNIT_ASSERT(mpPdfPage);
|
|
|
|
|
|
|
|
// Make sure there is a filled rectangle inside.
|
2017-10-19 09:08:32 +02:00
|
|
|
int nPageObjectCount = FPDFPage_CountObjects(mpPdfPage);
|
2017-09-11 22:38:49 +02:00
|
|
|
int nYellowPathCount = 0;
|
|
|
|
for (int i = 0; i < nPageObjectCount; ++i)
|
|
|
|
{
|
|
|
|
FPDF_PAGEOBJECT pPdfPageObject = FPDFPage_GetObject(mpPdfPage, i);
|
|
|
|
if (FPDFPageObj_GetType(pPdfPageObject) != FPDF_PAGEOBJ_PATH)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
unsigned int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 0;
|
|
|
|
FPDFPath_GetFillColor(pPdfPageObject, &nRed, &nGreen, &nBlue, &nAlpha);
|
|
|
|
if (RGB_COLORDATA(nRed, nGreen, nBlue) == COL_YELLOW)
|
|
|
|
{
|
|
|
|
++nYellowPathCount;
|
2017-10-19 09:08:32 +02:00
|
|
|
// The path described a yellow rectangle, but it was not rotated.
|
|
|
|
int nSegments = FPDFPath_CountSegments(pPdfPageObject);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(5, nSegments);
|
|
|
|
FPDF_PATHSEGMENT pSegment = FPDFPath_GetPathSegment(pPdfPageObject, 0);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(pSegment));
|
|
|
|
float fX = 0;
|
|
|
|
float fY = 0;
|
|
|
|
FPDFPathSegment_GetPoint(pSegment, &fX, &fY);
|
2018-02-05 10:23:27 +00:00
|
|
|
CPPUNIT_ASSERT_EQUAL(245395, static_cast<int>(round(fX * 1000)));
|
|
|
|
CPPUNIT_ASSERT_EQUAL(244233, static_cast<int>(round(fY * 1000)));
|
2017-10-19 09:08:32 +02:00
|
|
|
CPPUNIT_ASSERT(!FPDFPathSegment_GetClose(pSegment));
|
|
|
|
|
|
|
|
pSegment = FPDFPath_GetPathSegment(pPdfPageObject, 1);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(pSegment));
|
|
|
|
FPDFPathSegment_GetPoint(pSegment, &fX, &fY);
|
2018-02-05 10:23:27 +00:00
|
|
|
CPPUNIT_ASSERT_EQUAL(275102, static_cast<int>(round(fX * 1000)));
|
2018-02-23 15:05:33 +00:00
|
|
|
CPPUNIT_ASSERT_EQUAL(267590, static_cast<int>(round(fY * 1000)));
|
2017-10-19 09:08:32 +02:00
|
|
|
CPPUNIT_ASSERT(!FPDFPathSegment_GetClose(pSegment));
|
|
|
|
|
|
|
|
pSegment = FPDFPath_GetPathSegment(pPdfPageObject, 2);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(pSegment));
|
|
|
|
FPDFPathSegment_GetPoint(pSegment, &fX, &fY);
|
2018-02-05 10:23:27 +00:00
|
|
|
CPPUNIT_ASSERT_EQUAL(287518, static_cast<int>(round(fX * 1000)));
|
2018-02-23 15:05:33 +00:00
|
|
|
CPPUNIT_ASSERT_EQUAL(251801, static_cast<int>(round(fY * 1000)));
|
2017-10-19 09:08:32 +02:00
|
|
|
CPPUNIT_ASSERT(!FPDFPathSegment_GetClose(pSegment));
|
|
|
|
|
|
|
|
pSegment = FPDFPath_GetPathSegment(pPdfPageObject, 3);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(pSegment));
|
|
|
|
FPDFPathSegment_GetPoint(pSegment, &fX, &fY);
|
2018-02-05 10:23:27 +00:00
|
|
|
CPPUNIT_ASSERT_EQUAL(257839, static_cast<int>(round(fX * 1000)));
|
|
|
|
CPPUNIT_ASSERT_EQUAL(228444, static_cast<int>(round(fY * 1000)));
|
2017-10-19 09:08:32 +02:00
|
|
|
CPPUNIT_ASSERT(!FPDFPathSegment_GetClose(pSegment));
|
|
|
|
|
|
|
|
pSegment = FPDFPath_GetPathSegment(pPdfPageObject, 4);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(pSegment));
|
|
|
|
FPDFPathSegment_GetPoint(pSegment, &fX, &fY);
|
2018-02-05 10:23:27 +00:00
|
|
|
CPPUNIT_ASSERT_EQUAL(245395, static_cast<int>(round(fX * 1000)));
|
|
|
|
CPPUNIT_ASSERT_EQUAL(244233, static_cast<int>(round(fY * 1000)));
|
2017-10-19 09:08:32 +02:00
|
|
|
CPPUNIT_ASSERT(FPDFPathSegment_GetClose(pSegment));
|
2017-09-11 22:38:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CPPUNIT_ASSERT_EQUAL(1, nYellowPathCount);
|
|
|
|
}
|
2017-02-25 17:06:31 +01:00
|
|
|
#endif
|
2017-02-24 13:46:52 +01:00
|
|
|
|
|
|
|
CPPUNIT_TEST_SUITE_REGISTRATION(PdfExportTest);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
CPPUNIT_PLUGIN_IMPLEMENT();
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|