Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */