Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/helper/canvasbitmap.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 <sal/config.h>
21
22
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
23
#include <com/sun/star/util/Endianness.hpp>
24
#include <com/sun/star/rendering/ColorComponentTag.hpp>
25
#include <com/sun/star/rendering/ColorSpaceType.hpp>
26
#include <com/sun/star/rendering/RenderingIntent.hpp>
27
28
#include <comphelper/diagnose_ex.hxx>
29
#include <canvasbitmap.hxx>
30
#include <vcl/canvastools.hxx>
31
#include <vcl/BitmapReadAccess.hxx>
32
#include <vcl/svapp.hxx>
33
34
#include <algorithm>
35
36
using namespace vcl::unotools;
37
using namespace ::com::sun::star;
38
39
namespace
40
{
41
    // TODO(Q3): move to o3tl bithacks or somesuch. A similar method is in canvas/canvastools.hxx
42
43
    // Good ole HAKMEM tradition. Calc number of 1 bits in 32bit word,
44
    // unrolled loop. See e.g. Hackers Delight, p. 66
45
    sal_Int32 bitcount( sal_uInt32 val )
46
0
    {
47
0
        val = val - ((val >> 1) & 0x55555555);
48
0
        val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
49
0
        val = (val + (val >> 4)) & 0x0F0F0F0F;
50
0
        val = val + (val >> 8);
51
0
        val = val + (val >> 16);
52
0
        return sal_Int32(val & 0x0000003F);
53
0
    }
54
}
55
56
void VclCanvasBitmap::setComponentInfo( sal_uInt32 redShift, sal_uInt32 greenShift, sal_uInt32 blueShift )
57
0
{
58
    // sort channels in increasing order of appearance in the pixel
59
    // (starting with the least significant bits)
60
0
    sal_Int8 redPos(0);
61
0
    sal_Int8 greenPos(1);
62
0
    sal_Int8 bluePos(2);
63
64
0
    if( redShift > greenShift )
65
0
    {
66
0
        std::swap(redPos,greenPos);
67
0
        if( redShift > blueShift )
68
0
        {
69
0
            std::swap(redPos,bluePos);
70
0
            if( greenShift > blueShift )
71
0
                std::swap(greenPos,bluePos);
72
0
        }
73
0
    }
74
0
    else
75
0
    {
76
0
        if( greenShift > blueShift )
77
0
        {
78
0
            std::swap(greenPos,bluePos);
79
0
            if( redShift > blueShift )
80
0
                std::swap(redPos,bluePos);
81
0
        }
82
0
    }
83
84
0
    m_aComponentTags.realloc(3);
85
0
    sal_Int8* pTags = m_aComponentTags.getArray();
86
0
    pTags[redPos]   = rendering::ColorComponentTag::RGB_RED;
87
0
    pTags[greenPos] = rendering::ColorComponentTag::RGB_GREEN;
88
0
    pTags[bluePos]  = rendering::ColorComponentTag::RGB_BLUE;
89
90
0
    m_aComponentBitCounts.realloc(3);
91
0
    sal_Int32* pCounts = m_aComponentBitCounts.getArray();
92
0
    pCounts[redPos]   = bitcount(redShift);
93
0
    pCounts[greenPos] = bitcount(greenShift);
94
0
    pCounts[bluePos]  = bitcount(blueShift);
95
0
}
96
97
BitmapScopedReadAccess& VclCanvasBitmap::getBitmapReadAccess()
98
0
{
99
    // BitmapReadAccess is more expensive than BitmapInfoAccess,
100
    // as the latter requires also pixels, which may need converted
101
    // from the system format (and even fetched). Most calls here
102
    // need only info access, create read access only on demand.
103
0
    if(!m_pBmpReadAcc)
104
0
        m_pBmpReadAcc.emplace(m_aBmp);
105
0
    return *m_pBmpReadAcc;
106
0
}
107
108
VclCanvasBitmap::VclCanvasBitmap( const Bitmap& rBitmap ) :
109
4
    m_aBmp( rBitmap ),
110
4
    m_pBmpAcc( m_aBmp ),
111
4
    m_nBitsPerInputPixel(0),
112
4
    m_nBitsPerOutputPixel(0),
113
4
    m_nRedIndex(-1),
114
4
    m_nGreenIndex(-1),
115
4
    m_nBlueIndex(-1),
116
4
    m_nAlphaIndex(-1),
117
4
    m_nIndexIndex(-1),
118
4
    m_bPalette(false)
119
4
{
120
4
    m_aLayout.ScanLines      = 0;
121
4
    m_aLayout.ScanLineBytes  = 0;
122
4
    m_aLayout.ScanLineStride = 0;
123
4
    m_aLayout.PlaneStride    = 0;
124
4
    m_aLayout.ColorSpace.clear();
125
4
    m_aLayout.Palette.clear();
126
4
    m_aLayout.IsMsbFirst     = false;
127
128
4
    if( !m_pBmpAcc )
129
0
        return;
130
131
4
    m_aLayout.ScanLines      = m_pBmpAcc->Height();
132
4
    m_aLayout.ScanLineBytes  = (m_pBmpAcc->GetBitCount()*m_pBmpAcc->Width() + 7) / 8;
133
4
    m_aLayout.ScanLineStride = m_pBmpAcc->GetScanlineSize();
134
4
    m_aLayout.PlaneStride    = 0;
135
136
4
    switch( m_pBmpAcc->GetScanlineFormat() )
137
4
    {
138
0
        case ScanlineFormat::N8BitPal:
139
0
            m_bPalette           = true;
140
0
            m_nBitsPerInputPixel = 8;
141
0
            m_aLayout.IsMsbFirst = false; // doesn't matter
142
0
            break;
143
144
0
        case ScanlineFormat::N24BitTcBgr:
145
0
            m_bPalette           = false;
146
0
            m_nBitsPerInputPixel = 24;
147
0
            m_aLayout.IsMsbFirst = false; // doesn't matter
148
0
            setComponentInfo( static_cast<sal_uInt32>(0xff0000UL),
149
0
                              static_cast<sal_uInt32>(0x00ff00UL),
150
0
                              static_cast<sal_uInt32>(0x0000ffUL) );
151
0
            break;
152
153
0
        case ScanlineFormat::N24BitTcRgb:
154
0
            m_bPalette           = false;
155
0
            m_nBitsPerInputPixel = 24;
156
0
            m_aLayout.IsMsbFirst = false; // doesn't matter
157
0
            setComponentInfo( static_cast<sal_uInt32>(0x0000ffUL),
158
0
                              static_cast<sal_uInt32>(0x00ff00UL),
159
0
                              static_cast<sal_uInt32>(0xff0000UL) );
160
0
            break;
161
162
0
        case ScanlineFormat::N32BitTcAbgr:
163
0
        case ScanlineFormat::N32BitTcXbgr:
164
0
        {
165
0
            m_bPalette           = false;
166
0
            m_nBitsPerInputPixel = 24;
167
0
            m_aLayout.IsMsbFirst = false; // doesn't matter
168
169
0
            m_aComponentTags = { /* 0 */ rendering::ColorComponentTag::ALPHA,
170
0
                                 /* 1 */ rendering::ColorComponentTag::RGB_BLUE,
171
0
                                 /* 2 */ rendering::ColorComponentTag::RGB_GREEN,
172
0
                                 /* 3 */ rendering::ColorComponentTag::RGB_RED };
173
174
0
            m_aComponentBitCounts = { /* 0 */ 8,
175
0
                                      /* 1 */ 8,
176
0
                                      /* 2 */ 8,
177
0
                                      /* 3 */ 8 };
178
179
0
            m_nRedIndex   = 3;
180
0
            m_nGreenIndex = 2;
181
0
            m_nBlueIndex  = 1;
182
0
            m_nAlphaIndex = 0;
183
0
        }
184
0
        break;
185
186
0
        case ScanlineFormat::N32BitTcArgb:
187
0
        case ScanlineFormat::N32BitTcXrgb:
188
0
        {
189
0
            m_bPalette           = false;
190
0
            m_nBitsPerInputPixel = 24;
191
0
            m_aLayout.IsMsbFirst = false; // doesn't matter
192
193
0
            m_aComponentTags = { /* 0 */ rendering::ColorComponentTag::ALPHA,
194
0
                                 /* 1 */ rendering::ColorComponentTag::RGB_RED,
195
0
                                 /* 2 */ rendering::ColorComponentTag::RGB_GREEN,
196
0
                                 /* 3 */ rendering::ColorComponentTag::RGB_BLUE };
197
198
0
            m_aComponentBitCounts = { /* 0 */ 8,
199
0
                                      /* 1 */ 8,
200
0
                                      /* 2 */ 8,
201
0
                                      /* 3 */ 8 };
202
203
0
            m_nRedIndex   = 1;
204
0
            m_nGreenIndex = 2;
205
0
            m_nBlueIndex  = 3;
206
0
            m_nAlphaIndex = 0;
207
0
        }
208
0
        break;
209
210
4
        case ScanlineFormat::N32BitTcBgra:
211
4
        case ScanlineFormat::N32BitTcBgrx:
212
4
        {
213
4
            m_bPalette           = false;
214
4
            m_nBitsPerInputPixel = 24;
215
4
            m_aLayout.IsMsbFirst = false; // doesn't matter
216
217
4
            m_aComponentTags = { /* 0 */ rendering::ColorComponentTag::RGB_BLUE,
218
4
                                 /* 1 */ rendering::ColorComponentTag::RGB_GREEN,
219
4
                                 /* 2 */ rendering::ColorComponentTag::RGB_RED,
220
4
                                 /* 3 */ rendering::ColorComponentTag::ALPHA };
221
222
4
            m_aComponentBitCounts = { /* 0 */ 8,
223
4
                                      /* 1 */ 8,
224
4
                                      /* 2 */ 8,
225
4
                                      /* 3 */ 8 };
226
227
4
            m_nRedIndex   = 2;
228
4
            m_nGreenIndex = 1;
229
4
            m_nBlueIndex  = 0;
230
4
            m_nAlphaIndex = 3;
231
4
        }
232
4
        break;
233
234
0
        case ScanlineFormat::N32BitTcRgba:
235
0
        case ScanlineFormat::N32BitTcRgbx:
236
0
        {
237
0
            m_bPalette           = false;
238
0
            m_nBitsPerInputPixel = 24;
239
0
            m_aLayout.IsMsbFirst = false; // doesn't matter
240
241
0
            m_aComponentTags = { /* 0 */ rendering::ColorComponentTag::RGB_RED,
242
0
                                 /* 1 */ rendering::ColorComponentTag::RGB_GREEN,
243
0
                                 /* 2 */ rendering::ColorComponentTag::RGB_BLUE,
244
0
                                 /* 3 */ rendering::ColorComponentTag::ALPHA };
245
246
0
            m_aComponentBitCounts = { /* 0 */ 8,
247
0
                                      /* 1 */ 8,
248
0
                                      /* 2 */ 8,
249
0
                                      /* 3 */ 8 };
250
251
0
            m_nRedIndex   = 0;
252
0
            m_nGreenIndex = 1;
253
0
            m_nBlueIndex  = 2;
254
0
            m_nAlphaIndex = 3;
255
0
        }
256
0
        break;
257
258
0
        default:
259
0
            OSL_FAIL( "unsupported bitmap format" );
260
0
            break;
261
4
    }
262
263
4
    if( m_bPalette )
264
0
    {
265
0
        m_aComponentTags = { rendering::ColorComponentTag::INDEX };
266
267
0
        m_aComponentBitCounts = { m_nBitsPerInputPixel };
268
269
0
        m_nIndexIndex = 0;
270
0
    }
271
272
4
    m_nBitsPerOutputPixel = m_nBitsPerInputPixel;
273
4
    if( !m_aBmp.HasAlpha() )
274
0
        return;
275
276
    // TODO(P1): need to interleave alpha with bitmap data -
277
    // won't fuss with less-than-8 bit for now
278
4
    m_nBitsPerOutputPixel = std::max(sal_Int32(8),m_nBitsPerInputPixel);
279
280
    // check whether alpha goes in front or behind the
281
    // bitcount sequence. If pixel format is little endian,
282
    // put it behind all the other channels. If it's big
283
    // endian, put it in front (because later, the actual data
284
    // always gets written after the pixel data)
285
286
    // TODO(Q1): slight catch - in the case of the
287
    // BMP_FORMAT_32BIT_XX_ARGB formats, duplicate alpha
288
    // channels might happen!
289
4
    m_aComponentTags.realloc(m_aComponentTags.getLength()+1);
290
4
    m_aComponentTags.getArray()[m_aComponentTags.getLength()-1] = rendering::ColorComponentTag::ALPHA;
291
292
4
    m_aComponentBitCounts.realloc(m_aComponentBitCounts.getLength()+1);
293
4
    m_aComponentBitCounts.getArray()[m_aComponentBitCounts.getLength()-1] = m_aBmp.HasAlpha() ? 8 : 1;
294
295
    // always add a full byte to the pixel size, otherwise
296
    // pixel packing hell breaks loose.
297
4
    m_nBitsPerOutputPixel += 8;
298
299
    // adapt scanline parameters
300
4
    const Size aSize = m_aBmp.GetSizePixel();
301
4
    m_aLayout.ScanLineBytes  =
302
4
    m_aLayout.ScanLineStride = (aSize.Width()*m_nBitsPerOutputPixel + 7)/8;
303
4
}
304
305
VclCanvasBitmap::~VclCanvasBitmap()
306
4
{
307
4
}
308
309
// XBitmap
310
geometry::IntegerSize2D SAL_CALL VclCanvasBitmap::getSize()
311
0
{
312
0
    SolarMutexGuard aGuard;
313
0
    return integerSize2DFromSize( m_aBmp.GetSizePixel() );
314
0
}
315
316
sal_Bool SAL_CALL VclCanvasBitmap::hasAlpha()
317
0
{
318
0
    SolarMutexGuard aGuard;
319
0
    return m_aBmp.HasAlpha();
320
0
}
321
322
uno::Reference< rendering::XBitmap > SAL_CALL VclCanvasBitmap::getScaledBitmap( const geometry::RealSize2D& newSize,
323
                                                                                sal_Bool beFast )
324
0
{
325
0
    SolarMutexGuard aGuard;
326
327
0
    Bitmap aNewBmp( m_aBmp );
328
0
    aNewBmp.Scale( sizeFromRealSize2D( newSize ), beFast ? BmpScaleFlag::Default : BmpScaleFlag::BestQuality );
329
0
    return uno::Reference<rendering::XBitmap>( new VclCanvasBitmap( aNewBmp ) );
330
0
}
331
332
// XIntegerReadOnlyBitmap
333
uno::Sequence< sal_Int8 > SAL_CALL VclCanvasBitmap::getData( rendering::IntegerBitmapLayout&     bitmapLayout,
334
                                                             const geometry::IntegerRectangle2D& rect )
335
0
{
336
0
    SolarMutexGuard aGuard;
337
338
0
    bitmapLayout = getMemoryLayout();
339
340
0
    const ::tools::Rectangle aRequestedArea( vcl::unotools::rectangleFromIntegerRectangle2D(rect) );
341
0
    if( aRequestedArea.IsEmpty() )
342
0
        return uno::Sequence< sal_Int8 >();
343
344
    // Invalid/empty bitmap: no data available
345
0
    if( !m_pBmpAcc )
346
0
        throw lang::IndexOutOfBoundsException();
347
348
0
    if( aRequestedArea.Left() < 0 || aRequestedArea.Top() < 0 ||
349
0
        aRequestedArea.Right() > m_pBmpAcc->Width() ||
350
0
        aRequestedArea.Bottom() > m_pBmpAcc->Height() )
351
0
    {
352
0
        throw lang::IndexOutOfBoundsException();
353
0
    }
354
355
0
    uno::Sequence< sal_Int8 > aRet;
356
0
    tools::Rectangle aRequestedBytes( aRequestedArea );
357
358
    // adapt to byte boundaries
359
0
    aRequestedBytes.SetLeft( aRequestedArea.Left()*m_nBitsPerOutputPixel/8 );
360
0
    aRequestedBytes.SetRight( (aRequestedArea.Right()*m_nBitsPerOutputPixel + 7)/8 );
361
362
    // copy stuff to output sequence
363
0
    aRet.realloc(aRequestedBytes.getOpenWidth()*aRequestedBytes.getOpenHeight());
364
0
    sal_Int8* pOutBuf = aRet.getArray();
365
366
0
    bitmapLayout.ScanLines     = aRequestedBytes.getOpenHeight();
367
0
    bitmapLayout.ScanLineBytes =
368
0
    bitmapLayout.ScanLineStride= aRequestedBytes.getOpenWidth();
369
370
0
    sal_Int32 nScanlineStride=bitmapLayout.ScanLineStride;
371
0
    if (m_pBmpAcc->IsBottomUp())
372
0
    {
373
0
        pOutBuf += bitmapLayout.ScanLineStride*(aRequestedBytes.getOpenHeight()-1);
374
0
        nScanlineStride *= -1;
375
0
    }
376
377
0
    if( !m_aBmp.HasAlpha() )
378
0
    {
379
0
        BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess();
380
0
        OSL_ENSURE(pBmpAcc,"Invalid bmp read access");
381
382
        // can return bitmap data as-is
383
0
        for( tools::Long y=aRequestedBytes.Top(); y<aRequestedBytes.Bottom(); ++y )
384
0
        {
385
0
            Scanline pScan = pBmpAcc->GetScanline(y);
386
0
            memcpy(pOutBuf, pScan+aRequestedBytes.Left(), aRequestedBytes.getOpenWidth());
387
0
            pOutBuf += nScanlineStride;
388
0
        }
389
0
    }
390
0
    else
391
0
    {
392
0
        assert( m_nBitsPerInputPixel == 24 );
393
0
        assert( m_nBitsPerOutputPixel == 32 );
394
395
0
        BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess();
396
0
        assert(pBmpAcc && "Invalid bmp read access");
397
398
0
        for( tools::Long y=aRequestedArea.Top(); y<aRequestedArea.Bottom(); ++y )
399
0
        {
400
0
            sal_Int8* pOutScan = pOutBuf;
401
402
0
            const tools::Long nScanlineOffsetLeft(aRequestedArea.Left()*m_nBitsPerOutputPixel/8);
403
0
            Scanline pScan = pBmpAcc->GetScanline(y) + nScanlineOffsetLeft;
404
405
0
            for( tools::Long x=aRequestedArea.Left(); x<aRequestedArea.Right(); ++x )
406
0
            {
407
                // return it always in the same format. This makes the conversion
408
                // in the convertIntegerTo* methods easier.
409
0
                BitmapColor aCol = pBmpAcc->GetPixelFromData(pScan, x);
410
0
                *pOutScan++ = aCol.GetBlue();
411
0
                *pOutScan++ = aCol.GetGreen();
412
0
                *pOutScan++ = aCol.GetRed();
413
                // vcl used to store transparency. Now it stores alpha. But we need the UNO
414
                // interface to still preserve the old interface.
415
0
                *pOutScan++ = 255 - aCol.GetAlpha();
416
0
            }
417
418
0
            pOutBuf += nScanlineStride;
419
0
        }
420
0
    }
421
422
0
    return aRet;
423
0
}
424
425
uno::Sequence< sal_Int8 > SAL_CALL VclCanvasBitmap::getPixel( rendering::IntegerBitmapLayout&   bitmapLayout,
426
                                                              const geometry::IntegerPoint2D&   pos )
427
0
{
428
0
    SolarMutexGuard aGuard;
429
430
0
    bitmapLayout = getMemoryLayout();
431
432
    // Invalid/empty bitmap: no data available
433
0
    if( !m_pBmpAcc )
434
0
        throw lang::IndexOutOfBoundsException();
435
436
0
    if( pos.X < 0 || pos.Y < 0 ||
437
0
        pos.X > m_pBmpAcc->Width() || pos.Y > m_pBmpAcc->Height() )
438
0
    {
439
0
        throw lang::IndexOutOfBoundsException();
440
0
    }
441
442
0
    uno::Sequence< sal_Int8 > aRet((m_nBitsPerOutputPixel + 7)/8);
443
0
    sal_Int8* pOutBuf = aRet.getArray();
444
445
    // copy stuff to output sequence
446
0
    bitmapLayout.ScanLines     = 1;
447
0
    bitmapLayout.ScanLineBytes =
448
0
    bitmapLayout.ScanLineStride= aRet.getLength();
449
450
0
    BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess();
451
0
    assert(pBmpAcc && "Invalid bmp read access");
452
453
0
    if( !m_aBmp.HasAlpha() )
454
0
    {
455
        // can return bitmap data as-is
456
0
        Scanline pScan = pBmpAcc->GetScanline(pos.Y);
457
0
        const tools::Long nScanlineLeftOffset( pos.X*m_nBitsPerOutputPixel/8 );
458
0
        memcpy(pOutBuf, pScan+nScanlineLeftOffset, aRet.getLength() );
459
0
    }
460
0
    else
461
0
    {
462
0
        assert( m_nBitsPerInputPixel == 24 );
463
0
        assert( m_nBitsPerOutputPixel == 32 );
464
465
        // return it always in the same format. This makes the conversion
466
        // in the convertIntegerTo* methods easier.
467
0
        BitmapColor aCol = pBmpAcc->GetPixel(pos.Y, pos.X);
468
0
        *pOutBuf++ = aCol.GetBlue();
469
0
        *pOutBuf++ = aCol.GetGreen();
470
0
        *pOutBuf++ = aCol.GetRed();
471
        // vcl used to store transparency. Now it stores alpha. But we need the UNO
472
        // interface to still preserve the old interface.
473
0
        *pOutBuf++ = 255 - aCol.GetAlpha();
474
0
    }
475
476
0
    return aRet;
477
0
}
478
479
uno::Reference< rendering::XBitmapPalette > VclCanvasBitmap::getPalette()
480
0
{
481
0
    SolarMutexGuard aGuard;
482
483
0
    uno::Reference< XBitmapPalette > aRet;
484
0
    if( m_bPalette )
485
0
        aRet.set(this);
486
487
0
    return aRet;
488
0
}
489
490
rendering::IntegerBitmapLayout SAL_CALL VclCanvasBitmap::getMemoryLayout()
491
0
{
492
0
    SolarMutexGuard aGuard;
493
494
0
    rendering::IntegerBitmapLayout aLayout( m_aLayout );
495
496
    // only set references to self on separate copy of
497
    // IntegerBitmapLayout - if we'd set that on m_aLayout, we'd have
498
    // a circular reference!
499
0
    if( m_bPalette )
500
0
        aLayout.Palette.set( this );
501
502
0
    aLayout.ColorSpace.set( this );
503
504
0
    return aLayout;
505
0
}
506
507
sal_Int32 SAL_CALL VclCanvasBitmap::getNumberOfEntries()
508
0
{
509
0
    SolarMutexGuard aGuard;
510
511
0
    if( !m_pBmpAcc )
512
0
        return 0;
513
514
0
    return m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ;
515
0
}
516
517
sal_Bool SAL_CALL VclCanvasBitmap::getIndex( uno::Sequence< double >& o_entry, sal_Int32 nIndex )
518
0
{
519
0
    SolarMutexGuard aGuard;
520
521
0
    const sal_uInt16 nCount( m_pBmpAcc ?
522
0
                         (m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ) : 0 );
523
0
    OSL_ENSURE(nIndex >= 0 && nIndex < nCount,"Palette index out of range");
524
0
    if( nIndex < 0 || nIndex >= nCount )
525
0
        throw lang::IndexOutOfBoundsException(u"Palette index out of range"_ustr,
526
0
                                              static_cast<rendering::XBitmapPalette*>(this));
527
528
0
    const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(sal::static_int_cast<sal_uInt16>(nIndex));
529
0
    o_entry.realloc(3);
530
0
    double* pColor=o_entry.getArray();
531
0
    pColor[0] = aCol.GetRed();
532
0
    pColor[1] = aCol.GetGreen();
533
0
    pColor[2] = aCol.GetBlue();
534
535
0
    return true; // no palette transparency here.
536
0
}
537
538
sal_Bool SAL_CALL VclCanvasBitmap::setIndex( const uno::Sequence< double >&, sal_Bool, sal_Int32 nIndex )
539
0
{
540
0
    SolarMutexGuard aGuard;
541
542
0
    const sal_uInt16 nCount( m_pBmpAcc ?
543
0
                         (m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ) : 0 );
544
545
0
    OSL_ENSURE(nIndex >= 0 && nIndex < nCount,"Palette index out of range");
546
0
    if( nIndex < 0 || nIndex >= nCount )
547
0
        throw lang::IndexOutOfBoundsException(u"Palette index out of range"_ustr,
548
0
                                              static_cast<rendering::XBitmapPalette*>(this));
549
550
0
    return false; // read-only implementation
551
0
}
552
553
uno::Reference< rendering::XColorSpace > SAL_CALL VclCanvasBitmap::getColorSpace(  )
554
0
{
555
    // this is the method from XBitmapPalette. Return palette color
556
    // space here
557
0
    static uno::Reference<rendering::XColorSpace> gColorSpace = vcl::unotools::createStandardColorSpace();
558
0
    return gColorSpace;
559
0
}
560
561
sal_Int8 SAL_CALL VclCanvasBitmap::getType(  )
562
0
{
563
0
    return rendering::ColorSpaceType::RGB;
564
0
}
565
566
uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::getComponentTags(  )
567
0
{
568
0
    SolarMutexGuard aGuard;
569
0
    return m_aComponentTags;
570
0
}
571
572
sal_Int8 SAL_CALL VclCanvasBitmap::getRenderingIntent(  )
573
0
{
574
0
    return rendering::RenderingIntent::PERCEPTUAL;
575
0
}
576
577
uno::Sequence< ::beans::PropertyValue > SAL_CALL VclCanvasBitmap::getProperties(  )
578
0
{
579
0
    return uno::Sequence< ::beans::PropertyValue >();
580
0
}
581
582
uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertColorSpace( const uno::Sequence< double >& deviceColor,
583
                                                                     const uno::Reference< ::rendering::XColorSpace >& targetColorSpace )
584
0
{
585
    // TODO(P3): if we know anything about target
586
    // colorspace, this can be greatly sped up
587
0
    uno::Sequence<rendering::ARGBColor> aIntermediate(
588
0
        convertToARGB(deviceColor));
589
0
    return targetColorSpace->convertFromARGB(aIntermediate);
590
0
}
591
592
uno::Sequence<rendering::RGBColor> SAL_CALL VclCanvasBitmap::convertToRGB( const uno::Sequence< double >& deviceColor )
593
0
{
594
0
    SolarMutexGuard aGuard;
595
596
0
    const std::size_t nLen( deviceColor.getLength() );
597
0
    const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
598
0
    ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
599
0
                         "number of channels no multiple of pixel element count",
600
0
                         static_cast<rendering::XBitmapPalette*>(this), 01);
601
602
0
    uno::Sequence< rendering::RGBColor > aRes(nLen/nComponentsPerPixel);
603
0
    rendering::RGBColor* pOut( aRes.getArray() );
604
605
0
    if( m_bPalette )
606
0
    {
607
0
        OSL_ENSURE(m_nIndexIndex != -1,
608
0
                   "Invalid color channel indices");
609
0
        ENSURE_OR_THROW(m_pBmpAcc,
610
0
                        "Unable to get BitmapAccess");
611
612
0
        for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel )
613
0
        {
614
0
            const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
615
0
                sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex]));
616
617
            // TODO(F3): Convert result to sRGB color space
618
0
            *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()),
619
0
                                          toDoubleColor(aCol.GetGreen()),
620
0
                                          toDoubleColor(aCol.GetBlue()));
621
0
        }
622
0
    }
623
0
    else
624
0
    {
625
0
        OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
626
0
                   "Invalid color channel indices");
627
628
0
        for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel )
629
0
        {
630
            // TODO(F3): Convert result to sRGB color space
631
0
            *pOut++ = rendering::RGBColor(
632
0
                deviceColor[i+m_nRedIndex],
633
0
                deviceColor[i+m_nGreenIndex],
634
0
                deviceColor[i+m_nBlueIndex]);
635
0
        }
636
0
    }
637
638
0
    return aRes;
639
0
}
640
641
uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertToARGB( const uno::Sequence< double >& deviceColor )
642
0
{
643
0
    SolarMutexGuard aGuard;
644
645
0
    const std::size_t nLen( deviceColor.getLength() );
646
0
    const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
647
0
    ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
648
0
                         "number of channels no multiple of pixel element count",
649
0
                         static_cast<rendering::XBitmapPalette*>(this), 01);
650
651
0
    uno::Sequence< rendering::ARGBColor > aRes(nLen/nComponentsPerPixel);
652
0
    rendering::ARGBColor* pOut( aRes.getArray() );
653
654
0
    if( m_bPalette )
655
0
    {
656
0
        OSL_ENSURE(m_nIndexIndex != -1,
657
0
                   "Invalid color channel indices");
658
0
        ENSURE_OR_THROW(m_pBmpAcc,
659
0
                        "Unable to get BitmapAccess");
660
661
0
        for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel )
662
0
        {
663
0
            const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
664
0
                sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex]));
665
666
            // TODO(F3): Convert result to sRGB color space
667
0
            const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
668
0
            *pOut++ = rendering::ARGBColor(nAlpha,
669
0
                                           toDoubleColor(aCol.GetRed()),
670
0
                                           toDoubleColor(aCol.GetGreen()),
671
0
                                           toDoubleColor(aCol.GetBlue()));
672
0
        }
673
0
    }
674
0
    else
675
0
    {
676
0
        OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
677
0
                   "Invalid color channel indices");
678
679
0
        for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel )
680
0
        {
681
            // TODO(F3): Convert result to sRGB color space
682
0
            const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
683
0
            *pOut++ = rendering::ARGBColor(
684
0
                nAlpha,
685
0
                deviceColor[i+m_nRedIndex],
686
0
                deviceColor[i+m_nGreenIndex],
687
0
                deviceColor[i+m_nBlueIndex]);
688
0
        }
689
0
    }
690
691
0
    return aRes;
692
0
}
693
694
uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertToPARGB( const uno::Sequence< double >& deviceColor )
695
0
{
696
0
    SolarMutexGuard aGuard;
697
698
0
    const std::size_t nLen( deviceColor.getLength() );
699
0
    const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
700
0
    ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
701
0
                         "number of channels no multiple of pixel element count",
702
0
                         static_cast<rendering::XBitmapPalette*>(this), 01);
703
704
0
    uno::Sequence< rendering::ARGBColor > aRes(nLen/nComponentsPerPixel);
705
0
    rendering::ARGBColor* pOut( aRes.getArray() );
706
707
0
    if( m_bPalette )
708
0
    {
709
0
        OSL_ENSURE(m_nIndexIndex != -1,
710
0
                   "Invalid color channel indices");
711
0
        ENSURE_OR_THROW(m_pBmpAcc,
712
0
                        "Unable to get BitmapAccess");
713
714
0
        for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel )
715
0
        {
716
0
            const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
717
0
                sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex]));
718
719
            // TODO(F3): Convert result to sRGB color space
720
0
            const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
721
0
            *pOut++ = rendering::ARGBColor(nAlpha,
722
0
                                           nAlpha*toDoubleColor(aCol.GetRed()),
723
0
                                           nAlpha*toDoubleColor(aCol.GetGreen()),
724
0
                                           nAlpha*toDoubleColor(aCol.GetBlue()));
725
0
        }
726
0
    }
727
0
    else
728
0
    {
729
0
        OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
730
0
                   "Invalid color channel indices");
731
732
0
        for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel )
733
0
        {
734
            // TODO(F3): Convert result to sRGB color space
735
0
            const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
736
0
            *pOut++ = rendering::ARGBColor(
737
0
                nAlpha,
738
0
                nAlpha*deviceColor[i+m_nRedIndex],
739
0
                nAlpha*deviceColor[i+m_nGreenIndex],
740
0
                nAlpha*deviceColor[i+m_nBlueIndex]);
741
0
        }
742
0
    }
743
744
0
    return aRes;
745
0
}
746
747
uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromRGB( const uno::Sequence<rendering::RGBColor>& rgbColor )
748
0
{
749
0
    SolarMutexGuard aGuard;
750
751
0
    const std::size_t nLen( rgbColor.getLength() );
752
0
    const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
753
754
0
    uno::Sequence< double > aRes(nLen*nComponentsPerPixel);
755
0
    double* pColors=aRes.getArray();
756
757
0
    if( m_bPalette )
758
0
    {
759
0
        for( const auto& rIn : rgbColor )
760
0
        {
761
0
            pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex(
762
0
                    BitmapColor(toByteColor(rIn.Red),
763
0
                                toByteColor(rIn.Green),
764
0
                                toByteColor(rIn.Blue)));
765
0
            if( m_nAlphaIndex != -1 )
766
0
                pColors[m_nAlphaIndex] = 1.0;
767
768
0
            pColors += nComponentsPerPixel;
769
0
        }
770
0
    }
771
0
    else
772
0
    {
773
0
        for( const auto& rIn : rgbColor )
774
0
        {
775
0
            pColors[m_nRedIndex]   = rIn.Red;
776
0
            pColors[m_nGreenIndex] = rIn.Green;
777
0
            pColors[m_nBlueIndex]  = rIn.Blue;
778
0
            if( m_nAlphaIndex != -1 )
779
0
                pColors[m_nAlphaIndex] = 1.0;
780
781
0
            pColors += nComponentsPerPixel;
782
0
        }
783
0
    }
784
0
    return aRes;
785
0
}
786
787
uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor )
788
0
{
789
0
    SolarMutexGuard aGuard;
790
791
0
    const std::size_t nLen( rgbColor.getLength() );
792
0
    const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
793
794
0
    uno::Sequence< double > aRes(nLen*nComponentsPerPixel);
795
0
    double* pColors=aRes.getArray();
796
797
0
    if( m_bPalette )
798
0
    {
799
0
        for( const auto& rIn : rgbColor )
800
0
        {
801
0
            pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex(
802
0
                    BitmapColor(toByteColor(rIn.Red),
803
0
                                toByteColor(rIn.Green),
804
0
                                toByteColor(rIn.Blue)));
805
0
            if( m_nAlphaIndex != -1 )
806
0
                pColors[m_nAlphaIndex] = rIn.Alpha;
807
808
0
            pColors += nComponentsPerPixel;
809
0
        }
810
0
    }
811
0
    else
812
0
    {
813
0
        for( const auto& rIn : rgbColor )
814
0
        {
815
0
            pColors[m_nRedIndex]   = rIn.Red;
816
0
            pColors[m_nGreenIndex] = rIn.Green;
817
0
            pColors[m_nBlueIndex]  = rIn.Blue;
818
0
            if( m_nAlphaIndex != -1 )
819
0
                pColors[m_nAlphaIndex] = rIn.Alpha;
820
821
0
            pColors += nComponentsPerPixel;
822
0
        }
823
0
    }
824
0
    return aRes;
825
0
}
826
827
uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromPARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor )
828
0
{
829
0
    SolarMutexGuard aGuard;
830
831
0
    const std::size_t nLen( rgbColor.getLength() );
832
0
    const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
833
834
0
    uno::Sequence< double > aRes(nLen*nComponentsPerPixel);
835
0
    double* pColors=aRes.getArray();
836
837
0
    if( m_bPalette )
838
0
    {
839
0
        for( const auto& rIn : rgbColor )
840
0
        {
841
0
            const double nAlpha( rIn.Alpha );
842
0
            pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex(
843
0
                    BitmapColor(toByteColor(rIn.Red / nAlpha),
844
0
                                toByteColor(rIn.Green / nAlpha),
845
0
                                toByteColor(rIn.Blue / nAlpha)));
846
0
            if( m_nAlphaIndex != -1 )
847
0
                pColors[m_nAlphaIndex] = nAlpha;
848
849
0
            pColors += nComponentsPerPixel;
850
0
        }
851
0
    }
852
0
    else
853
0
    {
854
0
        for( const auto& rIn : rgbColor )
855
0
        {
856
0
            const double nAlpha( rIn.Alpha );
857
0
            pColors[m_nRedIndex]   = rIn.Red / nAlpha;
858
0
            pColors[m_nGreenIndex] = rIn.Green / nAlpha;
859
0
            pColors[m_nBlueIndex]  = rIn.Blue / nAlpha;
860
0
            if( m_nAlphaIndex != -1 )
861
0
                pColors[m_nAlphaIndex] = nAlpha;
862
863
0
            pColors += nComponentsPerPixel;
864
0
        }
865
0
    }
866
0
    return aRes;
867
0
}
868
869
sal_Int32 SAL_CALL VclCanvasBitmap::getBitsPerPixel(  )
870
0
{
871
0
    return m_nBitsPerOutputPixel;
872
0
}
873
874
uno::Sequence< ::sal_Int32 > SAL_CALL VclCanvasBitmap::getComponentBitCounts(  )
875
0
{
876
0
    return m_aComponentBitCounts;
877
0
}
878
879
sal_Int8 SAL_CALL VclCanvasBitmap::getEndianness(  )
880
0
{
881
0
    return util::Endianness::LITTLE;
882
0
}
883
884
uno::Sequence<double> SAL_CALL VclCanvasBitmap::convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
885
                                                                              const uno::Reference< ::rendering::XColorSpace >& targetColorSpace )
886
0
{
887
0
    if( dynamic_cast<VclCanvasBitmap*>(targetColorSpace.get()) )
888
0
    {
889
0
        SolarMutexGuard aGuard;
890
891
0
        const std::size_t nLen( deviceColor.getLength() );
892
0
        const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
893
0
        ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
894
0
                             "number of channels no multiple of pixel element count",
895
0
                             static_cast<rendering::XBitmapPalette*>(this), 01);
896
897
0
        uno::Sequence<double> aRes(nLen);
898
0
        double* pOut( aRes.getArray() );
899
900
0
        if( m_bPalette )
901
0
        {
902
0
            OSL_ENSURE(m_nIndexIndex != -1,
903
0
                       "Invalid color channel indices");
904
0
            ENSURE_OR_THROW(m_pBmpAcc,
905
0
                            "Unable to get BitmapAccess");
906
907
0
            for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel )
908
0
            {
909
0
                const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
910
0
                    sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex]));
911
912
                // TODO(F3): Convert result to sRGB color space
913
0
                const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
914
0
                *pOut++ = toDoubleColor(aCol.GetRed());
915
0
                *pOut++ = toDoubleColor(aCol.GetGreen());
916
0
                *pOut++ = toDoubleColor(aCol.GetBlue());
917
0
                *pOut++ = nAlpha;
918
0
            }
919
0
        }
920
0
        else
921
0
        {
922
0
            OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
923
0
                       "Invalid color channel indices");
924
925
0
            for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel )
926
0
            {
927
                // TODO(F3): Convert result to sRGB color space
928
0
                const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
929
0
                *pOut++ = deviceColor[i+m_nRedIndex];
930
0
                *pOut++ = deviceColor[i+m_nGreenIndex];
931
0
                *pOut++ = deviceColor[i+m_nBlueIndex];
932
0
                *pOut++ = nAlpha;
933
0
            }
934
0
        }
935
936
0
        return aRes;
937
0
    }
938
0
    else
939
0
    {
940
        // TODO(P3): if we know anything about target
941
        // colorspace, this can be greatly sped up
942
0
        uno::Sequence<rendering::ARGBColor> aIntermediate(
943
0
            convertIntegerToARGB(deviceColor));
944
0
        return targetColorSpace->convertFromARGB(aIntermediate);
945
0
    }
946
0
}
947
948
uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
949
                                                                                  const uno::Reference< ::rendering::XIntegerBitmapColorSpace >& targetColorSpace )
950
0
{
951
0
    if( dynamic_cast<VclCanvasBitmap*>(targetColorSpace.get()) )
952
0
    {
953
        // it's us, so simply pass-through the data
954
0
        return deviceColor;
955
0
    }
956
0
    else
957
0
    {
958
        // TODO(P3): if we know anything about target
959
        // colorspace, this can be greatly sped up
960
0
        uno::Sequence<rendering::ARGBColor> aIntermediate(
961
0
            convertIntegerToARGB(deviceColor));
962
0
        return targetColorSpace->convertIntegerFromARGB(aIntermediate);
963
0
    }
964
0
}
965
966
uno::Sequence<rendering::RGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor )
967
0
{
968
0
    SolarMutexGuard aGuard;
969
970
0
    const sal_uInt8*     pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) );
971
0
    const std::size_t nLen( deviceColor.getLength() );
972
0
    const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel);
973
974
0
    uno::Sequence< rendering::RGBColor > aRes(nNumColors);
975
0
    rendering::RGBColor* pOut( aRes.getArray() );
976
977
0
    BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess();
978
0
    ENSURE_OR_THROW(pBmpAcc,
979
0
                    "Unable to get BitmapAccess");
980
981
0
    if( m_aBmp.HasAlpha() )
982
0
    {
983
0
        assert(!m_bPalette && "alpha bitmaps never have palette");
984
0
        const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8);
985
0
        for( std::size_t i=0; i<nLen; i+=nBytesPerPixel )
986
0
        {
987
            // TODO(F3): Convert result to sRGB color space
988
0
            *pOut++ = rendering::RGBColor(toDoubleColor(pIn[2]),
989
0
                                          toDoubleColor(pIn[1]),
990
0
                                          toDoubleColor(pIn[0]));
991
            // skips alpha
992
0
            pIn += nBytesPerPixel;
993
0
        }
994
0
    }
995
0
    else
996
0
    {
997
0
        for( sal_Int32 i=0; i<nNumColors; ++i )
998
0
        {
999
0
            const BitmapColor aCol =
1000
0
                m_bPalette ?
1001
0
                pBmpAcc->GetPaletteColor( pBmpAcc->GetPixelFromData( pIn, i ).GetIndex()) :
1002
0
                pBmpAcc->GetPixelFromData(pIn, i);
1003
1004
            // TODO(F3): Convert result to sRGB color space
1005
0
            *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()),
1006
0
                                          toDoubleColor(aCol.GetGreen()),
1007
0
                                          toDoubleColor(aCol.GetBlue()));
1008
0
        }
1009
0
    }
1010
1011
0
    return aRes;
1012
0
}
1013
1014
uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor )
1015
0
{
1016
0
    SolarMutexGuard aGuard;
1017
1018
0
    const sal_uInt8*     pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) );
1019
0
    const std::size_t nLen( deviceColor.getLength() );
1020
0
    const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel);
1021
1022
0
    uno::Sequence< rendering::ARGBColor > aRes(nNumColors);
1023
0
    rendering::ARGBColor* pOut( aRes.getArray() );
1024
1025
0
    BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess();
1026
0
    ENSURE_OR_THROW(pBmpAcc,
1027
0
                    "Unable to get BitmapAccess");
1028
1029
0
    if( m_aBmp.HasAlpha() )
1030
0
    {
1031
0
        assert(!m_bPalette && "alpha bitmaps never have palette");
1032
0
        const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8);
1033
0
        for( std::size_t i=0; i<nLen; i+=nBytesPerPixel )
1034
0
        {
1035
            // TODO(F3): Convert result to sRGB color space
1036
0
            *pOut++ = rendering::ARGBColor(1.0 - toDoubleColor(pIn[3]),
1037
0
                                           toDoubleColor(pIn[2]),
1038
0
                                           toDoubleColor(pIn[1]),
1039
0
                                           toDoubleColor(pIn[0]));
1040
0
            pIn += nBytesPerPixel;
1041
0
        }
1042
0
    }
1043
0
    else
1044
0
    {
1045
0
        for( sal_Int32 i=0; i<nNumColors; ++i )
1046
0
        {
1047
0
            const BitmapColor aCol =
1048
0
                m_bPalette ?
1049
0
                pBmpAcc->GetPaletteColor( pBmpAcc->GetPixelFromData( pIn, i ).GetIndex() ) :
1050
0
                pBmpAcc->GetPixelFromData(pIn, i);
1051
1052
            // TODO(F3): Convert result to sRGB color space
1053
0
            *pOut++ = rendering::ARGBColor(1.0,
1054
0
                                           toDoubleColor(aCol.GetRed()),
1055
0
                                           toDoubleColor(aCol.GetGreen()),
1056
0
                                           toDoubleColor(aCol.GetBlue()));
1057
0
        }
1058
0
    }
1059
1060
0
    return aRes;
1061
0
}
1062
1063
uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor )
1064
0
{
1065
0
    SolarMutexGuard aGuard;
1066
1067
0
    const sal_uInt8*     pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) );
1068
0
    const std::size_t nLen( deviceColor.getLength() );
1069
0
    const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel);
1070
1071
0
    uno::Sequence< rendering::ARGBColor > aRes(nNumColors);
1072
0
    rendering::ARGBColor* pOut( aRes.getArray() );
1073
1074
0
    BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess();
1075
0
    ENSURE_OR_THROW(pBmpAcc,
1076
0
                    "Unable to get BitmapAccess");
1077
1078
0
    if( m_aBmp.HasAlpha() )
1079
0
    {
1080
0
        assert(!m_bPalette && "alpha bitmaps never have palette");
1081
0
        const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8);
1082
0
        for( std::size_t i=0; i<nLen; i+=nBytesPerPixel )
1083
0
        {
1084
            // TODO(F3): Convert result to sRGB color space
1085
0
            const double nAlpha( 1.0 - toDoubleColor(pIn[3]) );
1086
0
            *pOut++ = rendering::ARGBColor(nAlpha,
1087
0
                                           nAlpha*toDoubleColor(pIn[2]),
1088
0
                                           nAlpha*toDoubleColor(pIn[1]),
1089
0
                                           nAlpha*toDoubleColor(pIn[0]));
1090
0
            pIn += nBytesPerPixel;
1091
0
        }
1092
0
    }
1093
0
    else
1094
0
    {
1095
0
        for( sal_Int32 i=0; i<nNumColors; ++i )
1096
0
        {
1097
0
            const BitmapColor aCol =
1098
0
                m_bPalette ?
1099
0
                pBmpAcc->GetPaletteColor( pBmpAcc->GetPixelFromData( pIn, i ).GetIndex() ) :
1100
0
                pBmpAcc->GetPixelFromData(pIn, i);
1101
1102
            // TODO(F3): Convert result to sRGB color space
1103
0
            *pOut++ = rendering::ARGBColor(1.0,
1104
0
                                           toDoubleColor(aCol.GetRed()),
1105
0
                                           toDoubleColor(aCol.GetGreen()),
1106
0
                                           toDoubleColor(aCol.GetBlue()));
1107
0
        }
1108
0
    }
1109
1110
0
    return aRes;
1111
0
}
1112
1113
uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromRGB( const uno::Sequence<rendering::RGBColor>& rgbColor )
1114
0
{
1115
0
    SolarMutexGuard aGuard;
1116
1117
0
    const std::size_t nLen( rgbColor.getLength() );
1118
0
    const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8);
1119
1120
0
    uno::Sequence< sal_Int8 > aRes(nNumBytes);
1121
0
    sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray());
1122
0
    BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess();
1123
1124
0
    if( m_aBmp.HasAlpha() )
1125
0
    {
1126
0
        assert(!m_bPalette && "alpha bitmaps never have palette");
1127
0
        for( std::size_t i=0; i<nLen; ++i )
1128
0
        {
1129
0
            *pColors++ = toByteColor(rgbColor[i].Blue);
1130
0
            *pColors++ = toByteColor(rgbColor[i].Green);
1131
0
            *pColors++ = toByteColor(rgbColor[i].Red);
1132
0
            *pColors++ = 0;
1133
0
        }
1134
0
    }
1135
0
    else
1136
0
    {
1137
0
        for( std::size_t i=0; i<nLen; ++i )
1138
0
        {
1139
0
            const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1140
0
                                   toByteColor(rgbColor[i].Green),
1141
0
                                   toByteColor(rgbColor[i].Blue));
1142
0
            const BitmapColor aCol2 =
1143
0
                m_bPalette ?
1144
0
                BitmapColor(
1145
0
                    sal::static_int_cast<sal_uInt8>(pBmpAcc->GetBestPaletteIndex( aCol ))) :
1146
0
                aCol;
1147
1148
0
            pBmpAcc->SetPixelOnData(pColors,i,aCol2);
1149
0
        }
1150
0
    }
1151
1152
0
    return aRes;
1153
0
}
1154
1155
uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor )
1156
0
{
1157
0
    SolarMutexGuard aGuard;
1158
1159
0
    const std::size_t nLen( rgbColor.getLength() );
1160
0
    const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8);
1161
1162
0
    uno::Sequence< sal_Int8 > aRes(nNumBytes);
1163
0
    sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray());
1164
0
    BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess();
1165
1166
0
    if( m_aBmp.HasAlpha() )
1167
0
    {
1168
0
        assert(!m_bPalette && "alpha bitmaps never have palette");
1169
0
        for( std::size_t i=0; i<nLen; ++i )
1170
0
        {
1171
0
            *pColors++ = toByteColor(rgbColor[i].Blue);
1172
0
            *pColors++ = toByteColor(rgbColor[i].Green);
1173
0
            *pColors++ = toByteColor(rgbColor[i].Red);
1174
0
            *pColors++ = 255 - toByteColor(rgbColor[i].Alpha);
1175
0
        }
1176
0
    }
1177
0
    else
1178
0
    {
1179
0
        for( std::size_t i=0; i<nLen; ++i )
1180
0
        {
1181
0
            const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1182
0
                                   toByteColor(rgbColor[i].Green),
1183
0
                                   toByteColor(rgbColor[i].Blue));
1184
0
            const BitmapColor aCol2 =
1185
0
                m_bPalette ?
1186
0
                BitmapColor(
1187
0
                    sal::static_int_cast<sal_uInt8>(pBmpAcc->GetBestPaletteIndex( aCol ))) :
1188
0
                aCol;
1189
1190
0
            pBmpAcc->SetPixelOnData(pColors,i,aCol2);
1191
0
        }
1192
0
    }
1193
1194
0
    return aRes;
1195
0
}
1196
1197
uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromPARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor )
1198
0
{
1199
0
    SolarMutexGuard aGuard;
1200
1201
0
    const std::size_t nLen( rgbColor.getLength() );
1202
0
    const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8);
1203
1204
0
    uno::Sequence< sal_Int8 > aRes(nNumBytes);
1205
0
    sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray());
1206
0
    BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess();
1207
1208
0
    if( m_aBmp.HasAlpha() )
1209
0
    {
1210
0
        assert(!m_bPalette && "alpha bitmaps never have palette");
1211
0
        for( std::size_t i=0; i<nLen; ++i )
1212
0
        {
1213
0
            const double nAlpha( rgbColor[i].Alpha );
1214
0
            *pColors++ = toByteColor(rgbColor[i].Blue / nAlpha);
1215
0
            *pColors++ = toByteColor(rgbColor[i].Green / nAlpha);
1216
0
            *pColors++ = toByteColor(rgbColor[i].Red / nAlpha);
1217
0
            *pColors++ = 255 - toByteColor(nAlpha);
1218
0
        }
1219
0
    }
1220
0
    else
1221
0
    {
1222
0
        for( std::size_t i=0; i<nLen; ++i )
1223
0
        {
1224
0
            const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1225
0
                                   toByteColor(rgbColor[i].Green),
1226
0
                                   toByteColor(rgbColor[i].Blue));
1227
0
            const BitmapColor aCol2 =
1228
0
                m_bPalette ?
1229
0
                BitmapColor(
1230
0
                    sal::static_int_cast<sal_uInt8>(pBmpAcc->GetBestPaletteIndex( aCol ))) :
1231
0
                aCol;
1232
1233
0
            pBmpAcc->SetPixelOnData(pColors,i,aCol2);
1234
0
        }
1235
0
    }
1236
1237
0
    return aRes;
1238
0
}
1239
1240
1241
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */