/src/libreoffice/svx/source/unodraw/UnoGraphicExporter.cxx
Line | Count | Source |
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 | | #include <vector> |
21 | | #include <com/sun/star/io/XOutputStream.hpp> |
22 | | #include <com/sun/star/beans/XPropertySet.hpp> |
23 | | #include <com/sun/star/container/XChild.hpp> |
24 | | #include <com/sun/star/lang/XServiceInfo.hpp> |
25 | | #include <com/sun/star/lang/XComponent.hpp> |
26 | | #include <com/sun/star/drawing/XShape.hpp> |
27 | | #include <com/sun/star/drawing/XDrawPage.hpp> |
28 | | #include <com/sun/star/drawing/XGraphicExportFilter.hpp> |
29 | | #include <com/sun/star/graphic/XGraphic.hpp> |
30 | | #include <com/sun/star/graphic/XGraphicRenderer.hpp> |
31 | | #include <com/sun/star/task/XStatusIndicator.hpp> |
32 | | #include <com/sun/star/task/XInteractionHandler.hpp> |
33 | | #include <com/sun/star/task/XInteractionContinuation.hpp> |
34 | | #include <com/sun/star/uno/XComponentContext.hpp> |
35 | | |
36 | | #include <boost/property_tree/json_parser/error.hpp> |
37 | | #include <tools/debug.hxx> |
38 | | #include <comphelper/diagnose_ex.hxx> |
39 | | #include <tools/urlobj.hxx> |
40 | | #include <comphelper/interaction.hxx> |
41 | | #include <framework/interaction.hxx> |
42 | | #include <com/sun/star/drawing/GraphicFilterRequest.hpp> |
43 | | #include <com/sun/star/util/URL.hpp> |
44 | | #include <cppuhelper/implbase.hxx> |
45 | | #include <cppuhelper/supportsservice.hxx> |
46 | | #include <vcl/metaact.hxx> |
47 | | #include <vcl/rendercontext/DrawModeFlags.hxx> |
48 | | #include <vcl/svapp.hxx> |
49 | | #include <vcl/virdev.hxx> |
50 | | #include <svl/outstrm.hxx> |
51 | | #include <sdr/contact/objectcontactofobjlistpainter.hxx> |
52 | | #include <svx/sdr/contact/viewobjectcontact.hxx> |
53 | | #include <svx/sdr/contact/viewcontact.hxx> |
54 | | #include <svx/sdr/contact/displayinfo.hxx> |
55 | | #include <editeng/numitem.hxx> |
56 | | #include <svx/svdograf.hxx> |
57 | | #include <svx/xoutbmp.hxx> |
58 | | #include <vcl/graphicfilter.hxx> |
59 | | #include <svx/svdpage.hxx> |
60 | | #include <svx/svdmodel.hxx> |
61 | | #include <svx/fmview.hxx> |
62 | | #include <svx/fmmodel.hxx> |
63 | | #include <svx/unopage.hxx> |
64 | | #include <svx/svdoutl.hxx> |
65 | | #include <svx/xlineit0.hxx> |
66 | | #include <editeng/flditem.hxx> |
67 | | #include <svtools/optionsdrawinglayer.hxx> |
68 | | #include <comphelper/sequenceashashmap.hxx> |
69 | | #include <comphelper/propertysequence.hxx> |
70 | | #include <comphelper/sequence.hxx> |
71 | | #include <UnoGraphicExporter.hxx> |
72 | | #include <memory> |
73 | | // #i102251# |
74 | | #include <editeng/editstat.hxx> |
75 | | |
76 | 0 | #define MAX_EXT_PIX 2048 |
77 | | |
78 | | using namespace ::comphelper; |
79 | | using namespace ::cppu; |
80 | | using namespace ::com::sun::star; |
81 | | using namespace ::com::sun::star::uno; |
82 | | using namespace ::com::sun::star::util; |
83 | | using namespace ::com::sun::star::container; |
84 | | using namespace ::com::sun::star::drawing; |
85 | | using namespace ::com::sun::star::lang; |
86 | | using namespace ::com::sun::star::beans; |
87 | | using namespace ::com::sun::star::task; |
88 | | |
89 | | namespace { |
90 | | |
91 | | struct ExportSettings |
92 | | { |
93 | | OUString maFilterName; |
94 | | OUString maMediaType; |
95 | | URL maURL; |
96 | | css::uno::Reference< css::io::XOutputStream > mxOutputStream; |
97 | | css::uno::Reference< css::graphic::XGraphicRenderer > mxGraphicRenderer; |
98 | | css::uno::Reference< css::task::XStatusIndicator > mxStatusIndicator; |
99 | | css::uno::Reference< css::task::XInteractionHandler > mxInteractionHandler; |
100 | | |
101 | | sal_Int32 mnWidth; |
102 | | sal_Int32 mnHeight; |
103 | | bool mbExportOnlyBackground; |
104 | | bool mbScrollText; |
105 | | bool mbUseHighContrast; |
106 | | bool mbTranslucent; |
107 | | |
108 | | Sequence< PropertyValue > maFilterData; |
109 | | |
110 | | Fraction maScaleX; |
111 | | Fraction maScaleY; |
112 | | |
113 | | TriState meAntiAliasing = TRISTATE_INDET; |
114 | | |
115 | | explicit ExportSettings(); |
116 | | }; |
117 | | |
118 | | ExportSettings::ExportSettings() |
119 | 271 | : mnWidth( 0 ) |
120 | 271 | ,mnHeight( 0 ) |
121 | 271 | ,mbExportOnlyBackground( false ) |
122 | 271 | ,mbScrollText( false ) |
123 | 271 | ,mbUseHighContrast( false ) |
124 | 271 | ,mbTranslucent( false ) |
125 | 271 | ,maScaleX(1, 1) |
126 | 271 | ,maScaleY(1, 1) |
127 | 271 | { |
128 | 271 | } |
129 | | |
130 | | /** implements a component to export shapes or pages to external graphic formats. |
131 | | |
132 | | @implements com.sun.star.drawing.GraphicExportFilter |
133 | | */ |
134 | | class GraphicExporter : public ::cppu::WeakImplHelper< XGraphicExportFilter, XServiceInfo > |
135 | | { |
136 | | public: |
137 | | GraphicExporter(); |
138 | | |
139 | | // XFilter |
140 | | virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& aDescriptor ) override; |
141 | | virtual void SAL_CALL cancel( ) override; |
142 | | |
143 | | // XExporter |
144 | | virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) override; |
145 | | |
146 | | // XServiceInfo |
147 | | virtual OUString SAL_CALL getImplementationName( ) override; |
148 | | virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; |
149 | | virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; |
150 | | |
151 | | // XMimeTypeInfo |
152 | | virtual sal_Bool SAL_CALL supportsMimeType( const OUString& MimeTypeName ) override; |
153 | | virtual Sequence< OUString > SAL_CALL getSupportedMimeTypeNames( ) override; |
154 | | |
155 | | VclPtr<VirtualDevice> CreatePageVDev( SdrPage* pPage, tools::Long nWidthPixel, tools::Long nHeightPixel ) const; |
156 | | |
157 | | DECL_LINK( CalcFieldValueHdl, EditFieldInfo*, void ); |
158 | | |
159 | | void ParseSettings( const Sequence< PropertyValue >& aDescriptor, ExportSettings& rSettings ); |
160 | | bool GetGraphic( ExportSettings const & rSettings, Graphic& aGraphic, bool bVectorType ); |
161 | | |
162 | | private: |
163 | | Reference< XShape > mxShape; |
164 | | Reference< XDrawPage > mxPage; |
165 | | Reference< XShapes > mxShapes; |
166 | | Graphic maGraphic; |
167 | | |
168 | | SvxDrawPage* mpUnoPage; |
169 | | |
170 | | Link<EditFieldInfo*,void> maOldCalcFieldValueHdl; |
171 | | sal_Int32 mnPageNumber; |
172 | | SdrPage* mpCurrentPage; |
173 | | SdrModel* mpDoc; |
174 | | }; |
175 | | |
176 | | Size* CalcSize( sal_Int32 nWidth, sal_Int32 nHeight, const Size& aBoundSize, Size& aOutSize ) |
177 | 0 | { |
178 | 0 | if( (nWidth == 0) && (nHeight == 0) ) |
179 | 0 | return nullptr; |
180 | | |
181 | 0 | if( (nWidth == 0) && (nHeight != 0) && (aBoundSize.Height() != 0) ) |
182 | 0 | { |
183 | 0 | nWidth = ( nHeight * aBoundSize.Width() ) / aBoundSize.Height(); |
184 | 0 | } |
185 | 0 | else if( (nWidth != 0) && (nHeight == 0) && (aBoundSize.Width() != 0) ) |
186 | 0 | { |
187 | 0 | nHeight = ( nWidth * aBoundSize.Height() ) / aBoundSize.Width(); |
188 | 0 | } |
189 | |
|
190 | 0 | aOutSize.setWidth( nWidth ); |
191 | 0 | aOutSize.setHeight( nHeight ); |
192 | |
|
193 | 0 | return &aOutSize; |
194 | 0 | } |
195 | | |
196 | | class ImplExportCheckVisisbilityRedirector : public sdr::contact::ViewObjectContactRedirector |
197 | | { |
198 | | public: |
199 | | explicit ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage ); |
200 | | |
201 | | virtual void createRedirectedPrimitive2DSequence( |
202 | | const sdr::contact::ViewObjectContact& rOriginal, |
203 | | const sdr::contact::DisplayInfo& rDisplayInfo, |
204 | | drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) override; |
205 | | |
206 | | private: |
207 | | SdrPage* mpCurrentPage; |
208 | | }; |
209 | | |
210 | | ImplExportCheckVisisbilityRedirector::ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage ) |
211 | 271 | : mpCurrentPage( pCurrentPage ) |
212 | 271 | { |
213 | 271 | } |
214 | | |
215 | | void ImplExportCheckVisisbilityRedirector::createRedirectedPrimitive2DSequence( |
216 | | const sdr::contact::ViewObjectContact& rOriginal, |
217 | | const sdr::contact::DisplayInfo& rDisplayInfo, |
218 | | drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) |
219 | 863 | { |
220 | 863 | SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject(); |
221 | | |
222 | 863 | if(pObject) |
223 | 863 | { |
224 | 863 | SdrPage* pPage = mpCurrentPage; |
225 | | |
226 | 863 | if(nullptr == pPage) |
227 | 863 | { |
228 | 863 | pPage = pObject->getSdrPageFromSdrObject(); |
229 | 863 | } |
230 | | |
231 | 863 | if( (pPage == nullptr) || pPage->checkVisibility(rOriginal, rDisplayInfo, false) ) |
232 | 863 | { |
233 | 863 | return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo, rVisitor); |
234 | 863 | } |
235 | | |
236 | 0 | return; |
237 | 863 | } |
238 | 0 | else |
239 | 0 | { |
240 | | // not an object, maybe a page |
241 | 0 | sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo, rVisitor); |
242 | 0 | } |
243 | 863 | } |
244 | | |
245 | | GraphicExporter::GraphicExporter() |
246 | 271 | : mpUnoPage( nullptr ), mnPageNumber(-1), mpCurrentPage(nullptr), mpDoc( nullptr ) |
247 | 271 | { |
248 | 271 | } |
249 | | |
250 | | IMPL_LINK(GraphicExporter, CalcFieldValueHdl, EditFieldInfo*, pInfo, void) |
251 | 0 | { |
252 | 0 | if( pInfo ) |
253 | 0 | { |
254 | 0 | if( mpCurrentPage ) |
255 | 0 | { |
256 | 0 | pInfo->SetSdrPage( mpCurrentPage ); |
257 | 0 | } |
258 | 0 | else if( mnPageNumber != -1 ) |
259 | 0 | { |
260 | 0 | const SvxFieldData* pField = pInfo->GetField().GetField(); |
261 | 0 | if( dynamic_cast<const SvxPageField*>( pField) ) |
262 | 0 | { |
263 | 0 | OUString aPageNumValue; |
264 | 0 | bool bUpper = false; |
265 | |
|
266 | 0 | switch(mpDoc->GetPageNumType()) |
267 | 0 | { |
268 | 0 | case css::style::NumberingType::CHARS_UPPER_LETTER: |
269 | 0 | aPageNumValue += OUStringChar( sal_Unicode((mnPageNumber - 1) % 26 + 'A') ); |
270 | 0 | break; |
271 | 0 | case css::style::NumberingType::CHARS_LOWER_LETTER: |
272 | 0 | aPageNumValue += OUStringChar( sal_Unicode((mnPageNumber - 1) % 26 + 'a') ); |
273 | 0 | break; |
274 | 0 | case css::style::NumberingType::ROMAN_UPPER: |
275 | 0 | bUpper = true; |
276 | 0 | [[fallthrough]]; |
277 | 0 | case css::style::NumberingType::ROMAN_LOWER: |
278 | 0 | aPageNumValue += SvxNumberFormat::CreateRomanString(mnPageNumber, bUpper); |
279 | 0 | break; |
280 | 0 | case css::style::NumberingType::NUMBER_NONE: |
281 | 0 | aPageNumValue = " "; |
282 | 0 | break; |
283 | 0 | default: |
284 | 0 | aPageNumValue += OUString::number( mnPageNumber ); |
285 | 0 | } |
286 | | |
287 | 0 | pInfo->SetRepresentation( aPageNumValue ); |
288 | |
|
289 | 0 | return; |
290 | 0 | } |
291 | 0 | } |
292 | 0 | } |
293 | | |
294 | 0 | maOldCalcFieldValueHdl.Call( pInfo ); |
295 | |
|
296 | 0 | if( pInfo && mpCurrentPage ) |
297 | 0 | pInfo->SetSdrPage( nullptr ); |
298 | 0 | } |
299 | | |
300 | | /** creates a virtual device for the given page |
301 | | |
302 | | @return the returned VirtualDevice is owned by the caller |
303 | | */ |
304 | | VclPtr<VirtualDevice> GraphicExporter::CreatePageVDev( SdrPage* pPage, tools::Long nWidthPixel, tools::Long nHeightPixel ) const |
305 | 0 | { |
306 | 0 | VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create(); |
307 | 0 | MapMode aMM( MapUnit::Map100thMM ); |
308 | |
|
309 | 0 | Point aPoint( 0, 0 ); |
310 | 0 | Size aPageSize(pPage->GetSize()); |
311 | | |
312 | | // use scaling? |
313 | 0 | if( nWidthPixel != 0 ) |
314 | 0 | { |
315 | 0 | const Fraction aFrac( nWidthPixel, pVDev->LogicToPixel( aPageSize, aMM ).Width() ); |
316 | |
|
317 | 0 | aMM.SetScaleX( aFrac ); |
318 | |
|
319 | 0 | if( nHeightPixel == 0 ) |
320 | 0 | aMM.SetScaleY( aFrac ); |
321 | 0 | } |
322 | |
|
323 | 0 | if( nHeightPixel != 0 ) |
324 | 0 | { |
325 | 0 | const Fraction aFrac( nHeightPixel, pVDev->LogicToPixel( aPageSize, aMM ).Height() ); |
326 | |
|
327 | 0 | if( nWidthPixel == 0 ) |
328 | 0 | aMM.SetScaleX( aFrac ); |
329 | |
|
330 | 0 | aMM.SetScaleY( aFrac ); |
331 | 0 | } |
332 | |
|
333 | 0 | pVDev->SetMapMode( aMM ); |
334 | 0 | bool bSuccess(false); |
335 | | |
336 | | // #i122820# If available, use pixel size directly |
337 | 0 | if(nWidthPixel && nHeightPixel) |
338 | 0 | { |
339 | 0 | bSuccess = pVDev->SetOutputSizePixel(Size(nWidthPixel, nHeightPixel)); |
340 | 0 | } |
341 | 0 | else |
342 | 0 | { |
343 | 0 | bSuccess = pVDev->SetOutputSize(aPageSize); |
344 | 0 | } |
345 | |
|
346 | 0 | if(bSuccess) |
347 | 0 | { |
348 | 0 | SdrView aView(*mpDoc, pVDev); |
349 | |
|
350 | 0 | aView.SetPageVisible( false ); |
351 | 0 | aView.SetBordVisible( false ); |
352 | 0 | aView.SetGridVisible( false ); |
353 | 0 | aView.SetHlplVisible( false ); |
354 | 0 | aView.SetGlueVisible( false ); |
355 | 0 | aView.ShowSdrPage(pPage); |
356 | |
|
357 | 0 | vcl::Region aRegion (tools::Rectangle( aPoint, aPageSize ) ); |
358 | |
|
359 | 0 | ImplExportCheckVisisbilityRedirector aRedirector( mpCurrentPage ); |
360 | |
|
361 | 0 | aView.CompleteRedraw(pVDev, aRegion, &aRedirector); |
362 | 0 | } |
363 | 0 | else |
364 | 0 | { |
365 | 0 | OSL_ENSURE(false, "Could not get a VirtualDevice of requested size (!)"); |
366 | 0 | } |
367 | |
|
368 | 0 | return pVDev; |
369 | 0 | } |
370 | | |
371 | | void GraphicExporter::ParseSettings(const Sequence<PropertyValue>& rDescriptor, |
372 | | ExportSettings& rSettings) |
373 | 271 | { |
374 | 271 | Sequence<PropertyValue> aDescriptor = rDescriptor; |
375 | 271 | if (aDescriptor.hasElements()) |
376 | 271 | { |
377 | 271 | comphelper::SequenceAsHashMap aMap(aDescriptor); |
378 | 271 | Sequence<PropertyValue> aFilterData; |
379 | 271 | OUString aFilterOptions; |
380 | 271 | auto it = aMap.find(u"FilterData"_ustr); |
381 | 271 | if (it != aMap.end()) |
382 | 271 | { |
383 | 271 | it->second >>= aFilterData; |
384 | 271 | } |
385 | 271 | it = aMap.find(u"FilterOptions"_ustr); |
386 | 271 | if (it != aMap.end()) |
387 | 0 | { |
388 | 0 | it->second >>= aFilterOptions; |
389 | 0 | } |
390 | 271 | if (!aFilterData.hasElements() && !aFilterOptions.isEmpty()) |
391 | 0 | { |
392 | | // Allow setting filter data keys from the cmdline. |
393 | 0 | try |
394 | 0 | { |
395 | 0 | std::vector<PropertyValue> aData |
396 | 0 | = comphelper::JsonToPropertyValues(aFilterOptions.toUtf8()); |
397 | 0 | aFilterData = comphelper::containerToSequence(aData); |
398 | 0 | } |
399 | 0 | catch (const boost::property_tree::json_parser::json_parser_error&) |
400 | 0 | { |
401 | | // This wasn't a valid json; maybe came from import filter (tdf#162528) |
402 | 0 | } |
403 | 0 | if (aFilterData.hasElements()) |
404 | 0 | { |
405 | 0 | aMap[u"FilterData"_ustr] <<= aFilterData; |
406 | 0 | aDescriptor = aMap.getAsConstPropertyValueList(); |
407 | 0 | } |
408 | 0 | } |
409 | 271 | } |
410 | | |
411 | 271 | for( const PropertyValue& rValue : aDescriptor ) |
412 | 813 | { |
413 | 813 | if ( rValue.Name == "FilterName" ) |
414 | 271 | { |
415 | 271 | rValue.Value >>= rSettings.maFilterName; |
416 | 271 | } |
417 | 542 | else if ( rValue.Name == "MediaType" ) |
418 | 0 | { |
419 | 0 | rValue.Value >>= rSettings.maMediaType; |
420 | 0 | } |
421 | 542 | else if ( rValue.Name == "URL" ) |
422 | 0 | { |
423 | 0 | if( !( rValue.Value >>= rSettings.maURL ) ) |
424 | 0 | { |
425 | 0 | rValue.Value >>= rSettings.maURL.Complete; |
426 | 0 | } |
427 | 0 | } |
428 | 542 | else if ( rValue.Name == "OutputStream" ) |
429 | 271 | { |
430 | 271 | rValue.Value >>= rSettings.mxOutputStream; |
431 | 271 | } |
432 | 271 | else if ( rValue.Name == "GraphicRenderer" ) |
433 | 0 | { |
434 | 0 | rValue.Value >>= rSettings.mxGraphicRenderer; |
435 | 0 | } |
436 | 271 | else if ( rValue.Name == "StatusIndicator" ) |
437 | 0 | { |
438 | 0 | rValue.Value >>= rSettings.mxStatusIndicator; |
439 | 0 | } |
440 | 271 | else if ( rValue.Name == "InteractionHandler" ) |
441 | 0 | { |
442 | 0 | rValue.Value >>= rSettings.mxInteractionHandler; |
443 | 0 | } |
444 | 271 | else if( rValue.Name == "Width" ) // for compatibility reasons, deprecated |
445 | 0 | { |
446 | 0 | rValue.Value >>= rSettings.mnWidth; |
447 | 0 | } |
448 | 271 | else if( rValue.Name == "Height" ) // for compatibility reasons, deprecated |
449 | 0 | { |
450 | 0 | rValue.Value >>= rSettings.mnHeight; |
451 | 0 | } |
452 | 271 | else if( rValue.Name == "ExportOnlyBackground" ) // for compatibility reasons, deprecated |
453 | 0 | { |
454 | 0 | rValue.Value >>= rSettings.mbExportOnlyBackground; |
455 | 0 | } |
456 | 271 | else if ( rValue.Name == "FilterData" ) |
457 | 271 | { |
458 | 271 | rValue.Value >>= rSettings.maFilterData; |
459 | | |
460 | 271 | for( PropertyValue& rDataValue : asNonConstRange(rSettings.maFilterData) ) |
461 | 1.08k | { |
462 | 1.08k | if ( rDataValue.Name == "Translucent" ) |
463 | 0 | { |
464 | 0 | if ( !( rDataValue.Value >>= rSettings.mbTranslucent ) ) // SJ: TODO: The GIF Transparency is stored as int32 in |
465 | 0 | { // configuration files, this has to be changed to boolean |
466 | 0 | sal_Int32 nTranslucent = 0; |
467 | 0 | if ( rDataValue.Value >>= nTranslucent ) |
468 | 0 | rSettings.mbTranslucent = nTranslucent != 0; |
469 | 0 | } |
470 | 0 | } |
471 | 1.08k | else if ( rDataValue.Name == "PixelWidth" ) |
472 | 271 | { |
473 | 271 | rDataValue.Value >>= rSettings.mnWidth; |
474 | 271 | } |
475 | 813 | else if ( rDataValue.Name == "PixelHeight" ) |
476 | 271 | { |
477 | 271 | rDataValue.Value >>= rSettings.mnHeight; |
478 | 271 | } |
479 | 542 | else if( rDataValue.Name == "Width" ) // for compatibility reasons, deprecated |
480 | 0 | { |
481 | 0 | rDataValue.Value >>= rSettings.mnWidth; |
482 | 0 | rDataValue.Name = "PixelWidth"; |
483 | 0 | } |
484 | 542 | else if( rDataValue.Name == "Height" ) // for compatibility reasons, deprecated |
485 | 0 | { |
486 | 0 | rDataValue.Value >>= rSettings.mnHeight; |
487 | 0 | rDataValue.Name = "PixelHeight"; |
488 | 0 | } |
489 | 542 | else if ( rDataValue.Name == "ExportOnlyBackground" ) |
490 | 0 | { |
491 | 0 | rDataValue.Value >>= rSettings.mbExportOnlyBackground; |
492 | 0 | } |
493 | 542 | else if ( rDataValue.Name == "HighContrast" ) |
494 | 0 | { |
495 | 0 | rDataValue.Value >>= rSettings.mbUseHighContrast; |
496 | 0 | } |
497 | 542 | else if ( rDataValue.Name == "PageNumber" ) |
498 | 0 | { |
499 | 0 | rDataValue.Value >>= mnPageNumber; |
500 | 0 | } |
501 | 542 | else if ( rDataValue.Name == "ScrollText" ) |
502 | 0 | { |
503 | | // #110496# Read flag solitary scroll text metafile |
504 | 0 | rDataValue.Value >>= rSettings.mbScrollText; |
505 | 0 | } |
506 | 542 | else if ( rDataValue.Name == "CurrentPage" ) |
507 | 0 | { |
508 | 0 | Reference< XDrawPage > xPage; |
509 | 0 | rDataValue.Value >>= xPage; |
510 | 0 | if( xPage.is() ) |
511 | 0 | { |
512 | 0 | SvxDrawPage* pUnoPage = comphelper::getFromUnoTunnel<SvxDrawPage>( xPage ); |
513 | 0 | if( pUnoPage && pUnoPage->GetSdrPage() ) |
514 | 0 | mpCurrentPage = pUnoPage->GetSdrPage(); |
515 | 0 | } |
516 | 0 | } |
517 | 542 | else if ( rDataValue.Name == "ScaleXNumerator" ) |
518 | 0 | { |
519 | 0 | sal_Int32 nVal = 1; |
520 | 0 | if( rDataValue.Value >>= nVal ) |
521 | 0 | rSettings.maScaleX = Fraction( nVal, rSettings.maScaleX.GetDenominator() ); |
522 | 0 | } |
523 | 542 | else if ( rDataValue.Name == "ScaleXDenominator" ) |
524 | 0 | { |
525 | 0 | sal_Int32 nVal = 1; |
526 | 0 | if( rDataValue.Value >>= nVal ) |
527 | 0 | rSettings.maScaleX = Fraction( rSettings.maScaleX.GetNumerator(), nVal ); |
528 | 0 | } |
529 | 542 | else if ( rDataValue.Name == "ScaleYNumerator" ) |
530 | 0 | { |
531 | 0 | sal_Int32 nVal = 1; |
532 | 0 | if( rDataValue.Value >>= nVal ) |
533 | 0 | rSettings.maScaleY = Fraction( nVal, rSettings.maScaleY.GetDenominator() ); |
534 | 0 | } |
535 | 542 | else if ( rDataValue.Name == "ScaleYDenominator" ) |
536 | 0 | { |
537 | 0 | sal_Int32 nVal = 1; |
538 | 0 | if( rDataValue.Value >>= nVal ) |
539 | 0 | rSettings.maScaleY = Fraction( rSettings.maScaleY.GetNumerator(), nVal ); |
540 | 0 | } |
541 | 542 | else if (rDataValue.Name == "AntiAliasing") |
542 | 0 | { |
543 | 0 | bool bAntiAliasing; |
544 | 0 | if (rDataValue.Value >>= bAntiAliasing) |
545 | 0 | rSettings.meAntiAliasing = bAntiAliasing ? TRISTATE_TRUE : TRISTATE_FALSE; |
546 | 0 | } |
547 | 1.08k | } |
548 | 271 | } |
549 | 813 | } |
550 | | |
551 | | // putting the StatusIndicator that we got from the MediaDescriptor into our local FilterData copy |
552 | 271 | if ( rSettings.mxStatusIndicator.is() ) |
553 | 0 | { |
554 | 0 | int i = rSettings.maFilterData.getLength(); |
555 | 0 | rSettings.maFilterData.realloc( i + 1 ); |
556 | 0 | auto pFilterData = rSettings.maFilterData.getArray(); |
557 | 0 | pFilterData[ i ].Name = "StatusIndicator"; |
558 | 0 | pFilterData[ i ].Value <<= rSettings.mxStatusIndicator; |
559 | 0 | } |
560 | 271 | } |
561 | | |
562 | | bool GraphicExporter::GetGraphic( ExportSettings const & rSettings, Graphic& aGraphic, bool bVectorType ) |
563 | 271 | { |
564 | 271 | if( !mpDoc || !mpUnoPage ) |
565 | 0 | return false; |
566 | | |
567 | 271 | SdrPage* pPage = mpUnoPage->GetSdrPage(); |
568 | 271 | if( !pPage ) |
569 | 0 | return false; |
570 | | |
571 | 271 | ScopedVclPtrInstance< VirtualDevice > aVDev; |
572 | 271 | const MapMode aMap( mpDoc->GetScaleUnit(), Point(), rSettings.maScaleX, rSettings.maScaleY ); |
573 | | |
574 | 271 | SdrOutliner& rOutl=mpDoc->GetDrawOutliner(); |
575 | 271 | maOldCalcFieldValueHdl = rOutl.GetCalcFieldValueHdl(); |
576 | 271 | rOutl.SetCalcFieldValueHdl( LINK(this, GraphicExporter, CalcFieldValueHdl) ); |
577 | 271 | ::Color aOldBackColor(rOutl.GetBackgroundColor()); |
578 | 271 | rOutl.SetBackgroundColor(pPage->GetPageBackgroundColor()); |
579 | | |
580 | | // #i102251# |
581 | 271 | const EEControlBits nOldCntrl(rOutl.GetControlWord()); |
582 | 271 | EEControlBits nCntrl = nOldCntrl & ~EEControlBits::ONLINESPELLING; |
583 | 271 | rOutl.SetControlWord(nCntrl); |
584 | | |
585 | 271 | rtl::Reference<SdrObject> pTempBackgroundShape; |
586 | 271 | std::vector< SdrObject* > aShapes; |
587 | 271 | bool bRet = true; |
588 | | |
589 | | // export complete page? |
590 | 271 | if ( !mxShape.is() ) |
591 | 0 | { |
592 | 0 | if( rSettings.mbExportOnlyBackground ) |
593 | 0 | { |
594 | 0 | const SdrPageProperties* pCorrectProperties = pPage->getCorrectSdrPageProperties(); |
595 | |
|
596 | 0 | if(pCorrectProperties) |
597 | 0 | { |
598 | 0 | pTempBackgroundShape = new SdrRectObj( |
599 | 0 | *mpDoc, |
600 | 0 | tools::Rectangle(Point(0,0), pPage->GetSize())); |
601 | 0 | pTempBackgroundShape->SetMergedItemSet(pCorrectProperties->GetItemSet()); |
602 | 0 | pTempBackgroundShape->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE)); |
603 | 0 | pTempBackgroundShape->NbcSetStyleSheet(pCorrectProperties->GetStyleSheet(), true); |
604 | 0 | aShapes.push_back(pTempBackgroundShape.get()); |
605 | 0 | } |
606 | 0 | } |
607 | 0 | else |
608 | 0 | { |
609 | 0 | const Size aSize( pPage->GetSize() ); |
610 | | |
611 | | // generate a bitmap to convert it to a pixel format. |
612 | | // For gif pictures there can also be a vector format used (bTranslucent) |
613 | 0 | if ( !bVectorType && !rSettings.mbTranslucent ) |
614 | 0 | { |
615 | 0 | tools::Long nWidthPix = 0; |
616 | 0 | tools::Long nHeightPix = 0; |
617 | 0 | if ( rSettings.mnWidth > 0 && rSettings.mnHeight > 0 ) |
618 | 0 | { |
619 | 0 | nWidthPix = rSettings.mnWidth; |
620 | 0 | nHeightPix = rSettings.mnHeight; |
621 | 0 | } |
622 | 0 | else |
623 | 0 | { |
624 | 0 | const Size aSizePix( Application::GetDefaultDevice()->LogicToPixel( aSize, aMap ) ); |
625 | 0 | if (aSizePix.Width() > MAX_EXT_PIX || aSizePix.Height() > MAX_EXT_PIX) |
626 | 0 | { |
627 | 0 | if (aSizePix.Width() > MAX_EXT_PIX) |
628 | 0 | nWidthPix = MAX_EXT_PIX; |
629 | 0 | else |
630 | 0 | nWidthPix = aSizePix.Width(); |
631 | 0 | if (aSizePix.Height() > MAX_EXT_PIX) |
632 | 0 | nHeightPix = MAX_EXT_PIX; |
633 | 0 | else |
634 | 0 | nHeightPix = aSizePix.Height(); |
635 | |
|
636 | 0 | double fWidthDif = static_cast<double>(aSizePix.Width()) / nWidthPix; |
637 | 0 | double fHeightDif = static_cast<double>(aSizePix.Height()) / nHeightPix; |
638 | |
|
639 | 0 | if (fWidthDif > fHeightDif) |
640 | 0 | nHeightPix = static_cast<tools::Long>(aSizePix.Height() / fWidthDif); |
641 | 0 | else |
642 | 0 | nWidthPix = static_cast<tools::Long>(aSizePix.Width() / fHeightDif); |
643 | 0 | } |
644 | 0 | else |
645 | 0 | { |
646 | 0 | nWidthPix = aSizePix.Width(); |
647 | 0 | nHeightPix = aSizePix.Height(); |
648 | 0 | } |
649 | 0 | } |
650 | |
|
651 | 0 | std::unique_ptr<SdrView> xLocalView; |
652 | |
|
653 | 0 | if (FmFormModel* pFormModel = dynamic_cast<FmFormModel*>(mpDoc)) |
654 | 0 | { |
655 | 0 | xLocalView.reset(new FmFormView(*pFormModel, aVDev)); |
656 | 0 | } |
657 | 0 | else |
658 | 0 | { |
659 | 0 | xLocalView.reset(new SdrView(*mpDoc, aVDev)); |
660 | 0 | } |
661 | |
|
662 | 0 | ScopedVclPtr<VirtualDevice> pVDev(CreatePageVDev( pPage, nWidthPix, nHeightPix )); |
663 | |
|
664 | 0 | if( pVDev ) |
665 | 0 | { |
666 | 0 | aGraphic = pVDev->GetBitmap( Point(), pVDev->GetOutputSize() ); |
667 | 0 | aGraphic.SetPrefMapMode( aMap ); |
668 | 0 | aGraphic.SetPrefSize( aSize ); |
669 | 0 | } |
670 | 0 | } |
671 | | // create a metafile to export a vector format |
672 | 0 | else |
673 | 0 | { |
674 | 0 | GDIMetaFile aMtf; |
675 | |
|
676 | 0 | aVDev->SetMapMode( aMap ); |
677 | 0 | if( rSettings.mbUseHighContrast ) |
678 | 0 | aVDev->SetDrawMode( aVDev->GetDrawMode() | DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient ); |
679 | 0 | aVDev->EnableOutput( false ); |
680 | 0 | aMtf.Record( aVDev ); |
681 | 0 | Size aNewSize; |
682 | | |
683 | | // create a view |
684 | 0 | std::unique_ptr< SdrView > pView; |
685 | |
|
686 | 0 | if (FmFormModel *pFormModel = dynamic_cast<FmFormModel*>(mpDoc)) |
687 | 0 | { |
688 | 0 | pView.reset(new FmFormView(*pFormModel, aVDev)); |
689 | 0 | } |
690 | 0 | else |
691 | 0 | { |
692 | 0 | pView.reset(new SdrView(*mpDoc, aVDev)); |
693 | 0 | } |
694 | |
|
695 | 0 | pView->SetBordVisible( false ); |
696 | 0 | pView->SetPageVisible( false ); |
697 | 0 | pView->ShowSdrPage( pPage ); |
698 | | |
699 | | // tdf#96922 deactivate EditView PageVisualization, including PageBackground |
700 | | // (formerly 'wiese'). Do *not* switch off MasterPageVisualizationAllowed, we |
701 | | // want MasterPage content if a whole SdrPage is exported |
702 | 0 | pView->SetPageDecorationAllowed(false); |
703 | |
|
704 | 0 | const Point aNewOrg( pPage->GetLeftBorder(), pPage->GetUpperBorder() ); |
705 | 0 | aNewSize = Size( aSize.Width() - pPage->GetLeftBorder() - pPage->GetRightBorder(), |
706 | 0 | aSize.Height() - pPage->GetUpperBorder() - pPage->GetLowerBorder() ); |
707 | 0 | const tools::Rectangle aClipRect( aNewOrg, aNewSize ); |
708 | 0 | MapMode aVMap( aMap ); |
709 | |
|
710 | 0 | aVDev->Push(); |
711 | 0 | aVMap.SetOrigin( Point( -aNewOrg.X(), -aNewOrg.Y() ) ); |
712 | 0 | aVDev->SetRelativeMapMode( aVMap ); |
713 | 0 | aVDev->IntersectClipRegion( aClipRect ); |
714 | | |
715 | | // Use new StandardCheckVisisbilityRedirector |
716 | 0 | ImplExportCheckVisisbilityRedirector aRedirector( mpCurrentPage ); |
717 | |
|
718 | 0 | pView->CompleteRedraw(aVDev, vcl::Region(tools::Rectangle(aNewOrg, aNewSize)), &aRedirector); |
719 | |
|
720 | 0 | aVDev->Pop(); |
721 | |
|
722 | 0 | aMtf.Stop(); |
723 | 0 | aMtf.WindStart(); |
724 | 0 | aMtf.SetPrefMapMode( aMap ); |
725 | 0 | aMtf.SetPrefSize( aNewSize ); |
726 | | |
727 | | // AW: Here the current version was filtering out the MetaActionType::CLIPREGIONs |
728 | | // from the metafile. I asked some other developers why this was done, but no |
729 | | // one knew a direct reason. Since it's in for long time, it may be an old |
730 | | // piece of code. MetaFiles save and load ClipRegions with polygons with preserving |
731 | | // the polygons, so a resolution-independent roundtrip is supported. Removed this |
732 | | // code since it destroys some MetaFiles where ClipRegions are used. Anyways, |
733 | | // just filtering them out is a hack, at least the encapsulated content would need |
734 | | // to be clipped geometrically. |
735 | 0 | aGraphic = Graphic(aMtf); |
736 | |
|
737 | 0 | pView->HideSdrPage(); |
738 | |
|
739 | 0 | if( rSettings.mbTranslucent ) |
740 | 0 | { |
741 | 0 | Size aOutSize; |
742 | 0 | aGraphic = GetBitmapFromMetaFile( aGraphic.GetGDIMetaFile(), CalcSize( rSettings.mnWidth, rSettings.mnHeight, aNewSize, aOutSize ) ); |
743 | 0 | } |
744 | 0 | } |
745 | 0 | } |
746 | 0 | } |
747 | | |
748 | | // export only single shape or shape collection |
749 | 271 | else |
750 | 271 | { |
751 | | // build list of SdrObject |
752 | 271 | if( mxShapes.is() ) |
753 | 0 | { |
754 | 0 | Reference< XShape > xShape; |
755 | 0 | const sal_Int32 nCount = mxShapes->getCount(); |
756 | |
|
757 | 0 | for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ ) |
758 | 0 | { |
759 | 0 | mxShapes->getByIndex( nIndex ) >>= xShape; |
760 | 0 | SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xShape); |
761 | 0 | if( pObj ) |
762 | 0 | aShapes.push_back( pObj ); |
763 | 0 | } |
764 | 0 | } |
765 | 271 | else |
766 | 271 | { |
767 | | // only one shape |
768 | 271 | SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mxShape); |
769 | 271 | if( pObj ) |
770 | 271 | aShapes.push_back( pObj ); |
771 | 271 | } |
772 | | |
773 | 271 | if( aShapes.empty() ) |
774 | 0 | bRet = false; |
775 | 271 | } |
776 | | |
777 | 271 | if( bRet && !aShapes.empty() ) |
778 | 271 | { |
779 | | // special treatment for only one SdrGrafObj that has text |
780 | 271 | bool bSingleGraphic = false; |
781 | | |
782 | 271 | if( 1 == aShapes.size() ) |
783 | 271 | { |
784 | 271 | if( !bVectorType ) |
785 | 0 | { |
786 | 0 | if( auto pGrafObj = dynamic_cast<const SdrGrafObj*>(aShapes.front()) ) |
787 | 0 | if (pGrafObj->HasText() ) |
788 | 0 | { |
789 | 0 | aGraphic = pGrafObj->GetTransformedGraphic(); |
790 | 0 | if ( aGraphic.GetType() == GraphicType::Bitmap ) |
791 | 0 | { |
792 | 0 | Size aSizePixel( aGraphic.GetSizePixel() ); |
793 | 0 | if( rSettings.mnWidth && rSettings.mnHeight && |
794 | 0 | ( ( rSettings.mnWidth != aSizePixel.Width() ) || |
795 | 0 | ( rSettings.mnHeight != aSizePixel.Height() ) ) ) |
796 | 0 | { |
797 | 0 | Bitmap aBmp( aGraphic.GetBitmap() ); |
798 | | // export: use highest quality |
799 | 0 | aBmp.Scale( Size( rSettings.mnWidth, rSettings.mnHeight ), BmpScaleFlag::Lanczos ); |
800 | 0 | aGraphic = aBmp; |
801 | 0 | } |
802 | | |
803 | | // #118804# only accept for bitmap graphics, else the |
804 | | // conversion to bitmap will happen anywhere without size control |
805 | | // as evtl. defined in rSettings.mnWidth/mnHeight |
806 | 0 | bSingleGraphic = true; |
807 | 0 | } |
808 | 0 | } |
809 | 0 | } |
810 | 271 | else if( rSettings.mbScrollText ) |
811 | 0 | { |
812 | 0 | SdrObject* pObj = aShapes.front(); |
813 | 0 | auto pTextObj = DynCastSdrTextObj( pObj); |
814 | 0 | if( pTextObj && pTextObj->HasText() ) |
815 | 0 | { |
816 | 0 | tools::Rectangle aScrollRectangle; |
817 | 0 | tools::Rectangle aPaintRectangle; |
818 | |
|
819 | 0 | const std::unique_ptr< GDIMetaFile > pMtf( |
820 | 0 | pTextObj->GetTextScrollMetaFileAndRectangle( |
821 | 0 | aScrollRectangle, aPaintRectangle ) ); |
822 | | |
823 | | // take the larger one of the two rectangles (that |
824 | | // should be the bound rect of the retrieved |
825 | | // metafile) |
826 | 0 | tools::Rectangle aTextRect; |
827 | |
|
828 | 0 | if( aScrollRectangle.Contains( aPaintRectangle ) ) |
829 | 0 | aTextRect = aScrollRectangle; |
830 | 0 | else |
831 | 0 | aTextRect = aPaintRectangle; |
832 | | |
833 | | // setup pref size and mapmode |
834 | 0 | pMtf->SetPrefSize( aTextRect.GetSize() ); |
835 | | |
836 | | // set actual origin (mtf is at actual shape |
837 | | // output position) |
838 | 0 | MapMode aLocalMapMode( aMap ); |
839 | 0 | aLocalMapMode.SetOrigin( |
840 | 0 | Point( -aPaintRectangle.Left(), |
841 | 0 | -aPaintRectangle.Top() ) ); |
842 | 0 | pMtf->SetPrefMapMode( aLocalMapMode ); |
843 | |
|
844 | 0 | pMtf->AddAction( new MetaCommentAction( |
845 | 0 | "XTEXT_SCROLLRECT"_ostr, 0, |
846 | 0 | reinterpret_cast<sal_uInt8 const*>(&aScrollRectangle), |
847 | 0 | sizeof( tools::Rectangle ) ) ); |
848 | 0 | pMtf->AddAction( new MetaCommentAction( |
849 | 0 | "XTEXT_PAINTRECT"_ostr, 0, |
850 | 0 | reinterpret_cast<sal_uInt8 const*>(&aPaintRectangle), |
851 | 0 | sizeof( tools::Rectangle ) ) ); |
852 | |
|
853 | 0 | aGraphic = Graphic( *pMtf ); |
854 | |
|
855 | 0 | bSingleGraphic = true; |
856 | 0 | } |
857 | 0 | } |
858 | 271 | } |
859 | | |
860 | 271 | if( !bSingleGraphic ) |
861 | 271 | { |
862 | | // create a metafile for all shapes |
863 | 271 | ScopedVclPtrInstance< VirtualDevice > aOut; |
864 | | |
865 | | // calculate bound rect for all shapes |
866 | | // tdf#126319 I did not convert all rendering to primitives, |
867 | | // that would be too much for this fix. But I did so for the |
868 | | // range calculation to get a valid high quality range. |
869 | | // Based on that the conversion is reliable. With the BoundRect |
870 | | // fetched from the Metafile it was just not possible to get the |
871 | | // examples from the task handled in a way to fit all cases - |
872 | | // due to bad-quality range data from it. |
873 | 271 | basegfx::B2DRange aBound; |
874 | 271 | const drawinglayer::geometry::ViewInformation2D aViewInformation2D; |
875 | | |
876 | 271 | { |
877 | 271 | for( SdrObject* pObj : aShapes ) |
878 | 271 | { |
879 | 271 | drawinglayer::primitive2d::Primitive2DContainer aSequence; |
880 | 271 | pObj->GetViewContact().getViewIndependentPrimitive2DContainer(aSequence); |
881 | 271 | aBound.expand(aSequence.getB2DRange(aViewInformation2D)); |
882 | 271 | } |
883 | 271 | } |
884 | | |
885 | 271 | aOut->EnableOutput( false ); |
886 | 271 | aOut->SetMapMode( aMap ); |
887 | 271 | if( rSettings.mbUseHighContrast ) |
888 | 0 | aOut->SetDrawMode( aOut->GetDrawMode() | DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient ); |
889 | | |
890 | 271 | GDIMetaFile aMtf; |
891 | 271 | aMtf.Clear(); |
892 | 271 | aMtf.Record( aOut ); |
893 | | |
894 | 271 | MapMode aOutMap( aMap ); |
895 | 271 | const Size aOnePixelInMtf( |
896 | 271 | Application::GetDefaultDevice()->PixelToLogic( |
897 | 271 | Size(1, 1), |
898 | 271 | aMap)); |
899 | 271 | const Size aHalfPixelInMtf( |
900 | 271 | (aOnePixelInMtf.getWidth() + 1) / 2, |
901 | 271 | (aOnePixelInMtf.getHeight() + 1) / 2); |
902 | | |
903 | | // tdf#126319 Immediately add needed offset to create metafile, |
904 | | // that avoids to do it later by Metafile::Move what would be expensive |
905 | 271 | aOutMap.SetOrigin( |
906 | 271 | Point( |
907 | 271 | basegfx::fround<tools::Long>(-aBound.getMinX() - aHalfPixelInMtf.getWidth()), |
908 | 271 | basegfx::fround<tools::Long>(-aBound.getMinY() - aHalfPixelInMtf.getHeight()) ) ); |
909 | 271 | aOut->SetRelativeMapMode( aOutMap ); |
910 | | |
911 | 271 | sdr::contact::DisplayInfo aDisplayInfo; |
912 | | |
913 | 271 | if(mpCurrentPage) |
914 | 0 | { |
915 | 0 | if(mpCurrentPage->TRG_HasMasterPage() && pPage->IsMasterPage()) |
916 | 0 | { |
917 | | // MasterPage is processed as another page's SubContent |
918 | 0 | aDisplayInfo.SetProcessLayers(mpCurrentPage->TRG_GetMasterPageVisibleLayers()); |
919 | 0 | aDisplayInfo.SetSubContentActive(true); |
920 | 0 | } |
921 | 0 | } |
922 | | |
923 | 271 | if(!aShapes.empty()) |
924 | 271 | { |
925 | | // more effective way to paint a vector of SdrObjects. Hand over the processed page |
926 | | // to have it in the |
927 | 271 | ImplExportCheckVisisbilityRedirector aCheckVisibilityRedirector(mpCurrentPage); |
928 | 271 | sdr::contact::ObjectContactOfObjListPainter aMultiObjectPainter(*aOut, std::move(aShapes), mpCurrentPage); |
929 | 271 | aMultiObjectPainter.SetViewObjectContactRedirector(&aCheckVisibilityRedirector); |
930 | | |
931 | 271 | aMultiObjectPainter.ProcessDisplay(aDisplayInfo); |
932 | 271 | } |
933 | | |
934 | 271 | aMtf.Stop(); |
935 | 271 | aMtf.WindStart(); |
936 | | |
937 | | // tdf#126319 Immediately add needed size to target's PrefSize |
938 | | // tdf#150102 Checked that in aBound is indeed the size - 1 (probably |
939 | | // due to old integer stuff using Size()/Rectangle() and getWidth()/GetWidth() |
940 | | // with the old one-less paradigm somewhere), so just correct to the |
941 | | // correct size. Be aware that checking of tdf#126319 is needed, but |
942 | | // looks good in my tests. Still: Changing the central UNO API Metafile |
943 | | // export is always a risky thing, so it will have to show if this will |
944 | | // not influence something else. |
945 | 271 | const Size aBoundSize( |
946 | 271 | basegfx::fround<tools::Long>(aBound.getWidth() + 1), |
947 | 271 | basegfx::fround<tools::Long>(aBound.getHeight() + 1)); |
948 | 271 | aMtf.SetPrefMapMode( aMap ); |
949 | 271 | aMtf.SetPrefSize( aBoundSize ); |
950 | | |
951 | 271 | if( !bVectorType ) |
952 | 0 | { |
953 | 0 | Size aOutSize; |
954 | 0 | aGraphic = GetBitmapFromMetaFile( aMtf, CalcSize( rSettings.mnWidth, rSettings.mnHeight, aBoundSize, aOutSize ) ); |
955 | 0 | } |
956 | 271 | else |
957 | 271 | { |
958 | 271 | aGraphic = aMtf; |
959 | 271 | } |
960 | 271 | } |
961 | 271 | } |
962 | | |
963 | 271 | pTempBackgroundShape.clear(); |
964 | | |
965 | 271 | rOutl.SetCalcFieldValueHdl( maOldCalcFieldValueHdl ); |
966 | | |
967 | | // #i102251# |
968 | 271 | rOutl.SetControlWord(nOldCntrl); |
969 | | |
970 | 271 | rOutl.SetBackgroundColor(aOldBackColor); |
971 | | |
972 | 271 | return bRet; |
973 | | |
974 | 271 | } |
975 | | |
976 | | // XFilter |
977 | | sal_Bool SAL_CALL GraphicExporter::filter( const Sequence< PropertyValue >& aDescriptor ) |
978 | 271 | { |
979 | 271 | ::SolarMutexGuard aGuard; |
980 | | |
981 | 271 | if( maGraphic.IsNone() && nullptr == mpUnoPage ) |
982 | 0 | return false; |
983 | | |
984 | 271 | if( maGraphic.IsNone() && ( nullptr == mpUnoPage->GetSdrPage() || nullptr == mpDoc ) ) |
985 | 0 | return false; |
986 | | |
987 | 271 | GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter(); |
988 | | |
989 | | // get the arguments from the descriptor |
990 | 271 | ExportSettings aSettings; |
991 | 271 | ParseSettings(aDescriptor, aSettings); |
992 | | |
993 | 271 | const sal_uInt16 nFilter = !aSettings.maMediaType.isEmpty() |
994 | 271 | ? rFilter.GetExportFormatNumberForMediaType( aSettings.maMediaType ) |
995 | 271 | : rFilter.GetExportFormatNumberForShortName( aSettings.maFilterName ); |
996 | 271 | bool bVectorType = !rFilter.IsExportPixelFormat( nFilter ); |
997 | | |
998 | | // create the output stuff |
999 | 271 | Graphic aGraphic = maGraphic; |
1000 | | |
1001 | 271 | ErrCode nStatus = ERRCODE_NONE; |
1002 | 271 | if (maGraphic.IsNone()) |
1003 | 271 | { |
1004 | 271 | bool bAntiAliasing = SvtOptionsDrawinglayer::IsAntiAliasing(); |
1005 | 271 | AllSettings aAllSettings = Application::GetSettings(); |
1006 | 271 | StyleSettings aStyleSettings = aAllSettings.GetStyleSettings(); |
1007 | 271 | bool bUseFontAAFromSystem = aStyleSettings.GetUseFontAAFromSystem(); |
1008 | 271 | bool bUseSubpixelAA = aStyleSettings.GetUseSubpixelAA(); |
1009 | 271 | aStyleSettings.SetUseSubpixelAA(false); |
1010 | 271 | if (aSettings.meAntiAliasing != TRISTATE_INDET) |
1011 | 0 | { |
1012 | | // This is safe to do globally as we own the solar mutex. |
1013 | 0 | SvtOptionsDrawinglayer::SetAntiAliasing(aSettings.meAntiAliasing == TRISTATE_TRUE, /*bTemporary*/true); |
1014 | | // Opt in to have AA affect font rendering as well. |
1015 | 0 | aStyleSettings.SetUseFontAAFromSystem(false); |
1016 | 0 | } |
1017 | 271 | aAllSettings.SetStyleSettings(aStyleSettings); |
1018 | 271 | Application::SetSettings(aAllSettings, /*bTemporary*/true); |
1019 | 271 | nStatus = GetGraphic( aSettings, aGraphic, bVectorType ) ? ERRCODE_NONE : ERRCODE_GRFILTER_FILTERERROR; |
1020 | 271 | if (aSettings.meAntiAliasing != TRISTATE_INDET) |
1021 | 0 | { |
1022 | 0 | SvtOptionsDrawinglayer::SetAntiAliasing(bAntiAliasing, /*bTemporary*/true); |
1023 | 0 | aStyleSettings.SetUseFontAAFromSystem(bUseFontAAFromSystem); |
1024 | 0 | } |
1025 | 271 | aStyleSettings.SetUseSubpixelAA(bUseSubpixelAA); |
1026 | 271 | aAllSettings.SetStyleSettings(aStyleSettings); |
1027 | 271 | Application::SetSettings(aAllSettings, /*bTemporary*/true); |
1028 | 271 | } |
1029 | | |
1030 | 271 | if( nStatus == ERRCODE_NONE ) |
1031 | 271 | { |
1032 | | // export graphic only if it has a size |
1033 | 271 | const Size aGraphSize( aGraphic.GetPrefSize() ); |
1034 | 271 | if ( aGraphSize.IsEmpty() ) |
1035 | 0 | { |
1036 | 0 | nStatus = ERRCODE_GRFILTER_FILTERERROR; |
1037 | 0 | } |
1038 | 271 | else |
1039 | 271 | { |
1040 | | // now we have a graphic, so export it |
1041 | 271 | if( aSettings.mxGraphicRenderer.is() ) |
1042 | 0 | { |
1043 | | // render graphic directly into given renderer |
1044 | 0 | aSettings.mxGraphicRenderer->render( aGraphic.GetXGraphic() ); |
1045 | 0 | } |
1046 | 271 | else if( aSettings.mxOutputStream.is() ) |
1047 | 271 | { |
1048 | | // TODO: Either utilize optional XSeekable functionality for the |
1049 | | // SvOutputStream, or adapt the graphic filter to not seek anymore. |
1050 | 271 | SvMemoryStream aStream( 1024, 1024 ); |
1051 | | |
1052 | 271 | nStatus = rFilter.ExportGraphic( aGraphic, u"", aStream, nFilter, &aSettings.maFilterData ); |
1053 | | |
1054 | | // copy temp stream to XOutputStream |
1055 | 271 | SvOutputStream aOutputStream( aSettings.mxOutputStream ); |
1056 | 271 | aStream.Seek(0); |
1057 | 271 | aOutputStream.WriteStream( aStream ); |
1058 | 271 | } |
1059 | 0 | else |
1060 | 0 | { |
1061 | 0 | INetURLObject aURLObject( aSettings.maURL.Complete ); |
1062 | 0 | DBG_ASSERT( aURLObject.GetProtocol() != INetProtocol::NotValid, "invalid URL" ); |
1063 | |
|
1064 | 0 | nStatus = XOutBitmap::ExportGraphic( aGraphic, aURLObject, rFilter, nFilter, &aSettings.maFilterData ); |
1065 | 0 | } |
1066 | 271 | } |
1067 | 271 | } |
1068 | | |
1069 | 271 | if ( aSettings.mxInteractionHandler.is() && ( nStatus != ERRCODE_NONE ) ) |
1070 | 0 | { |
1071 | 0 | Any aInteraction; |
1072 | 0 | Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations{ |
1073 | 0 | new ::comphelper::OInteractionApprove() |
1074 | 0 | }; |
1075 | |
|
1076 | 0 | GraphicFilterRequest aErrorCode; |
1077 | 0 | aErrorCode.ErrCode = sal_uInt32(nStatus); |
1078 | 0 | aInteraction <<= aErrorCode; |
1079 | 0 | aSettings.mxInteractionHandler->handle( framework::InteractionRequest::CreateRequest( aInteraction, lContinuations ) ); |
1080 | 0 | } |
1081 | 271 | return nStatus == ERRCODE_NONE; |
1082 | 271 | } |
1083 | | |
1084 | | void SAL_CALL GraphicExporter::cancel() |
1085 | 0 | { |
1086 | 0 | } |
1087 | | |
1088 | | // XExporter |
1089 | | |
1090 | | /** the source 'document' could be a XDrawPage, a XShape or a generic XShapes */ |
1091 | | void SAL_CALL GraphicExporter::setSourceDocument( const Reference< lang::XComponent >& xComponent ) |
1092 | 271 | { |
1093 | 271 | ::SolarMutexGuard aGuard; |
1094 | | |
1095 | 271 | mxShapes = nullptr; |
1096 | 271 | mpUnoPage = nullptr; |
1097 | | |
1098 | 271 | try |
1099 | 271 | { |
1100 | | // any break inside this one loop while will throw an IllegalArgumentException |
1101 | 271 | do |
1102 | 271 | { |
1103 | 271 | mxPage.set( xComponent, UNO_QUERY ); |
1104 | 271 | mxShapes.set( xComponent, UNO_QUERY ); |
1105 | 271 | mxShape.set( xComponent, UNO_QUERY ); |
1106 | | |
1107 | | // Step 1: try a generic XShapes |
1108 | 271 | if( !mxPage.is() && !mxShape.is() && mxShapes.is() ) |
1109 | 0 | { |
1110 | | // we do not support empty shape collections |
1111 | 0 | if( 0 == mxShapes->getCount() ) |
1112 | 0 | break; |
1113 | | |
1114 | | // get first shape to detect corresponding page and model |
1115 | 0 | mxShapes->getByIndex(0) >>= mxShape; |
1116 | 0 | } |
1117 | 271 | else |
1118 | 271 | { |
1119 | 271 | mxShapes = nullptr; |
1120 | 271 | } |
1121 | | |
1122 | | // Step 2: try a shape |
1123 | 271 | if( mxShape.is() ) |
1124 | 271 | { |
1125 | 271 | if (nullptr == SdrObject::getSdrObjectFromXShape(mxShape)) |
1126 | 0 | { |
1127 | | // This is not a Draw shape, let's see if it's a Writer one. |
1128 | 0 | uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY); |
1129 | 0 | if (!xPropertySet.is()) |
1130 | 0 | break; |
1131 | 0 | uno::Reference<graphic::XGraphic> xGraphic( |
1132 | 0 | xPropertySet->getPropertyValue(u"Graphic"_ustr), uno::UNO_QUERY); |
1133 | 0 | if (!xGraphic.is()) |
1134 | 0 | break; |
1135 | | |
1136 | 0 | maGraphic = Graphic(xGraphic); |
1137 | 0 | if (!maGraphic.IsNone()) |
1138 | 0 | return; |
1139 | 0 | else |
1140 | 0 | break; |
1141 | 0 | } |
1142 | | |
1143 | | // get page for this shape |
1144 | 271 | Reference< XChild > xChild( mxShape, UNO_QUERY ); |
1145 | 271 | if( !xChild.is() ) |
1146 | 0 | break; |
1147 | | |
1148 | 271 | Reference< XInterface > xInt; |
1149 | 271 | do |
1150 | 271 | { |
1151 | 271 | xInt = xChild->getParent(); |
1152 | 271 | mxPage.set( xInt, UNO_QUERY ); |
1153 | 271 | if( !mxPage.is() ) |
1154 | 0 | xChild.set( xInt, UNO_QUERY ); |
1155 | 271 | } |
1156 | 271 | while( !mxPage.is() && xChild.is() ); |
1157 | | |
1158 | 271 | if( !mxPage.is() ) |
1159 | 0 | break; |
1160 | 271 | } |
1161 | | |
1162 | | // Step 3: check the page |
1163 | 271 | if( !mxPage.is() ) |
1164 | 0 | break; |
1165 | | |
1166 | 271 | mpUnoPage = comphelper::getFromUnoTunnel<SvxDrawPage>( mxPage ); |
1167 | | |
1168 | 271 | if( nullptr == mpUnoPage || nullptr == mpUnoPage->GetSdrPage() ) |
1169 | 0 | break; |
1170 | | |
1171 | 271 | mpDoc = &mpUnoPage->GetSdrPage()->getSdrModelFromSdrPage(); |
1172 | | |
1173 | | // Step 4: If we got a generic XShapes test all contained shapes |
1174 | | // if they belong to the same XDrawPage |
1175 | | |
1176 | 271 | if( mxShapes.is() ) |
1177 | 0 | { |
1178 | 0 | SdrPage* pPage = mpUnoPage->GetSdrPage(); |
1179 | 0 | SdrObject* pObj; |
1180 | 0 | Reference< XShape > xShape; |
1181 | |
|
1182 | 0 | bool bOk = true; |
1183 | |
|
1184 | 0 | const sal_Int32 nCount = mxShapes->getCount(); |
1185 | | |
1186 | | // test all but the first shape if they have the same page than |
1187 | | // the first shape |
1188 | 0 | for( sal_Int32 nIndex = 1; bOk && ( nIndex < nCount ); nIndex++ ) |
1189 | 0 | { |
1190 | 0 | mxShapes->getByIndex( nIndex ) >>= xShape; |
1191 | 0 | pObj = SdrObject::getSdrObjectFromXShape(xShape); |
1192 | 0 | bOk = pObj && pObj->getSdrPageFromSdrObject() == pPage; |
1193 | 0 | } |
1194 | |
|
1195 | 0 | if( !bOk ) |
1196 | 0 | break; |
1197 | 0 | } |
1198 | | |
1199 | | // no errors so far |
1200 | 271 | return; |
1201 | 271 | } |
1202 | 271 | while( false ); |
1203 | 271 | } |
1204 | 271 | catch( Exception& ) |
1205 | 271 | { |
1206 | 0 | } |
1207 | | |
1208 | 0 | throw IllegalArgumentException(); |
1209 | 271 | } |
1210 | | |
1211 | | // XServiceInfo |
1212 | | OUString SAL_CALL GraphicExporter::getImplementationName( ) |
1213 | 0 | { |
1214 | 0 | return u"com.sun.star.comp.Draw.GraphicExporter"_ustr; |
1215 | 0 | } |
1216 | | |
1217 | | sal_Bool SAL_CALL GraphicExporter::supportsService( const OUString& ServiceName ) |
1218 | 0 | { |
1219 | 0 | return cppu::supportsService(this, ServiceName); |
1220 | 0 | } |
1221 | | |
1222 | | Sequence< OUString > SAL_CALL GraphicExporter::getSupportedServiceNames( ) |
1223 | 0 | { |
1224 | 0 | Sequence< OUString > aSupportedServiceNames { u"com.sun.star.drawing.GraphicExportFilter"_ustr }; |
1225 | 0 | return aSupportedServiceNames; |
1226 | 0 | } |
1227 | | |
1228 | | // XMimeTypeInfo |
1229 | | sal_Bool SAL_CALL GraphicExporter::supportsMimeType( const OUString& rMimeTypeName ) |
1230 | 0 | { |
1231 | 0 | GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter(); |
1232 | 0 | sal_uInt16 nCount = rFilter.GetExportFormatCount(); |
1233 | 0 | sal_uInt16 nFilter; |
1234 | 0 | for( nFilter = 0; nFilter < nCount; nFilter++ ) |
1235 | 0 | { |
1236 | 0 | if( rMimeTypeName == rFilter.GetExportFormatMediaType( nFilter ) ) |
1237 | 0 | { |
1238 | 0 | return true; |
1239 | 0 | } |
1240 | 0 | } |
1241 | | |
1242 | 0 | return false; |
1243 | 0 | } |
1244 | | |
1245 | | Sequence< OUString > SAL_CALL GraphicExporter::getSupportedMimeTypeNames( ) |
1246 | 0 | { |
1247 | 0 | GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter(); |
1248 | 0 | sal_uInt16 nCount = rFilter.GetExportFormatCount(); |
1249 | 0 | sal_uInt16 nFilter; |
1250 | 0 | sal_uInt16 nFound = 0; |
1251 | |
|
1252 | 0 | Sequence< OUString > aSeq( nCount ); |
1253 | 0 | OUString* pStr = aSeq.getArray(); |
1254 | |
|
1255 | 0 | for( nFilter = 0; nFilter < nCount; nFilter++ ) |
1256 | 0 | { |
1257 | 0 | OUString aMimeType( rFilter.GetExportFormatMediaType( nFilter ) ); |
1258 | 0 | if( !aMimeType.isEmpty() ) |
1259 | 0 | { |
1260 | 0 | *pStr++ = aMimeType; |
1261 | 0 | nFound++; |
1262 | 0 | } |
1263 | 0 | } |
1264 | |
|
1265 | 0 | if( nFound < nCount ) |
1266 | 0 | aSeq.realloc( nFound ); |
1267 | |
|
1268 | 0 | return aSeq; |
1269 | 0 | } |
1270 | | |
1271 | | } |
1272 | | |
1273 | | /** creates a bitmap that is optionally transparent from a metafile |
1274 | | */ |
1275 | | Bitmap GetBitmapFromMetaFile(const GDIMetaFile& rMtf, const Size* pSize) |
1276 | 0 | { |
1277 | | // use new primitive conversion tooling |
1278 | 0 | basegfx::B2DRange aRange(basegfx::B2DPoint(0.0, 0.0)); |
1279 | 0 | sal_uInt32 nMaximumQuadraticPixels; |
1280 | |
|
1281 | 0 | if (pSize) |
1282 | 0 | { |
1283 | | // use 100th mm for primitive bitmap converter tool, input is pixel |
1284 | | // use a real OutDev to get the correct DPI, the static LogicToLogic assumes 72dpi which is wrong (!) |
1285 | 0 | const Size aSize100th( |
1286 | 0 | Application::GetDefaultDevice()->PixelToLogic(*pSize, MapMode(MapUnit::Map100thMM))); |
1287 | |
|
1288 | 0 | aRange.expand(basegfx::B2DPoint(aSize100th.Width(), aSize100th.Height())); |
1289 | | |
1290 | | // when explicitly pixels are requested from the GraphicExporter, use a *very* high limit |
1291 | | // of 16gb (4096x4096 pixels) |
1292 | 0 | nMaximumQuadraticPixels = 4096 * 4096; |
1293 | 0 | } |
1294 | 0 | else |
1295 | 0 | { |
1296 | | // use 100th mm for primitive bitmap converter tool |
1297 | 0 | const Size aSize100th(OutputDevice::LogicToLogic(rMtf.GetPrefSize(), rMtf.GetPrefMapMode(), |
1298 | 0 | MapMode(MapUnit::Map100thMM))); |
1299 | |
|
1300 | 0 | aRange.expand(basegfx::B2DPoint(aSize100th.Width(), aSize100th.Height())); |
1301 | | |
1302 | | // limit to 2048x2048 pixels, as in ImpGraphic::getBitmap (vcl/source/gdi/impgraph.cxx): |
1303 | 0 | nMaximumQuadraticPixels = 2048 * 2048; |
1304 | 0 | } |
1305 | |
|
1306 | 0 | return convertMetafileToBitmap(rMtf, aRange, nMaximumQuadraticPixels); |
1307 | 0 | } |
1308 | | |
1309 | | Graphic SvxGetGraphicForShape( SdrObject& rShape ) |
1310 | 0 | { |
1311 | 0 | Graphic aGraphic; |
1312 | 0 | try |
1313 | 0 | { |
1314 | 0 | rtl::Reference< GraphicExporter > xExporter( new GraphicExporter() ); |
1315 | 0 | Reference< XComponent > xComp( rShape.getUnoShape(), UNO_QUERY_THROW ); |
1316 | 0 | xExporter->setSourceDocument( xComp ); |
1317 | 0 | ExportSettings aSettings; |
1318 | 0 | xExporter->GetGraphic( aSettings, aGraphic, true/*bVector*/ ); |
1319 | 0 | } |
1320 | 0 | catch( Exception& ) |
1321 | 0 | { |
1322 | 0 | TOOLS_WARN_EXCEPTION("svx", ""); |
1323 | 0 | } |
1324 | 0 | return aGraphic; |
1325 | 0 | } |
1326 | | |
1327 | | extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * |
1328 | | com_sun_star_comp_Draw_GraphicExporter_get_implementation( |
1329 | | css::uno::XComponentContext *, |
1330 | | css::uno::Sequence<css::uno::Any> const &) |
1331 | 271 | { |
1332 | 271 | return cppu::acquire(new GraphicExporter); |
1333 | 271 | } |
1334 | | |
1335 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |