Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/helper/canvastools.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 <com/sun/star/geometry/RealSize2D.hpp>
21
#include <com/sun/star/geometry/IntegerSize2D.hpp>
22
#include <com/sun/star/geometry/IntegerPoint2D.hpp>
23
#include <com/sun/star/geometry/IntegerRectangle2D.hpp>
24
25
#include <com/sun/star/rendering/ColorSpaceType.hpp>
26
#include <com/sun/star/rendering/RenderingIntent.hpp>
27
#include <com/sun/star/rendering/VolatileContentDestroyedException.hpp>
28
#include <com/sun/star/rendering/XBitmap.hpp>
29
#include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
30
#include <com/sun/star/rendering/ColorComponentTag.hpp>
31
32
#include <basegfx/point/b2dpoint.hxx>
33
#include <basegfx/vector/b2dsize.hxx>
34
#include <basegfx/range/b2drectangle.hxx>
35
#include <basegfx/point/b2ipoint.hxx>
36
#include <basegfx/range/b2irectangle.hxx>
37
38
#include <sal/log.hxx>
39
#include <tools/helpers.hxx>
40
#include <comphelper/diagnose_ex.hxx>
41
42
#include <vcl/bitmap.hxx>
43
44
#include <canvasbitmap.hxx>
45
#include <vcl/canvastools.hxx>
46
#include <vcl/BitmapWriteAccess.hxx>
47
48
using namespace ::com::sun::star;
49
50
namespace vcl::unotools
51
{
52
        uno::Reference< rendering::XBitmap > xBitmapFromBitmap(const ::Bitmap& inputBitmap )
53
4
        {
54
4
            SAL_INFO( "vcl.helper", "vcl::unotools::xBitmapFromBitmapEx()" );
55
56
4
            return new vcl::unotools::VclCanvasBitmap( inputBitmap );
57
4
        }
58
59
        namespace
60
        {
61
            bool equalsLayout( const rendering::IntegerBitmapLayout& rLHS,
62
                                    const rendering::IntegerBitmapLayout& rRHS )
63
0
            {
64
0
                return
65
0
                    rLHS.ScanLineBytes       == rRHS.ScanLineBytes &&
66
0
                    rLHS.ScanLineStride      == rRHS.ScanLineStride &&
67
0
                    rLHS.PlaneStride         == rRHS.PlaneStride &&
68
0
                    rLHS.ColorSpace          == rRHS.ColorSpace &&
69
0
                    rLHS.Palette             == rRHS.Palette &&
70
0
                    rLHS.IsMsbFirst          == rRHS.IsMsbFirst;
71
0
            }
72
            bool readBmp( sal_Int32                                                  nWidth,
73
                          sal_Int32                                                  nHeight,
74
                          const rendering::IntegerBitmapLayout&                      rLayout,
75
                          const uno::Reference< rendering::XIntegerReadOnlyBitmap >& xInputBitmap,
76
                          BitmapScopedWriteAccess&                                   rWriteAcc,
77
                          bool bHasAlpha )
78
0
            {
79
0
                rendering::IntegerBitmapLayout      aCurrLayout;
80
0
                geometry::IntegerRectangle2D        aRect;
81
0
                uno::Sequence<sal_Int8>             aPixelData;
82
0
                uno::Sequence<rendering::RGBColor>  aRGBColors;
83
0
                uno::Sequence<rendering::ARGBColor> aARGBColors;
84
85
0
                for( aRect.Y1=0; aRect.Y1<nHeight; ++aRect.Y1 )
86
0
                {
87
0
                    aRect.X1 = 0; aRect.X2 = nWidth; aRect.Y2 = aRect.Y1+1;
88
0
                    try
89
0
                    {
90
0
                        aPixelData = xInputBitmap->getData(aCurrLayout,aRect);
91
0
                    }
92
0
                    catch( rendering::VolatileContentDestroyedException& )
93
0
                    {
94
                        // re-read bmp from the start
95
0
                        return false;
96
0
                    }
97
0
                    if( !equalsLayout(aCurrLayout, rLayout) )
98
0
                        return false; // re-read bmp from the start
99
100
0
                    Scanline pScanline = rWriteAcc->GetScanline( aRect.Y1 );
101
0
                    if( bHasAlpha )
102
0
                    {
103
                        // read ARGB color
104
0
                        aARGBColors = rLayout.ColorSpace->convertIntegerToARGB(aPixelData);
105
106
0
                        assert( !rWriteAcc->HasPalette() );
107
0
                        for( sal_Int32 x=0; x<nWidth; ++x )
108
0
                        {
109
0
                            const rendering::ARGBColor& rColor=aARGBColors[x];
110
0
                            rWriteAcc->SetPixelOnData( pScanline, x,
111
0
                                                 BitmapColor( ColorAlpha,
112
0
                                                              toByteColor(rColor.Red),
113
0
                                                              toByteColor(rColor.Green),
114
0
                                                              toByteColor(rColor.Blue),
115
0
                                                              toByteColor(rColor.Alpha) ));
116
0
                        }
117
0
                    }
118
0
                    else
119
0
                    {
120
                        // read RGB color
121
0
                        aRGBColors = rLayout.ColorSpace->convertIntegerToRGB(aPixelData);
122
0
                        if( rWriteAcc->HasPalette() )
123
0
                        {
124
0
                            for( sal_Int32 x=0; x<nWidth; ++x )
125
0
                            {
126
0
                                const rendering::RGBColor& rColor=aRGBColors[x];
127
0
                                rWriteAcc->SetPixelOnData( pScanline, x,
128
0
                                                     BitmapColor(static_cast<sal_uInt8>(rWriteAcc->GetBestPaletteIndex(
129
0
                                                         BitmapColor( toByteColor(rColor.Red),
130
0
                                                                      toByteColor(rColor.Green),
131
0
                                                                      toByteColor(rColor.Blue))))) );
132
0
                            }
133
0
                        }
134
0
                        else
135
0
                        {
136
0
                            for( sal_Int32 x=0; x<nWidth; ++x )
137
0
                            {
138
0
                                const rendering::RGBColor& rColor=aRGBColors[x];
139
0
                                rWriteAcc->SetPixelOnData( pScanline, x,
140
0
                                                     BitmapColor( toByteColor(rColor.Red),
141
0
                                                                  toByteColor(rColor.Green),
142
0
                                                                  toByteColor(rColor.Blue) ));
143
0
                            }
144
0
                        }
145
0
                    }
146
0
                }
147
148
0
                return true;
149
0
            }
150
        }
151
152
        ::Bitmap bitmapFromXBitmap( const uno::Reference< rendering::XIntegerReadOnlyBitmap >& xInputBitmap )
153
4
        {
154
4
            SAL_INFO( "vcl.helper", "vcl::unotools::bitmapExFromXBitmap()" );
155
156
4
            if( !xInputBitmap.is() )
157
0
                return ::Bitmap();
158
159
            // tunnel directly for known implementation
160
4
            VclCanvasBitmap* pImplBitmap = dynamic_cast<VclCanvasBitmap*>(xInputBitmap.get());
161
4
            if( pImplBitmap )
162
4
                return pImplBitmap->getBitmap();
163
164
            // retrieve data via UNO interface
165
166
            // volatile bitmaps are a bit more complicated to read
167
            // from...
168
169
            // loop a few times, until successfully read (for XVolatileBitmap)
170
0
            for( int i=0; i<10; ++i )
171
0
            {
172
0
                sal_Int32 nDepth=0;
173
0
                bool bHasAlpha = false;
174
0
                const rendering::IntegerBitmapLayout aLayout(
175
0
                    xInputBitmap->getMemoryLayout());
176
177
0
                OSL_ENSURE(aLayout.ColorSpace.is(),
178
0
                           "Cannot convert image without color space!");
179
0
                if( !aLayout.ColorSpace.is() )
180
0
                    return ::Bitmap();
181
182
0
                nDepth = aLayout.ColorSpace->getBitsPerPixel();
183
184
0
                if( xInputBitmap->hasAlpha() )
185
0
                {
186
                    // determine alpha channel depth
187
0
                    const uno::Sequence<sal_Int8> aTags(
188
0
                        aLayout.ColorSpace->getComponentTags() );
189
0
                    const sal_Int8* pStart(aTags.getConstArray());
190
0
                    const std::size_t  nLen(aTags.getLength());
191
0
                    const sal_Int8* pEnd(pStart+nLen);
192
193
0
                    const std::ptrdiff_t nAlphaIndex =
194
0
                        std::find(pStart,pEnd,
195
0
                                  rendering::ColorComponentTag::ALPHA) - pStart;
196
197
0
                    ENSURE_OR_THROW( nAlphaIndex < sal::static_int_cast<std::ptrdiff_t>(nLen),
198
0
                        "bitmap has alpha, but alphaindex not valid");
199
0
                    auto nAlphaBitCount = aLayout.ColorSpace->getComponentBitCounts()[nAlphaIndex];
200
0
                    ENSURE_OR_THROW(nAlphaBitCount == 8, "unsupported alpha bit count");
201
0
                    bHasAlpha = true;
202
0
                    nDepth -= nAlphaBitCount;
203
0
                }
204
205
0
                BitmapPalette aPalette;
206
0
                if( aLayout.Palette.is() )
207
0
                {
208
0
                    ENSURE_OR_THROW(!bHasAlpha, "unsupported");
209
0
                    uno::Reference< rendering::XColorSpace > xPaletteColorSpace(
210
0
                        aLayout.Palette->getColorSpace());
211
0
                    ENSURE_OR_THROW(xPaletteColorSpace.is(),
212
0
                                    "Palette without color space");
213
214
0
                    const sal_Int32 nEntryCount( aLayout.Palette->getNumberOfEntries() );
215
0
                    if( nEntryCount <= 256 )
216
0
                    {
217
0
                        if( nEntryCount <= 2 )
218
0
                            nDepth = 1;
219
0
                        else
220
0
                            nDepth = 8;
221
222
0
                        const sal_uInt16 nPaletteEntries(
223
0
                            sal::static_int_cast<sal_uInt16>(
224
0
                                std::min(sal_Int32(255), nEntryCount)));
225
226
                        // copy palette entries
227
0
                        aPalette.SetEntryCount(nPaletteEntries);
228
0
                        uno::Reference<rendering::XBitmapPalette> xPalette( aLayout.Palette );
229
0
                        uno::Reference<rendering::XColorSpace>    xPalColorSpace( xPalette->getColorSpace() );
230
231
0
                        uno::Sequence<double> aPaletteEntry;
232
0
                        for( sal_uInt16 j=0; j<nPaletteEntries; ++j )
233
0
                        {
234
0
                            bool b = xPalette->getIndex(aPaletteEntry,j);
235
0
                            ENSURE_OR_THROW(b, "transparent entry in palette unsupported");
236
0
                            uno::Sequence<rendering::RGBColor> aColors=xPalColorSpace->convertToRGB(aPaletteEntry);
237
0
                            ENSURE_OR_THROW(aColors.getLength() == 1,
238
0
                                            "Palette returned more or less than one entry");
239
0
                            const rendering::RGBColor& rColor=aColors[0];
240
0
                            aPalette[j] = BitmapColor(toByteColor(rColor.Red),
241
0
                                                      toByteColor(rColor.Green),
242
0
                                                      toByteColor(rColor.Blue));
243
0
                        }
244
0
                    }
245
0
                }
246
247
0
                const ::Size aPixelSize(
248
0
                    sizeFromIntegerSize2D(xInputBitmap->getSize()));
249
250
                // normalize bitcount
251
0
                vcl::PixelFormat ePixelFormat;
252
0
                if (bHasAlpha)
253
0
                    ePixelFormat = vcl::PixelFormat::N32_BPP;
254
0
                else if ( nDepth <= 8 )
255
0
                    ePixelFormat = vcl::PixelFormat::N8_BPP;
256
0
                else
257
0
                    ePixelFormat = vcl::PixelFormat::N24_BPP;
258
259
0
                ::Bitmap aBitmap( aPixelSize,
260
0
                                  ePixelFormat,
261
0
                                  aLayout.Palette.is() ? &aPalette : nullptr );
262
263
0
                { // limit scoped access
264
0
                    BitmapScopedWriteAccess pWriteAccess( aBitmap );
265
0
                    ENSURE_OR_THROW(pWriteAccess.get() != nullptr,
266
0
                                    "Cannot get write access to bitmap");
267
268
0
                    const sal_Int32 nWidth(aPixelSize.Width());
269
0
                    const sal_Int32 nHeight(aPixelSize.Height());
270
271
0
                    if( !readBmp(nWidth,nHeight,aLayout,xInputBitmap,pWriteAccess,bHasAlpha) )
272
0
                        continue;
273
0
                } // limit scoped access
274
275
0
                return aBitmap;
276
0
            }
277
278
            // failed to read data 10 times - bail out
279
0
            return ::Bitmap();
280
0
        }
281
282
        geometry::RealSize2D size2DFromSize( const Size& rSize )
283
0
        {
284
0
            return geometry::RealSize2D( rSize.Width(),
285
0
                                         rSize.Height() );
286
0
        }
287
288
        Size sizeFromRealSize2D( const geometry::RealSize2D& rSize )
289
0
        {
290
0
            return Size( static_cast<tools::Long>(rSize.Width + .5),
291
0
                         static_cast<tools::Long>(rSize.Height + .5) );
292
0
        }
293
294
        ::Size sizeFromB2DSize( const basegfx::B2DVector& rVec )
295
0
        {
296
0
            return ::Size(basegfx::fround<tools::Long>(rVec.getX()),
297
0
                          basegfx::fround<tools::Long>(rVec.getY()));
298
0
        }
299
300
        ::Point pointFromB2DPoint( const basegfx::B2DPoint& rPoint )
301
0
        {
302
0
            return pointFromB2IPoint(basegfx::fround(rPoint));
303
0
        }
304
305
        ::tools::Rectangle rectangleFromB2DRectangle( const basegfx::B2DRange& rRect )
306
0
        {
307
0
            return rectangleFromB2IRectangle(basegfx::fround(rRect));
308
0
        }
309
310
        Point pointFromB2IPoint( const basegfx::B2IPoint& rPoint )
311
0
        {
312
0
            return ::Point( rPoint.getX(),
313
0
                            rPoint.getY() );
314
0
        }
315
316
        basegfx::B2IPoint b2IPointFromPoint(Point const& rPoint)
317
27.7k
        {
318
27.7k
            return basegfx::B2IPoint(rPoint.X(), rPoint.Y());
319
27.7k
        }
320
321
        tools::Rectangle rectangleFromB2IRectangle( const basegfx::B2IRange& rRect )
322
0
        {
323
0
            return ::tools::Rectangle( rRect.getMinX(),
324
0
                                rRect.getMinY(),
325
0
                                rRect.getMaxX(),
326
0
                                rRect.getMaxY() );
327
0
        }
328
329
        basegfx::B2IRectangle b2IRectangleFromRectangle(tools::Rectangle const& rRect)
330
110k
        {
331
            // although B2IRange internally has separate height/width emptiness, it doesn't
332
            // expose any API to let us set them separately, so just do the best we can.
333
110k
            if (rRect.IsWidthEmpty() && rRect.IsHeightEmpty())
334
0
                return basegfx::B2IRange( basegfx::B2ITuple( rRect.Left(), rRect.Top() ) );
335
110k
            return basegfx::B2IRange( rRect.Left(),
336
110k
                                  rRect.Top(),
337
110k
                                  rRect.IsWidthEmpty() ? rRect.Left() : rRect.Right(),
338
110k
                                  rRect.IsHeightEmpty() ? rRect.Top() : rRect.Bottom() );
339
110k
        }
340
341
        basegfx::B2DSize b2DSizeFromSize(const Size& rSize)
342
0
        {
343
0
            return basegfx::B2DSize(rSize.Width(), rSize.Height());
344
0
        }
345
346
        basegfx::B2DVector b2DVectorFromSize(const Size& rSize)
347
0
        {
348
0
            return basegfx::B2DVector(rSize.Width(), rSize.Height());
349
0
        }
350
351
        basegfx::B2DPoint b2DPointFromPoint( const ::Point& rPoint )
352
0
        {
353
0
            return basegfx::B2DPoint( rPoint.X(),
354
0
                                        rPoint.Y() );
355
0
        }
356
357
        basegfx::B2DRange b2DRectangleFromRectangle( const ::tools::Rectangle& rRect )
358
223k
        {
359
            // although B2DRange internally has separate height/width emptiness, it doesn't
360
            // expose any API to let us set them separately, so just do the best we can.
361
223k
            if (rRect.IsWidthEmpty() && rRect.IsHeightEmpty())
362
305
                return basegfx::B2DRange( basegfx::B2DTuple( rRect.Left(), rRect.Top() ) );
363
223k
            return basegfx::B2DRectangle( rRect.Left(),
364
223k
                                  rRect.Top(),
365
223k
                                  rRect.IsWidthEmpty() ? rRect.Left() : rRect.Right(),
366
223k
                                  rRect.IsHeightEmpty() ? rRect.Top() : rRect.Bottom() );
367
223k
        }
368
369
        geometry::IntegerSize2D integerSize2DFromSize( const Size& rSize )
370
0
        {
371
0
            return geometry::IntegerSize2D( rSize.Width(),
372
0
                                            rSize.Height() );
373
0
        }
374
375
        Size sizeFromIntegerSize2D( const geometry::IntegerSize2D& rSize )
376
0
        {
377
0
            return Size( rSize.Width,
378
0
                         rSize.Height );
379
0
        }
380
381
        Point pointFromIntegerPoint2D( const geometry::IntegerPoint2D& rPoint )
382
0
        {
383
0
            return Point( rPoint.X,
384
0
                          rPoint.Y );
385
0
        }
386
387
        tools::Rectangle rectangleFromIntegerRectangle2D( const geometry::IntegerRectangle2D& rRectangle )
388
0
        {
389
0
            return tools::Rectangle( rRectangle.X1, rRectangle.Y1,
390
0
                              rRectangle.X2, rRectangle.Y2 );
391
0
        }
392
393
        namespace
394
        {
395
            class StandardColorSpace : public cppu::WeakImplHelper< css::rendering::XColorSpace >
396
            {
397
            private:
398
                uno::Sequence< sal_Int8 > m_aComponentTags;
399
400
                virtual ::sal_Int8 SAL_CALL getType(  ) override
401
0
                {
402
0
                    return rendering::ColorSpaceType::RGB;
403
0
                }
404
                virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags(  ) override
405
0
                {
406
0
                    return m_aComponentTags;
407
0
                }
408
                virtual ::sal_Int8 SAL_CALL getRenderingIntent(  ) override
409
0
                {
410
0
                    return rendering::RenderingIntent::PERCEPTUAL;
411
0
                }
412
                virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties(  ) override
413
0
                {
414
0
                    return uno::Sequence< beans::PropertyValue >();
415
0
                }
416
                virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor,
417
                                                                            const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override
418
0
                {
419
                    // TODO(P3): if we know anything about target
420
                    // colorspace, this can be greatly sped up
421
0
                    uno::Sequence<rendering::ARGBColor> aIntermediate(
422
0
                        convertToARGB(deviceColor));
423
0
                    return targetColorSpace->convertFromARGB(aIntermediate);
424
0
                }
425
                virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) override
426
0
                {
427
0
                    const double*  pIn( deviceColor.getConstArray() );
428
0
                    const std::size_t nLen( deviceColor.getLength() );
429
0
                    ENSURE_ARG_OR_THROW2(nLen%4==0,
430
0
                                         "number of channels no multiple of 4",
431
0
                                         static_cast<rendering::XColorSpace*>(this), 0);
432
433
0
                    uno::Sequence< rendering::RGBColor > aRes(nLen/4);
434
0
                    rendering::RGBColor* pOut( aRes.getArray() );
435
0
                    for( std::size_t i=0; i<nLen; i+=4 )
436
0
                    {
437
0
                        *pOut++ = rendering::RGBColor(pIn[0],pIn[1],pIn[2]);
438
0
                        pIn += 4;
439
0
                    }
440
0
                    return aRes;
441
0
                }
442
                virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) override
443
0
                {
444
0
                    const double*  pIn( deviceColor.getConstArray() );
445
0
                    const std::size_t nLen( deviceColor.getLength() );
446
0
                    ENSURE_ARG_OR_THROW2(nLen%4==0,
447
0
                                         "number of channels no multiple of 4",
448
0
                                         static_cast<rendering::XColorSpace*>(this), 0);
449
450
0
                    uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
451
0
                    rendering::ARGBColor* pOut( aRes.getArray() );
452
0
                    for( std::size_t i=0; i<nLen; i+=4 )
453
0
                    {
454
0
                        *pOut++ = rendering::ARGBColor(pIn[3],pIn[0],pIn[1],pIn[2]);
455
0
                        pIn += 4;
456
0
                    }
457
0
                    return aRes;
458
0
                }
459
                virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) override
460
0
                {
461
0
                    const double*  pIn( deviceColor.getConstArray() );
462
0
                    const std::size_t nLen( deviceColor.getLength() );
463
0
                    ENSURE_ARG_OR_THROW2(nLen%4==0,
464
0
                                         "number of channels no multiple of 4",
465
0
                                         static_cast<rendering::XColorSpace*>(this), 0);
466
467
0
                    uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
468
0
                    rendering::ARGBColor* pOut( aRes.getArray() );
469
0
                    for( std::size_t i=0; i<nLen; i+=4 )
470
0
                    {
471
0
                        *pOut++ = rendering::ARGBColor(pIn[3],pIn[3]*pIn[0],pIn[3]*pIn[1],pIn[3]*pIn[2]);
472
0
                        pIn += 4;
473
0
                    }
474
0
                    return aRes;
475
0
                }
476
                virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override
477
0
                {
478
0
                    const std::size_t             nLen( rgbColor.getLength() );
479
480
0
                    uno::Sequence< double > aRes(nLen*4);
481
0
                    double* pColors=aRes.getArray();
482
0
                    for( const auto& rIn : rgbColor )
483
0
                    {
484
0
                        *pColors++ = rIn.Red;
485
0
                        *pColors++ = rIn.Green;
486
0
                        *pColors++ = rIn.Blue;
487
0
                        *pColors++ = 1.0;
488
0
                    }
489
0
                    return aRes;
490
0
                }
491
                virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
492
0
                {
493
0
                    const std::size_t              nLen( rgbColor.getLength() );
494
495
0
                    uno::Sequence< double > aRes(nLen*4);
496
0
                    double* pColors=aRes.getArray();
497
0
                    for( const auto& rIn : rgbColor )
498
0
                    {
499
0
                        *pColors++ = rIn.Red;
500
0
                        *pColors++ = rIn.Green;
501
0
                        *pColors++ = rIn.Blue;
502
0
                        *pColors++ = rIn.Alpha;
503
0
                    }
504
0
                    return aRes;
505
0
                }
506
                virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
507
0
                {
508
0
                    const std::size_t              nLen( rgbColor.getLength() );
509
510
0
                    uno::Sequence< double > aRes(nLen*4);
511
0
                    double* pColors=aRes.getArray();
512
0
                    for( const auto& rIn : rgbColor )
513
0
                    {
514
0
                        *pColors++ = rIn.Red/rIn.Alpha;
515
0
                        *pColors++ = rIn.Green/rIn.Alpha;
516
0
                        *pColors++ = rIn.Blue/rIn.Alpha;
517
0
                        *pColors++ = rIn.Alpha;
518
0
                    }
519
0
                    return aRes;
520
0
                }
521
522
            public:
523
0
                StandardColorSpace() : m_aComponentTags(4)
524
0
                {
525
0
                    sal_Int8* pTags = m_aComponentTags.getArray();
526
0
                    pTags[0] = rendering::ColorComponentTag::RGB_RED;
527
0
                    pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
528
0
                    pTags[2] = rendering::ColorComponentTag::RGB_BLUE;
529
0
                    pTags[3] = rendering::ColorComponentTag::ALPHA;
530
0
                }
531
            };
532
        }
533
534
        uno::Reference<rendering::XColorSpace> createStandardColorSpace()
535
0
        {
536
0
            return new StandardColorSpace();
537
0
        }
538
539
        uno::Sequence< double > colorToStdColorSpaceSequence( const Color& rColor )
540
0
        {
541
0
            return
542
0
            {
543
0
                toDoubleColor(rColor.GetRed()),
544
0
                toDoubleColor(rColor.GetGreen()),
545
0
                toDoubleColor(rColor.GetBlue()),
546
0
                toDoubleColor(rColor.GetAlpha())
547
0
            };
548
0
        }
549
550
        Color stdColorSpaceSequenceToColor( const uno::Sequence< double >& rColor        )
551
0
        {
552
0
            ENSURE_ARG_OR_THROW( rColor.getLength() == 4,
553
0
                                 "color must have 4 channels" );
554
555
0
            Color aColor;
556
557
0
            aColor.SetRed  ( toByteColor(rColor[0]) );
558
0
            aColor.SetGreen( toByteColor(rColor[1]) );
559
0
            aColor.SetBlue ( toByteColor(rColor[2]) );
560
0
            aColor.SetAlpha( toByteColor(rColor[3]) );
561
562
0
            return aColor;
563
0
        }
564
565
        uno::Sequence< double > colorToDoubleSequence(
566
            const Color&                                    rColor,
567
            const uno::Reference< rendering::XColorSpace >& xColorSpace )
568
0
        {
569
0
            uno::Sequence<rendering::ARGBColor> aSeq
570
0
            {
571
0
                {
572
0
                    toDoubleColor(rColor.GetAlpha()),
573
0
                    toDoubleColor(rColor.GetRed()),
574
0
                    toDoubleColor(rColor.GetGreen()),
575
0
                    toDoubleColor(rColor.GetBlue())
576
0
                }
577
0
            };
578
579
0
            return xColorSpace->convertFromARGB(aSeq);
580
0
        }
581
582
        Color doubleSequenceToColor(
583
            const uno::Sequence< double >&                  rColor,
584
            const uno::Reference< rendering::XColorSpace >& xColorSpace )
585
0
        {
586
0
            const rendering::ARGBColor aARGBColor(
587
0
                xColorSpace->convertToARGB(rColor)[0]);
588
589
0
            return Color( ColorAlpha, toByteColor(aARGBColor.Alpha),
590
0
                          toByteColor(aARGBColor.Red),
591
0
                          toByteColor(aARGBColor.Green),
592
0
                          toByteColor(aARGBColor.Blue) );
593
0
        }
594
595
} // namespace canvas
596
597
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */