Coverage Report

Created: 2026-10-14 09:33

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
3
        {
54
3
            SAL_INFO( "vcl.helper", "vcl::unotools::xBitmapFromBitmapEx()" );
55
56
3
            return new vcl::unotools::VclCanvasBitmap( inputBitmap );
57
3
        }
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
3
        {
154
3
            SAL_INFO( "vcl.helper", "vcl::unotools::bitmapExFromXBitmap()" );
155
156
3
            if( !xInputBitmap.is() )
157
0
                return ::Bitmap();
158
159
            // tunnel directly for known implementation
160
3
            VclCanvasBitmap* pImplBitmap = dynamic_cast<VclCanvasBitmap*>(xInputBitmap.get());
161
3
            if( pImplBitmap )
162
3
                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
22.3k
        {
318
22.3k
            return basegfx::B2IPoint(rPoint.X(), rPoint.Y());
319
22.3k
        }
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
0
        {
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
0
            if (rRect.IsWidthEmpty() && rRect.IsHeightEmpty())
334
0
                return basegfx::B2IRange( basegfx::B2ITuple( rRect.Left(), rRect.Top() ) );
335
0
            return basegfx::B2IRange( rRect.Left(),
336
0
                                  rRect.Top(),
337
0
                                  rRect.IsWidthEmpty() ? rRect.Left() : rRect.Right(),
338
0
                                  rRect.IsHeightEmpty() ? rRect.Top() : rRect.Bottom() );
339
0
        }
340
341
        basegfx::B2IRectangle b2IRectangleFromClosedRectangle(tools::Rectangle const& rRect)
342
157k
        {
343
            // although B2IRange internally has separate height/width emptiness, it doesn't
344
            // expose any API to let us set them separately, so just do the best we can.
345
157k
            if (rRect.IsWidthEmpty() && rRect.IsHeightEmpty())
346
0
            {
347
0
                return basegfx::B2IRange(basegfx::B2ITuple(rRect.Left(), rRect.Top()));
348
0
            }
349
350
157k
            return basegfx::B2IRange(rRect.Left(), rRect.Top(), rRect.Left() + rRect.GetWidth(),
351
157k
                                     rRect.Top() + rRect.GetHeight());
352
157k
        }
353
354
        basegfx::B2DSize b2DSizeFromSize(const Size& rSize)
355
0
        {
356
0
            return basegfx::B2DSize(rSize.Width(), rSize.Height());
357
0
        }
358
359
        basegfx::B2DVector b2DVectorFromSize(const Size& rSize)
360
0
        {
361
0
            return basegfx::B2DVector(rSize.Width(), rSize.Height());
362
0
        }
363
364
        basegfx::B2DPoint b2DPointFromPoint( const ::Point& rPoint )
365
0
        {
366
0
            return basegfx::B2DPoint( rPoint.X(),
367
0
                                        rPoint.Y() );
368
0
        }
369
370
        basegfx::B2DRange b2DRectangleFromRectangle( const ::tools::Rectangle& rRect )
371
335k
        {
372
            // although B2DRange internally has separate height/width emptiness, it doesn't
373
            // expose any API to let us set them separately, so just do the best we can.
374
335k
            if (rRect.IsWidthEmpty() && rRect.IsHeightEmpty())
375
462
                return basegfx::B2DRange( basegfx::B2DTuple( rRect.Left(), rRect.Top() ) );
376
335k
            return basegfx::B2DRectangle( rRect.Left(),
377
335k
                                  rRect.Top(),
378
335k
                                  rRect.IsWidthEmpty() ? rRect.Left() : rRect.Right(),
379
335k
                                  rRect.IsHeightEmpty() ? rRect.Top() : rRect.Bottom() );
380
335k
        }
381
382
        geometry::IntegerSize2D integerSize2DFromSize( const Size& rSize )
383
0
        {
384
0
            return geometry::IntegerSize2D( rSize.Width(),
385
0
                                            rSize.Height() );
386
0
        }
387
388
        Size sizeFromIntegerSize2D( const geometry::IntegerSize2D& rSize )
389
0
        {
390
0
            return Size( rSize.Width,
391
0
                         rSize.Height );
392
0
        }
393
394
        Point pointFromIntegerPoint2D( const geometry::IntegerPoint2D& rPoint )
395
0
        {
396
0
            return Point( rPoint.X,
397
0
                          rPoint.Y );
398
0
        }
399
400
        tools::Rectangle rectangleFromIntegerRectangle2D( const geometry::IntegerRectangle2D& rRectangle )
401
0
        {
402
0
            return tools::Rectangle( rRectangle.X1, rRectangle.Y1,
403
0
                              rRectangle.X2, rRectangle.Y2 );
404
0
        }
405
406
        namespace
407
        {
408
            class StandardColorSpace : public cppu::WeakImplHelper< css::rendering::XColorSpace >
409
            {
410
            private:
411
                uno::Sequence< sal_Int8 > m_aComponentTags;
412
413
                virtual ::sal_Int8 SAL_CALL getType(  ) override
414
0
                {
415
0
                    return rendering::ColorSpaceType::RGB;
416
0
                }
417
                virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags(  ) override
418
0
                {
419
0
                    return m_aComponentTags;
420
0
                }
421
                virtual ::sal_Int8 SAL_CALL getRenderingIntent(  ) override
422
0
                {
423
0
                    return rendering::RenderingIntent::PERCEPTUAL;
424
0
                }
425
                virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties(  ) override
426
0
                {
427
0
                    return uno::Sequence< beans::PropertyValue >();
428
0
                }
429
                virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor,
430
                                                                            const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override
431
0
                {
432
                    // TODO(P3): if we know anything about target
433
                    // colorspace, this can be greatly sped up
434
0
                    uno::Sequence<rendering::ARGBColor> aIntermediate(
435
0
                        convertToARGB(deviceColor));
436
0
                    return targetColorSpace->convertFromARGB(aIntermediate);
437
0
                }
438
                virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) override
439
0
                {
440
0
                    const double*  pIn( deviceColor.getConstArray() );
441
0
                    const std::size_t nLen( deviceColor.getLength() );
442
0
                    ENSURE_ARG_OR_THROW2(nLen%4==0,
443
0
                                         "number of channels no multiple of 4",
444
0
                                         static_cast<rendering::XColorSpace*>(this), 0);
445
446
0
                    uno::Sequence< rendering::RGBColor > aRes(nLen/4);
447
0
                    rendering::RGBColor* pOut( aRes.getArray() );
448
0
                    for( std::size_t i=0; i<nLen; i+=4 )
449
0
                    {
450
0
                        *pOut++ = rendering::RGBColor(pIn[0],pIn[1],pIn[2]);
451
0
                        pIn += 4;
452
0
                    }
453
0
                    return aRes;
454
0
                }
455
                virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) override
456
0
                {
457
0
                    const double*  pIn( deviceColor.getConstArray() );
458
0
                    const std::size_t nLen( deviceColor.getLength() );
459
0
                    ENSURE_ARG_OR_THROW2(nLen%4==0,
460
0
                                         "number of channels no multiple of 4",
461
0
                                         static_cast<rendering::XColorSpace*>(this), 0);
462
463
0
                    uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
464
0
                    rendering::ARGBColor* pOut( aRes.getArray() );
465
0
                    for( std::size_t i=0; i<nLen; i+=4 )
466
0
                    {
467
0
                        *pOut++ = rendering::ARGBColor(pIn[3],pIn[0],pIn[1],pIn[2]);
468
0
                        pIn += 4;
469
0
                    }
470
0
                    return aRes;
471
0
                }
472
                virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) override
473
0
                {
474
0
                    const double*  pIn( deviceColor.getConstArray() );
475
0
                    const std::size_t nLen( deviceColor.getLength() );
476
0
                    ENSURE_ARG_OR_THROW2(nLen%4==0,
477
0
                                         "number of channels no multiple of 4",
478
0
                                         static_cast<rendering::XColorSpace*>(this), 0);
479
480
0
                    uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
481
0
                    rendering::ARGBColor* pOut( aRes.getArray() );
482
0
                    for( std::size_t i=0; i<nLen; i+=4 )
483
0
                    {
484
0
                        *pOut++ = rendering::ARGBColor(pIn[3],pIn[3]*pIn[0],pIn[3]*pIn[1],pIn[3]*pIn[2]);
485
0
                        pIn += 4;
486
0
                    }
487
0
                    return aRes;
488
0
                }
489
                virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override
490
0
                {
491
0
                    const std::size_t             nLen( rgbColor.getLength() );
492
493
0
                    uno::Sequence< double > aRes(nLen*4);
494
0
                    double* pColors=aRes.getArray();
495
0
                    for( const auto& rIn : rgbColor )
496
0
                    {
497
0
                        *pColors++ = rIn.Red;
498
0
                        *pColors++ = rIn.Green;
499
0
                        *pColors++ = rIn.Blue;
500
0
                        *pColors++ = 1.0;
501
0
                    }
502
0
                    return aRes;
503
0
                }
504
                virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
505
0
                {
506
0
                    const std::size_t              nLen( rgbColor.getLength() );
507
508
0
                    uno::Sequence< double > aRes(nLen*4);
509
0
                    double* pColors=aRes.getArray();
510
0
                    for( const auto& rIn : rgbColor )
511
0
                    {
512
0
                        *pColors++ = rIn.Red;
513
0
                        *pColors++ = rIn.Green;
514
0
                        *pColors++ = rIn.Blue;
515
0
                        *pColors++ = rIn.Alpha;
516
0
                    }
517
0
                    return aRes;
518
0
                }
519
                virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
520
0
                {
521
0
                    const std::size_t              nLen( rgbColor.getLength() );
522
523
0
                    uno::Sequence< double > aRes(nLen*4);
524
0
                    double* pColors=aRes.getArray();
525
0
                    for( const auto& rIn : rgbColor )
526
0
                    {
527
0
                        *pColors++ = rIn.Red/rIn.Alpha;
528
0
                        *pColors++ = rIn.Green/rIn.Alpha;
529
0
                        *pColors++ = rIn.Blue/rIn.Alpha;
530
0
                        *pColors++ = rIn.Alpha;
531
0
                    }
532
0
                    return aRes;
533
0
                }
534
535
            public:
536
0
                StandardColorSpace() : m_aComponentTags(4)
537
0
                {
538
0
                    sal_Int8* pTags = m_aComponentTags.getArray();
539
0
                    pTags[0] = rendering::ColorComponentTag::RGB_RED;
540
0
                    pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
541
0
                    pTags[2] = rendering::ColorComponentTag::RGB_BLUE;
542
0
                    pTags[3] = rendering::ColorComponentTag::ALPHA;
543
0
                }
544
            };
545
        }
546
547
        uno::Reference<rendering::XColorSpace> createStandardColorSpace()
548
0
        {
549
0
            return new StandardColorSpace();
550
0
        }
551
552
        uno::Sequence< double > colorToStdColorSpaceSequence( const Color& rColor )
553
0
        {
554
0
            return
555
0
            {
556
0
                toDoubleColor(rColor.GetRed()),
557
0
                toDoubleColor(rColor.GetGreen()),
558
0
                toDoubleColor(rColor.GetBlue()),
559
0
                toDoubleColor(rColor.GetAlpha())
560
0
            };
561
0
        }
562
563
        Color stdColorSpaceSequenceToColor( const uno::Sequence< double >& rColor        )
564
0
        {
565
0
            ENSURE_ARG_OR_THROW( rColor.getLength() == 4,
566
0
                                 "color must have 4 channels" );
567
568
0
            Color aColor;
569
570
0
            aColor.SetRed  ( toByteColor(rColor[0]) );
571
0
            aColor.SetGreen( toByteColor(rColor[1]) );
572
0
            aColor.SetBlue ( toByteColor(rColor[2]) );
573
0
            aColor.SetAlpha( toByteColor(rColor[3]) );
574
575
0
            return aColor;
576
0
        }
577
578
        uno::Sequence< double > colorToDoubleSequence(
579
            const Color&                                    rColor,
580
            const uno::Reference< rendering::XColorSpace >& xColorSpace )
581
0
        {
582
0
            uno::Sequence<rendering::ARGBColor> aSeq
583
0
            {
584
0
                {
585
0
                    toDoubleColor(rColor.GetAlpha()),
586
0
                    toDoubleColor(rColor.GetRed()),
587
0
                    toDoubleColor(rColor.GetGreen()),
588
0
                    toDoubleColor(rColor.GetBlue())
589
0
                }
590
0
            };
591
592
0
            return xColorSpace->convertFromARGB(aSeq);
593
0
        }
594
595
        Color doubleSequenceToColor(
596
            const uno::Sequence< double >&                  rColor,
597
            const uno::Reference< rendering::XColorSpace >& xColorSpace )
598
0
        {
599
0
            const rendering::ARGBColor aARGBColor(
600
0
                xColorSpace->convertToARGB(rColor)[0]);
601
602
0
            return Color( ColorAlpha, toByteColor(aARGBColor.Alpha),
603
0
                          toByteColor(aARGBColor.Red),
604
0
                          toByteColor(aARGBColor.Green),
605
0
                          toByteColor(aARGBColor.Blue) );
606
0
        }
607
608
} // namespace canvas
609
610
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */