1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
21 #include <osl/file.hxx>
22 #include <tools/debug.hxx>
23 #include <tools/urlobj.hxx>
24 #include <tools/poly.hxx>
25 #include <tools/diagnose_ex.h>
26 #include <unotools/resmgr.hxx>
27 #include <vcl/canvastools.hxx>
28 #include <vcl/mapmod.hxx>
29 #include <vcl/gdimtf.hxx>
30 #include <comphelper/sequence.hxx>
31 #include <comphelper/string.hxx>
32 #include <comphelper/storagehelper.hxx>
33 #include <basegfx/polygon/b2dpolygon.hxx>
34 #include <basegfx/polygon/b2dpolypolygon.hxx>
35 #include <basegfx/polygon/b2dpolygontools.hxx>
36 #include <toolkit/awt/vclxdevice.hxx>
37 #include <unotools/configmgr.hxx>
38 #include <cppuhelper/compbase.hxx>
39 #include <cppuhelper/basemutex.hxx>
40
41 #include "pdfexport.hxx"
42 #include <strings.hrc>
43
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/configuration/theDefaultProvider.hpp>
46 #include <com/sun/star/awt/XDevice.hpp>
47 #include <com/sun/star/frame/XModel.hpp>
48 #include <com/sun/star/frame/ModuleManager.hpp>
49 #include <com/sun/star/frame/XStorable.hpp>
50 #include <com/sun/star/document/XDocumentProperties.hpp>
51 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
52 #include <com/sun/star/container/XNameAccess.hpp>
53 #include <com/sun/star/view/XViewSettingsSupplier.hpp>
54 #include <com/sun/star/task/XInteractionRequest.hpp>
55 #include <com/sun/star/task/PDFExportException.hpp>
56 #include <com/sun/star/io/IOException.hpp>
57 #include <com/sun/star/io/XOutputStream.hpp>
58 #include <com/sun/star/lang/XServiceInfo.hpp>
59 #include <com/sun/star/drawing/XShapes.hpp>
60 #include <com/sun/star/security/XCertificate.hpp>
61 #include <com/sun/star/beans/XMaterialHolder.hpp>
62
63 #include <memory>
64
65 using namespace ::com::sun::star;
66 using namespace ::com::sun::star::io;
67 using namespace ::com::sun::star::uno;
68 using namespace ::com::sun::star::lang;
69 using namespace ::com::sun::star::beans;
70 using namespace ::com::sun::star::view;
71 using namespace ::com::sun::star::graphic;
72
73
PDFExport(const Reference<XComponent> & rxSrcDoc,const Reference<task::XStatusIndicator> & rxStatusIndicator,const Reference<task::XInteractionHandler> & rxIH,const Reference<XComponentContext> & xContext)74 PDFExport::PDFExport( const Reference< XComponent >& rxSrcDoc,
75 const Reference< task::XStatusIndicator >& rxStatusIndicator,
76 const Reference< task::XInteractionHandler >& rxIH,
77 const Reference< XComponentContext >& xContext ) :
78 mxSrcDoc ( rxSrcDoc ),
79 mxContext ( xContext ),
80 mxStatusIndicator ( rxStatusIndicator ),
81 mxIH ( rxIH ),
82 mbUseTaggedPDF ( false ),
83 mnPDFTypeSelection ( 0 ),
84 mbPDFUACompliance ( false),
85 mbExportNotes ( true ),
86 mbExportPlaceholders ( false ),
87 mbUseReferenceXObject ( false ),
88 mbExportNotesPages ( false ),
89 mbExportOnlyNotesPages ( false ),
90 mbUseTransitionEffects ( true ),
91 mbExportBookmarks ( true ),
92 mbExportHiddenSlides ( false ),
93 mbSinglePageSheets ( false ),
94 mnOpenBookmarkLevels ( -1 ),
95 mbUseLosslessCompression ( false ),
96 mbReduceImageResolution ( true ),
97 mbSkipEmptyPages ( true ),
98 mbAddStream ( false ),
99 mnMaxImageResolution ( 300 ),
100 mnQuality ( 80 ),
101 mnFormsFormat ( 0 ),
102 mbExportFormFields ( true ),
103 mbAllowDuplicateFieldNames ( false ),
104 mnProgressValue ( 0 ),
105 mbRemoveTransparencies ( false ),
106
107 mbIsRedactMode ( false ),
108
109 mbHideViewerToolbar ( false ),
110 mbHideViewerMenubar ( false ),
111 mbHideViewerWindowControls ( false ),
112 mbFitWindow ( false ),
113 mbCenterWindow ( false ),
114 mbOpenInFullScreenMode ( false ),
115 mbDisplayPDFDocumentTitle ( true ),
116 mnPDFDocumentMode ( 0 ),
117 mnPDFDocumentAction ( 0 ),
118 mnZoom ( 100 ),
119 mnInitialPage ( 1 ),
120 mnPDFPageLayout ( 0 ),
121
122 mbEncrypt ( false ),
123 mbRestrictPermissions ( false ),
124 mnPrintAllowed ( 2 ),
125 mnChangesAllowed ( 4 ),
126 mbCanCopyOrExtract ( true ),
127 mbCanExtractForAccessibility( true ),
128
129 // #i56629
130 mbExportRelativeFsysLinks ( false ),
131 mnDefaultLinkAction ( 0 ),
132 mbConvertOOoTargetToPDFTarget( false ),
133 mbExportBmkToDest ( false ),
134 mbSignPDF ( false )
135 {
136 }
137
138
~PDFExport()139 PDFExport::~PDFExport()
140 {
141 }
142
143
ExportSelection(vcl::PDFWriter & rPDFWriter,Reference<css::view::XRenderable> const & rRenderable,const Any & rSelection,const StringRangeEnumerator & rRangeEnum,Sequence<PropertyValue> & rRenderOptions,sal_Int32 nPageCount)144 bool PDFExport::ExportSelection( vcl::PDFWriter& rPDFWriter,
145 Reference< css::view::XRenderable > const & rRenderable,
146 const Any& rSelection,
147 const StringRangeEnumerator& rRangeEnum,
148 Sequence< PropertyValue >& rRenderOptions,
149 sal_Int32 nPageCount )
150 {
151 bool bRet = false;
152 try
153 {
154 Any* pFirstPage = nullptr;
155 Any* pLastPage = nullptr;
156
157 bool bExportNotesPages = false;
158
159 for( sal_Int32 nData = 0, nDataCount = rRenderOptions.getLength(); nData < nDataCount; ++nData )
160 {
161 if ( rRenderOptions[ nData ].Name == "IsFirstPage" )
162 pFirstPage = &rRenderOptions[ nData ].Value;
163 else if ( rRenderOptions[ nData ].Name == "IsLastPage" )
164 pLastPage = &rRenderOptions[ nData ].Value;
165 else if ( rRenderOptions[ nData ].Name == "ExportNotesPages" )
166 rRenderOptions[ nData ].Value >>= bExportNotesPages;
167 }
168
169 OutputDevice* pOut = rPDFWriter.GetReferenceDevice();
170
171 if( pOut )
172 {
173 if ( nPageCount )
174 {
175 vcl::PDFExtOutDevData& rPDFExtOutDevData = dynamic_cast<vcl::PDFExtOutDevData&>(*pOut->GetExtOutDevData());
176 rPDFExtOutDevData.SetIsExportNotesPages( bExportNotesPages );
177
178 sal_Int32 nCurrentPage(0);
179 StringRangeEnumerator::Iterator aIter = rRangeEnum.begin();
180 StringRangeEnumerator::Iterator aEnd = rRangeEnum.end();
181 while ( aIter != aEnd )
182 {
183 const Sequence< PropertyValue > aRenderer( rRenderable->getRenderer( *aIter, rSelection, rRenderOptions ) );
184 awt::Size aPageSize;
185
186 for( const PropertyValue& rProp : aRenderer )
187 {
188 if ( rProp.Name == "PageSize" )
189 {
190 rProp.Value >>= aPageSize;
191 break;
192 }
193 }
194
195 rPDFExtOutDevData.SetCurrentPageNumber( nCurrentPage );
196
197 GDIMetaFile aMtf;
198 const MapMode aMapMode( MapUnit::Map100thMM );
199 const Size aMtfSize( aPageSize.Width, aPageSize.Height );
200
201 pOut->Push();
202 pOut->EnableOutput( false );
203 pOut->SetMapMode( aMapMode );
204
205 aMtf.SetPrefSize( aMtfSize );
206 aMtf.SetPrefMapMode( aMapMode );
207 aMtf.Record( pOut );
208
209 // #i35176#
210 // IsLastPage property.
211 const sal_Int32 nCurrentRenderer = *aIter;
212 ++aIter;
213 if ( pLastPage && aIter == aEnd )
214 *pLastPage <<= true;
215
216 rRenderable->render( nCurrentRenderer, rSelection, rRenderOptions );
217
218 aMtf.Stop();
219 aMtf.WindStart();
220
221 bool bEmptyPage = false;
222 if( aMtf.GetActionSize() &&
223 ( !mbSkipEmptyPages || aPageSize.Width || aPageSize.Height ) )
224 {
225 // We convert the whole metafile into a bitmap to get rid of the
226 // text covered by redaction shapes
227 if (mbIsRedactMode)
228 {
229 try
230 {
231 Graphic aGraph(aMtf);
232 // use antialiasing to improve how graphic objects look
233 BitmapEx bmp = aGraph.GetBitmapEx(GraphicConversionParameters(Size(0, 0), false, true, false));
234 Graphic bgraph(bmp);
235 aMtf = bgraph.GetGDIMetaFile();
236 }
237 catch(const Exception&)
238 {
239 TOOLS_WARN_EXCEPTION("filter.pdf", "Something went wrong while converting metafile to bitmap");
240 }
241 }
242
243 ImplExportPage(rPDFWriter, rPDFExtOutDevData, aMtf);
244 bRet = true;
245 }
246 else
247 {
248 bEmptyPage = true;
249 }
250
251 pOut->Pop();
252
253 if ( mxStatusIndicator.is() )
254 mxStatusIndicator->setValue( mnProgressValue );
255 if ( pFirstPage )
256 *pFirstPage <<= false;
257
258 ++mnProgressValue;
259 if (!bEmptyPage)
260 {
261 // Calculate the page number in the PDF output, which may be smaller than the page number in
262 // case of hidden slides or a partial export.
263 ++nCurrentPage;
264 }
265 }
266 }
267 else
268 {
269 bRet = true; // #i18334# nPageCount == 0,
270 rPDFWriter.NewPage( 10000, 10000 ); // creating dummy page
271 rPDFWriter.SetMapMode(MapMode(MapUnit::Map100thMM));
272 }
273 }
274 }
275 catch(const RuntimeException &)
276 {
277 }
278 return bRet;
279 }
280
281 namespace {
282
283 class PDFExportStreamDoc : public vcl::PDFOutputStream
284 {
285 private:
286
287 Reference< XComponent > m_xSrcDoc;
288 Sequence< beans::NamedValue > m_aPreparedPassword;
289
290 public:
291
PDFExportStreamDoc(const Reference<XComponent> & xDoc,const Sequence<beans::NamedValue> & rPwd)292 PDFExportStreamDoc( const Reference< XComponent >& xDoc, const Sequence<beans::NamedValue>& rPwd )
293 : m_xSrcDoc( xDoc ),
294 m_aPreparedPassword( rPwd )
295 {}
296
297 virtual void write( const Reference< XOutputStream >& xStream ) override;
298 };
299
300 }
301
write(const Reference<XOutputStream> & xStream)302 void PDFExportStreamDoc::write( const Reference< XOutputStream >& xStream )
303 {
304 Reference< css::frame::XStorable > xStore( m_xSrcDoc, UNO_QUERY );
305 if( !xStore.is() )
306 return;
307
308 Sequence< beans::PropertyValue > aArgs( 2 + (m_aPreparedPassword.hasElements() ? 1 : 0) );
309 aArgs.getArray()[0].Name = "FilterName";
310 aArgs.getArray()[1].Name = "OutputStream";
311 aArgs.getArray()[1].Value <<= xStream;
312 if( m_aPreparedPassword.hasElements() )
313 {
314 aArgs.getArray()[2].Name = "EncryptionData";
315 aArgs.getArray()[2].Value <<= m_aPreparedPassword;
316 }
317
318 try
319 {
320 xStore->storeToURL( "private:stream", aArgs );
321 }
322 catch( const IOException& )
323 {
324 }
325 }
326
327
getMimetypeForDocument(const Reference<XComponentContext> & xContext,const Reference<XComponent> & xDoc)328 static OUString getMimetypeForDocument( const Reference< XComponentContext >& xContext,
329 const Reference< XComponent >& xDoc ) noexcept
330 {
331 OUString aDocMimetype;
332 try
333 {
334 // get document service name
335 Reference< css::frame::XStorable > xStore( xDoc, UNO_QUERY );
336 Reference< frame::XModuleManager2 > xModuleManager = frame::ModuleManager::create(xContext);
337 if( xStore.is() )
338 {
339 OUString aDocServiceName = xModuleManager->identify( Reference< XInterface >( xStore, uno::UNO_QUERY ) );
340 if ( !aDocServiceName.isEmpty() )
341 {
342 // get the actual filter name
343 Reference< lang::XMultiServiceFactory > xConfigProvider =
344 configuration::theDefaultProvider::get( xContext );
345 uno::Sequence< uno::Any > aArgs( 1 );
346 beans::NamedValue aPathProp;
347 aPathProp.Name = "nodepath";
348 aPathProp.Value <<= OUString( "/org.openoffice.Setup/Office/Factories/" );
349 aArgs[0] <<= aPathProp;
350
351 Reference< container::XNameAccess > xSOFConfig(
352 xConfigProvider->createInstanceWithArguments(
353 "com.sun.star.configuration.ConfigurationAccess", aArgs ),
354 uno::UNO_QUERY );
355
356 Reference< container::XNameAccess > xApplConfig;
357 xSOFConfig->getByName( aDocServiceName ) >>= xApplConfig;
358 if ( xApplConfig.is() )
359 {
360 OUString aFilterName;
361 xApplConfig->getByName( "ooSetupFactoryActualFilter" ) >>= aFilterName;
362 if( !aFilterName.isEmpty() )
363 {
364 // find the related type name
365 OUString aTypeName;
366 Reference< container::XNameAccess > xFilterFactory(
367 xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", xContext),
368 uno::UNO_QUERY );
369
370 Sequence< beans::PropertyValue > aFilterData;
371 xFilterFactory->getByName( aFilterName ) >>= aFilterData;
372 for ( const beans::PropertyValue& rProp : std::as_const(aFilterData) )
373 if ( rProp.Name == "Type" )
374 rProp.Value >>= aTypeName;
375
376 if ( !aTypeName.isEmpty() )
377 {
378 // find the mediatype
379 Reference< container::XNameAccess > xTypeDetection(
380 xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", xContext),
381 UNO_QUERY );
382
383 Sequence< beans::PropertyValue > aTypeData;
384 xTypeDetection->getByName( aTypeName ) >>= aTypeData;
385 for ( const beans::PropertyValue& rProp : std::as_const(aTypeData) )
386 if ( rProp.Name == "MediaType" )
387 rProp.Value >>= aDocMimetype;
388 }
389 }
390 }
391 }
392 }
393 }
394 catch (...)
395 {
396 }
397 return aDocMimetype;
398 }
399
400
Export(const OUString & rFile,const Sequence<PropertyValue> & rFilterData)401 bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& rFilterData )
402 {
403 INetURLObject aURL( rFile );
404 bool bRet = false;
405
406 std::set< vcl::PDFWriter::ErrorCode > aErrors;
407
408 if( aURL.GetProtocol() != INetProtocol::File )
409 {
410 OUString aTmp;
411
412 if( osl::FileBase::getFileURLFromSystemPath( rFile, aTmp ) == osl::FileBase::E_None )
413 aURL = INetURLObject(aTmp);
414 }
415
416 if( aURL.GetProtocol() == INetProtocol::File )
417 {
418 Reference< XRenderable > xRenderable( mxSrcDoc, UNO_QUERY );
419
420 if( xRenderable.is() )
421 {
422 rtl::Reference<VCLXDevice> xDevice(new VCLXDevice);
423 OUString aPageRange;
424 Any aSelection;
425 vcl::PDFWriter::PDFWriterContext aContext;
426 OUString aOpenPassword, aPermissionPassword;
427 Reference< beans::XMaterialHolder > xEnc;
428 Sequence< beans::NamedValue > aPreparedPermissionPassword;
429
430
431 // getting the string for the creator
432 OUString aCreator;
433 Reference< XServiceInfo > xInfo( mxSrcDoc, UNO_QUERY );
434 if ( xInfo.is() )
435 {
436 if ( xInfo->supportsService( "com.sun.star.presentation.PresentationDocument" ) )
437 aCreator += "Impress";
438 else if ( xInfo->supportsService( "com.sun.star.drawing.DrawingDocument" ) )
439 aCreator += "Draw";
440 else if ( xInfo->supportsService( "com.sun.star.text.TextDocument" ) )
441 aCreator += "Writer";
442 else if ( xInfo->supportsService( "com.sun.star.sheet.SpreadsheetDocument" ) )
443 aCreator += "Calc";
444 else if ( xInfo->supportsService( "com.sun.star.formula.FormulaProperties" ) )
445 aCreator += "Math";
446 }
447
448 Reference< document::XDocumentPropertiesSupplier > xDocumentPropsSupplier( mxSrcDoc, UNO_QUERY );
449 if ( xDocumentPropsSupplier.is() )
450 {
451 Reference< document::XDocumentProperties > xDocumentProps( xDocumentPropsSupplier->getDocumentProperties() );
452 if ( xDocumentProps.is() )
453 {
454 aContext.DocumentInfo.Title = xDocumentProps->getTitle();
455 aContext.DocumentInfo.Author = xDocumentProps->getAuthor();
456 aContext.DocumentInfo.Subject = xDocumentProps->getSubject();
457 aContext.DocumentInfo.Keywords = ::comphelper::string::convertCommaSeparated(xDocumentProps->getKeywords());
458 }
459 }
460 // getting the string for the producer
461 aContext.DocumentInfo.Producer =
462 utl::ConfigManager::getProductName() +
463 " " +
464 utl::ConfigManager::getProductVersion();
465 aContext.DocumentInfo.Creator = aCreator;
466
467 for ( const beans::PropertyValue& rProp : rFilterData )
468 {
469 if ( rProp.Name == "PageRange" )
470 rProp.Value >>= aPageRange;
471 else if ( rProp.Name == "Selection" )
472 aSelection = rProp.Value;
473 else if ( rProp.Name == "UseLosslessCompression" )
474 rProp.Value >>= mbUseLosslessCompression;
475 else if ( rProp.Name == "Quality" )
476 rProp.Value >>= mnQuality;
477 else if ( rProp.Name == "ReduceImageResolution" )
478 rProp.Value >>= mbReduceImageResolution;
479 else if ( rProp.Name == "IsSkipEmptyPages" )
480 rProp.Value >>= mbSkipEmptyPages;
481 else if ( rProp.Name == "MaxImageResolution" )
482 rProp.Value >>= mnMaxImageResolution;
483 else if ( rProp.Name == "UseTaggedPDF" )
484 rProp.Value >>= mbUseTaggedPDF;
485 else if ( rProp.Name == "SelectPdfVersion" )
486 rProp.Value >>= mnPDFTypeSelection;
487 else if ( rProp.Name == "PDFUACompliance" )
488 rProp.Value >>= mbPDFUACompliance;
489 else if ( rProp.Name == "ExportNotes" )
490 rProp.Value >>= mbExportNotes;
491 else if ( rProp.Name == "ExportNotesPages" )
492 rProp.Value >>= mbExportNotesPages;
493 else if ( rProp.Name == "ExportOnlyNotesPages" )
494 rProp.Value >>= mbExportOnlyNotesPages;
495 else if ( rProp.Name == "UseTransitionEffects" )
496 rProp.Value >>= mbUseTransitionEffects;
497 else if ( rProp.Name == "ExportFormFields" )
498 rProp.Value >>= mbExportFormFields;
499 else if ( rProp.Name == "FormsType" )
500 rProp.Value >>= mnFormsFormat;
501 else if ( rProp.Name == "AllowDuplicateFieldNames" )
502 rProp.Value >>= mbAllowDuplicateFieldNames;
503 // viewer properties
504 else if ( rProp.Name == "HideViewerToolbar" )
505 rProp.Value >>= mbHideViewerToolbar;
506 else if ( rProp.Name == "HideViewerMenubar" )
507 rProp.Value >>= mbHideViewerMenubar;
508 else if ( rProp.Name == "HideViewerWindowControls" )
509 rProp.Value >>= mbHideViewerWindowControls;
510 else if ( rProp.Name == "ResizeWindowToInitialPage" )
511 rProp.Value >>= mbFitWindow;
512 else if ( rProp.Name == "CenterWindow" )
513 rProp.Value >>= mbCenterWindow;
514 else if ( rProp.Name == "OpenInFullScreenMode" )
515 rProp.Value >>= mbOpenInFullScreenMode;
516 else if ( rProp.Name == "DisplayPDFDocumentTitle" )
517 rProp.Value >>= mbDisplayPDFDocumentTitle;
518 else if ( rProp.Name == "InitialView" )
519 rProp.Value >>= mnPDFDocumentMode;
520 else if ( rProp.Name == "Magnification" )
521 rProp.Value >>= mnPDFDocumentAction;
522 else if ( rProp.Name == "Zoom" )
523 rProp.Value >>= mnZoom;
524 else if ( rProp.Name == "InitialPage" )
525 rProp.Value >>= mnInitialPage;
526 else if ( rProp.Name == "PageLayout" )
527 rProp.Value >>= mnPDFPageLayout;
528 else if ( rProp.Name == "FirstPageOnLeft" )
529 rProp.Value >>= aContext.FirstPageLeft;
530 else if ( rProp.Name == "IsAddStream" )
531 rProp.Value >>= mbAddStream;
532 else if ( rProp.Name == "Watermark" )
533 rProp.Value >>= msWatermark;
534 else if ( rProp.Name == "TiledWatermark" )
535 rProp.Value >>= msTiledWatermark;
536 // now all the security related properties...
537 else if ( rProp.Name == "EncryptFile" )
538 rProp.Value >>= mbEncrypt;
539 else if ( rProp.Name == "DocumentOpenPassword" )
540 rProp.Value >>= aOpenPassword;
541 else if ( rProp.Name == "RestrictPermissions" )
542 rProp.Value >>= mbRestrictPermissions;
543 else if ( rProp.Name == "PermissionPassword" )
544 rProp.Value >>= aPermissionPassword;
545 else if ( rProp.Name == "PreparedPasswords" )
546 rProp.Value >>= xEnc;
547 else if ( rProp.Name == "PreparedPermissionPassword" )
548 rProp.Value >>= aPreparedPermissionPassword;
549 else if ( rProp.Name == "Printing" )
550 rProp.Value >>= mnPrintAllowed;
551 else if ( rProp.Name == "Changes" )
552 rProp.Value >>= mnChangesAllowed;
553 else if ( rProp.Name == "EnableCopyingOfContent" )
554 rProp.Value >>= mbCanCopyOrExtract;
555 else if ( rProp.Name == "EnableTextAccessForAccessibilityTools" )
556 rProp.Value >>= mbCanExtractForAccessibility;
557 // i56629 links extra (relative links and other related stuff)
558 else if ( rProp.Name == "ExportLinksRelativeFsys" )
559 rProp.Value >>= mbExportRelativeFsysLinks;
560 else if ( rProp.Name == "PDFViewSelection" )
561 rProp.Value >>= mnDefaultLinkAction;
562 else if ( rProp.Name == "ConvertOOoTargetToPDFTarget" )
563 rProp.Value >>= mbConvertOOoTargetToPDFTarget;
564 else if ( rProp.Name == "ExportBookmarksToPDFDestination" )
565 rProp.Value >>= mbExportBmkToDest;
566 else if ( rProp.Name == "ExportBookmarks" )
567 rProp.Value >>= mbExportBookmarks;
568 else if ( rProp.Name == "ExportHiddenSlides" )
569 rProp.Value >>= mbExportHiddenSlides;
570 else if ( rProp.Name == "SinglePageSheets" )
571 rProp.Value >>= mbSinglePageSheets;
572 else if ( rProp.Name == "OpenBookmarkLevels" )
573 rProp.Value >>= mnOpenBookmarkLevels;
574 else if ( rProp.Name == "SignPDF" )
575 rProp.Value >>= mbSignPDF;
576 else if ( rProp.Name == "SignatureLocation" )
577 rProp.Value >>= msSignLocation;
578 else if ( rProp.Name == "SignatureReason" )
579 rProp.Value >>= msSignReason;
580 else if ( rProp.Name == "SignatureContactInfo" )
581 rProp.Value >>= msSignContact;
582 else if ( rProp.Name == "SignaturePassword" )
583 rProp.Value >>= msSignPassword;
584 else if ( rProp.Name == "SignatureCertificate" )
585 rProp.Value >>= maSignCertificate;
586 else if ( rProp.Name == "SignatureTSA" )
587 rProp.Value >>= msSignTSA;
588 else if ( rProp.Name == "ExportPlaceholders" )
589 rProp.Value >>= mbExportPlaceholders;
590 else if ( rProp.Name == "UseReferenceXObject" )
591 rProp.Value >>= mbUseReferenceXObject;
592 // Redaction & bitmap related stuff
593 else if ( rProp.Name == "IsRedactMode" )
594 rProp.Value >>= mbIsRedactMode;
595 }
596
597 aContext.URL = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
598
599 // set the correct version, depending on user request
600 switch( mnPDFTypeSelection )
601 {
602 default:
603 case 0:
604 aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_6;
605 break;
606 case 1:
607 aContext.Version = vcl::PDFWriter::PDFVersion::PDF_A_1;
608 mbUseTaggedPDF = true; // force the tagged PDF as well
609 mbRemoveTransparencies = true; // does not allow transparencies
610 mbEncrypt = false; // no encryption
611 xEnc.clear();
612 break;
613 case 2:
614 aContext.Version = vcl::PDFWriter::PDFVersion::PDF_A_2;
615 mbUseTaggedPDF = true; // force the tagged PDF as well
616 mbRemoveTransparencies = false; // does allow transparencies
617 mbEncrypt = false; // no encryption
618 xEnc.clear();
619 break;
620 case 3:
621 aContext.Version = vcl::PDFWriter::PDFVersion::PDF_A_3;
622 mbUseTaggedPDF = true; // force the tagged PDF as well
623 mbRemoveTransparencies = false; // does allow transparencies
624 mbEncrypt = false; // no encryption
625 xEnc.clear();
626 break;
627 case 15:
628 aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_5;
629 break;
630 case 16:
631 aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_6;
632 break;
633 }
634
635 // PDF/UA support
636 aContext.UniversalAccessibilityCompliance = mbPDFUACompliance;
637 if (mbPDFUACompliance)
638 {
639 mbUseTaggedPDF = true;
640 }
641
642 // copy in context the values default in the constructor or set by the FilterData sequence of properties
643 aContext.Tagged = mbUseTaggedPDF;
644
645 // values used in viewer
646 aContext.HideViewerToolbar = mbHideViewerToolbar;
647 aContext.HideViewerMenubar = mbHideViewerMenubar;
648 aContext.HideViewerWindowControls = mbHideViewerWindowControls;
649 aContext.FitWindow = mbFitWindow;
650 aContext.CenterWindow = mbCenterWindow;
651 aContext.OpenInFullScreenMode = mbOpenInFullScreenMode;
652 aContext.DisplayPDFDocumentTitle = mbDisplayPDFDocumentTitle;
653 aContext.InitialPage = mnInitialPage-1;
654 aContext.OpenBookmarkLevels = mnOpenBookmarkLevels;
655
656 switch( mnPDFDocumentMode )
657 {
658 default:
659 case 0:
660 aContext.PDFDocumentMode = vcl::PDFWriter::ModeDefault;
661 break;
662 case 1:
663 aContext.PDFDocumentMode = vcl::PDFWriter::UseOutlines;
664 break;
665 case 2:
666 aContext.PDFDocumentMode = vcl::PDFWriter::UseThumbs;
667 break;
668 }
669 switch( mnPDFDocumentAction )
670 {
671 default:
672 case 0:
673 aContext.PDFDocumentAction = vcl::PDFWriter::ActionDefault;
674 break;
675 case 1:
676 aContext.PDFDocumentAction = vcl::PDFWriter::FitInWindow;
677 break;
678 case 2:
679 aContext.PDFDocumentAction = vcl::PDFWriter::FitWidth;
680 break;
681 case 3:
682 aContext.PDFDocumentAction = vcl::PDFWriter::FitVisible;
683 break;
684 case 4:
685 aContext.PDFDocumentAction = vcl::PDFWriter::ActionZoom;
686 aContext.Zoom = mnZoom;
687 break;
688 }
689
690 switch( mnPDFPageLayout )
691 {
692 default:
693 case 0:
694 aContext.PageLayout = vcl::PDFWriter::DefaultLayout;
695 break;
696 case 1:
697 aContext.PageLayout = vcl::PDFWriter::SinglePage;
698 break;
699 case 2:
700 aContext.PageLayout = vcl::PDFWriter::Continuous;
701 break;
702 case 3:
703 aContext.PageLayout = vcl::PDFWriter::ContinuousFacing;
704 break;
705 }
706
707 aContext.FirstPageLeft = false;
708
709 // check if PDF/A, which does not allow encryption
710 if( aContext.Version != vcl::PDFWriter::PDFVersion::PDF_A_1 )
711 {
712 // set check for permission change password
713 // if not enabled and no permission password, force permissions to default as if PDF where without encryption
714 if( mbRestrictPermissions && (xEnc.is() || !aPermissionPassword.isEmpty()) )
715 {
716 mbEncrypt = true; // permission set as desired, done after
717 }
718 else
719 {
720 // force permission to default
721 mnPrintAllowed = 2 ;
722 mnChangesAllowed = 4 ;
723 mbCanCopyOrExtract = true;
724 mbCanExtractForAccessibility = true ;
725 }
726
727 switch( mnPrintAllowed )
728 {
729 case 0: // initialized when aContext is build, means no printing
730 break;
731 default:
732 case 2:
733 aContext.Encryption.CanPrintFull = true;
734 [[fallthrough]];
735 case 1:
736 aContext.Encryption.CanPrintTheDocument = true;
737 break;
738 }
739
740 switch( mnChangesAllowed )
741 {
742 case 0: // already in struct PDFSecPermissions CTOR
743 break;
744 case 1:
745 aContext.Encryption.CanAssemble = true;
746 break;
747 case 2:
748 aContext.Encryption.CanFillInteractive = true;
749 break;
750 case 3:
751 aContext.Encryption.CanAddOrModify = true;
752 break;
753 default:
754 case 4:
755 aContext.Encryption.CanModifyTheContent =
756 aContext.Encryption.CanCopyOrExtract =
757 aContext.Encryption.CanAddOrModify =
758 aContext.Encryption.CanFillInteractive = true;
759 break;
760 }
761
762 aContext.Encryption.CanCopyOrExtract = mbCanCopyOrExtract;
763 aContext.Encryption.CanExtractForAccessibility = mbCanExtractForAccessibility;
764 if( mbEncrypt && ! xEnc.is() )
765 xEnc = vcl::PDFWriter::InitEncryption( aPermissionPassword, aOpenPassword );
766 if( mbEncrypt && !aPermissionPassword.isEmpty() && ! aPreparedPermissionPassword.hasElements() )
767 aPreparedPermissionPassword = comphelper::OStorageHelper::CreatePackageEncryptionData( aPermissionPassword );
768 }
769 // after this point we don't need the legacy clear passwords anymore
770 // however they are still inside the passed filter data sequence
771 // which is sadly out of our control
772 aPermissionPassword.clear();
773 aOpenPassword.clear();
774
775 /*
776 * FIXME: the entries are only implicitly defined by the resource file. Should there
777 * ever be an additional form submit format this could get invalid.
778 */
779 switch( mnFormsFormat )
780 {
781 case 1:
782 aContext.SubmitFormat = vcl::PDFWriter::PDF;
783 break;
784 case 2:
785 aContext.SubmitFormat = vcl::PDFWriter::HTML;
786 break;
787 case 3:
788 aContext.SubmitFormat = vcl::PDFWriter::XML;
789 break;
790 default:
791 case 0:
792 aContext.SubmitFormat = vcl::PDFWriter::FDF;
793 break;
794 }
795 aContext.AllowDuplicateFieldNames = mbAllowDuplicateFieldNames;
796
797 // get model
798 Reference< frame::XModel > xModel( mxSrcDoc, UNO_QUERY );
799 {
800 // #i56629: Relative link stuff
801 // set the base URL of the file: then base URL
802 aContext.BaseURL = xModel->getURL();
803 // relative link option is private to PDF Export filter and limited to local filesystem only
804 aContext.RelFsys = mbExportRelativeFsysLinks;
805 // determine the default acton for PDF links
806 switch( mnDefaultLinkAction )
807 {
808 default:
809 // default: URI, without fragment conversion (the bookmark in PDF may not work)
810 case 0:
811 aContext.DefaultLinkAction = vcl::PDFWriter::URIAction;
812 break;
813 case 1:
814 // view PDF through the reader application
815 aContext.ForcePDFAction = true;
816 aContext.DefaultLinkAction = vcl::PDFWriter::LaunchAction;
817 break;
818 case 2:
819 // view PDF through an Internet browser
820 aContext.DefaultLinkAction = vcl::PDFWriter::URIActionDestination;
821 break;
822 }
823 aContext.ConvertOOoTargetToPDFTarget = mbConvertOOoTargetToPDFTarget;
824
825 // check for Link Launch action, not allowed on PDF/A-1
826 // this code chunk checks when the filter is called from scripting
827 if( aContext.Version == vcl::PDFWriter::PDFVersion::PDF_A_1 &&
828 aContext.DefaultLinkAction == vcl::PDFWriter::LaunchAction )
829 {
830 // force the similar allowed URI action
831 aContext.DefaultLinkAction = vcl::PDFWriter::URIActionDestination;
832 // and remove the remote goto action forced on PDF file
833 aContext.ForcePDFAction = false;
834 }
835 }
836
837 aContext.SignPDF = mbSignPDF;
838 aContext.SignLocation = msSignLocation;
839 aContext.SignContact = msSignContact;
840 aContext.SignReason = msSignReason;
841 aContext.SignPassword = msSignPassword;
842 aContext.SignCertificate = maSignCertificate;
843 aContext.SignTSA = msSignTSA;
844 aContext.UseReferenceXObject = mbUseReferenceXObject;
845
846 // all context data set, time to create the printing device
847 vcl::PDFWriter aPDFWriter( aContext, xEnc );
848 OutputDevice* pOut = aPDFWriter.GetReferenceDevice();
849
850 DBG_ASSERT( pOut, "PDFExport::Export: no reference device" );
851 xDevice->SetOutputDevice(pOut);
852
853 if( mbAddStream )
854 {
855 // export stream
856 // get mimetype
857 OUString aSrcMimetype = getMimetypeForDocument( mxContext, mxSrcDoc );
858 aPDFWriter.AddStream( aSrcMimetype,
859 new PDFExportStreamDoc( mxSrcDoc, aPreparedPermissionPassword )
860 );
861 }
862
863 if ( pOut )
864 {
865 DBG_ASSERT( pOut->GetExtOutDevData() == nullptr, "PDFExport: ExtOutDevData already set!!!" );
866 vcl::PDFExtOutDevData aPDFExtOutDevData( *pOut );
867 pOut->SetExtOutDevData( &aPDFExtOutDevData );
868 aPDFExtOutDevData.SetIsExportNotes( mbExportNotes );
869 aPDFExtOutDevData.SetIsExportTaggedPDF( mbUseTaggedPDF );
870 aPDFExtOutDevData.SetIsExportTransitionEffects( mbUseTransitionEffects );
871 aPDFExtOutDevData.SetIsExportFormFields( mbExportFormFields );
872 aPDFExtOutDevData.SetIsExportBookmarks( mbExportBookmarks );
873 aPDFExtOutDevData.SetIsExportHiddenSlides( mbExportHiddenSlides );
874 aPDFExtOutDevData.SetIsSinglePageSheets( mbSinglePageSheets );
875 aPDFExtOutDevData.SetIsLosslessCompression( mbUseLosslessCompression );
876 aPDFExtOutDevData.SetCompressionQuality( mnQuality );
877 aPDFExtOutDevData.SetIsReduceImageResolution( mbReduceImageResolution );
878 aPDFExtOutDevData.SetIsExportNamedDestinations( mbExportBmkToDest );
879
880 Sequence< PropertyValue > aRenderOptions( 8 );
881 aRenderOptions[ 0 ].Name = "RenderDevice";
882 aRenderOptions[ 0 ].Value <<= uno::Reference<awt::XDevice>(xDevice);
883 aRenderOptions[ 1 ].Name = "ExportNotesPages";
884 aRenderOptions[ 1 ].Value <<= false;
885 Any& rExportNotesValue = aRenderOptions[ 1 ].Value;
886 aRenderOptions[ 2 ].Name = "IsFirstPage";
887 aRenderOptions[ 2 ].Value <<= true;
888 aRenderOptions[ 3 ].Name = "IsLastPage";
889 aRenderOptions[ 3 ].Value <<= false;
890 aRenderOptions[ 4 ].Name = "IsSkipEmptyPages";
891 aRenderOptions[ 4 ].Value <<= mbSkipEmptyPages;
892 aRenderOptions[ 5 ].Name = "PageRange";
893 aRenderOptions[ 5 ].Value <<= aPageRange;
894 aRenderOptions[ 6 ].Name = "ExportPlaceholders";
895 aRenderOptions[ 6 ].Value <<= mbExportPlaceholders;
896 aRenderOptions[ 7 ].Name = "SinglePageSheets";
897 aRenderOptions[ 7 ].Value <<= mbSinglePageSheets;
898
899 if( !aPageRange.isEmpty() || !aSelection.hasValue() )
900 {
901 aSelection = Any();
902 aSelection <<= mxSrcDoc;
903 }
904 bool bExportNotesPages = false;
905 bool bReChangeToNormalView = false;
906 static const OUStringLiteral sShowOnlineLayout( u"ShowOnlineLayout" );
907 bool bReHideWhitespace = false;
908 static const OUStringLiteral sHideWhitespace(u"HideWhitespace");
909 uno::Reference< beans::XPropertySet > xViewProperties;
910
911 if ( aCreator == "Writer" )
912 {
913 // #i92835: if Writer is in web layout mode this has to be switched to normal view and back to web view in the end
914 try
915 {
916 Reference< view::XViewSettingsSupplier > xVSettingsSupplier( xModel->getCurrentController(), uno::UNO_QUERY_THROW );
917 xViewProperties = xVSettingsSupplier->getViewSettings();
918 xViewProperties->getPropertyValue( sShowOnlineLayout ) >>= bReChangeToNormalView;
919 if( bReChangeToNormalView )
920 {
921 xViewProperties->setPropertyValue( sShowOnlineLayout, uno::makeAny( false ) );
922 }
923
924 // Also, disable hide-whitespace during export.
925 xViewProperties->getPropertyValue(sHideWhitespace) >>= bReHideWhitespace;
926 if (bReHideWhitespace)
927 {
928 xViewProperties->setPropertyValue(sHideWhitespace, uno::makeAny(false));
929 }
930 }
931 catch( const uno::Exception& )
932 {
933 }
934
935 }
936
937 const sal_Int32 nPageCount = xRenderable->getRendererCount( aSelection, aRenderOptions );
938
939 if ( mbExportNotesPages && aCreator == "Impress" )
940 {
941 uno::Reference< drawing::XShapes > xShapes; // do not allow to export notes when exporting a selection
942 if ( ! ( aSelection >>= xShapes ) )
943 bExportNotesPages = true;
944 }
945 const bool bExportPages = !bExportNotesPages || !mbExportOnlyNotesPages;
946
947 if( aPageRange.isEmpty() || mbSinglePageSheets)
948 {
949 aPageRange = OUString::number( 1 ) + "-" + OUString::number(nPageCount );
950 }
951 StringRangeEnumerator aRangeEnum( aPageRange, 0, nPageCount-1 );
952
953 if ( mxStatusIndicator.is() )
954 {
955 std::locale loc(Translate::Create("flt"));
956 sal_Int32 nTotalPageCount = aRangeEnum.size();
957 if ( bExportPages && bExportNotesPages )
958 nTotalPageCount *= 2;
959 mxStatusIndicator->start(Translate::get(PDF_PROGRESS_BAR, loc), nTotalPageCount);
960 }
961
962 bRet = nPageCount > 0;
963
964 if ( bRet && bExportPages )
965 bRet = ExportSelection( aPDFWriter, xRenderable, aSelection, aRangeEnum, aRenderOptions, nPageCount );
966
967 if ( bRet && bExportNotesPages )
968 {
969 rExportNotesValue <<= true;
970 bRet = ExportSelection( aPDFWriter, xRenderable, aSelection, aRangeEnum, aRenderOptions, nPageCount );
971 }
972 if ( mxStatusIndicator.is() )
973 mxStatusIndicator->end();
974
975 // if during the export the doc locale was set copy it to PDF writer
976 const css::lang::Locale& rLoc( aPDFExtOutDevData.GetDocumentLocale() );
977 if( !rLoc.Language.isEmpty() )
978 aPDFWriter.SetDocumentLocale( rLoc );
979
980 if( bRet )
981 {
982 aPDFExtOutDevData.PlayGlobalActions( aPDFWriter );
983 bRet = aPDFWriter.Emit();
984 aErrors = aPDFWriter.GetErrors();
985 }
986 pOut->SetExtOutDevData( nullptr );
987 if( bReChangeToNormalView )
988 {
989 try
990 {
991 xViewProperties->setPropertyValue( sShowOnlineLayout, uno::makeAny( true ) );
992 }
993 catch( const uno::Exception& )
994 {
995 }
996 }
997 if( bReHideWhitespace )
998 {
999 try
1000 {
1001 xViewProperties->setPropertyValue( sHideWhitespace, uno::makeAny( true ) );
1002 }
1003 catch( const uno::Exception& )
1004 {
1005 }
1006 }
1007 }
1008 }
1009 }
1010
1011 // show eventual errors during export
1012 showErrors( aErrors );
1013
1014 return bRet;
1015 }
1016
1017
1018 namespace
1019 {
1020
1021 typedef cppu::WeakComponentImplHelper< task::XInteractionRequest > PDFErrorRequestBase;
1022
1023 class PDFErrorRequest : private cppu::BaseMutex,
1024 public PDFErrorRequestBase
1025 {
1026 task::PDFExportException maExc;
1027 public:
1028 explicit PDFErrorRequest( const task::PDFExportException& i_rExc );
1029
1030 // XInteractionRequest
1031 virtual uno::Any SAL_CALL getRequest() override;
1032 virtual uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL getContinuations() override;
1033 };
1034
1035
PDFErrorRequest(const task::PDFExportException & i_rExc)1036 PDFErrorRequest::PDFErrorRequest( const task::PDFExportException& i_rExc ) :
1037 PDFErrorRequestBase( m_aMutex ),
1038 maExc( i_rExc )
1039 {
1040 }
1041
1042
getRequest()1043 uno::Any SAL_CALL PDFErrorRequest::getRequest()
1044 {
1045 osl::MutexGuard const guard( m_aMutex );
1046
1047 uno::Any aRet;
1048 aRet <<= maExc;
1049 return aRet;
1050 }
1051
1052
getContinuations()1053 uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL PDFErrorRequest::getContinuations()
1054 {
1055 return uno::Sequence< uno::Reference< task::XInteractionContinuation > >();
1056 }
1057
1058 } // end anonymous namespace
1059
1060
showErrors(const std::set<vcl::PDFWriter::ErrorCode> & rErrors)1061 void PDFExport::showErrors( const std::set< vcl::PDFWriter::ErrorCode >& rErrors )
1062 {
1063 if( ! rErrors.empty() && mxIH.is() )
1064 {
1065 task::PDFExportException aExc;
1066 aExc.ErrorCodes = comphelper::containerToSequence<sal_Int32>( rErrors );
1067 Reference< task::XInteractionRequest > xReq( new PDFErrorRequest( aExc ) );
1068 mxIH->handle( xReq );
1069 }
1070 }
1071
1072
ImplExportPage(vcl::PDFWriter & rWriter,vcl::PDFExtOutDevData & rPDFExtOutDevData,const GDIMetaFile & rMtf)1073 void PDFExport::ImplExportPage( vcl::PDFWriter& rWriter, vcl::PDFExtOutDevData& rPDFExtOutDevData, const GDIMetaFile& rMtf )
1074 {
1075 //Rectangle(Point, Size) creates a rectangle off by 1, use Rectangle(long, long, long, long) instead
1076 basegfx::B2DPolygon aSize(tools::Polygon(tools::Rectangle(0, 0, rMtf.GetPrefSize().Width(), rMtf.GetPrefSize().Height())).getB2DPolygon());
1077 basegfx::B2DPolygon aSizePDF(OutputDevice::LogicToLogic(aSize, rMtf.GetPrefMapMode(), MapMode(MapUnit::MapPoint)));
1078 basegfx::B2DRange aRangePDF(aSizePDF.getB2DRange());
1079 tools::Rectangle aPageRect( Point(), rMtf.GetPrefSize() );
1080
1081 rWriter.NewPage( aRangePDF.getWidth(), aRangePDF.getHeight() );
1082 rWriter.SetMapMode( rMtf.GetPrefMapMode() );
1083
1084 vcl::PDFWriter::PlayMetafileContext aCtx;
1085 GDIMetaFile aMtf;
1086 if( mbRemoveTransparencies )
1087 {
1088 aCtx.m_bTransparenciesWereRemoved = rWriter.GetReferenceDevice()->
1089 RemoveTransparenciesFromMetaFile( rMtf, aMtf, mnMaxImageResolution, mnMaxImageResolution,
1090 false, true, mbReduceImageResolution );
1091 // tdf#134736 if the metafile was replaced then rPDFExtOutDevData's PageSyncData mActions
1092 // all still point to MetaAction indexes in the original metafile that are now invalid.
1093 // Throw them all away in the absence of a way to reposition them to new positions of
1094 // their replacements.
1095 if (aCtx.m_bTransparenciesWereRemoved)
1096 rPDFExtOutDevData.ResetSyncData();
1097 }
1098 else
1099 {
1100 aMtf = rMtf;
1101 }
1102 aCtx.m_nMaxImageResolution = mbReduceImageResolution ? mnMaxImageResolution : 0;
1103 aCtx.m_bOnlyLosslessCompression = mbUseLosslessCompression;
1104 aCtx.m_nJPEGQuality = mnQuality;
1105
1106
1107 rWriter.SetClipRegion( basegfx::B2DPolyPolygon(
1108 basegfx::utils::createPolygonFromRect( vcl::unotools::b2DRectangleFromRectangle(aPageRect) ) ) );
1109
1110 rWriter.PlayMetafile( aMtf, aCtx, &rPDFExtOutDevData );
1111
1112 rPDFExtOutDevData.ResetSyncData();
1113
1114 if (!msWatermark.isEmpty())
1115 {
1116 ImplWriteWatermark( rWriter, Size(aRangePDF.getWidth(), aRangePDF.getHeight()) );
1117 }
1118 else if (!msTiledWatermark.isEmpty())
1119 {
1120 ImplWriteTiledWatermark( rWriter, Size(aRangePDF.getWidth(), aRangePDF.getHeight()) );
1121 }
1122 }
1123
1124
ImplWriteWatermark(vcl::PDFWriter & rWriter,const Size & rPageSize)1125 void PDFExport::ImplWriteWatermark( vcl::PDFWriter& rWriter, const Size& rPageSize )
1126 {
1127 vcl::Font aFont( "Helvetica", Size( 0, 3*rPageSize.Height()/4 ) );
1128 aFont.SetItalic( ITALIC_NONE );
1129 aFont.SetWidthType( WIDTH_NORMAL );
1130 aFont.SetWeight( WEIGHT_NORMAL );
1131 aFont.SetAlignment( ALIGN_BOTTOM );
1132 tools::Long nTextWidth = rPageSize.Width();
1133 if( rPageSize.Width() < rPageSize.Height() )
1134 {
1135 nTextWidth = rPageSize.Height();
1136 aFont.SetOrientation( 2700_deg10 );
1137 }
1138
1139 // adjust font height for text to fit
1140 OutputDevice* pDev = rWriter.GetReferenceDevice();
1141 pDev->Push();
1142 pDev->SetFont( aFont );
1143 pDev->SetMapMode( MapMode( MapUnit::MapPoint ) );
1144 int w = 0;
1145 while( ( w = pDev->GetTextWidth( msWatermark ) ) > nTextWidth )
1146 {
1147 if (w == 0)
1148 break;
1149 tools::Long nNewHeight = aFont.GetFontHeight() * nTextWidth / w;
1150 if( nNewHeight == aFont.GetFontHeight() )
1151 {
1152 nNewHeight--;
1153 if( nNewHeight <= 0 )
1154 break;
1155 }
1156 aFont.SetFontHeight( nNewHeight );
1157 pDev->SetFont( aFont );
1158 }
1159 tools::Long nTextHeight = pDev->GetTextHeight();
1160 // leave some maneuvering room for rounding issues, also
1161 // some fonts go a little outside ascent/descent
1162 nTextHeight += nTextHeight/20;
1163 pDev->Pop();
1164
1165 rWriter.Push();
1166 rWriter.SetMapMode( MapMode( MapUnit::MapPoint ) );
1167 rWriter.SetFont( aFont );
1168 rWriter.SetTextColor( COL_LIGHTGREEN );
1169 Point aTextPoint;
1170 tools::Rectangle aTextRect;
1171 if( rPageSize.Width() > rPageSize.Height() )
1172 {
1173 aTextPoint = Point( (rPageSize.Width()-w)/2,
1174 rPageSize.Height()-(rPageSize.Height()-nTextHeight)/2 );
1175 aTextRect = tools::Rectangle( Point( (rPageSize.Width()-w)/2,
1176 (rPageSize.Height()-nTextHeight)/2 ),
1177 Size( w, nTextHeight ) );
1178 }
1179 else
1180 {
1181 aTextPoint = Point( (rPageSize.Width()-nTextHeight)/2,
1182 (rPageSize.Height()-w)/2 );
1183 aTextRect = tools::Rectangle( aTextPoint, Size( nTextHeight, w ) );
1184 }
1185 rWriter.SetClipRegion();
1186 rWriter.BeginTransparencyGroup();
1187 rWriter.DrawText( aTextPoint, msWatermark );
1188 rWriter.EndTransparencyGroup( aTextRect, 50 );
1189 rWriter.Pop();
1190 }
1191
ImplWriteTiledWatermark(vcl::PDFWriter & rWriter,const Size & rPageSize)1192 void PDFExport::ImplWriteTiledWatermark( vcl::PDFWriter& rWriter, const Size& rPageSize )
1193 {
1194 OUString watermark = msTiledWatermark;
1195 // Maximum number of characters in one line.
1196 // it is set to 21 to make it look like tiled watermarks as online in secure view
1197 const int lineLength = 21;
1198 vcl::Font aFont( "Liberation Sans", Size( 0, 40 ) );
1199 aFont.SetItalic( ITALIC_NONE );
1200 aFont.SetWidthType( WIDTH_NORMAL );
1201 aFont.SetWeight( WEIGHT_NORMAL );
1202 aFont.SetAlignment( ALIGN_BOTTOM );
1203 aFont.SetFontHeight(40);
1204 aFont.SetOrientation(450_deg10);
1205
1206 OutputDevice* pDev = rWriter.GetReferenceDevice();
1207 pDev->SetFont(aFont);
1208 pDev->Push();
1209 pDev->SetFont(aFont);
1210 pDev->SetMapMode( MapMode( MapUnit::MapPoint ) );
1211 int w = 0;
1212 int watermarkcount = ((rPageSize.Width()) / 200)+1;
1213 tools::Long nTextWidth = rPageSize.Width() / (watermarkcount*1.5);
1214 OUString oneLineText = watermark;
1215
1216 if(watermark.getLength() > lineLength)
1217 oneLineText = watermark.copy(0, lineLength);
1218
1219 while((w = pDev->GetTextWidth(oneLineText)) > nTextWidth)
1220 {
1221 if(w==0)
1222 break;
1223
1224 tools::Long nNewHeight = aFont.GetFontHeight() * nTextWidth / w;
1225 aFont.SetFontHeight(nNewHeight);
1226 pDev->SetFont( aFont );
1227 }
1228 // maximum number of watermark count for the width
1229 if(watermarkcount > 8)
1230 watermarkcount = 8;
1231
1232 pDev->Pop();
1233
1234 rWriter.Push();
1235 rWriter.SetMapMode( MapMode( MapUnit::MapPoint ) );
1236 rWriter.SetFont(aFont);
1237 rWriter.SetTextColor( Color(19,20,22) );
1238 // center watermarks horizontally
1239 Point aTextPoint( (rPageSize.Width()/2) - (((nTextWidth*watermarkcount)+(watermarkcount-1)*nTextWidth)/2),
1240 pDev->GetTextHeight());
1241
1242 for( int i = 0; i < watermarkcount; i ++)
1243 {
1244 while(aTextPoint.getY()+pDev->GetTextHeight()*3 <= rPageSize.Height())
1245 {
1246 tools::Rectangle aTextRect(aTextPoint, Size(nTextWidth*2,pDev->GetTextHeight()*4));
1247
1248 pDev->Push();
1249 rWriter.SetClipRegion();
1250 rWriter.BeginTransparencyGroup();
1251 rWriter.SetTextColor( Color(19,20,22) );
1252 rWriter.DrawText(aTextRect, watermark, DrawTextFlags::MultiLine|DrawTextFlags::Center|DrawTextFlags::VCenter|DrawTextFlags::WordBreak|DrawTextFlags::Bottom);
1253 rWriter.EndTransparencyGroup( aTextRect, 50 );
1254 pDev->Pop();
1255
1256 pDev->Push();
1257 rWriter.SetClipRegion();
1258 rWriter.BeginTransparencyGroup();
1259 rWriter.SetTextColor( Color(236,235,233) );
1260 rWriter.DrawText(aTextRect, watermark, DrawTextFlags::MultiLine|DrawTextFlags::Center|DrawTextFlags::VCenter|DrawTextFlags::WordBreak|DrawTextFlags::Bottom);
1261 rWriter.EndTransparencyGroup( aTextRect, 50 );
1262 pDev->Pop();
1263
1264 aTextPoint.Move(0, pDev->GetTextHeight()*3);
1265 }
1266 aTextPoint=Point( aTextPoint.getX(), pDev->GetTextHeight() );
1267 aTextPoint.Move( nTextWidth*1.5, 0 );
1268 }
1269
1270 rWriter.Pop();
1271 }
1272
1273 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1274