Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/graphic/UnoGraphicProvider.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 <o3tl/string_view.hxx>
21
#include <o3tl/temporary.hxx>
22
#include <vcl/svapp.hxx>
23
#include <vcl/image.hxx>
24
#include <vcl/metaact.hxx>
25
#include <vcl/metaactiontypes.hxx>
26
#include <imagerepository.hxx>
27
#include <tools/fract.hxx>
28
#include <tools/mapunit.hxx>
29
#include <tools/stream.hxx>
30
#include <unotools/ucbstreamhelper.hxx>
31
#include <vcl/graphic/BitmapHelper.hxx>
32
#include <vcl/graphicfilter.hxx>
33
#include <vcl/stdtext.hxx>
34
#include <vcl/wmfexternal.hxx>
35
#include <vcl/virdev.hxx>
36
#include <com/sun/star/awt/XBitmap.hpp>
37
#include <com/sun/star/graphic/XGraphicProvider2.hpp>
38
#include <com/sun/star/io/XStream.hpp>
39
#include <com/sun/star/lang/XServiceInfo.hpp>
40
#include <com/sun/star/text/GraphicCrop.hpp>
41
#include <com/sun/star/uno/XComponentContext.hpp>
42
#include <comphelper/fileformat.h>
43
#include <comphelper/servicehelper.hxx>
44
#include <cppuhelper/implbase.hxx>
45
#include <cppuhelper/supportsservice.hxx>
46
#include <sal/log.hxx>
47
48
#include <graphic/UnoGraphicDescriptor.hxx>
49
#include <graphic/UnoGraphic.hxx>
50
#include <rtl/ref.hxx>
51
#include <vcl/dibtools.hxx>
52
#include <comphelper/sequence.hxx>
53
#include <memory>
54
#include <string_view>
55
56
#include <vcl/TypeSerializer.hxx>
57
58
using namespace com::sun::star;
59
60
namespace
61
{
62
SvMemoryStream AsStream(const css::uno::Sequence<sal_Int8>& s)
63
0
{
64
0
    return SvMemoryStream(const_cast<sal_Int8*>(s.getConstArray()), s.getLength(),
65
0
                          StreamMode::READ);
66
0
}
67
68
Bitmap BitmapFromDIB(const css::uno::Sequence<sal_Int8>& dib)
69
0
{
70
0
    Bitmap bmp;
71
0
    if (dib.hasElements())
72
0
        ReadDIB(bmp, o3tl::temporary(AsStream(dib)), true);
73
0
    return bmp;
74
0
}
75
}
76
77
namespace vcl
78
{
79
Bitmap GetBitmap(const css::uno::Reference<css::awt::XBitmap>& xBitmap)
80
0
{
81
0
    if (!xBitmap)
82
0
        return {};
83
84
0
    if (auto xGraphic = xBitmap.query<css::graphic::XGraphic>())
85
0
        return Graphic(xGraphic).GetBitmap();
86
87
    // This is an unknown implementation of a XBitmap interface
88
0
    if (Bitmap aMask = BitmapFromDIB(xBitmap->getMaskDIB()); !aMask.IsEmpty())
89
0
    {
90
0
        aMask.Invert(); // Convert from transparency to alpha
91
0
        return Bitmap(BitmapFromDIB(xBitmap->getDIB()), aMask);
92
0
    }
93
94
0
    Bitmap aBmp;
95
0
    ReadDIBBitmapEx(aBmp, o3tl::temporary(AsStream(xBitmap->getDIB())), true);
96
0
    return aBmp;
97
0
}
98
99
css::uno::Reference<css::graphic::XGraphic> GetGraphic(const css::uno::Any& any)
100
0
{
101
0
    if (auto xRet = any.query<css::graphic::XGraphic>())
102
0
        return xRet;
103
104
0
    if (Bitmap aBmp = GetBitmap(any.query<css::awt::XBitmap>()); !aBmp.IsEmpty())
105
0
    {
106
0
        return Graphic(aBmp).GetXGraphic();
107
0
    }
108
109
0
    return {};
110
0
}
111
}
112
113
namespace {
114
115
class GraphicProvider : public ::cppu::WeakImplHelper< css::graphic::XGraphicProvider2,
116
                                                        css::lang::XServiceInfo >
117
{
118
public:
119
120
    GraphicProvider();
121
122
protected:
123
124
    // XServiceInfo
125
    virtual OUString SAL_CALL getImplementationName() override;
126
    virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
127
    virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
128
129
    // XTypeProvider
130
    virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes(  ) override;
131
    virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId(  ) override;
132
133
    // XGraphicProvider
134
    virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL queryGraphicDescriptor( const css::uno::Sequence< css::beans::PropertyValue >& MediaProperties ) override;
135
    virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL queryGraphic( const css::uno::Sequence< css::beans::PropertyValue >& MediaProperties ) override;
136
    virtual void SAL_CALL storeGraphic( const css::uno::Reference< css::graphic::XGraphic >& Graphic, const css::uno::Sequence< css::beans::PropertyValue >& MediaProperties ) override;
137
138
    // XGraphicProvider2
139
    uno::Sequence< uno::Reference<graphic::XGraphic> > SAL_CALL queryGraphics(const uno::Sequence< uno::Sequence<beans::PropertyValue> >& MediaPropertiesSeq ) override;
140
141
private:
142
143
    static css::uno::Reference< css::graphic::XGraphic > implLoadMemory( std::u16string_view rResourceURL );
144
    static css::uno::Reference< css::graphic::XGraphic > implLoadRepositoryImage( std::u16string_view rResourceURL );
145
    static css::uno::Reference< css::graphic::XGraphic > implLoadStandardImage( std::u16string_view rResourceURL );
146
};
147
148
GraphicProvider::GraphicProvider()
149
32.8k
{
150
32.8k
}
151
152
OUString SAL_CALL GraphicProvider::getImplementationName()
153
0
{
154
0
    return u"com.sun.star.comp.graphic.GraphicProvider"_ustr;
155
0
}
156
157
sal_Bool SAL_CALL GraphicProvider::supportsService( const OUString& ServiceName )
158
0
{
159
0
    return cppu::supportsService( this, ServiceName );
160
0
}
161
162
uno::Sequence< OUString > SAL_CALL GraphicProvider::getSupportedServiceNames()
163
0
{
164
0
    return { u"com.sun.star.graphic.GraphicProvider"_ustr };
165
0
}
166
167
uno::Sequence< uno::Type > SAL_CALL GraphicProvider::getTypes()
168
0
{
169
0
    static const uno::Sequence< uno::Type > aTypes {
170
0
        cppu::UnoType<lang::XServiceInfo>::get(),
171
0
        cppu::UnoType<lang::XTypeProvider>::get(),
172
0
        cppu::UnoType<graphic::XGraphicProvider>::get()
173
0
    };
174
0
    return aTypes;
175
0
}
176
177
uno::Sequence< sal_Int8 > SAL_CALL GraphicProvider::getImplementationId()
178
0
{
179
0
    return css::uno::Sequence<sal_Int8>();
180
0
}
181
182
uno::Reference< ::graphic::XGraphic > GraphicProvider::implLoadMemory( std::u16string_view rResourceURL )
183
0
{
184
0
    sal_Int32                               nIndex = 0;
185
186
0
    if( o3tl::getToken(rResourceURL, 0, '/', nIndex ) != u"private:memorygraphic" )
187
0
        return nullptr;
188
189
0
    sal_Int64 nGraphicAddress = o3tl::toInt64(o3tl::getToken(rResourceURL, 0, '/', nIndex ));
190
0
    if( nGraphicAddress == 0 )
191
0
        return nullptr;
192
193
0
    return reinterpret_cast<::Graphic*>(nGraphicAddress)->GetXGraphic();
194
0
}
195
196
uno::Reference< ::graphic::XGraphic > GraphicProvider::implLoadRepositoryImage( std::u16string_view rResourceURL )
197
0
{
198
0
    uno::Reference< ::graphic::XGraphic >   xRet;
199
200
0
    std::u16string_view sPathName;
201
0
    if( o3tl::starts_with(rResourceURL, u"private:graphicrepository/", &sPathName) )
202
0
    {
203
0
        Bitmap aBitmap;
204
0
        if ( vcl::ImageRepository::loadImage( OUString(sPathName), aBitmap ) )
205
0
        {
206
0
            Graphic aGraphic(aBitmap);
207
0
            aGraphic.setOriginURL(OUString(rResourceURL));
208
0
            xRet = aGraphic.GetXGraphic();
209
0
        }
210
0
    }
211
0
    return xRet;
212
0
}
213
214
uno::Reference< ::graphic::XGraphic > GraphicProvider::implLoadStandardImage( std::u16string_view rResourceURL )
215
0
{
216
0
    uno::Reference< ::graphic::XGraphic >   xRet;
217
218
0
    std::u16string_view sImageName;
219
0
    if( o3tl::starts_with(rResourceURL, u"private:standardimage/", &sImageName) )
220
0
    {
221
0
        if ( sImageName == u"info" )
222
0
        {
223
0
            xRet = Graphic(GetStandardInfoBoxImage().GetBitmap()).GetXGraphic();
224
0
        }
225
0
        else if ( sImageName == u"warning" )
226
0
        {
227
0
            xRet = Graphic(GetStandardWarningBoxImage().GetBitmap()).GetXGraphic();
228
0
        }
229
0
        else if ( sImageName == u"error" )
230
0
        {
231
0
            xRet = Graphic(GetStandardErrorBoxImage().GetBitmap()).GetXGraphic();
232
0
        }
233
0
        else if ( sImageName == u"query" )
234
0
        {
235
0
            xRet = Graphic(GetStandardQueryBoxImage().GetBitmap()).GetXGraphic();
236
0
        }
237
0
    }
238
0
    return xRet;
239
0
}
240
241
242
uno::Reference< beans::XPropertySet > SAL_CALL GraphicProvider::queryGraphicDescriptor( const uno::Sequence< beans::PropertyValue >& rMediaProperties )
243
0
{
244
0
    OUString aURL;
245
0
    uno::Reference< io::XInputStream > xIStm;
246
0
    uno::Any aBtm;
247
248
0
    for( const auto& rMediaProperty : rMediaProperties )
249
0
    {
250
0
        const OUString   aName( rMediaProperty.Name );
251
0
        const uno::Any          aValue( rMediaProperty.Value );
252
253
0
        if (aName == "URL")
254
0
        {
255
0
            aValue >>= aURL;
256
0
        }
257
0
        else if (aName == "InputStream")
258
0
        {
259
0
            aValue >>= xIStm;
260
0
        }
261
0
        else if (aName == "Bitmap")
262
0
        {
263
0
            aBtm = aValue;
264
0
        }
265
0
    }
266
267
0
    SolarMutexGuard g;
268
269
0
    uno::Reference<beans::XPropertySet> xRet;
270
0
    if( xIStm.is() )
271
0
    {
272
0
        rtl::Reference<unographic::GraphicDescriptor> pDescriptor = new unographic::GraphicDescriptor;
273
0
        pDescriptor->init( xIStm, aURL );
274
0
        xRet = pDescriptor;
275
0
    }
276
0
    else if( !aURL.isEmpty() )
277
0
    {
278
0
        uno::Reference< ::graphic::XGraphic > xGraphic( implLoadMemory( aURL ) );
279
280
0
        if ( !xGraphic.is() )
281
0
            xGraphic = implLoadRepositoryImage( aURL );
282
283
0
        if ( !xGraphic.is() )
284
0
            xGraphic = implLoadStandardImage( aURL );
285
286
0
        if( xGraphic.is() )
287
0
        {
288
0
            xRet.set( xGraphic, uno::UNO_QUERY );
289
0
        }
290
0
        else
291
0
        {
292
0
            rtl::Reference<unographic::GraphicDescriptor> pDescriptor = new unographic::GraphicDescriptor;
293
0
            pDescriptor->init( aURL );
294
0
            xRet = pDescriptor;
295
0
        }
296
0
    }
297
0
    else if (aBtm.hasValue())
298
0
    {
299
0
        xRet.set(vcl::GetGraphic(aBtm), uno::UNO_QUERY);
300
0
    }
301
302
0
    return xRet;
303
0
}
304
305
306
uno::Reference< ::graphic::XGraphic > SAL_CALL GraphicProvider::queryGraphic( const uno::Sequence< ::beans::PropertyValue >& rMediaProperties )
307
1.02k
{
308
1.02k
    OUString                                aPath;
309
310
1.02k
    uno::Reference< io::XInputStream > xIStm;
311
1.02k
    uno::Any aBtm;
312
313
1.02k
    uno::Sequence< ::beans::PropertyValue > aFilterData;
314
315
1.02k
    bool bLazyRead = false;
316
1.02k
    bool bLoadAsLink = false;
317
318
1.02k
    for (const auto& rMediaProperty : rMediaProperties)
319
2.06k
    {
320
2.06k
        const OUString   aName( rMediaProperty.Name );
321
2.06k
        const uno::Any          aValue( rMediaProperty.Value );
322
323
2.06k
        if (aName == "URL")
324
0
        {
325
0
            aValue >>= aPath;
326
0
        }
327
2.06k
        else if (aName == "InputStream")
328
1.02k
        {
329
1.02k
            aValue >>= xIStm;
330
1.02k
        }
331
1.04k
        else if (aName == "Bitmap")
332
0
        {
333
0
            aBtm = aValue;
334
0
        }
335
1.04k
        else if (aName == "FilterData")
336
20
        {
337
20
            aValue >>= aFilterData;
338
20
        }
339
1.02k
        else if (aName == "LazyRead")
340
1.02k
        {
341
1.02k
            aValue >>= bLazyRead;
342
1.02k
        }
343
0
        else if (aName == "LoadAsLink")
344
0
        {
345
0
            aValue >>= bLoadAsLink;
346
0
        }
347
2.06k
    }
348
349
1.02k
    sal_uInt16 nExtMapMode = 0;
350
1.02k
    for (const auto& rProp : aFilterData)
351
60
    {
352
60
        const OUString   aName( rProp.Name );
353
60
        const uno::Any          aValue( rProp.Value );
354
355
60
        if (aName == "ExternalMapMode")
356
20
        {
357
20
            aValue >>= nExtMapMode;
358
20
        }
359
60
    }
360
361
1.02k
    SolarMutexGuard g;
362
363
1.02k
    uno::Reference<::graphic::XGraphic> xRet;
364
1.02k
    std::unique_ptr<SvStream> pIStm;
365
366
1.02k
    if( xIStm.is() )
367
1.02k
    {
368
1.02k
        pIStm = ::utl::UcbStreamHelper::CreateStream( xIStm );
369
1.02k
    }
370
0
    else if( !aPath.isEmpty() )
371
0
    {
372
0
        xRet = implLoadMemory( aPath );
373
374
0
        if ( !xRet.is() )
375
0
            xRet = implLoadRepositoryImage( aPath );
376
377
0
        if ( !xRet.is() )
378
0
            xRet = implLoadStandardImage( aPath );
379
380
0
        if( !xRet.is() )
381
0
            pIStm = ::utl::UcbStreamHelper::CreateStream( aPath, StreamMode::READ );
382
0
    }
383
0
    else if (aBtm.hasValue())
384
0
    {
385
0
        xRet = vcl::GetGraphic(aBtm);
386
0
    }
387
388
1.02k
    if( pIStm )
389
1.02k
    {
390
1.02k
        ::GraphicFilter& rFilter = ::GraphicFilter::GetGraphicFilter();
391
392
1.02k
        if ( nExtMapMode > 0 )
393
20
        {
394
20
            bLazyRead = false;
395
20
        }
396
397
1.02k
        Graphic aVCLGraphic;
398
1.02k
        ErrCode error = ERRCODE_NONE;
399
1.02k
        if (bLazyRead)
400
1.00k
        {
401
1.00k
            aVCLGraphic = rFilter.ImportUnloadedGraphic(*pIStm);
402
1.00k
        }
403
1.02k
        if (aVCLGraphic.IsNone())
404
224
            error = rFilter.ImportGraphic(aVCLGraphic, aPath, *pIStm, GRFILTER_FORMAT_DONTKNOW, nullptr, GraphicFilterImportFlags::NONE);
405
406
1.02k
        if (error == ERRCODE_NONE && !aVCLGraphic.IsNone())
407
818
        {
408
818
            if (!aPath.isEmpty() && bLoadAsLink)
409
0
                aVCLGraphic.setOriginURL(aPath);
410
411
818
            xRet = aVCLGraphic.GetXGraphic();
412
818
        }
413
205
        else{
414
205
            SAL_WARN("svtools", "Could not create graphic for:" << aPath << " error: " << error);
415
205
        }
416
1.02k
    }
417
418
1.02k
    return xRet;
419
1.02k
}
420
421
uno::Sequence< uno::Reference<graphic::XGraphic> > SAL_CALL GraphicProvider::queryGraphics(const uno::Sequence< uno::Sequence<beans::PropertyValue> >& rMediaPropertiesSeq)
422
0
{
423
    // Turn properties into streams.
424
0
    std::vector< std::unique_ptr<SvStream> > aStreams;
425
0
    for (const auto& rMediaProperties : rMediaPropertiesSeq)
426
0
    {
427
0
        std::unique_ptr<SvStream> pStream;
428
0
        uno::Reference<io::XInputStream> xStream;
429
430
0
        auto pProp = std::find_if(rMediaProperties.begin(), rMediaProperties.end(),
431
0
            [](const beans::PropertyValue& rProp) { return rProp.Name == "InputStream"; });
432
0
        if (pProp != rMediaProperties.end())
433
0
        {
434
0
            pProp->Value >>= xStream;
435
0
            if (xStream.is())
436
0
                pStream = utl::UcbStreamHelper::CreateStream(xStream);
437
0
        }
438
439
0
        aStreams.push_back(std::move(pStream));
440
0
    }
441
442
    // Import: streams to graphics.
443
0
    GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
444
0
    std::vector<Graphic> aGraphics = rFilter.ImportGraphics(std::move(aStreams));
445
446
    // Returning: graphics to UNO objects.
447
0
    uno::Sequence<uno::Reference<graphic::XGraphic>> aRet(aGraphics.size());
448
0
    std::transform(aGraphics.begin(), aGraphics.end(), aRet.getArray(),
449
0
                   [](const auto& rGraphic) { return rGraphic.GetXGraphic(); });
450
0
    return aRet;
451
0
}
452
453
void ImplCalculateCropRect( ::Graphic const & rGraphic, const text::GraphicCrop& rGraphicCropLogic, tools::Rectangle& rGraphicCropPixel )
454
0
{
455
0
    if ( !(rGraphicCropLogic.Left || rGraphicCropLogic.Top || rGraphicCropLogic.Right || rGraphicCropLogic.Bottom) )
456
0
        return;
457
458
0
    Size aSourceSizePixel( rGraphic.GetSizePixel() );
459
0
    if ( !(aSourceSizePixel.Width() && aSourceSizePixel.Height()) )
460
0
        return;
461
462
0
    if ( !(rGraphicCropLogic.Left || rGraphicCropLogic.Top || rGraphicCropLogic.Right || rGraphicCropLogic.Bottom) )
463
0
        return;
464
465
0
    Size aSize100thMM( 0, 0 );
466
0
    if( rGraphic.GetPrefMapMode().GetMapUnit() != MapUnit::MapPixel )
467
0
    {
468
0
        aSize100thMM = OutputDevice::LogicToLogic(rGraphic.GetPrefSize(), rGraphic.GetPrefMapMode(), MapMode(MapUnit::Map100thMM));
469
0
    }
470
0
    else
471
0
    {
472
0
        aSize100thMM = Application::GetDefaultDevice()->PixelToLogic(rGraphic.GetPrefSize(), MapMode(MapUnit::Map100thMM));
473
0
    }
474
0
    if ( aSize100thMM.Width() && aSize100thMM.Height() )
475
0
    {
476
0
        double fSourceSizePixelWidth = static_cast<double>(aSourceSizePixel.Width());
477
0
        double fSourceSizePixelHeight= static_cast<double>(aSourceSizePixel.Height());
478
0
        rGraphicCropPixel.SetLeft( static_cast< sal_Int32 >((fSourceSizePixelWidth * rGraphicCropLogic.Left ) / aSize100thMM.Width()) );
479
0
        rGraphicCropPixel.SetTop( static_cast< sal_Int32 >((fSourceSizePixelHeight * rGraphicCropLogic.Top ) / aSize100thMM.Height()) );
480
0
        rGraphicCropPixel.SetRight( static_cast< sal_Int32 >(( fSourceSizePixelWidth * ( aSize100thMM.Width() - rGraphicCropLogic.Right ) ) / aSize100thMM.Width() ) );
481
0
        rGraphicCropPixel.SetBottom( static_cast< sal_Int32 >(( fSourceSizePixelHeight * ( aSize100thMM.Height() - rGraphicCropLogic.Bottom ) ) / aSize100thMM.Height() ) );
482
0
    }
483
0
}
484
485
void ImplApplyBitmapScaling( ::Graphic& rGraphic, sal_Int32 nPixelWidth, sal_Int32 nPixelHeight )
486
0
{
487
0
    if ( nPixelWidth && nPixelHeight )
488
0
    {
489
0
        Bitmap aBmp( rGraphic.GetBitmap() );
490
0
        MapMode aPrefMapMode( aBmp.GetPrefMapMode() );
491
0
        Size    aPrefSize( aBmp.GetPrefSize() );
492
0
        aBmp.Scale( Size( nPixelWidth, nPixelHeight ) );
493
0
        aBmp.SetPrefMapMode( aPrefMapMode );
494
0
        aBmp.SetPrefSize( aPrefSize );
495
0
        rGraphic = aBmp;
496
0
    }
497
0
}
498
499
void ImplApplyBitmapResolution( ::Graphic& rGraphic, sal_Int32 nImageResolution, const Size& rVisiblePixelSize, const awt::Size& rLogicalSize )
500
0
{
501
0
    if ( !(nImageResolution && rLogicalSize.Width && rLogicalSize.Height) )
502
0
        return;
503
504
0
    const double fImageResolution = static_cast<double>( nImageResolution );
505
0
    const double fSourceDPIX = ( static_cast<double>(rVisiblePixelSize.Width()) * 2540.0 ) / static_cast<double>(rLogicalSize.Width);
506
0
    const double fSourceDPIY = ( static_cast<double>(rVisiblePixelSize.Height()) * 2540.0 ) / static_cast<double>(rLogicalSize.Height);
507
0
    const sal_Int32 nSourcePixelWidth( rGraphic.GetSizePixel().Width() );
508
0
    const sal_Int32 nSourcePixelHeight( rGraphic.GetSizePixel().Height() );
509
0
    const double fSourcePixelWidth = static_cast<double>( nSourcePixelWidth );
510
0
    const double fSourcePixelHeight= static_cast<double>( nSourcePixelHeight );
511
512
0
    sal_Int32 nDestPixelWidth = nSourcePixelWidth;
513
0
    sal_Int32 nDestPixelHeight = nSourcePixelHeight;
514
515
    // check, if the bitmap DPI exceeds the maximum DPI
516
0
    if( fSourceDPIX > fImageResolution )
517
0
    {
518
0
        nDestPixelWidth = static_cast<sal_Int32>(( fSourcePixelWidth * fImageResolution ) / fSourceDPIX);
519
0
        if ( !nDestPixelWidth || ( nDestPixelWidth > nSourcePixelWidth ) )
520
0
            nDestPixelWidth = nSourcePixelWidth;
521
0
    }
522
0
    if ( fSourceDPIY > fImageResolution )
523
0
    {
524
0
        nDestPixelHeight= static_cast<sal_Int32>(( fSourcePixelHeight* fImageResolution ) / fSourceDPIY);
525
0
        if ( !nDestPixelHeight || ( nDestPixelHeight > nSourcePixelHeight ) )
526
0
            nDestPixelHeight = nSourcePixelHeight;
527
0
    }
528
0
    if ( ( nDestPixelWidth != nSourcePixelWidth ) || ( nDestPixelHeight != nSourcePixelHeight ) )
529
0
        ImplApplyBitmapScaling( rGraphic, nDestPixelWidth, nDestPixelHeight );
530
0
}
531
532
void ImplApplyFilterData( ::Graphic& rGraphic, const uno::Sequence< beans::PropertyValue >& rFilterData )
533
0
{
534
    /* this method applies following attributes to the graphic, in the first step the
535
       cropping area (logical size in 100thmm) is applied, in the second step the resolution
536
       is applied, in the third step the graphic is scaled to the corresponding pixelsize.
537
       if a parameter value is zero or not available the corresponding step will be skipped */
538
539
0
    sal_Int32 nPixelWidth = 0;
540
0
    sal_Int32 nPixelHeight= 0;
541
0
    sal_Int32 nImageResolution = 0;
542
0
    awt::Size aLogicalSize( 0, 0 );
543
0
    text::GraphicCrop aCropLogic( 0, 0, 0, 0 );
544
0
    bool bRemoveCropArea = true;
545
546
0
    for( const auto& rProp : rFilterData )
547
0
    {
548
0
        const OUString   aName(  rProp.Name );
549
0
        const uno::Any          aValue( rProp.Value );
550
551
0
        if (aName == "PixelWidth")
552
0
            aValue >>= nPixelWidth;
553
0
        else if (aName == "PixelHeight")
554
0
            aValue >>= nPixelHeight;
555
0
        else if (aName == "LogicalSize")
556
0
            aValue >>= aLogicalSize;
557
0
        else if (aName == "GraphicCropLogic")
558
0
            aValue >>= aCropLogic;
559
0
        else if (aName == "RemoveCropArea")
560
0
            aValue >>= bRemoveCropArea;
561
0
        else if (aName == "ImageResolution")
562
0
            aValue >>= nImageResolution;
563
0
    }
564
0
    if ( rGraphic.GetType() == GraphicType::Bitmap )
565
0
    {
566
0
        if(rGraphic.getVectorGraphicData())
567
0
        {
568
            // embedded Vector Graphic Data, no need to scale. Also no method to apply crop data currently
569
0
        }
570
0
        else
571
0
        {
572
0
            tools::Rectangle aCropPixel( Point( 0, 0 ), rGraphic.GetSizePixel() );
573
0
            ImplCalculateCropRect( rGraphic, aCropLogic, aCropPixel );
574
0
            if ( bRemoveCropArea )
575
0
            {
576
0
                Bitmap aBmp( rGraphic.GetBitmap() );
577
0
                aBmp.Crop( aCropPixel );
578
0
                rGraphic = aBmp;
579
0
            }
580
0
            Size aVisiblePixelSize( bRemoveCropArea ? rGraphic.GetSizePixel() : aCropPixel.GetSize() );
581
0
            ImplApplyBitmapResolution( rGraphic, nImageResolution, aVisiblePixelSize, aLogicalSize );
582
0
            ImplApplyBitmapScaling( rGraphic, nPixelWidth, nPixelHeight );
583
0
        }
584
0
    }
585
0
    else if ( ( rGraphic.GetType() == GraphicType::GdiMetafile ) && nImageResolution )
586
0
    {
587
0
        ScopedVclPtrInstance< VirtualDevice > aDummyVDev;
588
0
        GDIMetaFile aMtf( rGraphic.GetGDIMetaFile() );
589
0
        Size aMtfSize( OutputDevice::LogicToLogic(aMtf.GetPrefSize(), aMtf.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)) );
590
0
        if ( aMtfSize.Width() && aMtfSize.Height() )
591
0
        {
592
0
            MapMode aNewMapMode( MapUnit::Map100thMM );
593
0
            aNewMapMode.SetScaleX( double(aLogicalSize.Width) / aMtfSize.Width() );
594
0
            aNewMapMode.SetScaleY( double(aLogicalSize.Height) / aMtfSize.Height() );
595
0
            aDummyVDev->EnableOutput( false );
596
0
            aDummyVDev->SetMapMode( aNewMapMode );
597
598
0
            for( size_t i = 0, nObjCount = aMtf.GetActionSize(); i < nObjCount; i++ )
599
0
            {
600
0
                MetaAction* pAction = aMtf.GetAction( i );
601
0
                switch( pAction->GetType() )
602
0
                {
603
                    // only optimizing common bitmap actions:
604
0
                    case MetaActionType::MAPMODE:
605
0
                    {
606
0
                        pAction->Execute( aDummyVDev.get() );
607
0
                        break;
608
0
                    }
609
0
                    case MetaActionType::PUSH:
610
0
                    {
611
0
                        const MetaPushAction* pA = static_cast<const MetaPushAction*>(pAction);
612
0
                        aDummyVDev->Push( pA->GetFlags() );
613
0
                        break;
614
0
                    }
615
0
                    case MetaActionType::POP:
616
0
                    {
617
0
                        aDummyVDev->Pop();
618
0
                        break;
619
0
                    }
620
0
                    case MetaActionType::BMPSCALE:
621
0
                    case MetaActionType::BMPEXSCALE:
622
0
                    {
623
0
                        Bitmap aBmp;
624
0
                        Point aPos;
625
0
                        Size aSize;
626
0
                        if ( pAction->GetType() == MetaActionType::BMPSCALE )
627
0
                        {
628
0
                            MetaBmpScaleAction* pScaleAction = dynamic_cast< MetaBmpScaleAction* >( pAction );
629
0
                            assert(pScaleAction);
630
0
                            aBmp = pScaleAction->GetBitmap();
631
0
                            aPos = pScaleAction->GetPoint();
632
0
                            aSize = pScaleAction->GetSize();
633
0
                        }
634
0
                        else
635
0
                        {
636
0
                            MetaBmpExScaleAction* pScaleAction = dynamic_cast< MetaBmpExScaleAction* >( pAction );
637
0
                            assert(pScaleAction);
638
0
                            aBmp = pScaleAction->GetBitmap();
639
0
                            aPos = pScaleAction->GetPoint();
640
0
                            aSize = pScaleAction->GetSize();
641
0
                        }
642
0
                        ::Graphic aGraphic( aBmp );
643
0
                        const Size aSize100thmm( aDummyVDev->LogicToPixel( aSize ) );
644
0
                        Size aSize100thmm2( aDummyVDev->PixelToLogic(aSize100thmm, MapMode(MapUnit::Map100thMM)) );
645
646
0
                        ImplApplyBitmapResolution( aGraphic, nImageResolution,
647
0
                            aGraphic.GetSizePixel(), awt::Size( aSize100thmm2.Width(), aSize100thmm2.Height() ) );
648
649
0
                        rtl::Reference<MetaAction> pNewAction = new MetaBmpExScaleAction( aPos, aSize, aGraphic.GetBitmap() );
650
0
                        aMtf.ReplaceAction( pNewAction, i );
651
0
                        break;
652
0
                    }
653
0
                    default:
654
0
                    case MetaActionType::BMP:
655
0
                    case MetaActionType::BMPSCALEPART:
656
0
                    case MetaActionType::BMPEX:
657
0
                    case MetaActionType::BMPEXSCALEPART:
658
0
                    case MetaActionType::MASK:
659
0
                    case MetaActionType::MASKSCALE:
660
0
                    break;
661
0
                }
662
0
            }
663
0
            rGraphic = aMtf;
664
0
        }
665
0
    }
666
0
}
667
668
669
void SAL_CALL GraphicProvider::storeGraphic( const uno::Reference< ::graphic::XGraphic >& rxGraphic, const uno::Sequence< beans::PropertyValue >& rMediaProperties )
670
0
{
671
0
    std::unique_ptr<SvStream> pOStm;
672
0
    OUString    aPath;
673
674
0
    for( const auto& rMediaProperty : rMediaProperties )
675
0
    {
676
0
        const OUString   aName( rMediaProperty.Name );
677
0
        const uno::Any          aValue( rMediaProperty.Value );
678
679
0
        if (aName == "URL")
680
0
        {
681
0
            OUString aURL;
682
683
0
            aValue >>= aURL;
684
0
            pOStm = ::utl::UcbStreamHelper::CreateStream( aURL, StreamMode::WRITE | StreamMode::TRUNC );
685
0
            aPath = aURL;
686
0
        }
687
0
        else if (aName == "OutputStream")
688
0
        {
689
0
            uno::Reference< io::XStream > xOStm;
690
691
0
            aValue >>= xOStm;
692
693
0
            if( xOStm.is() )
694
0
                pOStm = ::utl::UcbStreamHelper::CreateStream( xOStm );
695
0
        }
696
697
0
        if( pOStm )
698
0
            break;
699
0
    }
700
701
0
    if( !pOStm )
702
0
        return;
703
704
0
    uno::Sequence< beans::PropertyValue >   aFilterDataSeq;
705
0
    OUString sFilterShortName;
706
707
0
    for( const auto& rMediaProperty : rMediaProperties )
708
0
    {
709
0
        const OUString   aName( rMediaProperty.Name );
710
0
        const uno::Any          aValue( rMediaProperty.Value );
711
712
0
        if (aName == "FilterData")
713
0
        {
714
0
            aValue >>= aFilterDataSeq;
715
0
        }
716
0
        else if (aName == "MimeType")
717
0
        {
718
0
            OUString aMimeType;
719
720
0
            aValue >>= aMimeType;
721
722
0
            if (aMimeType == MIMETYPE_BMP)
723
0
                sFilterShortName = "bmp";
724
0
            else if (aMimeType == MIMETYPE_EPS)
725
0
                sFilterShortName = "eps";
726
0
            else if (aMimeType == MIMETYPE_GIF)
727
0
                sFilterShortName = "gif";
728
0
            else if (aMimeType == MIMETYPE_JPG)
729
0
                sFilterShortName = "jpg";
730
0
            else if (aMimeType == MIMETYPE_MET)
731
0
                sFilterShortName = "met";
732
0
            else if (aMimeType == MIMETYPE_PNG)
733
0
                sFilterShortName = "png";
734
0
            else if (aMimeType == MIMETYPE_PCT)
735
0
                sFilterShortName = "pct";
736
0
            else if (aMimeType == MIMETYPE_PBM)
737
0
                sFilterShortName = "pbm";
738
0
            else if (aMimeType == MIMETYPE_PGM)
739
0
                sFilterShortName = "pgm";
740
0
            else if (aMimeType == MIMETYPE_PPM)
741
0
                sFilterShortName = "ppm";
742
0
            else if (aMimeType == MIMETYPE_RAS)
743
0
                sFilterShortName = "ras";
744
0
            else if (aMimeType == MIMETYPE_SVM)
745
0
                sFilterShortName = "svm";
746
0
            else if (aMimeType == MIMETYPE_TIF)
747
0
                sFilterShortName = "tif";
748
0
            else if (aMimeType == MIMETYPE_EMF)
749
0
                sFilterShortName = "emf";
750
0
            else if (aMimeType == MIMETYPE_WMF)
751
0
                sFilterShortName = "wmf";
752
0
            else if (aMimeType == MIMETYPE_XPM)
753
0
                sFilterShortName = "xpm";
754
0
            else if (aMimeType == MIMETYPE_SVG)
755
0
                sFilterShortName = "svg";
756
0
            else if (aMimeType == MIMETYPE_VCLGRAPHIC)
757
0
                sFilterShortName = MIMETYPE_VCLGRAPHIC;
758
0
        }
759
0
    }
760
761
0
    if( sFilterShortName.isEmpty() )
762
0
        return;
763
764
0
    ::GraphicFilter& rFilter = ::GraphicFilter::GetGraphicFilter();
765
766
0
    {
767
0
        const uno::Reference< XInterface >  xIFace( rxGraphic, uno::UNO_QUERY );
768
0
        const ::unographic::Graphic* pUnoGraphic = dynamic_cast<::unographic::Graphic*>(xIFace.get());
769
0
        const ::Graphic* pGraphic = pUnoGraphic ? &pUnoGraphic->GetGraphic() : nullptr;
770
771
0
        if( pGraphic && ( pGraphic->GetType() != GraphicType::NONE ) )
772
0
        {
773
0
            ::Graphic aGraphic( *pGraphic );
774
0
            ImplApplyFilterData( aGraphic, aFilterDataSeq );
775
776
            /* sj: using a temporary memory stream, because some graphic filters are seeking behind
777
               stream end (which leads to an invalid argument exception then). */
778
0
            SvMemoryStream aMemStrm;
779
0
            aMemStrm.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
780
0
            if( sFilterShortName == MIMETYPE_VCLGRAPHIC )
781
0
            {
782
0
                TypeSerializer aSerializer(aMemStrm);
783
0
                aSerializer.writeGraphic(aGraphic);
784
0
            }
785
0
            else
786
0
            {
787
0
                rFilter.ExportGraphic( aGraphic, aPath, aMemStrm,
788
0
                                        rFilter.GetExportFormatNumberForShortName( sFilterShortName ),
789
0
                                            ( aFilterDataSeq.hasElements() ? &aFilterDataSeq : nullptr ) );
790
0
            }
791
0
            pOStm->WriteBytes( aMemStrm.GetData(), aMemStrm.TellEnd() );
792
0
        }
793
0
    }
794
0
}
795
796
}
797
798
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
799
com_sun_star_comp_graphic_GraphicProvider_get_implementation(
800
    css::uno::XComponentContext *,
801
    css::uno::Sequence<css::uno::Any> const &)
802
32.8k
{
803
32.8k
    return cppu::acquire(new GraphicProvider);
804
32.8k
}
805
806
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */