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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <osl/file.hxx>
22 #include <tools/debug.hxx>
23 #include <tools/urlobj.hxx>
24 #include <tools/poly.hxx>
25 #include <comphelper/diagnose_ex.hxx>
27 #include <vcl/canvastools.hxx>
28 #include <vcl/mapmod.hxx>
29 #include <vcl/gdimtf.hxx>
30 #include <rtl/ustring.hxx>
31 #include <comphelper/propertyvalue.hxx>
32 #include <comphelper/sequence.hxx>
33 #include <comphelper/string.hxx>
34 #include <comphelper/storagehelper.hxx>
35 #include <basegfx/polygon/b2dpolygon.hxx>
36 #include <basegfx/polygon/b2dpolypolygon.hxx>
37 #include <basegfx/polygon/b2dpolygontools.hxx>
38 #include <toolkit/awt/vclxdevice.hxx>
39 #include <unotools/configmgr.hxx>
40 #include <comphelper/compbase.hxx>
41 #include <officecfg/Office/Common.hxx>
43 #include "pdfexport.hxx"
44 #include <strings.hrc>
46 #include <com/sun/star/beans/XPropertySet.hpp>
47 #include <com/sun/star/configuration/theDefaultProvider.hpp>
48 #include <com/sun/star/awt/XDevice.hpp>
49 #include <com/sun/star/frame/XModel.hpp>
50 #include <com/sun/star/frame/ModuleManager.hpp>
51 #include <com/sun/star/frame/XStorable.hpp>
52 #include <com/sun/star/document/XDocumentProperties.hpp>
53 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
54 #include <com/sun/star/container/XNameAccess.hpp>
55 #include <com/sun/star/view/XViewSettingsSupplier.hpp>
56 #include <com/sun/star/task/XInteractionRequest.hpp>
57 #include <com/sun/star/task/PDFExportException.hpp>
58 #include <com/sun/star/io/IOException.hpp>
59 #include <com/sun/star/io/XOutputStream.hpp>
60 #include <com/sun/star/lang/XServiceInfo.hpp>
61 #include <com/sun/star/drawing/XShapes.hpp>
62 #include <com/sun/star/security/XCertificate.hpp>
63 #include <com/sun/star/beans/XMaterialHolder.hpp>
64 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
68 using namespace ::com::sun::star
;
69 using namespace ::com::sun::star::io
;
70 using namespace ::com::sun::star::uno
;
71 using namespace ::com::sun::star::lang
;
72 using namespace ::com::sun::star::beans
;
73 using namespace ::com::sun::star::view
;
74 using namespace ::com::sun::star::graphic
;
77 PDFExport::PDFExport( const Reference
< XComponent
>& rxSrcDoc
,
78 const Reference
< task::XStatusIndicator
>& rxStatusIndicator
,
79 const Reference
< task::XInteractionHandler
>& rxIH
,
80 const Reference
< XComponentContext
>& xContext
) :
81 mxSrcDoc ( rxSrcDoc
),
82 mxContext ( xContext
),
83 mxStatusIndicator ( rxStatusIndicator
),
85 mbUseTaggedPDF ( false ),
86 mnPDFTypeSelection ( 0 ),
87 mbPDFUACompliance ( false),
88 mbExportNotes ( true ),
89 mbExportNotesInMargin ( false ),
90 mbExportPlaceholders ( false ),
91 mbUseReferenceXObject ( false ),
92 mbExportNotesPages ( false ),
93 mbExportOnlyNotesPages ( false ),
94 mbUseTransitionEffects ( true ),
95 mbExportBookmarks ( true ),
96 mbExportHiddenSlides ( false ),
97 mbSinglePageSheets ( false ),
98 mnOpenBookmarkLevels ( -1 ),
99 mbUseLosslessCompression ( false ),
100 mbReduceImageResolution ( true ),
101 mbSkipEmptyPages ( true ),
102 mbAddStream ( false ),
103 mnMaxImageResolution ( 300 ),
106 mbExportFormFields ( true ),
107 mbAllowDuplicateFieldNames ( false ),
108 mnProgressValue ( 0 ),
109 mbRemoveTransparencies ( false ),
111 mbIsRedactMode ( false ),
112 maWatermarkColor ( COL_LIGHTGREEN
),
113 maWatermarkFontName ( "Helvetica" ),
115 mbHideViewerToolbar ( false ),
116 mbHideViewerMenubar ( false ),
117 mbHideViewerWindowControls ( false ),
118 mbFitWindow ( false ),
119 mbCenterWindow ( false ),
120 mbOpenInFullScreenMode ( false ),
121 mbDisplayPDFDocumentTitle ( true ),
122 mnPDFDocumentMode ( 0 ),
123 mnPDFDocumentAction ( 0 ),
126 mnPDFPageLayout ( 0 ),
129 mbRestrictPermissions ( false ),
130 mnPrintAllowed ( 2 ),
131 mnChangesAllowed ( 4 ),
132 mbCanCopyOrExtract ( true ),
133 mbCanExtractForAccessibility( true ),
136 mbExportRelativeFsysLinks ( false ),
137 mnDefaultLinkAction ( 0 ),
138 mbConvertOOoTargetToPDFTarget( false ),
139 mbExportBmkToDest ( false ),
145 PDFExport::~PDFExport()
150 bool PDFExport::ExportSelection( vcl::PDFWriter
& rPDFWriter
,
151 Reference
< css::view::XRenderable
> const & rRenderable
,
152 const Any
& rSelection
,
153 const StringRangeEnumerator
& rRangeEnum
,
154 Sequence
< PropertyValue
>& rRenderOptions
,
155 sal_Int32 nPageCount
)
160 Any
* pFirstPage
= nullptr;
161 Any
* pLastPage
= nullptr;
163 bool bExportNotesPages
= false;
165 auto rRenderOptionsRange
= asNonConstRange(rRenderOptions
);
166 for( sal_Int32 nData
= 0, nDataCount
= rRenderOptions
.getLength(); nData
< nDataCount
; ++nData
)
168 if ( rRenderOptions
[ nData
].Name
== "IsFirstPage" )
169 pFirstPage
= &rRenderOptionsRange
[ nData
].Value
;
170 else if ( rRenderOptions
[ nData
].Name
== "IsLastPage" )
171 pLastPage
= &rRenderOptionsRange
[ nData
].Value
;
172 else if ( rRenderOptions
[ nData
].Name
== "ExportNotesPages" )
173 rRenderOptionsRange
[ nData
].Value
>>= bExportNotesPages
;
176 OutputDevice
* pOut
= rPDFWriter
.GetReferenceDevice();
182 vcl::PDFExtOutDevData
& rPDFExtOutDevData
= dynamic_cast<vcl::PDFExtOutDevData
&>(*pOut
->GetExtOutDevData());
183 rPDFExtOutDevData
.SetIsExportNotesPages( bExportNotesPages
);
185 sal_Int32
nCurrentPage(0);
186 StringRangeEnumerator::Iterator aIter
= rRangeEnum
.begin();
187 StringRangeEnumerator::Iterator aEnd
= rRangeEnum
.end();
188 while ( aIter
!= aEnd
)
190 const Sequence
< PropertyValue
> aRenderer( rRenderable
->getRenderer( *aIter
, rSelection
, rRenderOptions
) );
193 for( const PropertyValue
& rProp
: aRenderer
)
195 if ( rProp
.Name
== "PageSize" )
197 rProp
.Value
>>= aPageSize
;
202 rPDFExtOutDevData
.SetCurrentPageNumber( nCurrentPage
);
205 const MapMode
aMapMode( MapUnit::Map100thMM
);
206 const Size
aMtfSize( aPageSize
.Width
, aPageSize
.Height
);
209 pOut
->EnableOutput( false );
210 pOut
->SetMapMode( aMapMode
);
212 aMtf
.SetPrefSize( aMtfSize
);
213 aMtf
.SetPrefMapMode( aMapMode
);
217 // IsLastPage property.
218 const sal_Int32 nCurrentRenderer
= *aIter
;
220 if ( pLastPage
&& aIter
== aEnd
)
223 rRenderable
->render( nCurrentRenderer
, rSelection
, rRenderOptions
);
228 bool bEmptyPage
= false;
229 if( aMtf
.GetActionSize() &&
230 ( !mbSkipEmptyPages
|| aPageSize
.Width
|| aPageSize
.Height
) )
232 // We convert the whole metafile into a bitmap to get rid of the
233 // text covered by redaction shapes
238 Graphic
aGraph(aMtf
);
239 // use antialiasing to improve how graphic objects look
240 BitmapEx bmp
= aGraph
.GetBitmapEx(GraphicConversionParameters(Size(0, 0), false, true, false));
242 aMtf
= bgraph
.GetGDIMetaFile();
244 catch(const Exception
&)
246 TOOLS_WARN_EXCEPTION("filter.pdf", "Something went wrong while converting metafile to bitmap");
250 ImplExportPage(rPDFWriter
, rPDFExtOutDevData
, aMtf
);
260 if ( mxStatusIndicator
.is() )
261 mxStatusIndicator
->setValue( mnProgressValue
);
263 *pFirstPage
<<= false;
268 // Calculate the page number in the PDF output, which may be smaller than the page number in
269 // case of hidden slides or a partial export.
276 bRet
= true; // #i18334# nPageCount == 0,
277 rPDFWriter
.NewPage( 10000, 10000 ); // creating dummy page
278 rPDFWriter
.SetMapMode(MapMode(MapUnit::Map100thMM
));
282 catch(const RuntimeException
&)
290 class PDFExportStreamDoc
: public vcl::PDFOutputStream
294 Reference
< XComponent
> m_xSrcDoc
;
295 Sequence
< beans::NamedValue
> m_aPreparedPassword
;
299 PDFExportStreamDoc( const Reference
< XComponent
>& xDoc
, const Sequence
<beans::NamedValue
>& rPwd
)
301 m_aPreparedPassword( rPwd
)
304 virtual void write( const Reference
< XOutputStream
>& xStream
) override
;
309 void PDFExportStreamDoc::write( const Reference
< XOutputStream
>& xStream
)
311 Reference
< css::frame::XStorable
> xStore( m_xSrcDoc
, UNO_QUERY
);
315 std::vector
<beans::PropertyValue
> aArgs
{
316 comphelper::makePropertyValue("FilterName", OUString()),
317 comphelper::makePropertyValue("OutputStream", xStream
),
319 if (m_aPreparedPassword
.hasElements())
320 aArgs
.push_back(comphelper::makePropertyValue("EncryptionData", m_aPreparedPassword
));
324 xStore
->storeToURL("private:stream", comphelper::containerToSequence(aArgs
));
326 catch( const IOException
& )
332 static OUString
getMimetypeForDocument( const Reference
< XComponentContext
>& xContext
,
333 const Reference
< XComponent
>& xDoc
) noexcept
335 OUString aDocMimetype
;
338 // get document service name
339 Reference
< css::frame::XStorable
> xStore( xDoc
, UNO_QUERY
);
340 Reference
< frame::XModuleManager2
> xModuleManager
= frame::ModuleManager::create(xContext
);
343 OUString aDocServiceName
= xModuleManager
->identify( Reference
< XInterface
>( xStore
, uno::UNO_QUERY
) );
344 if ( !aDocServiceName
.isEmpty() )
346 // get the actual filter name
347 Reference
< lang::XMultiServiceFactory
> xConfigProvider
=
348 configuration::theDefaultProvider::get( xContext
);
349 beans::NamedValue aPathProp
;
350 aPathProp
.Name
= "nodepath";
351 aPathProp
.Value
<<= OUString( "/org.openoffice.Setup/Office/Factories/" );
352 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(aPathProp
) };
354 Reference
< container::XNameAccess
> xSOFConfig(
355 xConfigProvider
->createInstanceWithArguments(
356 "com.sun.star.configuration.ConfigurationAccess", aArgs
),
359 Reference
< container::XNameAccess
> xApplConfig
;
360 xSOFConfig
->getByName( aDocServiceName
) >>= xApplConfig
;
361 if ( xApplConfig
.is() )
363 OUString aFilterName
;
364 xApplConfig
->getByName( "ooSetupFactoryActualFilter" ) >>= aFilterName
;
365 if( !aFilterName
.isEmpty() )
367 // find the related type name
369 Reference
< container::XNameAccess
> xFilterFactory(
370 xContext
->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", xContext
),
373 Sequence
< beans::PropertyValue
> aFilterData
;
374 xFilterFactory
->getByName( aFilterName
) >>= aFilterData
;
375 for ( const beans::PropertyValue
& rProp
: std::as_const(aFilterData
) )
376 if ( rProp
.Name
== "Type" )
377 rProp
.Value
>>= aTypeName
;
379 if ( !aTypeName
.isEmpty() )
381 // find the mediatype
382 Reference
< container::XNameAccess
> xTypeDetection(
383 xContext
->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", xContext
),
386 Sequence
< beans::PropertyValue
> aTypeData
;
387 xTypeDetection
->getByName( aTypeName
) >>= aTypeData
;
388 for ( const beans::PropertyValue
& rProp
: std::as_const(aTypeData
) )
389 if ( rProp
.Name
== "MediaType" )
390 rProp
.Value
>>= aDocMimetype
;
403 uno::Reference
<security::XCertificate
>
404 PDFExport::GetCertificateFromSubjectName(const std::u16string_view
& rSubjectName
) const
406 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
407 = xml::crypto::SEInitializer::create(mxContext
);
408 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
409 = xSEInitializer
->createSecurityContext(OUString());
410 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
411 = xSecurityContext
->getSecurityEnvironment();
412 for (const auto& xCertificate
: xSecurityEnvironment
->getPersonalCertificates())
414 if (xCertificate
->getSubjectName() == rSubjectName
)
423 bool PDFExport::Export( const OUString
& rFile
, const Sequence
< PropertyValue
>& rFilterData
)
425 INetURLObject
aURL( rFile
);
428 std::set
< vcl::PDFWriter::ErrorCode
> aErrors
;
430 if( aURL
.GetProtocol() != INetProtocol::File
)
434 if( osl::FileBase::getFileURLFromSystemPath( rFile
, aTmp
) == osl::FileBase::E_None
)
435 aURL
= INetURLObject(aTmp
);
438 if( aURL
.GetProtocol() == INetProtocol::File
)
440 Reference
< XRenderable
> xRenderable( mxSrcDoc
, UNO_QUERY
);
442 if( xRenderable
.is() )
444 rtl::Reference
<VCLXDevice
> xDevice(new VCLXDevice
);
447 vcl::PDFWriter::PDFWriterContext aContext
;
448 OUString aOpenPassword
, aPermissionPassword
;
449 Reference
< beans::XMaterialHolder
> xEnc
;
450 Sequence
< beans::NamedValue
> aPreparedPermissionPassword
;
453 // getting the string for the creator
455 Reference
< XServiceInfo
> xInfo( mxSrcDoc
, UNO_QUERY
);
458 if ( xInfo
->supportsService( "com.sun.star.presentation.PresentationDocument" ) )
459 aCreator
+= "Impress";
460 else if ( xInfo
->supportsService( "com.sun.star.drawing.DrawingDocument" ) )
462 else if ( xInfo
->supportsService( "com.sun.star.text.TextDocument" ) )
463 aCreator
+= "Writer";
464 else if ( xInfo
->supportsService( "com.sun.star.sheet.SpreadsheetDocument" ) )
466 else if ( xInfo
->supportsService( "com.sun.star.formula.FormulaProperties" ) )
470 Reference
< document::XDocumentPropertiesSupplier
> xDocumentPropsSupplier( mxSrcDoc
, UNO_QUERY
);
471 if ( xDocumentPropsSupplier
.is() )
473 Reference
< document::XDocumentProperties
> xDocumentProps( xDocumentPropsSupplier
->getDocumentProperties() );
474 if ( xDocumentProps
.is() )
476 aContext
.DocumentInfo
.Title
= xDocumentProps
->getTitle();
477 aContext
.DocumentInfo
.Author
= xDocumentProps
->getAuthor();
478 aContext
.DocumentInfo
.Subject
= xDocumentProps
->getSubject();
479 aContext
.DocumentInfo
.Keywords
= ::comphelper::string::convertCommaSeparated(xDocumentProps
->getKeywords());
483 if (!utl::ConfigManager::IsFuzzing())
485 // getting the string for the producer
486 OUString aProducerOverride
= officecfg::Office::Common::Save::Document::GeneratorOverride::get();
487 if (!aProducerOverride
.isEmpty())
488 aContext
.DocumentInfo
.Producer
= aProducerOverride
;
490 aContext
.DocumentInfo
.Producer
=
491 utl::ConfigManager::getProductName() +
493 utl::ConfigManager::getProductVersion();
496 aContext
.DocumentInfo
.Creator
= aCreator
;
498 OUString aSignCertificateSubjectName
;
499 for ( const beans::PropertyValue
& rProp
: rFilterData
)
501 if ( rProp
.Name
== "PageRange" )
502 rProp
.Value
>>= aPageRange
;
503 else if ( rProp
.Name
== "Selection" )
504 aSelection
= rProp
.Value
;
505 else if ( rProp
.Name
== "UseLosslessCompression" )
506 rProp
.Value
>>= mbUseLosslessCompression
;
507 else if ( rProp
.Name
== "Quality" )
508 rProp
.Value
>>= mnQuality
;
509 else if ( rProp
.Name
== "ReduceImageResolution" )
510 rProp
.Value
>>= mbReduceImageResolution
;
511 else if ( rProp
.Name
== "IsSkipEmptyPages" )
512 rProp
.Value
>>= mbSkipEmptyPages
;
513 else if ( rProp
.Name
== "MaxImageResolution" )
514 rProp
.Value
>>= mnMaxImageResolution
;
515 else if ( rProp
.Name
== "UseTaggedPDF" )
516 rProp
.Value
>>= mbUseTaggedPDF
;
517 else if ( rProp
.Name
== "SelectPdfVersion" )
518 rProp
.Value
>>= mnPDFTypeSelection
;
519 else if ( rProp
.Name
== "PDFUACompliance" )
520 rProp
.Value
>>= mbPDFUACompliance
;
521 else if ( rProp
.Name
== "ExportNotes" )
522 rProp
.Value
>>= mbExportNotes
;
523 else if ( rProp
.Name
== "ExportNotesInMargin" )
524 rProp
.Value
>>= mbExportNotesInMargin
;
525 else if ( rProp
.Name
== "ExportNotesPages" )
526 rProp
.Value
>>= mbExportNotesPages
;
527 else if ( rProp
.Name
== "ExportOnlyNotesPages" )
528 rProp
.Value
>>= mbExportOnlyNotesPages
;
529 else if ( rProp
.Name
== "UseTransitionEffects" )
530 rProp
.Value
>>= mbUseTransitionEffects
;
531 else if ( rProp
.Name
== "ExportFormFields" )
532 rProp
.Value
>>= mbExportFormFields
;
533 else if ( rProp
.Name
== "FormsType" )
534 rProp
.Value
>>= mnFormsFormat
;
535 else if ( rProp
.Name
== "AllowDuplicateFieldNames" )
536 rProp
.Value
>>= mbAllowDuplicateFieldNames
;
538 else if ( rProp
.Name
== "HideViewerToolbar" )
539 rProp
.Value
>>= mbHideViewerToolbar
;
540 else if ( rProp
.Name
== "HideViewerMenubar" )
541 rProp
.Value
>>= mbHideViewerMenubar
;
542 else if ( rProp
.Name
== "HideViewerWindowControls" )
543 rProp
.Value
>>= mbHideViewerWindowControls
;
544 else if ( rProp
.Name
== "ResizeWindowToInitialPage" )
545 rProp
.Value
>>= mbFitWindow
;
546 else if ( rProp
.Name
== "CenterWindow" )
547 rProp
.Value
>>= mbCenterWindow
;
548 else if ( rProp
.Name
== "OpenInFullScreenMode" )
549 rProp
.Value
>>= mbOpenInFullScreenMode
;
550 else if ( rProp
.Name
== "DisplayPDFDocumentTitle" )
551 rProp
.Value
>>= mbDisplayPDFDocumentTitle
;
552 else if ( rProp
.Name
== "InitialView" )
553 rProp
.Value
>>= mnPDFDocumentMode
;
554 else if ( rProp
.Name
== "Magnification" )
555 rProp
.Value
>>= mnPDFDocumentAction
;
556 else if ( rProp
.Name
== "Zoom" )
557 rProp
.Value
>>= mnZoom
;
558 else if ( rProp
.Name
== "InitialPage" )
559 rProp
.Value
>>= mnInitialPage
;
560 else if ( rProp
.Name
== "PageLayout" )
561 rProp
.Value
>>= mnPDFPageLayout
;
562 else if ( rProp
.Name
== "FirstPageOnLeft" )
563 rProp
.Value
>>= aContext
.FirstPageLeft
;
564 else if ( rProp
.Name
== "IsAddStream" )
565 rProp
.Value
>>= mbAddStream
;
566 else if ( rProp
.Name
== "Watermark" )
567 rProp
.Value
>>= msWatermark
;
568 else if ( rProp
.Name
== "WatermarkColor" )
571 if (rProp
.Value
>>= nColor
)
573 maWatermarkColor
= Color(ColorTransparency
, nColor
);
576 else if (rProp
.Name
== "WatermarkFontHeight")
578 sal_Int32 nFontHeight
{};
579 if (rProp
.Value
>>= nFontHeight
)
581 moWatermarkFontHeight
= nFontHeight
;
584 else if (rProp
.Name
== "WatermarkRotateAngle")
586 sal_Int32 nRotateAngle
{};
587 if (rProp
.Value
>>= nRotateAngle
)
589 moWatermarkRotateAngle
= Degree10(nRotateAngle
);
592 else if (rProp
.Name
== "WatermarkFontName")
594 OUString aFontName
{};
595 if (rProp
.Value
>>= aFontName
)
597 maWatermarkFontName
= aFontName
;
600 else if ( rProp
.Name
== "TiledWatermark" )
601 rProp
.Value
>>= msTiledWatermark
;
602 // now all the security related properties...
603 else if ( rProp
.Name
== "EncryptFile" )
604 rProp
.Value
>>= mbEncrypt
;
605 else if ( rProp
.Name
== "DocumentOpenPassword" )
606 rProp
.Value
>>= aOpenPassword
;
607 else if ( rProp
.Name
== "RestrictPermissions" )
608 rProp
.Value
>>= mbRestrictPermissions
;
609 else if ( rProp
.Name
== "PermissionPassword" )
610 rProp
.Value
>>= aPermissionPassword
;
611 else if ( rProp
.Name
== "PreparedPasswords" )
612 rProp
.Value
>>= xEnc
;
613 else if ( rProp
.Name
== "PreparedPermissionPassword" )
614 rProp
.Value
>>= aPreparedPermissionPassword
;
615 else if ( rProp
.Name
== "Printing" )
616 rProp
.Value
>>= mnPrintAllowed
;
617 else if ( rProp
.Name
== "Changes" )
618 rProp
.Value
>>= mnChangesAllowed
;
619 else if ( rProp
.Name
== "EnableCopyingOfContent" )
620 rProp
.Value
>>= mbCanCopyOrExtract
;
621 else if ( rProp
.Name
== "EnableTextAccessForAccessibilityTools" )
622 rProp
.Value
>>= mbCanExtractForAccessibility
;
623 // i56629 links extra (relative links and other related stuff)
624 else if ( rProp
.Name
== "ExportLinksRelativeFsys" )
625 rProp
.Value
>>= mbExportRelativeFsysLinks
;
626 else if ( rProp
.Name
== "PDFViewSelection" )
627 rProp
.Value
>>= mnDefaultLinkAction
;
628 else if ( rProp
.Name
== "ConvertOOoTargetToPDFTarget" )
629 rProp
.Value
>>= mbConvertOOoTargetToPDFTarget
;
630 else if ( rProp
.Name
== "ExportBookmarksToPDFDestination" )
631 rProp
.Value
>>= mbExportBmkToDest
;
632 else if ( rProp
.Name
== "ExportBookmarks" )
633 rProp
.Value
>>= mbExportBookmarks
;
634 else if ( rProp
.Name
== "ExportHiddenSlides" )
635 rProp
.Value
>>= mbExportHiddenSlides
;
636 else if ( rProp
.Name
== "SinglePageSheets" )
637 rProp
.Value
>>= mbSinglePageSheets
;
638 else if ( rProp
.Name
== "OpenBookmarkLevels" )
639 rProp
.Value
>>= mnOpenBookmarkLevels
;
640 else if ( rProp
.Name
== "SignPDF" )
641 rProp
.Value
>>= mbSignPDF
;
642 else if ( rProp
.Name
== "SignatureLocation" )
643 rProp
.Value
>>= msSignLocation
;
644 else if ( rProp
.Name
== "SignatureReason" )
645 rProp
.Value
>>= msSignReason
;
646 else if ( rProp
.Name
== "SignatureContactInfo" )
647 rProp
.Value
>>= msSignContact
;
648 else if ( rProp
.Name
== "SignaturePassword" )
649 rProp
.Value
>>= msSignPassword
;
650 else if ( rProp
.Name
== "SignatureCertificate" )
651 rProp
.Value
>>= maSignCertificate
;
652 else if (rProp
.Name
== "SignCertificateSubjectName")
653 rProp
.Value
>>= aSignCertificateSubjectName
;
654 else if ( rProp
.Name
== "SignatureTSA" )
655 rProp
.Value
>>= msSignTSA
;
656 else if ( rProp
.Name
== "ExportPlaceholders" )
657 rProp
.Value
>>= mbExportPlaceholders
;
658 else if ( rProp
.Name
== "UseReferenceXObject" )
659 rProp
.Value
>>= mbUseReferenceXObject
;
660 // Redaction & bitmap related stuff
661 else if ( rProp
.Name
== "IsRedactMode" )
662 rProp
.Value
>>= mbIsRedactMode
;
665 if (!maSignCertificate
.is() && !aSignCertificateSubjectName
.isEmpty())
667 maSignCertificate
= GetCertificateFromSubjectName(aSignCertificateSubjectName
);
670 aContext
.URL
= aURL
.GetMainURL(INetURLObject::DecodeMechanism::ToIUri
);
672 // set the correct version, depending on user request
673 switch( mnPDFTypeSelection
)
677 aContext
.Version
= vcl::PDFWriter::PDFVersion::PDF_1_7
;
680 aContext
.Version
= vcl::PDFWriter::PDFVersion::PDF_A_1
;
681 mbUseTaggedPDF
= true; // force the tagged PDF as well
682 mbRemoveTransparencies
= true; // does not allow transparencies
683 mbEncrypt
= false; // no encryption
687 aContext
.Version
= vcl::PDFWriter::PDFVersion::PDF_A_2
;
688 mbUseTaggedPDF
= true; // force the tagged PDF as well
689 mbRemoveTransparencies
= false; // does allow transparencies
690 mbEncrypt
= false; // no encryption
694 aContext
.Version
= vcl::PDFWriter::PDFVersion::PDF_A_3
;
695 mbUseTaggedPDF
= true; // force the tagged PDF as well
696 mbRemoveTransparencies
= false; // does allow transparencies
697 mbEncrypt
= false; // no encryption
701 aContext
.Version
= vcl::PDFWriter::PDFVersion::PDF_1_5
;
704 aContext
.Version
= vcl::PDFWriter::PDFVersion::PDF_1_6
;
707 aContext
.Version
= vcl::PDFWriter::PDFVersion::PDF_1_7
;
712 aContext
.UniversalAccessibilityCompliance
= mbPDFUACompliance
;
713 if (mbPDFUACompliance
)
715 // ISO 14289-1:2014, Clause: 7.1
716 mbUseTaggedPDF
= true;
717 // ISO 14289-1:2014, Clause: 7.16
718 mbCanExtractForAccessibility
= true;
719 // ISO 14289-1:2014, Clause: 7.20
720 mbUseReferenceXObject
= false;
723 // copy in context the values default in the constructor or set by the FilterData sequence of properties
724 aContext
.Tagged
= mbUseTaggedPDF
;
726 // values used in viewer
727 aContext
.HideViewerToolbar
= mbHideViewerToolbar
;
728 aContext
.HideViewerMenubar
= mbHideViewerMenubar
;
729 aContext
.HideViewerWindowControls
= mbHideViewerWindowControls
;
730 aContext
.FitWindow
= mbFitWindow
;
731 aContext
.CenterWindow
= mbCenterWindow
;
732 aContext
.OpenInFullScreenMode
= mbOpenInFullScreenMode
;
733 aContext
.DisplayPDFDocumentTitle
= mbDisplayPDFDocumentTitle
;
734 aContext
.InitialPage
= mnInitialPage
-1;
735 aContext
.OpenBookmarkLevels
= mnOpenBookmarkLevels
;
737 switch( mnPDFDocumentMode
)
741 aContext
.PDFDocumentMode
= vcl::PDFWriter::ModeDefault
;
744 aContext
.PDFDocumentMode
= vcl::PDFWriter::UseOutlines
;
747 aContext
.PDFDocumentMode
= vcl::PDFWriter::UseThumbs
;
750 switch( mnPDFDocumentAction
)
754 aContext
.PDFDocumentAction
= vcl::PDFWriter::ActionDefault
;
757 aContext
.PDFDocumentAction
= vcl::PDFWriter::FitInWindow
;
760 aContext
.PDFDocumentAction
= vcl::PDFWriter::FitWidth
;
763 aContext
.PDFDocumentAction
= vcl::PDFWriter::FitVisible
;
766 aContext
.PDFDocumentAction
= vcl::PDFWriter::ActionZoom
;
767 aContext
.Zoom
= mnZoom
;
771 switch( mnPDFPageLayout
)
775 aContext
.PageLayout
= vcl::PDFWriter::DefaultLayout
;
778 aContext
.PageLayout
= vcl::PDFWriter::SinglePage
;
781 aContext
.PageLayout
= vcl::PDFWriter::Continuous
;
784 aContext
.PageLayout
= vcl::PDFWriter::ContinuousFacing
;
788 aContext
.FirstPageLeft
= false;
790 // check if PDF/A, which does not allow encryption
791 if( aContext
.Version
!= vcl::PDFWriter::PDFVersion::PDF_A_1
)
793 // set check for permission change password
794 // if not enabled and no permission password, force permissions to default as if PDF where without encryption
795 if( mbRestrictPermissions
&& (xEnc
.is() || !aPermissionPassword
.isEmpty()) )
797 mbEncrypt
= true; // permission set as desired, done after
801 // force permission to default
803 mnChangesAllowed
= 4 ;
804 mbCanCopyOrExtract
= true;
805 mbCanExtractForAccessibility
= true ;
808 switch( mnPrintAllowed
)
810 case 0: // initialized when aContext is build, means no printing
814 aContext
.Encryption
.CanPrintFull
= true;
817 aContext
.Encryption
.CanPrintTheDocument
= true;
821 switch( mnChangesAllowed
)
823 case 0: // already in struct PDFSecPermissions CTOR
826 aContext
.Encryption
.CanAssemble
= true;
829 aContext
.Encryption
.CanFillInteractive
= true;
832 aContext
.Encryption
.CanAddOrModify
= true;
836 aContext
.Encryption
.CanModifyTheContent
=
837 aContext
.Encryption
.CanCopyOrExtract
=
838 aContext
.Encryption
.CanAddOrModify
=
839 aContext
.Encryption
.CanFillInteractive
= true;
843 aContext
.Encryption
.CanCopyOrExtract
= mbCanCopyOrExtract
;
844 aContext
.Encryption
.CanExtractForAccessibility
= mbCanExtractForAccessibility
;
845 if( mbEncrypt
&& ! xEnc
.is() )
846 xEnc
= vcl::PDFWriter::InitEncryption( aPermissionPassword
, aOpenPassword
);
847 if( mbEncrypt
&& !aPermissionPassword
.isEmpty() && ! aPreparedPermissionPassword
.hasElements() )
848 aPreparedPermissionPassword
= comphelper::OStorageHelper::CreatePackageEncryptionData( aPermissionPassword
);
850 // after this point we don't need the legacy clear passwords anymore
851 // however they are still inside the passed filter data sequence
852 // which is sadly out of our control
853 aPermissionPassword
.clear();
854 aOpenPassword
.clear();
857 * FIXME: the entries are only implicitly defined by the resource file. Should there
858 * ever be an additional form submit format this could get invalid.
860 switch( mnFormsFormat
)
863 aContext
.SubmitFormat
= vcl::PDFWriter::PDF
;
866 aContext
.SubmitFormat
= vcl::PDFWriter::HTML
;
869 aContext
.SubmitFormat
= vcl::PDFWriter::XML
;
873 aContext
.SubmitFormat
= vcl::PDFWriter::FDF
;
876 aContext
.AllowDuplicateFieldNames
= mbAllowDuplicateFieldNames
;
879 Reference
< frame::XModel
> xModel( mxSrcDoc
, UNO_QUERY
);
881 // #i56629: Relative link stuff
882 // set the base URL of the file: then base URL
883 aContext
.BaseURL
= xModel
->getURL();
884 // relative link option is private to PDF Export filter and limited to local filesystem only
885 aContext
.RelFsys
= mbExportRelativeFsysLinks
;
886 // determine the default action for PDF links
887 switch( mnDefaultLinkAction
)
890 // default: URI, without fragment conversion (the bookmark in PDF may not work)
892 aContext
.DefaultLinkAction
= vcl::PDFWriter::URIAction
;
895 // view PDF through the reader application
896 aContext
.ForcePDFAction
= true;
897 aContext
.DefaultLinkAction
= vcl::PDFWriter::LaunchAction
;
900 // view PDF through an Internet browser
901 aContext
.DefaultLinkAction
= vcl::PDFWriter::URIActionDestination
;
904 aContext
.ConvertOOoTargetToPDFTarget
= mbConvertOOoTargetToPDFTarget
;
906 // check for Link Launch action, not allowed on PDF/A-1
907 // this code chunk checks when the filter is called from scripting
908 if( aContext
.Version
== vcl::PDFWriter::PDFVersion::PDF_A_1
&&
909 aContext
.DefaultLinkAction
== vcl::PDFWriter::LaunchAction
)
911 // force the similar allowed URI action
912 aContext
.DefaultLinkAction
= vcl::PDFWriter::URIActionDestination
;
913 // and remove the remote goto action forced on PDF file
914 aContext
.ForcePDFAction
= false;
918 aContext
.SignPDF
= mbSignPDF
;
919 aContext
.SignLocation
= msSignLocation
;
920 aContext
.SignContact
= msSignContact
;
921 aContext
.SignReason
= msSignReason
;
922 aContext
.SignPassword
= msSignPassword
;
923 aContext
.SignCertificate
= maSignCertificate
;
924 aContext
.SignTSA
= msSignTSA
;
925 aContext
.UseReferenceXObject
= mbUseReferenceXObject
;
927 // all context data set, time to create the printing device
928 vcl::PDFWriter
aPDFWriter( aContext
, xEnc
);
929 OutputDevice
* pOut
= aPDFWriter
.GetReferenceDevice();
931 DBG_ASSERT( pOut
, "PDFExport::Export: no reference device" );
932 xDevice
->SetOutputDevice(pOut
);
938 OUString aSrcMimetype
= getMimetypeForDocument( mxContext
, mxSrcDoc
);
940 if (aSrcMimetype
== "application/vnd.oasis.opendocument.text")
942 else if (aSrcMimetype
== "application/vnd.oasis.opendocument.presentation")
944 else if (aSrcMimetype
== "application/vnd.oasis.opendocument.spreadsheet")
946 else if (aSrcMimetype
== "application/vnd.oasis.opendocument.graphics")
948 std::unique_ptr
<vcl::PDFOutputStream
> pStream(new PDFExportStreamDoc(mxSrcDoc
, aPreparedPermissionPassword
));
949 aPDFWriter
.AddAttachedFile("Original" + aExt
, aSrcMimetype
, u
"Embedded original document of this PDF file", std::move(pStream
));
954 DBG_ASSERT( pOut
->GetExtOutDevData() == nullptr, "PDFExport: ExtOutDevData already set!!!" );
955 vcl::PDFExtOutDevData
aPDFExtOutDevData( *pOut
);
956 pOut
->SetExtOutDevData( &aPDFExtOutDevData
);
957 aPDFExtOutDevData
.SetIsExportNotes( mbExportNotes
);
958 aPDFExtOutDevData
.SetIsExportNotesInMargin( mbExportNotesInMargin
);
959 aPDFExtOutDevData
.SetIsExportTaggedPDF( mbUseTaggedPDF
);
960 aPDFExtOutDevData
.SetIsExportTransitionEffects( mbUseTransitionEffects
);
961 aPDFExtOutDevData
.SetIsExportFormFields( mbExportFormFields
);
962 aPDFExtOutDevData
.SetIsExportBookmarks( mbExportBookmarks
);
963 aPDFExtOutDevData
.SetIsExportHiddenSlides( mbExportHiddenSlides
);
964 aPDFExtOutDevData
.SetIsSinglePageSheets( mbSinglePageSheets
);
965 aPDFExtOutDevData
.SetIsLosslessCompression( mbUseLosslessCompression
);
966 aPDFExtOutDevData
.SetCompressionQuality( mnQuality
);
967 aPDFExtOutDevData
.SetIsReduceImageResolution( mbReduceImageResolution
);
968 aPDFExtOutDevData
.SetIsExportNamedDestinations( mbExportBmkToDest
);
970 Sequence
< PropertyValue
> aRenderOptions
{
971 comphelper::makePropertyValue("RenderDevice", uno::Reference
<awt::XDevice
>(xDevice
)),
972 comphelper::makePropertyValue("ExportNotesPages", false),
973 comphelper::makePropertyValue("IsFirstPage", true),
974 comphelper::makePropertyValue("IsLastPage", false),
975 comphelper::makePropertyValue("IsSkipEmptyPages", mbSkipEmptyPages
),
976 comphelper::makePropertyValue("PageRange", aPageRange
),
977 comphelper::makePropertyValue("ExportPlaceholders", mbExportPlaceholders
),
978 comphelper::makePropertyValue("SinglePageSheets", mbSinglePageSheets
),
979 comphelper::makePropertyValue("ExportNotesInMargin", mbExportNotesInMargin
)
981 Any
& rExportNotesValue
= aRenderOptions
.getArray()[ 1 ].Value
;
983 if( !aPageRange
.isEmpty() || !aSelection
.hasValue() )
986 aSelection
<<= mxSrcDoc
;
988 bool bExportNotesPages
= false;
989 bool bReChangeToNormalView
= false;
990 static const OUStringLiteral
sShowOnlineLayout( u
"ShowOnlineLayout" );
991 bool bReHideWhitespace
= false;
992 static const OUStringLiteral
sHideWhitespace(u
"HideWhitespace");
993 uno::Reference
< beans::XPropertySet
> xViewProperties
;
995 if ( aCreator
== "Writer" )
997 // #i92835: if Writer is in web layout mode this has to be switched to normal view and back to web view in the end
1000 Reference
< view::XViewSettingsSupplier
> xVSettingsSupplier( xModel
->getCurrentController(), uno::UNO_QUERY_THROW
);
1001 xViewProperties
= xVSettingsSupplier
->getViewSettings();
1002 xViewProperties
->getPropertyValue( sShowOnlineLayout
) >>= bReChangeToNormalView
;
1003 if( bReChangeToNormalView
)
1005 xViewProperties
->setPropertyValue( sShowOnlineLayout
, uno::Any( false ) );
1008 // Also, disable hide-whitespace during export.
1009 xViewProperties
->getPropertyValue(sHideWhitespace
) >>= bReHideWhitespace
;
1010 if (bReHideWhitespace
)
1012 xViewProperties
->setPropertyValue(sHideWhitespace
, uno::Any(false));
1015 catch( const uno::Exception
& )
1021 const sal_Int32 nPageCount
= xRenderable
->getRendererCount( aSelection
, aRenderOptions
);
1023 if ( mbExportNotesPages
&& aCreator
== "Impress" )
1025 uno::Reference
< drawing::XShapes
> xShapes
; // do not allow to export notes when exporting a selection
1026 if ( ! ( aSelection
>>= xShapes
) )
1027 bExportNotesPages
= true;
1029 const bool bExportPages
= !bExportNotesPages
|| !mbExportOnlyNotesPages
;
1031 if( aPageRange
.isEmpty() || mbSinglePageSheets
)
1033 aPageRange
= OUString::number( 1 ) + "-" + OUString::number(nPageCount
);
1035 StringRangeEnumerator
aRangeEnum( aPageRange
, 0, nPageCount
-1 );
1037 if ( mxStatusIndicator
.is() )
1039 sal_Int32 nTotalPageCount
= aRangeEnum
.size();
1040 if ( bExportPages
&& bExportNotesPages
)
1041 nTotalPageCount
*= 2;
1042 mxStatusIndicator
->start(FilterResId(PDF_PROGRESS_BAR
), nTotalPageCount
);
1045 bRet
= nPageCount
> 0;
1047 if ( bRet
&& bExportPages
)
1048 bRet
= ExportSelection( aPDFWriter
, xRenderable
, aSelection
, aRangeEnum
, aRenderOptions
, nPageCount
);
1050 if ( bRet
&& bExportNotesPages
)
1052 rExportNotesValue
<<= true;
1053 bRet
= ExportSelection( aPDFWriter
, xRenderable
, aSelection
, aRangeEnum
, aRenderOptions
, nPageCount
);
1055 if ( mxStatusIndicator
.is() )
1056 mxStatusIndicator
->end();
1058 // if during the export the doc locale was set copy it to PDF writer
1059 const css::lang::Locale
& rLoc( aPDFExtOutDevData
.GetDocumentLocale() );
1060 if( !rLoc
.Language
.isEmpty() )
1061 aPDFWriter
.SetDocumentLocale( rLoc
);
1065 aPDFExtOutDevData
.PlayGlobalActions( aPDFWriter
);
1066 bRet
= aPDFWriter
.Emit();
1067 aErrors
= aPDFWriter
.GetErrors();
1069 pOut
->SetExtOutDevData( nullptr );
1070 if( bReChangeToNormalView
)
1074 xViewProperties
->setPropertyValue( sShowOnlineLayout
, uno::Any( true ) );
1076 catch( const uno::Exception
& )
1080 if( bReHideWhitespace
)
1084 xViewProperties
->setPropertyValue( sHideWhitespace
, uno::Any( true ) );
1086 catch( const uno::Exception
& )
1094 // show eventual errors during export
1095 showErrors( aErrors
);
1104 typedef comphelper::WeakComponentImplHelper
< task::XInteractionRequest
> PDFErrorRequestBase
;
1106 class PDFErrorRequest
: public PDFErrorRequestBase
1108 task::PDFExportException maExc
;
1110 explicit PDFErrorRequest( task::PDFExportException aExc
);
1112 // XInteractionRequest
1113 virtual uno::Any SAL_CALL
getRequest() override
;
1114 virtual uno::Sequence
< uno::Reference
< task::XInteractionContinuation
> > SAL_CALL
getContinuations() override
;
1118 PDFErrorRequest::PDFErrorRequest( task::PDFExportException aExc
) :
1119 maExc(std::move( aExc
))
1124 uno::Any SAL_CALL
PDFErrorRequest::getRequest()
1126 std::unique_lock
guard( m_aMutex
);
1134 uno::Sequence
< uno::Reference
< task::XInteractionContinuation
> > SAL_CALL
PDFErrorRequest::getContinuations()
1136 return uno::Sequence
< uno::Reference
< task::XInteractionContinuation
> >();
1139 } // end anonymous namespace
1142 void PDFExport::showErrors( const std::set
< vcl::PDFWriter::ErrorCode
>& rErrors
)
1144 if( ! rErrors
.empty() && mxIH
.is() )
1146 task::PDFExportException aExc
;
1147 aExc
.ErrorCodes
= comphelper::containerToSequence
<sal_Int32
>( rErrors
);
1148 Reference
< task::XInteractionRequest
> xReq( new PDFErrorRequest( std::move(aExc
) ) );
1149 mxIH
->handle( xReq
);
1154 void PDFExport::ImplExportPage( vcl::PDFWriter
& rWriter
, vcl::PDFExtOutDevData
& rPDFExtOutDevData
, const GDIMetaFile
& rMtf
)
1156 //Rectangle(Point, Size) creates a rectangle off by 1, use Rectangle(long, long, long, long) instead
1157 basegfx::B2DPolygon
aSize(tools::Polygon(tools::Rectangle(0, 0, rMtf
.GetPrefSize().Width(), rMtf
.GetPrefSize().Height())).getB2DPolygon());
1158 basegfx::B2DPolygon
aSizePDF(OutputDevice::LogicToLogic(aSize
, rMtf
.GetPrefMapMode(), MapMode(MapUnit::MapPoint
)));
1159 basegfx::B2DRange
aRangePDF(aSizePDF
.getB2DRange());
1160 tools::Rectangle
aPageRect( Point(), rMtf
.GetPrefSize() );
1162 rWriter
.NewPage( aRangePDF
.getWidth(), aRangePDF
.getHeight() );
1163 rWriter
.SetMapMode( rMtf
.GetPrefMapMode() );
1165 vcl::PDFWriter::PlayMetafileContext aCtx
;
1167 if( mbRemoveTransparencies
)
1169 aCtx
.m_bTransparenciesWereRemoved
= rWriter
.GetReferenceDevice()->
1170 RemoveTransparenciesFromMetaFile( rMtf
, aMtf
, mnMaxImageResolution
, mnMaxImageResolution
,
1171 false, true, mbReduceImageResolution
);
1172 // tdf#134736 if the metafile was replaced then rPDFExtOutDevData's PageSyncData mActions
1173 // all still point to MetaAction indexes in the original metafile that are now invalid.
1174 // Throw them all away in the absence of a way to reposition them to new positions of
1175 // their replacements.
1176 if (aCtx
.m_bTransparenciesWereRemoved
)
1177 rPDFExtOutDevData
.ResetSyncData(&rWriter
);
1183 aCtx
.m_nMaxImageResolution
= mbReduceImageResolution
? mnMaxImageResolution
: 0;
1184 aCtx
.m_bOnlyLosslessCompression
= mbUseLosslessCompression
;
1185 aCtx
.m_nJPEGQuality
= mnQuality
;
1188 rWriter
.SetClipRegion( basegfx::B2DPolyPolygon(
1189 basegfx::utils::createPolygonFromRect( vcl::unotools::b2DRectangleFromRectangle(aPageRect
) ) ) );
1191 rWriter
.PlayMetafile( aMtf
, aCtx
, &rPDFExtOutDevData
);
1193 rPDFExtOutDevData
.ResetSyncData(nullptr);
1195 if (!msWatermark
.isEmpty())
1197 ImplWriteWatermark( rWriter
, Size(aRangePDF
.getWidth(), aRangePDF
.getHeight()) );
1199 else if (!msTiledWatermark
.isEmpty())
1201 ImplWriteTiledWatermark( rWriter
, Size(aRangePDF
.getWidth(), aRangePDF
.getHeight()) );
1206 void PDFExport::ImplWriteWatermark( vcl::PDFWriter
& rWriter
, const Size
& rPageSize
)
1208 vcl::Font
aFont( maWatermarkFontName
, Size( 0, moWatermarkFontHeight
? *moWatermarkFontHeight
: 3*rPageSize
.Height()/4 ) );
1209 aFont
.SetItalic( ITALIC_NONE
);
1210 aFont
.SetWidthType( WIDTH_NORMAL
);
1211 aFont
.SetWeight( WEIGHT_NORMAL
);
1212 aFont
.SetAlignment( ALIGN_BOTTOM
);
1213 tools::Long nTextWidth
= rPageSize
.Width();
1214 if( rPageSize
.Width() < rPageSize
.Height() )
1216 nTextWidth
= rPageSize
.Height();
1217 aFont
.SetOrientation( 2700_deg10
);
1220 if (moWatermarkRotateAngle
)
1222 aFont
.SetOrientation(*moWatermarkRotateAngle
);
1223 if (rPageSize
.Width() < rPageSize
.Height())
1225 // Set text width based on the shorter side, so rotation can't push text outside the
1227 nTextWidth
= rPageSize
.Width();
1231 // adjust font height for text to fit
1232 OutputDevice
* pDev
= rWriter
.GetReferenceDevice();
1234 pDev
->SetFont( aFont
);
1235 pDev
->SetMapMode( MapMode( MapUnit::MapPoint
) );
1237 if (moWatermarkFontHeight
)
1239 w
= pDev
->GetTextWidth(msWatermark
);
1243 while( ( w
= pDev
->GetTextWidth( msWatermark
) ) > nTextWidth
)
1247 tools::Long nNewHeight
= aFont
.GetFontHeight() * nTextWidth
/ w
;
1248 if( nNewHeight
== aFont
.GetFontHeight() )
1251 if( nNewHeight
<= 0 )
1254 aFont
.SetFontHeight( nNewHeight
);
1255 pDev
->SetFont( aFont
);
1258 tools::Long nTextHeight
= pDev
->GetTextHeight();
1259 // leave some maneuvering room for rounding issues, also
1260 // some fonts go a little outside ascent/descent
1261 nTextHeight
+= nTextHeight
/20;
1265 // tdf#152235 tag around the reference to the XObject on the page
1266 sal_Int32
const id
= rWriter
.EnsureStructureElement();
1267 rWriter
.InitStructureElement(id
, vcl::PDFWriter::NonStructElement
, ::std::u16string_view());
1268 rWriter
.BeginStructureElement(id
);
1269 rWriter
.SetStructureAttribute(vcl::PDFWriter::Type
, vcl::PDFWriter::Pagination
);
1270 rWriter
.SetStructureAttribute(vcl::PDFWriter::Subtype
, vcl::PDFWriter::Watermark
);
1271 // HACK: this should produce *nothing* itself but is necessary to output
1272 // the Artifact tag here, not inside the XObject
1273 rWriter
.DrawPolyLine({});
1274 rWriter
.SetMapMode( MapMode( MapUnit::MapPoint
) );
1275 rWriter
.SetFont( aFont
);
1276 rWriter
.SetTextColor(maWatermarkColor
);
1278 tools::Rectangle aTextRect
;
1279 if( rPageSize
.Width() > rPageSize
.Height() )
1281 aTextPoint
= Point( (rPageSize
.Width()-w
)/2,
1282 rPageSize
.Height()-(rPageSize
.Height()-nTextHeight
)/2 );
1283 aTextRect
= tools::Rectangle( Point( (rPageSize
.Width()-w
)/2,
1284 (rPageSize
.Height()-nTextHeight
)/2 ),
1285 Size( w
, nTextHeight
) );
1289 aTextPoint
= Point( (rPageSize
.Width()-nTextHeight
)/2,
1290 (rPageSize
.Height()-w
)/2 );
1291 aTextRect
= tools::Rectangle( aTextPoint
, Size( nTextHeight
, w
) );
1294 if (moWatermarkRotateAngle
)
1296 // First set the text's starting point to the center of the page.
1297 tools::Rectangle
aPageRectangle(Point(0, 0), rPageSize
);
1298 aTextPoint
= aPageRectangle
.Center();
1299 // Then adjust it so that the text remains centered, based on the rotation angle.
1300 basegfx::B2DPolygon aTextPolygon
1301 = basegfx::utils::createPolygonFromRect(basegfx::B2DRectangle(0, -nTextHeight
, w
, 0));
1302 basegfx::B2DHomMatrix aMatrix
;
1303 aMatrix
.rotate(-1 * toRadians(*moWatermarkRotateAngle
));
1304 aTextPolygon
.transform(aMatrix
);
1305 basegfx::B2DPoint aPolygonCenter
= aTextPolygon
.getB2DRange().getCenter();
1306 aTextPoint
.AdjustX(-aPolygonCenter
.getX());
1307 aTextPoint
.AdjustY(-aPolygonCenter
.getY());
1309 aTextRect
= aPageRectangle
;
1312 rWriter
.SetClipRegion();
1313 rWriter
.BeginTransparencyGroup();
1314 rWriter
.DrawText( aTextPoint
, msWatermark
);
1315 rWriter
.EndTransparencyGroup( aTextRect
, 50 );
1316 rWriter
.EndStructureElement();
1320 void PDFExport::ImplWriteTiledWatermark( vcl::PDFWriter
& rWriter
, const Size
& rPageSize
)
1322 OUString watermark
= msTiledWatermark
;
1323 // Maximum number of characters in one line.
1324 // it is set to 21 to make it look like tiled watermarks as online in secure view
1325 const int lineLength
= 21;
1326 vcl::Font
aFont( "Liberation Sans", Size( 0, 40 ) );
1327 aFont
.SetItalic( ITALIC_NONE
);
1328 aFont
.SetWidthType( WIDTH_NORMAL
);
1329 aFont
.SetWeight( WEIGHT_NORMAL
);
1330 aFont
.SetAlignment( ALIGN_BOTTOM
);
1331 aFont
.SetFontHeight(40);
1332 aFont
.SetOrientation(450_deg10
);
1334 OutputDevice
* pDev
= rWriter
.GetReferenceDevice();
1335 pDev
->SetFont(aFont
);
1337 pDev
->SetFont(aFont
);
1338 pDev
->SetMapMode( MapMode( MapUnit::MapPoint
) );
1340 int watermarkcount
= ((rPageSize
.Width()) / 200)+1;
1341 tools::Long nTextWidth
= rPageSize
.Width() / (watermarkcount
*1.5);
1342 OUString oneLineText
= watermark
;
1344 if(watermark
.getLength() > lineLength
)
1345 oneLineText
= watermark
.copy(0, lineLength
);
1347 while((w
= pDev
->GetTextWidth(oneLineText
)) > nTextWidth
)
1352 tools::Long nNewHeight
= aFont
.GetFontHeight() * nTextWidth
/ w
;
1353 aFont
.SetFontHeight(nNewHeight
);
1354 pDev
->SetFont( aFont
);
1356 // maximum number of watermark count for the width
1357 if(watermarkcount
> 8)
1363 // tdf#152235 tag around the reference to the XObject on the page
1364 sal_Int32
const id
= rWriter
.EnsureStructureElement();
1365 rWriter
.InitStructureElement(id
, vcl::PDFWriter::NonStructElement
, ::std::u16string_view());
1366 rWriter
.BeginStructureElement(id
);
1367 rWriter
.SetStructureAttribute(vcl::PDFWriter::Type
, vcl::PDFWriter::Pagination
);
1368 rWriter
.SetStructureAttribute(vcl::PDFWriter::Subtype
, vcl::PDFWriter::Watermark
);
1369 // HACK: this should produce *nothing* itself but is necessary to output
1370 // the Artifact tag here, not inside the XObject
1371 rWriter
.DrawPolyLine({});
1372 rWriter
.SetMapMode( MapMode( MapUnit::MapPoint
) );
1373 rWriter
.SetFont(aFont
);
1374 rWriter
.SetTextColor( Color(19,20,22) );
1375 // center watermarks horizontally
1376 Point
aTextPoint( (rPageSize
.Width()/2) - (((nTextWidth
*watermarkcount
)+(watermarkcount
-1)*nTextWidth
)/2),
1377 pDev
->GetTextHeight());
1379 for( int i
= 0; i
< watermarkcount
; i
++)
1381 while(aTextPoint
.getY()+pDev
->GetTextHeight()*3 <= rPageSize
.Height())
1383 tools::Rectangle
aTextRect(aTextPoint
, Size(nTextWidth
*2,pDev
->GetTextHeight()*4));
1386 rWriter
.SetClipRegion();
1387 rWriter
.BeginTransparencyGroup();
1388 rWriter
.SetTextColor( Color(19,20,22) );
1389 rWriter
.DrawText(aTextRect
, watermark
, DrawTextFlags::MultiLine
|DrawTextFlags::Center
|DrawTextFlags::VCenter
|DrawTextFlags::WordBreak
|DrawTextFlags::Bottom
);
1390 rWriter
.EndTransparencyGroup( aTextRect
, 50 );
1394 rWriter
.SetClipRegion();
1395 rWriter
.BeginTransparencyGroup();
1396 rWriter
.SetTextColor( Color(236,235,233) );
1397 rWriter
.DrawText(aTextRect
, watermark
, DrawTextFlags::MultiLine
|DrawTextFlags::Center
|DrawTextFlags::VCenter
|DrawTextFlags::WordBreak
|DrawTextFlags::Bottom
);
1398 rWriter
.EndTransparencyGroup( aTextRect
, 50 );
1401 aTextPoint
.Move(0, pDev
->GetTextHeight()*3);
1403 aTextPoint
=Point( aTextPoint
.getX(), pDev
->GetTextHeight() );
1404 aTextPoint
.Move( nTextWidth
*1.5, 0 );
1407 rWriter
.EndStructureElement();
1411 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */