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/fract.hxx>
25 #include <tools/poly.hxx>
26 #include <unotools/resmgr.hxx>
27 #include <vcl/mapmod.hxx>
28 #include <vcl/virdev.hxx>
29 #include <vcl/metaact.hxx>
30 #include <vcl/gdimtf.hxx>
31 #include <vcl/jobset.hxx>
32 #include <vcl/bitmapaccess.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/FilterConfigItem.hxx>
35 #include <vcl/graphicfilter.hxx>
36 #include <vcl/settings.hxx>
37 #include <vcl/graphictools.hxx>
38 #include <svl/solar.hrc>
39 #include <comphelper/sequence.hxx>
40 #include <comphelper/string.hxx>
41 #include <comphelper/storagehelper.hxx>
42 #include <basegfx/polygon/b2dpolygon.hxx>
43 #include <basegfx/polygon/b2dpolypolygon.hxx>
44 #include <basegfx/polygon/b2dpolygontools.hxx>
45 #include <toolkit/awt/vclxdevice.hxx>
46 #include <unotools/streamwrap.hxx>
47 #include <unotools/saveopt.hxx>
48 #include <unotools/configmgr.hxx>
49 #include <cppuhelper/exc_hlp.hxx>
50 #include <cppuhelper/compbase.hxx>
51 #include <cppuhelper/basemutex.hxx>
53 #include "pdfexport.hxx"
54 #include "impdialog.hxx"
55 #include <strings.hrc>
57 #include <com/sun/star/beans/XPropertySet.hpp>
58 #include <com/sun/star/configuration/theDefaultProvider.hpp>
59 #include <com/sun/star/awt/Rectangle.hpp>
60 #include <com/sun/star/awt/XDevice.hpp>
61 #include <com/sun/star/util/MeasureUnit.hpp>
62 #include <com/sun/star/frame/XModel.hpp>
63 #include <com/sun/star/frame/ModuleManager.hpp>
64 #include <com/sun/star/frame/XStorable.hpp>
65 #include <com/sun/star/document/XDocumentProperties.hpp>
66 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
67 #include <com/sun/star/container/XNameAccess.hpp>
68 #include <com/sun/star/view/XViewSettingsSupplier.hpp>
69 #include <com/sun/star/task/XInteractionRequest.hpp>
70 #include <com/sun/star/task/PDFExportException.hpp>
71 #include <com/sun/star/io/IOException.hpp>
72 #include <com/sun/star/io/XSeekable.hpp>
73 #include <com/sun/star/lang/XServiceInfo.hpp>
74 #include <com/sun/star/drawing/XShapes.hpp>
75 #include <com/sun/star/graphic/XGraphicProvider.hpp>
76 #include <com/sun/star/security/XCertificate.hpp>
77 #include <com/sun/star/beans/XMaterialHolder.hpp>
81 using namespace ::com::sun::star
;
82 using namespace ::com::sun::star::uno
;
83 using namespace ::com::sun::star::lang
;
84 using namespace ::com::sun::star::beans
;
85 using namespace ::com::sun::star::view
;
86 using namespace ::com::sun::star::graphic
;
89 PDFExport::PDFExport( const Reference
< XComponent
>& rxSrcDoc
,
90 const Reference
< task::XStatusIndicator
>& rxStatusIndicator
,
91 const Reference
< task::XInteractionHandler
>& rxIH
,
92 const Reference
< XComponentContext
>& xContext
) :
93 mxSrcDoc ( rxSrcDoc
),
94 mxContext ( xContext
),
95 mxStatusIndicator ( rxStatusIndicator
),
97 mbUseTaggedPDF ( false ),
98 mnPDFTypeSelection ( 0 ),
99 mbExportNotes ( true ),
100 mbExportPlaceholders ( false ),
101 mbUseReferenceXObject ( false ),
102 mbExportNotesPages ( false ),
103 mbExportOnlyNotesPages ( false ),
104 mbUseTransitionEffects ( true ),
105 mbExportBookmarks ( true ),
106 mbExportHiddenSlides ( false ),
107 mnOpenBookmarkLevels ( -1 ),
108 mbUseLosslessCompression ( false ),
109 mbReduceImageResolution ( true ),
110 mbSkipEmptyPages ( true ),
111 mbAddStream ( false ),
112 mnMaxImageResolution ( 300 ),
115 mbExportFormFields ( true ),
116 mbAllowDuplicateFieldNames ( false ),
117 mnProgressValue ( 0 ),
118 mbRemoveTransparencies ( false ),
120 mbIsRedactMode ( false ),
122 mbHideViewerToolbar ( false ),
123 mbHideViewerMenubar ( false ),
124 mbHideViewerWindowControls ( false ),
125 mbFitWindow ( false ),
126 mbCenterWindow ( false ),
127 mbOpenInFullScreenMode ( false ),
128 mbDisplayPDFDocumentTitle ( true ),
129 mnPDFDocumentMode ( 0 ),
130 mnPDFDocumentAction ( 0 ),
133 mnPDFPageLayout ( 0 ),
136 mbRestrictPermissions ( false ),
137 mnPrintAllowed ( 2 ),
138 mnChangesAllowed ( 4 ),
139 mbCanCopyOrExtract ( true ),
140 mbCanExtractForAccessibility( true ),
143 mbExportRelativeFsysLinks ( false ),
144 mnDefaultLinkAction ( 0 ),
145 mbConvertOOoTargetToPDFTarget( false ),
146 mbExportBmkToDest ( false ),
152 PDFExport::~PDFExport()
157 bool PDFExport::ExportSelection( vcl::PDFWriter
& rPDFWriter
,
158 Reference
< css::view::XRenderable
> const & rRenderable
,
159 const Any
& rSelection
,
160 const StringRangeEnumerator
& rRangeEnum
,
161 Sequence
< PropertyValue
>& rRenderOptions
,
162 sal_Int32 nPageCount
)
167 Any
* pFirstPage
= nullptr;
168 Any
* pLastPage
= nullptr;
170 bool bExportNotesPages
= false;
172 for( sal_Int32 nData
= 0, nDataCount
= rRenderOptions
.getLength(); nData
< nDataCount
; ++nData
)
174 if ( rRenderOptions
[ nData
].Name
== "IsFirstPage" )
175 pFirstPage
= &rRenderOptions
[ nData
].Value
;
176 else if ( rRenderOptions
[ nData
].Name
== "IsLastPage" )
177 pLastPage
= &rRenderOptions
[ nData
].Value
;
178 else if ( rRenderOptions
[ nData
].Name
== "ExportNotesPages" )
179 rRenderOptions
[ nData
].Value
>>= bExportNotesPages
;
182 OutputDevice
* pOut
= rPDFWriter
.GetReferenceDevice();
188 vcl::PDFExtOutDevData
& rPDFExtOutDevData
= dynamic_cast<vcl::PDFExtOutDevData
&>(*pOut
->GetExtOutDevData());
189 rPDFExtOutDevData
.SetIsExportNotesPages( bExportNotesPages
);
191 sal_Int32
nCurrentPage(0);
192 StringRangeEnumerator::Iterator aIter
= rRangeEnum
.begin();
193 StringRangeEnumerator::Iterator aEnd
= rRangeEnum
.end();
194 while ( aIter
!= aEnd
)
196 Sequence
< PropertyValue
> aRenderer( rRenderable
->getRenderer( *aIter
, rSelection
, rRenderOptions
) );
199 for( sal_Int32 nProperty
= 0, nPropertyCount
= aRenderer
.getLength(); nProperty
< nPropertyCount
; ++nProperty
)
201 if ( aRenderer
[ nProperty
].Name
== "PageSize" )
202 aRenderer
[ nProperty
].Value
>>= aPageSize
;
205 rPDFExtOutDevData
.SetCurrentPageNumber( nCurrentPage
);
208 const MapMode
aMapMode( MapUnit::Map100thMM
);
209 const Size
aMtfSize( aPageSize
.Width
, aPageSize
.Height
);
212 pOut
->EnableOutput( false );
213 pOut
->SetMapMode( aMapMode
);
215 aMtf
.SetPrefSize( aMtfSize
);
216 aMtf
.SetPrefMapMode( aMapMode
);
220 // IsLastPage property.
221 const sal_Int32 nCurrentRenderer
= *aIter
;
223 if ( pLastPage
&& aIter
== aEnd
)
226 rRenderable
->render( nCurrentRenderer
, rSelection
, rRenderOptions
);
231 if( aMtf
.GetActionSize() &&
232 ( !mbSkipEmptyPages
|| aPageSize
.Width
|| aPageSize
.Height
) )
234 // We convert the whole metafile into a bitmap to get rid of the
235 // text covered by redaction shapes
240 Graphic
aGraph(aMtf
);
241 BitmapEx bmp
= aGraph
.GetBitmapEx();
243 aMtf
= bgraph
.GetGDIMetaFile();
245 catch(const Exception
& e
)
247 SAL_WARN("filter.pdf", "Something went wrong while converting metafile to bitmap. Exception: "
252 ImplExportPage(rPDFWriter
, rPDFExtOutDevData
, aMtf
);
258 if ( mxStatusIndicator
.is() )
259 mxStatusIndicator
->setValue( mnProgressValue
);
261 *pFirstPage
<<= false;
269 bRet
= true; // #i18334# nPageCount == 0,
270 rPDFWriter
.NewPage( 10000, 10000 ); // creating dummy page
271 rPDFWriter
.SetMapMode(MapMode(MapUnit::Map100thMM
));
275 catch(const RuntimeException
&)
281 class PDFExportStreamDoc
: public vcl::PDFOutputStream
285 Reference
< XComponent
> m_xSrcDoc
;
286 Sequence
< beans::NamedValue
> m_aPreparedPassword
;
290 PDFExportStreamDoc( const Reference
< XComponent
>& xDoc
, const Sequence
<beans::NamedValue
>& rPwd
)
292 m_aPreparedPassword( rPwd
)
295 virtual void write( const Reference
< XOutputStream
>& xStream
) override
;
298 void PDFExportStreamDoc::write( const Reference
< XOutputStream
>& xStream
)
300 Reference
< css::frame::XStorable
> xStore( m_xSrcDoc
, UNO_QUERY
);
303 Sequence
< beans::PropertyValue
> aArgs( 2 + ((m_aPreparedPassword
.getLength() > 0) ? 1 : 0) );
304 aArgs
.getArray()[0].Name
= "FilterName";
305 aArgs
.getArray()[1].Name
= "OutputStream";
306 aArgs
.getArray()[1].Value
<<= xStream
;
307 if( m_aPreparedPassword
.getLength() )
309 aArgs
.getArray()[2].Name
= "EncryptionData";
310 aArgs
.getArray()[2].Value
<<= m_aPreparedPassword
;
315 xStore
->storeToURL( "private:stream", aArgs
);
317 catch( const IOException
& )
324 static OUString
getMimetypeForDocument( const Reference
< XComponentContext
>& xContext
,
325 const Reference
< XComponent
>& xDoc
) throw()
327 OUString aDocMimetype
;
330 // get document service name
331 Reference
< css::frame::XStorable
> xStore( xDoc
, UNO_QUERY
);
332 Reference
< frame::XModuleManager2
> xModuleManager
= frame::ModuleManager::create(xContext
);
335 OUString aDocServiceName
= xModuleManager
->identify( Reference
< XInterface
>( xStore
, uno::UNO_QUERY
) );
336 if ( !aDocServiceName
.isEmpty() )
338 // get the actual filter name
339 OUString aFilterName
;
340 Reference
< lang::XMultiServiceFactory
> xConfigProvider
=
341 configuration::theDefaultProvider::get( xContext
);
342 uno::Sequence
< uno::Any
> aArgs( 1 );
343 beans::NamedValue aPathProp
;
344 aPathProp
.Name
= "nodepath";
345 aPathProp
.Value
<<= OUString( "/org.openoffice.Setup/Office/Factories/" );
346 aArgs
[0] <<= aPathProp
;
348 Reference
< container::XNameAccess
> xSOFConfig(
349 xConfigProvider
->createInstanceWithArguments(
350 "com.sun.star.configuration.ConfigurationAccess", aArgs
),
353 Reference
< container::XNameAccess
> xApplConfig
;
354 xSOFConfig
->getByName( aDocServiceName
) >>= xApplConfig
;
355 if ( xApplConfig
.is() )
357 xApplConfig
->getByName( "ooSetupFactoryActualFilter" ) >>= aFilterName
;
358 if( !aFilterName
.isEmpty() )
360 // find the related type name
362 Reference
< container::XNameAccess
> xFilterFactory(
363 xContext
->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", xContext
),
366 Sequence
< beans::PropertyValue
> aFilterData
;
367 xFilterFactory
->getByName( aFilterName
) >>= aFilterData
;
368 for ( sal_Int32 nInd
= 0; nInd
< aFilterData
.getLength(); nInd
++ )
369 if ( aFilterData
[nInd
].Name
== "Type" )
370 aFilterData
[nInd
].Value
>>= aTypeName
;
372 if ( !aTypeName
.isEmpty() )
374 // find the mediatype
375 Reference
< container::XNameAccess
> xTypeDetection(
376 xContext
->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", xContext
),
379 Sequence
< beans::PropertyValue
> aTypeData
;
380 xTypeDetection
->getByName( aTypeName
) >>= aTypeData
;
381 for ( sal_Int32 nInd
= 0; nInd
< aTypeData
.getLength(); nInd
++ )
382 if ( aTypeData
[nInd
].Name
== "MediaType" )
383 aTypeData
[nInd
].Value
>>= aDocMimetype
;
397 bool PDFExport::Export( const OUString
& rFile
, const Sequence
< PropertyValue
>& rFilterData
)
399 INetURLObject
aURL( rFile
);
402 std::set
< vcl::PDFWriter::ErrorCode
> aErrors
;
404 if( aURL
.GetProtocol() != INetProtocol::File
)
408 if( osl::FileBase::getFileURLFromSystemPath( rFile
, aTmp
) == osl::FileBase::E_None
)
409 aURL
= INetURLObject(aTmp
);
412 if( aURL
.GetProtocol() == INetProtocol::File
)
414 Reference
< XRenderable
> xRenderable( mxSrcDoc
, UNO_QUERY
);
416 if( xRenderable
.is() )
418 rtl::Reference
<VCLXDevice
> xDevice(new VCLXDevice
);
421 vcl::PDFWriter::PDFWriterContext aContext
;
422 OUString aOpenPassword
, aPermissionPassword
;
423 Reference
< beans::XMaterialHolder
> xEnc
;
424 Sequence
< beans::NamedValue
> aPreparedPermissionPassword
;
427 // getting the string for the creator
429 Reference
< XServiceInfo
> xInfo( mxSrcDoc
, UNO_QUERY
);
432 if ( xInfo
->supportsService( "com.sun.star.presentation.PresentationDocument" ) )
433 aCreator
+= "Impress";
434 else if ( xInfo
->supportsService( "com.sun.star.drawing.DrawingDocument" ) )
436 else if ( xInfo
->supportsService( "com.sun.star.text.TextDocument" ) )
437 aCreator
+= "Writer";
438 else if ( xInfo
->supportsService( "com.sun.star.sheet.SpreadsheetDocument" ) )
440 else if ( xInfo
->supportsService( "com.sun.star.formula.FormulaProperties" ) )
444 Reference
< document::XDocumentPropertiesSupplier
> xDocumentPropsSupplier( mxSrcDoc
, UNO_QUERY
);
445 if ( xDocumentPropsSupplier
.is() )
447 Reference
< document::XDocumentProperties
> xDocumentProps( xDocumentPropsSupplier
->getDocumentProperties() );
448 if ( xDocumentProps
.is() )
450 aContext
.DocumentInfo
.Title
= xDocumentProps
->getTitle();
451 aContext
.DocumentInfo
.Author
= xDocumentProps
->getAuthor();
452 aContext
.DocumentInfo
.Subject
= xDocumentProps
->getSubject();
453 aContext
.DocumentInfo
.Keywords
= ::comphelper::string::convertCommaSeparated(xDocumentProps
->getKeywords());
456 // getting the string for the producer
457 aContext
.DocumentInfo
.Producer
=
458 utl::ConfigManager::getProductName() +
460 utl::ConfigManager::getProductVersion();
461 aContext
.DocumentInfo
.Creator
= aCreator
;
463 for( sal_Int32 nData
= 0, nDataCount
= rFilterData
.getLength(); nData
< nDataCount
; ++nData
)
465 if ( rFilterData
[ nData
].Name
== "PageRange" )
466 rFilterData
[ nData
].Value
>>= aPageRange
;
467 else if ( rFilterData
[ nData
].Name
== "Selection" )
468 aSelection
= rFilterData
[ nData
].Value
;
469 else if ( rFilterData
[ nData
].Name
== "UseLosslessCompression" )
470 rFilterData
[ nData
].Value
>>= mbUseLosslessCompression
;
471 else if ( rFilterData
[ nData
].Name
== "Quality" )
472 rFilterData
[ nData
].Value
>>= mnQuality
;
473 else if ( rFilterData
[ nData
].Name
== "ReduceImageResolution" )
474 rFilterData
[ nData
].Value
>>= mbReduceImageResolution
;
475 else if ( rFilterData
[ nData
].Name
== "IsSkipEmptyPages" )
476 rFilterData
[ nData
].Value
>>= mbSkipEmptyPages
;
477 else if ( rFilterData
[ nData
].Name
== "MaxImageResolution" )
478 rFilterData
[ nData
].Value
>>= mnMaxImageResolution
;
479 else if ( rFilterData
[ nData
].Name
== "UseTaggedPDF" )
480 rFilterData
[ nData
].Value
>>= mbUseTaggedPDF
;
481 else if ( rFilterData
[ nData
].Name
== "SelectPdfVersion" )
482 rFilterData
[ nData
].Value
>>= mnPDFTypeSelection
;
483 else if ( rFilterData
[ nData
].Name
== "ExportNotes" )
484 rFilterData
[ nData
].Value
>>= mbExportNotes
;
485 else if ( rFilterData
[ nData
].Name
== "ExportNotesPages" )
486 rFilterData
[ nData
].Value
>>= mbExportNotesPages
;
487 else if ( rFilterData
[ nData
].Name
== "ExportOnlyNotesPages" )
488 rFilterData
[ nData
].Value
>>= mbExportOnlyNotesPages
;
489 else if ( rFilterData
[ nData
].Name
== "UseTransitionEffects" )
490 rFilterData
[ nData
].Value
>>= mbUseTransitionEffects
;
491 else if ( rFilterData
[ nData
].Name
== "ExportFormFields" )
492 rFilterData
[ nData
].Value
>>= mbExportFormFields
;
493 else if ( rFilterData
[ nData
].Name
== "FormsType" )
494 rFilterData
[ nData
].Value
>>= mnFormsFormat
;
495 else if ( rFilterData
[ nData
].Name
== "AllowDuplicateFieldNames" )
496 rFilterData
[ nData
].Value
>>= mbAllowDuplicateFieldNames
;
498 else if ( rFilterData
[ nData
].Name
== "HideViewerToolbar" )
499 rFilterData
[ nData
].Value
>>= mbHideViewerToolbar
;
500 else if ( rFilterData
[ nData
].Name
== "HideViewerMenubar" )
501 rFilterData
[ nData
].Value
>>= mbHideViewerMenubar
;
502 else if ( rFilterData
[ nData
].Name
== "HideViewerWindowControls" )
503 rFilterData
[ nData
].Value
>>= mbHideViewerWindowControls
;
504 else if ( rFilterData
[ nData
].Name
== "ResizeWindowToInitialPage" )
505 rFilterData
[ nData
].Value
>>= mbFitWindow
;
506 else if ( rFilterData
[ nData
].Name
== "CenterWindow" )
507 rFilterData
[ nData
].Value
>>= mbCenterWindow
;
508 else if ( rFilterData
[ nData
].Name
== "OpenInFullScreenMode" )
509 rFilterData
[ nData
].Value
>>= mbOpenInFullScreenMode
;
510 else if ( rFilterData
[ nData
].Name
== "DisplayPDFDocumentTitle" )
511 rFilterData
[ nData
].Value
>>= mbDisplayPDFDocumentTitle
;
512 else if ( rFilterData
[ nData
].Name
== "InitialView" )
513 rFilterData
[ nData
].Value
>>= mnPDFDocumentMode
;
514 else if ( rFilterData
[ nData
].Name
== "Magnification" )
515 rFilterData
[ nData
].Value
>>= mnPDFDocumentAction
;
516 else if ( rFilterData
[ nData
].Name
== "Zoom" )
517 rFilterData
[ nData
].Value
>>= mnZoom
;
518 else if ( rFilterData
[ nData
].Name
== "InitialPage" )
519 rFilterData
[ nData
].Value
>>= mnInitialPage
;
520 else if ( rFilterData
[ nData
].Name
== "PageLayout" )
521 rFilterData
[ nData
].Value
>>= mnPDFPageLayout
;
522 else if ( rFilterData
[ nData
].Name
== "FirstPageOnLeft" )
523 rFilterData
[ nData
].Value
>>= aContext
.FirstPageLeft
;
524 else if ( rFilterData
[ nData
].Name
== "IsAddStream" )
525 rFilterData
[ nData
].Value
>>= mbAddStream
;
526 else if ( rFilterData
[ nData
].Name
== "Watermark" )
527 rFilterData
[ nData
].Value
>>= msWatermark
;
528 // now all the security related properties...
529 else if ( rFilterData
[ nData
].Name
== "EncryptFile" )
530 rFilterData
[ nData
].Value
>>= mbEncrypt
;
531 else if ( rFilterData
[ nData
].Name
== "DocumentOpenPassword" )
532 rFilterData
[ nData
].Value
>>= aOpenPassword
;
533 else if ( rFilterData
[ nData
].Name
== "RestrictPermissions" )
534 rFilterData
[ nData
].Value
>>= mbRestrictPermissions
;
535 else if ( rFilterData
[ nData
].Name
== "PermissionPassword" )
536 rFilterData
[ nData
].Value
>>= aPermissionPassword
;
537 else if ( rFilterData
[ nData
].Name
== "PreparedPasswords" )
538 rFilterData
[ nData
].Value
>>= xEnc
;
539 else if ( rFilterData
[ nData
].Name
== "PreparedPermissionPassword" )
540 rFilterData
[ nData
].Value
>>= aPreparedPermissionPassword
;
541 else if ( rFilterData
[ nData
].Name
== "Printing" )
542 rFilterData
[ nData
].Value
>>= mnPrintAllowed
;
543 else if ( rFilterData
[ nData
].Name
== "Changes" )
544 rFilterData
[ nData
].Value
>>= mnChangesAllowed
;
545 else if ( rFilterData
[ nData
].Name
== "EnableCopyingOfContent" )
546 rFilterData
[ nData
].Value
>>= mbCanCopyOrExtract
;
547 else if ( rFilterData
[ nData
].Name
== "EnableTextAccessForAccessibilityTools" )
548 rFilterData
[ nData
].Value
>>= mbCanExtractForAccessibility
;
549 // i56629 links extra (relative links and other related stuff)
550 else if ( rFilterData
[ nData
].Name
== "ExportLinksRelativeFsys" )
551 rFilterData
[ nData
].Value
>>= mbExportRelativeFsysLinks
;
552 else if ( rFilterData
[ nData
].Name
== "PDFViewSelection" )
553 rFilterData
[ nData
].Value
>>= mnDefaultLinkAction
;
554 else if ( rFilterData
[ nData
].Name
== "ConvertOOoTargetToPDFTarget" )
555 rFilterData
[ nData
].Value
>>= mbConvertOOoTargetToPDFTarget
;
556 else if ( rFilterData
[ nData
].Name
== "ExportBookmarksToPDFDestination" )
557 rFilterData
[ nData
].Value
>>= mbExportBmkToDest
;
558 else if ( rFilterData
[ nData
].Name
== "ExportBookmarks" )
559 rFilterData
[ nData
].Value
>>= mbExportBookmarks
;
560 else if ( rFilterData
[ nData
].Name
== "ExportHiddenSlides" )
561 rFilterData
[ nData
].Value
>>= mbExportHiddenSlides
;
562 else if ( rFilterData
[ nData
].Name
== "OpenBookmarkLevels" )
563 rFilterData
[ nData
].Value
>>= mnOpenBookmarkLevels
;
564 else if ( rFilterData
[ nData
].Name
== "SignPDF" )
565 rFilterData
[ nData
].Value
>>= mbSignPDF
;
566 else if ( rFilterData
[ nData
].Name
== "SignatureLocation" )
567 rFilterData
[ nData
].Value
>>= msSignLocation
;
568 else if ( rFilterData
[ nData
].Name
== "SignatureReason" )
569 rFilterData
[ nData
].Value
>>= msSignReason
;
570 else if ( rFilterData
[ nData
].Name
== "SignatureContactInfo" )
571 rFilterData
[ nData
].Value
>>= msSignContact
;
572 else if ( rFilterData
[ nData
].Name
== "SignaturePassword" )
573 rFilterData
[ nData
].Value
>>= msSignPassword
;
574 else if ( rFilterData
[ nData
].Name
== "SignatureCertificate" )
575 rFilterData
[ nData
].Value
>>= maSignCertificate
;
576 else if ( rFilterData
[ nData
].Name
== "SignatureTSA" )
577 rFilterData
[ nData
].Value
>>= msSignTSA
;
578 else if ( rFilterData
[ nData
].Name
== "ExportPlaceholders" )
579 rFilterData
[ nData
].Value
>>= mbExportPlaceholders
;
580 else if ( rFilterData
[ nData
].Name
== "UseReferenceXObject" )
581 rFilterData
[ nData
].Value
>>= mbUseReferenceXObject
;
582 // Redaction & bitmap related stuff
583 else if ( rFilterData
[ nData
].Name
== "IsRedactMode" )
584 rFilterData
[ nData
].Value
>>= mbIsRedactMode
;
587 aContext
.URL
= aURL
.GetMainURL(INetURLObject::DecodeMechanism::ToIUri
);
589 // set the correct version, depending on user request
590 switch( mnPDFTypeSelection
)
594 aContext
.Version
= vcl::PDFWriter::PDFVersion::PDF_1_5
;
597 aContext
.Version
= vcl::PDFWriter::PDFVersion::PDF_A_1
;
598 mbUseTaggedPDF
= true; // force the tagged PDF as well
599 mbExportFormFields
= false; // force disabling of form conversion
600 mbRemoveTransparencies
= true; // PDF/A does not allow transparencies
601 mbEncrypt
= false; // no encryption
605 aContext
.Version
= vcl::PDFWriter::PDFVersion::PDF_A_2
;
606 mbUseTaggedPDF
= true; // force the tagged PDF as well
607 mbRemoveTransparencies
= false; // PDF/A-2 does allow transparencies
608 mbEncrypt
= false; // no encryption
612 aContext
.Version
= vcl::PDFWriter::PDFVersion::PDF_1_6
;
616 // copy in context the values default in the constructor or set by the FilterData sequence of properties
617 aContext
.Tagged
= mbUseTaggedPDF
;
619 // values used in viewer
620 aContext
.HideViewerToolbar
= mbHideViewerToolbar
;
621 aContext
.HideViewerMenubar
= mbHideViewerMenubar
;
622 aContext
.HideViewerWindowControls
= mbHideViewerWindowControls
;
623 aContext
.FitWindow
= mbFitWindow
;
624 aContext
.CenterWindow
= mbCenterWindow
;
625 aContext
.OpenInFullScreenMode
= mbOpenInFullScreenMode
;
626 aContext
.DisplayPDFDocumentTitle
= mbDisplayPDFDocumentTitle
;
627 aContext
.InitialPage
= mnInitialPage
-1;
628 aContext
.OpenBookmarkLevels
= mnOpenBookmarkLevels
;
630 switch( mnPDFDocumentMode
)
634 aContext
.PDFDocumentMode
= vcl::PDFWriter::ModeDefault
;
637 aContext
.PDFDocumentMode
= vcl::PDFWriter::UseOutlines
;
640 aContext
.PDFDocumentMode
= vcl::PDFWriter::UseThumbs
;
643 switch( mnPDFDocumentAction
)
647 aContext
.PDFDocumentAction
= vcl::PDFWriter::ActionDefault
;
650 aContext
.PDFDocumentAction
= vcl::PDFWriter::FitInWindow
;
653 aContext
.PDFDocumentAction
= vcl::PDFWriter::FitWidth
;
656 aContext
.PDFDocumentAction
= vcl::PDFWriter::FitVisible
;
659 aContext
.PDFDocumentAction
= vcl::PDFWriter::ActionZoom
;
660 aContext
.Zoom
= mnZoom
;
664 switch( mnPDFPageLayout
)
668 aContext
.PageLayout
= vcl::PDFWriter::DefaultLayout
;
671 aContext
.PageLayout
= vcl::PDFWriter::SinglePage
;
674 aContext
.PageLayout
= vcl::PDFWriter::Continuous
;
677 aContext
.PageLayout
= vcl::PDFWriter::ContinuousFacing
;
681 aContext
.FirstPageLeft
= false;
683 // check if PDF/A, which does not allow encryption
684 if( aContext
.Version
!= vcl::PDFWriter::PDFVersion::PDF_A_1
)
686 // set check for permission change password
687 // if not enabled and no permission password, force permissions to default as if PDF where without encryption
688 if( mbRestrictPermissions
&& (xEnc
.is() || !aPermissionPassword
.isEmpty()) )
690 mbEncrypt
= true; // permission set as desired, done after
694 // force permission to default
696 mnChangesAllowed
= 4 ;
697 mbCanCopyOrExtract
= true;
698 mbCanExtractForAccessibility
= true ;
701 switch( mnPrintAllowed
)
703 case 0: // initialized when aContext is build, means no printing
707 aContext
.Encryption
.CanPrintFull
= true;
710 aContext
.Encryption
.CanPrintTheDocument
= true;
714 switch( mnChangesAllowed
)
716 case 0: // already in struct PDFSecPermissions CTOR
719 aContext
.Encryption
.CanAssemble
= true;
722 aContext
.Encryption
.CanFillInteractive
= true;
725 aContext
.Encryption
.CanAddOrModify
= true;
729 aContext
.Encryption
.CanModifyTheContent
=
730 aContext
.Encryption
.CanCopyOrExtract
=
731 aContext
.Encryption
.CanAddOrModify
=
732 aContext
.Encryption
.CanFillInteractive
= true;
736 aContext
.Encryption
.CanCopyOrExtract
= mbCanCopyOrExtract
;
737 aContext
.Encryption
.CanExtractForAccessibility
= mbCanExtractForAccessibility
;
738 if( mbEncrypt
&& ! xEnc
.is() )
739 xEnc
= vcl::PDFWriter::InitEncryption( aPermissionPassword
, aOpenPassword
);
740 if( mbEncrypt
&& !aPermissionPassword
.isEmpty() && ! aPreparedPermissionPassword
.getLength() )
741 aPreparedPermissionPassword
= comphelper::OStorageHelper::CreatePackageEncryptionData( aPermissionPassword
);
743 // after this point we don't need the legacy clear passwords anymore
744 // however they are still inside the passed filter data sequence
745 // which is sadly out of our control
746 aPermissionPassword
.clear();
747 aOpenPassword
.clear();
750 * FIXME: the entries are only implicitly defined by the resource file. Should there
751 * ever be an additional form submit format this could get invalid.
753 switch( mnFormsFormat
)
756 aContext
.SubmitFormat
= vcl::PDFWriter::PDF
;
759 aContext
.SubmitFormat
= vcl::PDFWriter::HTML
;
762 aContext
.SubmitFormat
= vcl::PDFWriter::XML
;
766 aContext
.SubmitFormat
= vcl::PDFWriter::FDF
;
769 aContext
.AllowDuplicateFieldNames
= mbAllowDuplicateFieldNames
;
772 Reference
< frame::XModel
> xModel( mxSrcDoc
, UNO_QUERY
);
774 // #i56629: Relative link stuff
775 // set the base URL of the file: then base URL
776 aContext
.BaseURL
= xModel
->getURL();
777 // relative link option is private to PDF Export filter and limited to local filesystem only
778 aContext
.RelFsys
= mbExportRelativeFsysLinks
;
779 // determine the default acton for PDF links
780 switch( mnDefaultLinkAction
)
783 // default: URI, without fragment conversion (the bookmark in PDF may not work)
785 aContext
.DefaultLinkAction
= vcl::PDFWriter::URIAction
;
788 // view PDF through the reader application
789 aContext
.ForcePDFAction
= true;
790 aContext
.DefaultLinkAction
= vcl::PDFWriter::LaunchAction
;
793 // view PDF through an Internet browser
794 aContext
.DefaultLinkAction
= vcl::PDFWriter::URIActionDestination
;
797 aContext
.ConvertOOoTargetToPDFTarget
= mbConvertOOoTargetToPDFTarget
;
799 // check for Link Launch action, not allowed on PDF/A-1
800 // this code chunk checks when the filter is called from scripting
801 if( aContext
.Version
== vcl::PDFWriter::PDFVersion::PDF_A_1
&&
802 aContext
.DefaultLinkAction
== vcl::PDFWriter::LaunchAction
)
804 // force the similar allowed URI action
805 aContext
.DefaultLinkAction
= vcl::PDFWriter::URIActionDestination
;
806 // and remove the remote goto action forced on PDF file
807 aContext
.ForcePDFAction
= false;
811 aContext
.SignPDF
= mbSignPDF
;
812 aContext
.SignLocation
= msSignLocation
;
813 aContext
.SignContact
= msSignContact
;
814 aContext
.SignReason
= msSignReason
;
815 aContext
.SignPassword
= msSignPassword
;
816 aContext
.SignCertificate
= maSignCertificate
;
817 aContext
.SignTSA
= msSignTSA
;
818 aContext
.UseReferenceXObject
= mbUseReferenceXObject
;
820 // all context data set, time to create the printing device
821 std::unique_ptr
<vcl::PDFWriter
> pPDFWriter(new vcl::PDFWriter( aContext
, xEnc
));
822 OutputDevice
* pOut
= pPDFWriter
->GetReferenceDevice();
824 DBG_ASSERT( pOut
, "PDFExport::Export: no reference device" );
825 xDevice
->SetOutputDevice(pOut
);
831 OUString aSrcMimetype
= getMimetypeForDocument( mxContext
, mxSrcDoc
);
832 pPDFWriter
->AddStream( aSrcMimetype
,
833 new PDFExportStreamDoc( mxSrcDoc
, aPreparedPermissionPassword
)
839 DBG_ASSERT( pOut
->GetExtOutDevData() == nullptr, "PDFExport: ExtOutDevData already set!!!" );
840 std::unique_ptr
<vcl::PDFExtOutDevData
> pPDFExtOutDevData(new vcl::PDFExtOutDevData( *pOut
));
841 pOut
->SetExtOutDevData( pPDFExtOutDevData
.get() );
842 pPDFExtOutDevData
->SetIsExportNotes( mbExportNotes
);
843 pPDFExtOutDevData
->SetIsExportTaggedPDF( mbUseTaggedPDF
);
844 pPDFExtOutDevData
->SetIsExportTransitionEffects( mbUseTransitionEffects
);
845 pPDFExtOutDevData
->SetIsExportFormFields( mbExportFormFields
);
846 pPDFExtOutDevData
->SetIsExportBookmarks( mbExportBookmarks
);
847 pPDFExtOutDevData
->SetIsExportHiddenSlides( mbExportHiddenSlides
);
848 pPDFExtOutDevData
->SetIsLosslessCompression( mbUseLosslessCompression
);
849 pPDFExtOutDevData
->SetCompressionQuality( mnQuality
);
850 pPDFExtOutDevData
->SetIsReduceImageResolution( mbReduceImageResolution
);
851 pPDFExtOutDevData
->SetIsExportNamedDestinations( mbExportBmkToDest
);
853 Sequence
< PropertyValue
> aRenderOptions( 7 );
854 aRenderOptions
[ 0 ].Name
= "RenderDevice";
855 aRenderOptions
[ 0 ].Value
<<= uno::Reference
<awt::XDevice
>(xDevice
.get());
856 aRenderOptions
[ 1 ].Name
= "ExportNotesPages";
857 aRenderOptions
[ 1 ].Value
<<= false;
858 Any
& rExportNotesValue
= aRenderOptions
[ 1 ].Value
;
859 aRenderOptions
[ 2 ].Name
= "IsFirstPage";
860 aRenderOptions
[ 2 ].Value
<<= true;
861 aRenderOptions
[ 3 ].Name
= "IsLastPage";
862 aRenderOptions
[ 3 ].Value
<<= false;
863 aRenderOptions
[ 4 ].Name
= "IsSkipEmptyPages";
864 aRenderOptions
[ 4 ].Value
<<= mbSkipEmptyPages
;
865 aRenderOptions
[ 5 ].Name
= "PageRange";
866 aRenderOptions
[ 5 ].Value
<<= aPageRange
;
867 aRenderOptions
[ 6 ].Name
= "ExportPlaceholders";
868 aRenderOptions
[ 6 ].Value
<<= mbExportPlaceholders
;
870 if( !aPageRange
.isEmpty() || !aSelection
.hasValue() )
873 aSelection
<<= mxSrcDoc
;
875 bool bExportNotesPages
= false;
876 bool bReChangeToNormalView
= false;
877 const OUString
sShowOnlineLayout( "ShowOnlineLayout" );
878 bool bReHideWhitespace
= false;
879 const OUString
sHideWhitespace("HideWhitespace");
880 uno::Reference
< beans::XPropertySet
> xViewProperties
;
882 if ( aCreator
== "Writer" )
884 // #i92835: if Writer is in web layout mode this has to be switched to normal view and back to web view in the end
887 Reference
< view::XViewSettingsSupplier
> xVSettingsSupplier( xModel
->getCurrentController(), uno::UNO_QUERY_THROW
);
888 xViewProperties
= xVSettingsSupplier
->getViewSettings();
889 xViewProperties
->getPropertyValue( sShowOnlineLayout
) >>= bReChangeToNormalView
;
890 if( bReChangeToNormalView
)
892 xViewProperties
->setPropertyValue( sShowOnlineLayout
, uno::makeAny( false ) );
895 // Also, disable hide-whitespace during export.
896 xViewProperties
->getPropertyValue(sHideWhitespace
) >>= bReHideWhitespace
;
897 if (bReHideWhitespace
)
899 xViewProperties
->setPropertyValue(sHideWhitespace
, uno::makeAny(false));
902 catch( const uno::Exception
& )
908 const sal_Int32 nPageCount
= xRenderable
->getRendererCount( aSelection
, aRenderOptions
);
910 if ( mbExportNotesPages
&& aCreator
== "Impress" )
912 uno::Reference
< drawing::XShapes
> xShapes
; // do not allow to export notes when exporting a selection
913 if ( ! ( aSelection
>>= xShapes
) )
914 bExportNotesPages
= true;
916 const bool bExportPages
= !bExportNotesPages
|| !mbExportOnlyNotesPages
;
918 if( aPageRange
.isEmpty() )
920 aPageRange
= OUString::number( 1 ) + "-" + OUString::number(nPageCount
);
922 StringRangeEnumerator
aRangeEnum( aPageRange
, 0, nPageCount
-1 );
924 if ( mxStatusIndicator
.is() )
926 std::locale
loc(Translate::Create("flt"));
927 sal_Int32 nTotalPageCount
= aRangeEnum
.size();
928 if ( bExportPages
&& bExportNotesPages
)
929 nTotalPageCount
*= 2;
930 mxStatusIndicator
->start(Translate::get(PDF_PROGRESS_BAR
, loc
), nTotalPageCount
);
933 bRet
= nPageCount
> 0;
935 if ( bRet
&& bExportPages
)
936 bRet
= ExportSelection( *pPDFWriter
, xRenderable
, aSelection
, aRangeEnum
, aRenderOptions
, nPageCount
);
938 if ( bRet
&& bExportNotesPages
)
940 rExportNotesValue
<<= true;
941 bRet
= ExportSelection( *pPDFWriter
, xRenderable
, aSelection
, aRangeEnum
, aRenderOptions
, nPageCount
);
943 if ( mxStatusIndicator
.is() )
944 mxStatusIndicator
->end();
946 // if during the export the doc locale was set copy it to PDF writer
947 const css::lang::Locale
& rLoc( pPDFExtOutDevData
->GetDocumentLocale() );
948 if( !rLoc
.Language
.isEmpty() )
949 pPDFWriter
->SetDocumentLocale( rLoc
);
953 pPDFExtOutDevData
->PlayGlobalActions( *pPDFWriter
);
954 bRet
= pPDFWriter
->Emit();
955 aErrors
= pPDFWriter
->GetErrors();
957 pOut
->SetExtOutDevData( nullptr );
958 if( bReChangeToNormalView
)
962 xViewProperties
->setPropertyValue( sShowOnlineLayout
, uno::makeAny( true ) );
964 catch( const uno::Exception
& )
968 if( bReHideWhitespace
)
972 xViewProperties
->setPropertyValue( sHideWhitespace
, uno::makeAny( true ) );
974 catch( const uno::Exception
& )
982 // show eventual errors during export
983 showErrors( aErrors
);
992 typedef cppu::WeakComponentImplHelper
< task::XInteractionRequest
> PDFErrorRequestBase
;
994 class PDFErrorRequest
: private cppu::BaseMutex
,
995 public PDFErrorRequestBase
997 task::PDFExportException maExc
;
999 explicit PDFErrorRequest( const task::PDFExportException
& i_rExc
);
1001 // XInteractionRequest
1002 virtual uno::Any SAL_CALL
getRequest() override
;
1003 virtual uno::Sequence
< uno::Reference
< task::XInteractionContinuation
> > SAL_CALL
getContinuations() override
;
1007 PDFErrorRequest::PDFErrorRequest( const task::PDFExportException
& i_rExc
) :
1008 PDFErrorRequestBase( m_aMutex
),
1014 uno::Any SAL_CALL
PDFErrorRequest::getRequest()
1016 osl::MutexGuard
const guard( m_aMutex
);
1024 uno::Sequence
< uno::Reference
< task::XInteractionContinuation
> > SAL_CALL
PDFErrorRequest::getContinuations()
1026 return uno::Sequence
< uno::Reference
< task::XInteractionContinuation
> >();
1029 } // end anonymous namespace
1032 void PDFExport::showErrors( const std::set
< vcl::PDFWriter::ErrorCode
>& rErrors
)
1034 if( ! rErrors
.empty() && mxIH
.is() )
1036 task::PDFExportException aExc
;
1037 aExc
.ErrorCodes
= comphelper::containerToSequence
<sal_Int32
>( rErrors
);
1038 Reference
< task::XInteractionRequest
> xReq( new PDFErrorRequest( aExc
) );
1039 mxIH
->handle( xReq
);
1044 void PDFExport::ImplExportPage( vcl::PDFWriter
& rWriter
, vcl::PDFExtOutDevData
& rPDFExtOutDevData
, const GDIMetaFile
& rMtf
)
1046 //Rectangle(Point, Size) creates a rectangle off by 1, use Rectangle(long, long, long, long) instead
1047 basegfx::B2DPolygon
aSize(tools::Polygon(tools::Rectangle(0, 0, rMtf
.GetPrefSize().Width(), rMtf
.GetPrefSize().Height())).getB2DPolygon());
1048 basegfx::B2DPolygon
aSizePDF(OutputDevice::LogicToLogic(aSize
, rMtf
.GetPrefMapMode(), MapMode(MapUnit::MapPoint
)));
1049 basegfx::B2DRange
aRangePDF(aSizePDF
.getB2DRange());
1050 tools::Rectangle
aPageRect( Point(), rMtf
.GetPrefSize() );
1052 rWriter
.NewPage( aRangePDF
.getWidth(), aRangePDF
.getHeight() );
1053 rWriter
.SetMapMode( rMtf
.GetPrefMapMode() );
1055 vcl::PDFWriter::PlayMetafileContext aCtx
;
1057 if( mbRemoveTransparencies
)
1059 aCtx
.m_bTransparenciesWereRemoved
= rWriter
.GetReferenceDevice()->
1060 RemoveTransparenciesFromMetaFile( rMtf
, aMtf
, mnMaxImageResolution
, mnMaxImageResolution
,
1061 false, true, mbReduceImageResolution
);
1067 aCtx
.m_nMaxImageResolution
= mbReduceImageResolution
? mnMaxImageResolution
: 0;
1068 aCtx
.m_bOnlyLosslessCompression
= mbUseLosslessCompression
;
1069 aCtx
.m_nJPEGQuality
= mnQuality
;
1072 basegfx::B2DRectangle
aB2DRect( aPageRect
.Left(), aPageRect
.Top(), aPageRect
.Right(), aPageRect
.Bottom() );
1073 rWriter
.SetClipRegion( basegfx::B2DPolyPolygon( basegfx::utils::createPolygonFromRect( aB2DRect
) ) );
1075 rWriter
.PlayMetafile( aMtf
, aCtx
, &rPDFExtOutDevData
);
1077 rPDFExtOutDevData
.ResetSyncData();
1079 if (!msWatermark
.isEmpty())
1080 ImplWriteWatermark( rWriter
, Size(aRangePDF
.getWidth(), aRangePDF
.getHeight()) );
1084 void PDFExport::ImplWriteWatermark( vcl::PDFWriter
& rWriter
, const Size
& rPageSize
)
1086 vcl::Font
aFont( OUString( "Helvetica" ), Size( 0, 3*rPageSize
.Height()/4 ) );
1087 aFont
.SetItalic( ITALIC_NONE
);
1088 aFont
.SetWidthType( WIDTH_NORMAL
);
1089 aFont
.SetWeight( WEIGHT_NORMAL
);
1090 aFont
.SetAlignment( ALIGN_BOTTOM
);
1091 long nTextWidth
= rPageSize
.Width();
1092 if( rPageSize
.Width() < rPageSize
.Height() )
1094 nTextWidth
= rPageSize
.Height();
1095 aFont
.SetOrientation( 2700 );
1098 // adjust font height for text to fit
1099 OutputDevice
* pDev
= rWriter
.GetReferenceDevice();
1101 pDev
->SetFont( aFont
);
1102 pDev
->SetMapMode( MapMode( MapUnit::MapPoint
) );
1104 while( ( w
= pDev
->GetTextWidth( msWatermark
) ) > nTextWidth
)
1108 long nNewHeight
= aFont
.GetFontHeight() * nTextWidth
/ w
;
1109 if( nNewHeight
== aFont
.GetFontHeight() )
1112 if( nNewHeight
<= 0 )
1115 aFont
.SetFontHeight( nNewHeight
);
1116 pDev
->SetFont( aFont
);
1118 long nTextHeight
= pDev
->GetTextHeight();
1119 // leave some maneuvering room for rounding issues, also
1120 // some fonts go a little outside ascent/descent
1121 nTextHeight
+= nTextHeight
/20;
1125 rWriter
.SetMapMode( MapMode( MapUnit::MapPoint
) );
1126 rWriter
.SetFont( aFont
);
1127 rWriter
.SetTextColor( COL_LIGHTGREEN
);
1129 tools::Rectangle aTextRect
;
1130 if( rPageSize
.Width() > rPageSize
.Height() )
1132 aTextPoint
= Point( (rPageSize
.Width()-w
)/2,
1133 rPageSize
.Height()-(rPageSize
.Height()-nTextHeight
)/2 );
1134 aTextRect
= tools::Rectangle( Point( (rPageSize
.Width()-w
)/2,
1135 (rPageSize
.Height()-nTextHeight
)/2 ),
1136 Size( w
, nTextHeight
) );
1140 aTextPoint
= Point( (rPageSize
.Width()-nTextHeight
)/2,
1141 (rPageSize
.Height()-w
)/2 );
1142 aTextRect
= tools::Rectangle( aTextPoint
, Size( nTextHeight
, w
) );
1144 rWriter
.SetClipRegion();
1145 rWriter
.BeginTransparencyGroup();
1146 rWriter
.DrawText( aTextPoint
, msWatermark
);
1147 rWriter
.EndTransparencyGroup( aTextRect
, 50 );
1151 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */