xref: /aoo41x/main/vcl/source/helper/canvasbitmap.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <com/sun/star/util/Endianness.hpp>
32 #include <com/sun/star/rendering/ColorComponentTag.hpp>
33 #include <com/sun/star/rendering/ColorSpaceType.hpp>
34 #include <com/sun/star/rendering/RenderingIntent.hpp>
35 
36 #include <rtl/instance.hxx>
37 #include <vos/mutex.hxx>
38 
39 #include <tools/diagnose_ex.h>
40 #include <canvasbitmap.hxx>
41 #include <vcl/canvastools.hxx>
42 #include <vcl/bmpacc.hxx>
43 #include <vcl/svapp.hxx>
44 
45 #include <algorithm>
46 
47 
48 using namespace ::vcl::unotools;
49 using namespace ::com::sun::star;
50 
51 namespace
52 {
53     // TODO(Q3): move to o3tl bithacks or somesuch. A similar method is in canvas/canvastools.hxx
54 
55     // Good ole HAKMEM tradition. Calc number of 1 bits in 32bit word,
56     // unrolled loop. See e.g. Hackers Delight, p. 66
57     inline sal_Int32 bitcount( sal_uInt32 val )
58     {
59         val = val - ((val >> 1) & 0x55555555);
60         val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
61         val = (val + (val >> 4)) & 0x0F0F0F0F;
62         val = val + (val >> 8);
63         val = val + (val >> 16);
64         return sal_Int32(val & 0x0000003F);
65     }
66 }
67 
68 void VclCanvasBitmap::setComponentInfo( sal_uLong redShift, sal_uLong greenShift, sal_uLong blueShift )
69 {
70     // sort channels in increasing order of appearance in the pixel
71     // (starting with the least significant bits)
72     sal_Int8 redPos(0);
73     sal_Int8 greenPos(1);
74     sal_Int8 bluePos(2);
75 
76     if( redShift > greenShift )
77     {
78         std::swap(redPos,greenPos);
79         if( redShift > blueShift )
80         {
81             std::swap(redPos,bluePos);
82             if( greenShift > blueShift )
83                 std::swap(greenPos,bluePos);
84         }
85     }
86     else
87     {
88         if( greenShift > blueShift )
89         {
90             std::swap(greenPos,bluePos);
91             if( redShift > blueShift )
92                 std::swap(redPos,bluePos);
93         }
94     }
95 
96     m_aComponentTags.realloc(3);
97     sal_Int8* pTags = m_aComponentTags.getArray();
98     pTags[redPos]   = rendering::ColorComponentTag::RGB_RED;
99     pTags[greenPos] = rendering::ColorComponentTag::RGB_GREEN;
100     pTags[bluePos]  = rendering::ColorComponentTag::RGB_BLUE;
101 
102     m_aComponentBitCounts.realloc(3);
103     sal_Int32* pCounts = m_aComponentBitCounts.getArray();
104     pCounts[redPos]    = bitcount(sal::static_int_cast<sal_uInt32>(redShift));
105     pCounts[greenPos]  = bitcount(sal::static_int_cast<sal_uInt32>(greenShift));
106     pCounts[bluePos]   = bitcount(sal::static_int_cast<sal_uInt32>(blueShift));
107 }
108 
109 VclCanvasBitmap::VclCanvasBitmap( const BitmapEx& rBitmap ) :
110     m_aBmpEx( rBitmap ),
111     m_aBitmap( rBitmap.GetBitmap() ),
112     m_aAlpha(),
113     m_pBmpAcc( m_aBitmap.AcquireReadAccess() ),
114     m_pAlphaAcc( NULL ),
115     m_aComponentTags(),
116     m_aComponentBitCounts(),
117     m_aLayout(),
118     m_nBitsPerInputPixel(0),
119     m_nBitsPerOutputPixel(0),
120     m_nRedIndex(-1),
121     m_nGreenIndex(-1),
122     m_nBlueIndex(-1),
123     m_nAlphaIndex(-1),
124     m_nIndexIndex(-1),
125     m_nEndianness(0),
126     m_bSwap(false),
127     m_bPalette(false)
128 {
129     if( m_aBmpEx.IsTransparent() )
130     {
131         m_aAlpha = m_aBmpEx.IsAlpha() ? m_aBmpEx.GetAlpha().GetBitmap() : m_aBmpEx.GetMask();
132         m_pAlphaAcc = m_aAlpha.AcquireReadAccess();
133     }
134 
135     m_aLayout.ScanLines      = 0;
136     m_aLayout.ScanLineBytes  = 0;
137     m_aLayout.ScanLineStride = 0;
138     m_aLayout.PlaneStride    = 0;
139     m_aLayout.ColorSpace.clear();
140     m_aLayout.Palette.clear();
141     m_aLayout.IsMsbFirst     = sal_False;
142 
143     if( m_pBmpAcc )
144     {
145         m_aLayout.ScanLines      = m_pBmpAcc->Height();
146         m_aLayout.ScanLineBytes  = (m_pBmpAcc->GetBitCount()*m_pBmpAcc->Width() + 7) / 8;
147         m_aLayout.ScanLineStride = m_pBmpAcc->GetScanlineSize();
148         m_aLayout.PlaneStride    = 0;
149 
150         switch( m_pBmpAcc->GetScanlineFormat() )
151         {
152             case BMP_FORMAT_1BIT_MSB_PAL:
153                 m_bPalette           = true;
154                 m_nBitsPerInputPixel = 1;
155                 m_nEndianness        = util::Endianness::LITTLE; // doesn't matter
156                 m_aLayout.IsMsbFirst = sal_True;
157                 break;
158 
159             case BMP_FORMAT_1BIT_LSB_PAL:
160                 m_bPalette           = true;
161                 m_nBitsPerInputPixel = 1;
162                 m_nEndianness        = util::Endianness::LITTLE; // doesn't matter
163                 m_aLayout.IsMsbFirst = sal_False;
164                 break;
165 
166             case BMP_FORMAT_4BIT_MSN_PAL:
167                 m_bPalette           = true;
168                 m_nBitsPerInputPixel = 4;
169                 m_nEndianness        = util::Endianness::LITTLE; // doesn't matter
170                 m_aLayout.IsMsbFirst = sal_True;
171                 break;
172 
173             case BMP_FORMAT_4BIT_LSN_PAL:
174                 m_bPalette           = true;
175                 m_nBitsPerInputPixel = 4;
176                 m_nEndianness        = util::Endianness::LITTLE; // doesn't matter
177                 m_aLayout.IsMsbFirst = sal_False;
178                 break;
179 
180             case BMP_FORMAT_8BIT_PAL:
181                 m_bPalette           = true;
182                 m_nBitsPerInputPixel = 8;
183                 m_nEndianness        = util::Endianness::LITTLE; // doesn't matter
184                 m_aLayout.IsMsbFirst = sal_False; // doesn't matter
185                 break;
186 
187             case BMP_FORMAT_8BIT_TC_MASK:
188                 m_bPalette           = false;
189                 m_nBitsPerInputPixel = 8;
190                 m_nEndianness        = util::Endianness::LITTLE; // doesn't matter
191                 m_aLayout.IsMsbFirst = sal_False; // doesn't matter
192                 setComponentInfo( m_pBmpAcc->GetColorMask().GetRedMask(),
193                                   m_pBmpAcc->GetColorMask().GetGreenMask(),
194                                   m_pBmpAcc->GetColorMask().GetBlueMask() );
195                 break;
196 
197             case BMP_FORMAT_16BIT_TC_MSB_MASK:
198                 m_bPalette           = false;
199                 m_nBitsPerInputPixel = 16;
200                 m_nEndianness        = util::Endianness::BIG;
201                 m_aLayout.IsMsbFirst = sal_False; // doesn't matter
202                 setComponentInfo( m_pBmpAcc->GetColorMask().GetRedMask(),
203                                   m_pBmpAcc->GetColorMask().GetGreenMask(),
204                                   m_pBmpAcc->GetColorMask().GetBlueMask() );
205                 break;
206 
207             case BMP_FORMAT_16BIT_TC_LSB_MASK:
208                 m_bPalette           = false;
209                 m_nBitsPerInputPixel = 16;
210                 m_nEndianness        = util::Endianness::LITTLE;
211                 m_aLayout.IsMsbFirst = sal_False; // doesn't matter
212                 setComponentInfo( m_pBmpAcc->GetColorMask().GetRedMask(),
213                                   m_pBmpAcc->GetColorMask().GetGreenMask(),
214                                   m_pBmpAcc->GetColorMask().GetBlueMask() );
215                 break;
216 
217             case BMP_FORMAT_24BIT_TC_BGR:
218                 m_bPalette           = false;
219                 m_nBitsPerInputPixel = 24;
220                 m_nEndianness        = util::Endianness::LITTLE;
221                 m_aLayout.IsMsbFirst = sal_False; // doesn't matter
222                 setComponentInfo( 0xff0000LL,
223                                   0x00ff00LL,
224                                   0x0000ffLL );
225                 break;
226 
227             case BMP_FORMAT_24BIT_TC_RGB:
228                 m_bPalette           = false;
229                 m_nBitsPerInputPixel = 24;
230                 m_nEndianness        = util::Endianness::LITTLE;
231                 m_aLayout.IsMsbFirst = sal_False; // doesn't matter
232                 setComponentInfo( 0x0000ffLL,
233                                   0x00ff00LL,
234                                   0xff0000LL );
235                 break;
236 
237             case BMP_FORMAT_24BIT_TC_MASK:
238                 m_bPalette           = false;
239                 m_nBitsPerInputPixel = 24;
240                 m_nEndianness        = util::Endianness::LITTLE;
241                 m_aLayout.IsMsbFirst = sal_False; // doesn't matter
242                 setComponentInfo( m_pBmpAcc->GetColorMask().GetRedMask(),
243                                   m_pBmpAcc->GetColorMask().GetGreenMask(),
244                                   m_pBmpAcc->GetColorMask().GetBlueMask() );
245                 break;
246 
247             case BMP_FORMAT_32BIT_TC_ABGR:
248             {
249                 m_bPalette           = false;
250                 m_nBitsPerInputPixel = 32;
251                 m_nEndianness        = util::Endianness::LITTLE;
252                 m_aLayout.IsMsbFirst = sal_False; // doesn't matter
253 
254                 m_aComponentTags.realloc(4);
255                 sal_Int8* pTags = m_aComponentTags.getArray();
256                 pTags[0]        = rendering::ColorComponentTag::ALPHA;
257                 pTags[1]        = rendering::ColorComponentTag::RGB_BLUE;
258                 pTags[2]        = rendering::ColorComponentTag::RGB_GREEN;
259                 pTags[3]        = rendering::ColorComponentTag::RGB_RED;
260 
261                 m_aComponentBitCounts.realloc(4);
262                 sal_Int32* pCounts = m_aComponentBitCounts.getArray();
263                 pCounts[0]         = 8;
264                 pCounts[1]         = 8;
265                 pCounts[2]         = 8;
266                 pCounts[3]         = 8;
267 
268                 m_nRedIndex   = 3;
269                 m_nGreenIndex = 2;
270                 m_nBlueIndex  = 1;
271                 m_nAlphaIndex = 0;
272             }
273             break;
274 
275             case BMP_FORMAT_32BIT_TC_ARGB:
276             {
277                 m_bPalette           = false;
278                 m_nBitsPerInputPixel = 32;
279                 m_nEndianness        = util::Endianness::LITTLE;
280                 m_aLayout.IsMsbFirst = sal_False; // doesn't matter
281 
282                 m_aComponentTags.realloc(4);
283                 sal_Int8* pTags = m_aComponentTags.getArray();
284                 pTags[0]        = rendering::ColorComponentTag::ALPHA;
285                 pTags[1]        = rendering::ColorComponentTag::RGB_RED;
286                 pTags[2]        = rendering::ColorComponentTag::RGB_GREEN;
287                 pTags[3]        = rendering::ColorComponentTag::RGB_BLUE;
288 
289                 m_aComponentBitCounts.realloc(4);
290                 sal_Int32* pCounts = m_aComponentBitCounts.getArray();
291                 pCounts[0]         = 8;
292                 pCounts[1]         = 8;
293                 pCounts[2]         = 8;
294                 pCounts[3]         = 8;
295 
296                 m_nRedIndex   = 1;
297                 m_nGreenIndex = 2;
298                 m_nBlueIndex  = 3;
299                 m_nAlphaIndex = 0;
300             }
301             break;
302 
303             case BMP_FORMAT_32BIT_TC_BGRA:
304             {
305                 m_bPalette           = false;
306                 m_nBitsPerInputPixel = 32;
307                 m_nEndianness        = util::Endianness::LITTLE;
308                 m_aLayout.IsMsbFirst = sal_False; // doesn't matter
309 
310                 m_aComponentTags.realloc(4);
311                 sal_Int8* pTags = m_aComponentTags.getArray();
312                 pTags[0]        = rendering::ColorComponentTag::RGB_BLUE;
313                 pTags[1]        = rendering::ColorComponentTag::RGB_GREEN;
314                 pTags[2]        = rendering::ColorComponentTag::RGB_RED;
315                 pTags[3]        = rendering::ColorComponentTag::ALPHA;
316 
317                 m_aComponentBitCounts.realloc(4);
318                 sal_Int32* pCounts = m_aComponentBitCounts.getArray();
319                 pCounts[0]         = 8;
320                 pCounts[1]         = 8;
321                 pCounts[2]         = 8;
322                 pCounts[3]         = 8;
323 
324                 m_nRedIndex   = 2;
325                 m_nGreenIndex = 1;
326                 m_nBlueIndex  = 0;
327                 m_nAlphaIndex = 3;
328             }
329             break;
330 
331             case BMP_FORMAT_32BIT_TC_RGBA:
332             {
333                 m_bPalette           = false;
334                 m_nBitsPerInputPixel = 32;
335                 m_nEndianness        = util::Endianness::LITTLE;
336                 m_aLayout.IsMsbFirst = sal_False; // doesn't matter
337 
338                 m_aComponentTags.realloc(4);
339                 sal_Int8* pTags = m_aComponentTags.getArray();
340                 pTags[0]        = rendering::ColorComponentTag::RGB_RED;
341                 pTags[1]        = rendering::ColorComponentTag::RGB_GREEN;
342                 pTags[2]        = rendering::ColorComponentTag::RGB_BLUE;
343                 pTags[3]        = rendering::ColorComponentTag::ALPHA;
344 
345                 m_aComponentBitCounts.realloc(4);
346                 sal_Int32* pCounts = m_aComponentBitCounts.getArray();
347                 pCounts[0]         = 8;
348                 pCounts[1]         = 8;
349                 pCounts[2]         = 8;
350                 pCounts[3]         = 8;
351 
352                 m_nRedIndex   = 0;
353                 m_nGreenIndex = 1;
354                 m_nBlueIndex  = 2;
355                 m_nAlphaIndex = 3;
356             }
357             break;
358 
359             case BMP_FORMAT_32BIT_TC_MASK:
360                 m_bPalette           = false;
361                 m_nBitsPerInputPixel = 32;
362                 m_nEndianness        = util::Endianness::LITTLE;
363                 m_aLayout.IsMsbFirst = sal_False; // doesn't matter
364                 setComponentInfo( m_pBmpAcc->GetColorMask().GetRedMask(),
365                                   m_pBmpAcc->GetColorMask().GetGreenMask(),
366                                   m_pBmpAcc->GetColorMask().GetBlueMask() );
367                 break;
368 
369             default:
370                 DBG_ERROR( "unsupported bitmap format" );
371                 break;
372         }
373 
374         if( m_bPalette )
375         {
376             m_aComponentTags.realloc(1);
377             m_aComponentTags[0] = rendering::ColorComponentTag::INDEX;
378 
379             m_aComponentBitCounts.realloc(1);
380             m_aComponentBitCounts[0] = m_nBitsPerInputPixel;
381 
382             m_nIndexIndex = 0;
383         }
384 
385         m_nBitsPerOutputPixel = m_nBitsPerInputPixel;
386         if( m_aBmpEx.IsTransparent() )
387         {
388             // TODO(P1): need to interleave alpha with bitmap data -
389             // won't fuss with less-than-8 bit for now
390             m_nBitsPerOutputPixel = std::max(sal_Int32(8),m_nBitsPerInputPixel);
391 
392             // check whether alpha goes in front or behind the
393             // bitcount sequence. If pixel format is little endian,
394             // put it behind all the other channels. If it's big
395             // endian, put it in front (because later, the actual data
396             // always gets written after the pixel data)
397 
398             // TODO(Q1): slight catch - in the case of the
399             // BMP_FORMAT_32BIT_XX_ARGB formats, duplicate alpha
400             // channels might happen!
401             m_aComponentTags.realloc(m_aComponentTags.getLength()+1);
402             m_aComponentTags[m_aComponentTags.getLength()-1] = rendering::ColorComponentTag::ALPHA;
403 
404             m_aComponentBitCounts.realloc(m_aComponentBitCounts.getLength()+1);
405             m_aComponentBitCounts[m_aComponentBitCounts.getLength()-1] = m_aBmpEx.IsAlpha() ? 8 : 1;
406 
407             if( m_nEndianness == util::Endianness::BIG )
408             {
409                 // put alpha in front of all the color channels
410                 sal_Int8*  pTags  =m_aComponentTags.getArray();
411                 sal_Int32* pCounts=m_aComponentBitCounts.getArray();
412                 std::rotate(pTags,
413                             pTags+m_aComponentTags.getLength()-1,
414                             pTags+m_aComponentTags.getLength());
415                 std::rotate(pCounts,
416                             pCounts+m_aComponentBitCounts.getLength()-1,
417                             pCounts+m_aComponentBitCounts.getLength());
418                 ++m_nRedIndex;
419                 ++m_nGreenIndex;
420                 ++m_nBlueIndex;
421                 ++m_nIndexIndex;
422                 m_nAlphaIndex=0;
423             }
424 
425             // always add a full byte to the pixel size, otherwise
426             // pixel packing hell breaks loose.
427             m_nBitsPerOutputPixel += 8;
428 
429             // adapt scanline parameters
430             const Size aSize = m_aBitmap.GetSizePixel();
431             m_aLayout.ScanLineBytes  =
432             m_aLayout.ScanLineStride = (aSize.Width()*m_nBitsPerOutputPixel + 7)/8;
433         }
434     }
435 }
436 
437 VclCanvasBitmap::~VclCanvasBitmap()
438 {
439     if( m_pAlphaAcc )
440         m_aAlpha.ReleaseAccess(m_pAlphaAcc);
441     if( m_pBmpAcc )
442         m_aBitmap.ReleaseAccess(m_pBmpAcc);
443 }
444 
445 // XBitmap
446 geometry::IntegerSize2D SAL_CALL VclCanvasBitmap::getSize() throw (uno::RuntimeException)
447 {
448     vos::OGuard aGuard( Application::GetSolarMutex() );
449     return integerSize2DFromSize( m_aBitmap.GetSizePixel() );
450 }
451 
452 ::sal_Bool SAL_CALL VclCanvasBitmap::hasAlpha() throw (uno::RuntimeException)
453 {
454     vos::OGuard aGuard( Application::GetSolarMutex() );
455     return m_aBmpEx.IsTransparent();
456 }
457 
458 uno::Reference< rendering::XBitmap > SAL_CALL VclCanvasBitmap::getScaledBitmap( const geometry::RealSize2D& newSize,
459                                                                                 sal_Bool beFast ) throw (uno::RuntimeException)
460 {
461     vos::OGuard aGuard( Application::GetSolarMutex() );
462 
463     BitmapEx aNewBmp( m_aBitmap );
464     aNewBmp.Scale( sizeFromRealSize2D( newSize ), beFast ? BMP_SCALE_FAST : BMP_SCALE_INTERPOLATE );
465     return uno::Reference<rendering::XBitmap>( new VclCanvasBitmap( aNewBmp ) );
466 }
467 
468 // XIntegerReadOnlyBitmap
469 uno::Sequence< sal_Int8 > SAL_CALL VclCanvasBitmap::getData( rendering::IntegerBitmapLayout& 	 bitmapLayout,
470                                                              const geometry::IntegerRectangle2D& rect ) throw( lang::IndexOutOfBoundsException,
471                                                                                                                rendering::VolatileContentDestroyedException,
472                                                                                                                uno::RuntimeException)
473 {
474     vos::OGuard aGuard( Application::GetSolarMutex() );
475 
476     bitmapLayout = getMemoryLayout();
477 
478     const ::Rectangle aRequestedArea( vcl::unotools::rectangleFromIntegerRectangle2D(rect) );
479     if( aRequestedArea.IsEmpty() )
480         return uno::Sequence< sal_Int8 >();
481 
482     // Invalid/empty bitmap: no data available
483     if( !m_pBmpAcc )
484         throw lang::IndexOutOfBoundsException();
485     if( m_aBmpEx.IsTransparent() && !m_pAlphaAcc )
486         throw lang::IndexOutOfBoundsException();
487 
488     if( aRequestedArea.Left() < 0 || aRequestedArea.Top() < 0 ||
489         aRequestedArea.Right() > m_pBmpAcc->Width() ||
490         aRequestedArea.Bottom() > m_pBmpAcc->Height() )
491     {
492         throw lang::IndexOutOfBoundsException();
493     }
494 
495     uno::Sequence< sal_Int8 > aRet;
496     Rectangle aRequestedBytes( aRequestedArea );
497 
498     // adapt to byte boundaries
499     aRequestedBytes.Left()  = aRequestedArea.Left()*m_nBitsPerOutputPixel/8;
500     aRequestedBytes.Right() = (aRequestedArea.Right()*m_nBitsPerOutputPixel + 7)/8;
501 
502     // copy stuff to output sequence
503     aRet.realloc(aRequestedBytes.getWidth()*aRequestedBytes.getHeight());
504     sal_Int8* pOutBuf = aRet.getArray();
505 
506     bitmapLayout.ScanLines     = aRequestedBytes.getHeight();
507     bitmapLayout.ScanLineBytes =
508     bitmapLayout.ScanLineStride= aRequestedBytes.getWidth();
509 
510     sal_Int32 nScanlineStride=bitmapLayout.ScanLineStride;
511     if( !(m_pBmpAcc->GetScanlineFormat() & BMP_FORMAT_TOP_DOWN) )
512     {
513         pOutBuf += bitmapLayout.ScanLineStride*(aRequestedBytes.getHeight()-1);
514         nScanlineStride *= -1;
515     }
516 
517     if( !m_aBmpEx.IsTransparent() )
518     {
519         OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access");
520 
521         // can return bitmap data as-is
522         for( long y=aRequestedBytes.Top(); y<aRequestedBytes.Bottom(); ++y )
523         {
524             Scanline pScan = m_pBmpAcc->GetScanline(y);
525             rtl_copyMemory(pOutBuf, pScan+aRequestedBytes.Left(), aRequestedBytes.getWidth());
526             pOutBuf += nScanlineStride;
527         }
528     }
529     else
530     {
531         OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access");
532         OSL_ENSURE(m_pAlphaAcc,"Invalid alpha read access");
533 
534         // interleave alpha with bitmap data - note, bitcount is
535         // always integer multiple of 8
536         OSL_ENSURE((m_nBitsPerOutputPixel & 0x07) == 0,
537                    "Transparent bitmap bitcount not integer multiple of 8" );
538 
539         for( long y=aRequestedArea.Top(); y<aRequestedArea.Bottom(); ++y )
540         {
541             sal_Int8* pOutScan = pOutBuf;
542 
543             if( m_nBitsPerInputPixel < 8 )
544             {
545                 // input less than a byte - copy via GetPixel()
546                 for( long x=aRequestedArea.Left(); x<aRequestedArea.Right(); ++x )
547                 {
548                     *pOutScan++ = m_pBmpAcc->GetPixel(y,x);
549                     *pOutScan++ = m_pAlphaAcc->GetPixel(y,x);
550                 }
551             }
552             else
553             {
554                 const long nNonAlphaBytes( m_nBitsPerInputPixel/8 );
555                 const long nScanlineOffsetLeft(aRequestedArea.Left()*nNonAlphaBytes);
556                 Scanline  pScan = m_pBmpAcc->GetScanline(y) + nScanlineOffsetLeft;
557 
558                 // input integer multiple of byte - copy directly
559                 for( long x=aRequestedArea.Left(); x<aRequestedArea.Right(); ++x )
560                 {
561                     for( long i=0; i<nNonAlphaBytes; ++i )
562                         *pOutScan++ = *pScan++;
563                     *pOutScan++ = m_pAlphaAcc->GetPixel(y,x);
564                 }
565             }
566 
567             pOutBuf += nScanlineStride;
568         }
569     }
570 
571     return aRet;
572 }
573 
574 uno::Sequence< sal_Int8 > SAL_CALL VclCanvasBitmap::getPixel( rendering::IntegerBitmapLayout&	bitmapLayout,
575                                                               const geometry::IntegerPoint2D&	pos ) throw (lang::IndexOutOfBoundsException,
576                                                                                                              rendering::VolatileContentDestroyedException,
577                                                                                                              uno::RuntimeException)
578 {
579     vos::OGuard aGuard( Application::GetSolarMutex() );
580 
581     bitmapLayout = getMemoryLayout();
582 
583     // Invalid/empty bitmap: no data available
584     if( !m_pBmpAcc )
585         throw lang::IndexOutOfBoundsException();
586     if( m_aBmpEx.IsTransparent() && !m_pAlphaAcc )
587         throw lang::IndexOutOfBoundsException();
588 
589     if( pos.X < 0 || pos.Y < 0 ||
590         pos.X > m_pBmpAcc->Width() || pos.Y > m_pBmpAcc->Height() )
591     {
592         throw lang::IndexOutOfBoundsException();
593     }
594 
595     uno::Sequence< sal_Int8 > aRet((m_nBitsPerOutputPixel + 7)/8);
596     sal_Int8* pOutBuf = aRet.getArray();
597 
598     // copy stuff to output sequence
599     bitmapLayout.ScanLines     = 1;
600     bitmapLayout.ScanLineBytes =
601     bitmapLayout.ScanLineStride= aRet.getLength();
602 
603     const long nScanlineLeftOffset( pos.X*m_nBitsPerInputPixel/8 );
604     if( !m_aBmpEx.IsTransparent() )
605     {
606         OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access");
607 
608         // can return bitmap data as-is
609         Scanline pScan = m_pBmpAcc->GetScanline(pos.Y);
610         rtl_copyMemory(pOutBuf, pScan+nScanlineLeftOffset, aRet.getLength() );
611     }
612     else
613     {
614         OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access");
615         OSL_ENSURE(m_pAlphaAcc,"Invalid alpha read access");
616 
617         // interleave alpha with bitmap data - note, bitcount is
618         // always integer multiple of 8
619         OSL_ENSURE((m_nBitsPerOutputPixel & 0x07) == 0,
620                    "Transparent bitmap bitcount not integer multiple of 8" );
621 
622         if( m_nBitsPerInputPixel < 8 )
623         {
624             // input less than a byte - copy via GetPixel()
625             *pOutBuf++ = m_pBmpAcc->GetPixel(pos.Y,pos.X);
626             *pOutBuf   = m_pAlphaAcc->GetPixel(pos.Y,pos.X);
627         }
628         else
629         {
630             const long nNonAlphaBytes( m_nBitsPerInputPixel/8 );
631             Scanline  pScan = m_pBmpAcc->GetScanline(pos.Y);
632 
633             // input integer multiple of byte - copy directly
634             rtl_copyMemory(pOutBuf, pScan+nScanlineLeftOffset, nNonAlphaBytes );
635             pOutBuf += nNonAlphaBytes;
636             *pOutBuf++ = m_pAlphaAcc->GetPixel(pos.Y,pos.X);
637         }
638     }
639 
640     return aRet;
641 }
642 
643 uno::Reference< rendering::XBitmapPalette > SAL_CALL VclCanvasBitmap::getPalette() throw (uno::RuntimeException)
644 {
645     vos::OGuard aGuard( Application::GetSolarMutex() );
646 
647     uno::Reference< XBitmapPalette > aRet;
648     if( m_bPalette )
649         aRet.set(this);
650 
651     return aRet;
652 }
653 
654 rendering::IntegerBitmapLayout SAL_CALL VclCanvasBitmap::getMemoryLayout() throw (uno::RuntimeException)
655 {
656     vos::OGuard aGuard( Application::GetSolarMutex() );
657 
658     rendering::IntegerBitmapLayout aLayout( m_aLayout );
659 
660     // only set references to self on separate copy of
661     // IntegerBitmapLayout - if we'd set that on m_aLayout, we'd have
662     // a circular reference!
663     if( m_bPalette )
664         aLayout.Palette.set( this );
665 
666     aLayout.ColorSpace.set( this );
667 
668     return aLayout;
669 }
670 
671 sal_Int32 SAL_CALL VclCanvasBitmap::getNumberOfEntries() throw (uno::RuntimeException)
672 {
673     vos::OGuard aGuard( Application::GetSolarMutex() );
674 
675     if( !m_pBmpAcc )
676         return 0;
677 
678     return m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ;
679 }
680 
681 sal_Bool SAL_CALL VclCanvasBitmap::getIndex( uno::Sequence< double >& o_entry, sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
682 {
683     vos::OGuard aGuard( Application::GetSolarMutex() );
684 
685     const sal_uInt16 nCount( m_pBmpAcc ?
686                          (m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ) : 0 );
687     OSL_ENSURE(nIndex >= 0 && nIndex < nCount,"Palette index out of range");
688     if( nIndex < 0 || nIndex >= nCount )
689         throw lang::IndexOutOfBoundsException(::rtl::OUString::createFromAscii("Palette index out of range"),
690                                               static_cast<rendering::XBitmapPalette*>(this));
691 
692     const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(sal::static_int_cast<sal_uInt16>(nIndex));
693     o_entry.realloc(3);
694     double* pColor=o_entry.getArray();
695     pColor[0] = aCol.GetRed();
696     pColor[1] = aCol.GetGreen();
697     pColor[2] = aCol.GetBlue();
698 
699     return sal_True; // no palette transparency here.
700 }
701 
702 sal_Bool SAL_CALL VclCanvasBitmap::setIndex( const uno::Sequence< double >&, sal_Bool, sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
703 {
704     vos::OGuard aGuard( Application::GetSolarMutex() );
705 
706     const sal_uInt16 nCount( m_pBmpAcc ?
707                          (m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ) : 0 );
708 
709     OSL_ENSURE(nIndex >= 0 && nIndex < nCount,"Palette index out of range");
710     if( nIndex < 0 || nIndex >= nCount )
711         throw lang::IndexOutOfBoundsException(::rtl::OUString::createFromAscii("Palette index out of range"),
712                                               static_cast<rendering::XBitmapPalette*>(this));
713 
714     return sal_False; // read-only implementation
715 }
716 
717 namespace
718 {
719     struct PaletteColorSpaceHolder: public rtl::StaticWithInit<uno::Reference<rendering::XColorSpace>,
720                                                                PaletteColorSpaceHolder>
721     {
722         uno::Reference<rendering::XColorSpace> operator()()
723         {
724             return vcl::unotools::createStandardColorSpace();
725         }
726     };
727 }
728 
729 uno::Reference< rendering::XColorSpace > SAL_CALL VclCanvasBitmap::getColorSpace(  ) throw (uno::RuntimeException)
730 {
731     // this is the method from XBitmapPalette. Return palette color
732     // space here
733     return PaletteColorSpaceHolder::get();
734 }
735 
736 sal_Int8 SAL_CALL VclCanvasBitmap::getType(  ) throw (uno::RuntimeException)
737 {
738     return rendering::ColorSpaceType::RGB;
739 }
740 
741 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::getComponentTags(  ) throw (uno::RuntimeException)
742 {
743     vos::OGuard aGuard( Application::GetSolarMutex() );
744     return m_aComponentTags;
745 }
746 
747 sal_Int8 SAL_CALL VclCanvasBitmap::getRenderingIntent(  ) throw (uno::RuntimeException)
748 {
749     return rendering::RenderingIntent::PERCEPTUAL;
750 }
751 
752 uno::Sequence< ::beans::PropertyValue > SAL_CALL VclCanvasBitmap::getProperties(  ) throw (uno::RuntimeException)
753 {
754     return uno::Sequence< ::beans::PropertyValue >();
755 }
756 
757 uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertColorSpace( const uno::Sequence< double >& deviceColor,
758                                                                      const uno::Reference< ::rendering::XColorSpace >& targetColorSpace ) throw (uno::RuntimeException)
759 {
760     // TODO(P3): if we know anything about target
761     // colorspace, this can be greatly sped up
762     uno::Sequence<rendering::ARGBColor> aIntermediate(
763         convertToARGB(deviceColor));
764     return targetColorSpace->convertFromARGB(aIntermediate);
765 }
766 
767 uno::Sequence<rendering::RGBColor> SAL_CALL VclCanvasBitmap::convertToRGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
768 {
769     vos::OGuard aGuard( Application::GetSolarMutex() );
770 
771     const sal_Size  nLen( deviceColor.getLength() );
772     const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
773     ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
774                          "number of channels no multiple of pixel element count",
775                          static_cast<rendering::XBitmapPalette*>(this), 01);
776 
777     uno::Sequence< rendering::RGBColor > aRes(nLen/nComponentsPerPixel);
778     rendering::RGBColor* pOut( aRes.getArray() );
779 
780     if( m_bPalette )
781     {
782         OSL_ENSURE(m_nIndexIndex != -1,
783                    "Invalid color channel indices");
784         ENSURE_OR_THROW(m_pBmpAcc,
785                         "Unable to get BitmapAccess");
786 
787         for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
788         {
789             const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
790                 sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex]));
791 
792             // TODO(F3): Convert result to sRGB color space
793             *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()),
794                                           toDoubleColor(aCol.GetGreen()),
795                                           toDoubleColor(aCol.GetBlue()));
796         }
797     }
798     else
799     {
800         OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
801                    "Invalid color channel indices");
802 
803         for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
804         {
805             // TODO(F3): Convert result to sRGB color space
806             *pOut++ = rendering::RGBColor(
807                 deviceColor[i+m_nRedIndex],
808                 deviceColor[i+m_nGreenIndex],
809                 deviceColor[i+m_nBlueIndex]);
810         }
811     }
812 
813     return aRes;
814 }
815 
816 uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertToARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
817 {
818     vos::OGuard aGuard( Application::GetSolarMutex() );
819 
820     const sal_Size  nLen( deviceColor.getLength() );
821     const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
822     ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
823                          "number of channels no multiple of pixel element count",
824                          static_cast<rendering::XBitmapPalette*>(this), 01);
825 
826     uno::Sequence< rendering::ARGBColor > aRes(nLen/nComponentsPerPixel);
827     rendering::ARGBColor* pOut( aRes.getArray() );
828 
829     if( m_bPalette )
830     {
831         OSL_ENSURE(m_nIndexIndex != -1,
832                    "Invalid color channel indices");
833         ENSURE_OR_THROW(m_pBmpAcc,
834                         "Unable to get BitmapAccess");
835 
836         for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
837         {
838             const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
839                 sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex]));
840 
841             // TODO(F3): Convert result to sRGB color space
842             const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
843             *pOut++ = rendering::ARGBColor(nAlpha,
844                                            toDoubleColor(aCol.GetRed()),
845                                            toDoubleColor(aCol.GetGreen()),
846                                            toDoubleColor(aCol.GetBlue()));
847         }
848     }
849     else
850     {
851         OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
852                    "Invalid color channel indices");
853 
854         for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
855         {
856             // TODO(F3): Convert result to sRGB color space
857             const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
858             *pOut++ = rendering::ARGBColor(
859                 nAlpha,
860                 deviceColor[i+m_nRedIndex],
861                 deviceColor[i+m_nGreenIndex],
862                 deviceColor[i+m_nBlueIndex]);
863         }
864     }
865 
866     return aRes;
867 }
868 
869 uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertToPARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
870 {
871     vos::OGuard aGuard( Application::GetSolarMutex() );
872 
873     const sal_Size  nLen( deviceColor.getLength() );
874     const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
875     ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
876                          "number of channels no multiple of pixel element count",
877                          static_cast<rendering::XBitmapPalette*>(this), 01);
878 
879     uno::Sequence< rendering::ARGBColor > aRes(nLen/nComponentsPerPixel);
880     rendering::ARGBColor* pOut( aRes.getArray() );
881 
882     if( m_bPalette )
883     {
884         OSL_ENSURE(m_nIndexIndex != -1,
885                    "Invalid color channel indices");
886         ENSURE_OR_THROW(m_pBmpAcc,
887                         "Unable to get BitmapAccess");
888 
889         for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
890         {
891             const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
892                 sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex]));
893 
894             // TODO(F3): Convert result to sRGB color space
895             const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
896             *pOut++ = rendering::ARGBColor(nAlpha,
897                                            nAlpha*toDoubleColor(aCol.GetRed()),
898                                            nAlpha*toDoubleColor(aCol.GetGreen()),
899                                            nAlpha*toDoubleColor(aCol.GetBlue()));
900         }
901     }
902     else
903     {
904         OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
905                    "Invalid color channel indices");
906 
907         for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
908         {
909             // TODO(F3): Convert result to sRGB color space
910             const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
911             *pOut++ = rendering::ARGBColor(
912                 nAlpha,
913                 nAlpha*deviceColor[i+m_nRedIndex],
914                 nAlpha*deviceColor[i+m_nGreenIndex],
915                 nAlpha*deviceColor[i+m_nBlueIndex]);
916         }
917     }
918 
919     return aRes;
920 }
921 
922 uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromRGB( const uno::Sequence<rendering::RGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
923 {
924     vos::OGuard aGuard( Application::GetSolarMutex() );
925 
926     const sal_Size  nLen( rgbColor.getLength() );
927     const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
928 
929     uno::Sequence< double > aRes(nLen*nComponentsPerPixel);
930     double* pColors=aRes.getArray();
931 
932     if( m_bPalette )
933     {
934         for( sal_Size i=0; i<nLen; ++i )
935         {
936             pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex(
937                     BitmapColor(toByteColor(rgbColor[i].Red),
938                                 toByteColor(rgbColor[i].Green),
939                                 toByteColor(rgbColor[i].Blue)));
940             if( m_nAlphaIndex != -1 )
941                 pColors[m_nAlphaIndex] = 1.0;
942 
943             pColors += nComponentsPerPixel;
944         }
945     }
946     else
947     {
948         for( sal_Size i=0; i<nLen; ++i )
949         {
950             pColors[m_nRedIndex]   = rgbColor[i].Red;
951             pColors[m_nGreenIndex] = rgbColor[i].Green;
952             pColors[m_nBlueIndex]  = rgbColor[i].Blue;
953             if( m_nAlphaIndex != -1 )
954                 pColors[m_nAlphaIndex] = 1.0;
955 
956             pColors += nComponentsPerPixel;
957         }
958     }
959     return aRes;
960 }
961 
962 uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
963 {
964     vos::OGuard aGuard( Application::GetSolarMutex() );
965 
966     const sal_Size  nLen( rgbColor.getLength() );
967     const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
968 
969     uno::Sequence< double > aRes(nLen*nComponentsPerPixel);
970     double* pColors=aRes.getArray();
971 
972     if( m_bPalette )
973     {
974         for( sal_Size i=0; i<nLen; ++i )
975         {
976             pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex(
977                     BitmapColor(toByteColor(rgbColor[i].Red),
978                                 toByteColor(rgbColor[i].Green),
979                                 toByteColor(rgbColor[i].Blue)));
980             if( m_nAlphaIndex != -1 )
981                 pColors[m_nAlphaIndex] = rgbColor[i].Alpha;
982 
983             pColors += nComponentsPerPixel;
984         }
985     }
986     else
987     {
988         for( sal_Size i=0; i<nLen; ++i )
989         {
990             pColors[m_nRedIndex]   = rgbColor[i].Red;
991             pColors[m_nGreenIndex] = rgbColor[i].Green;
992             pColors[m_nBlueIndex]  = rgbColor[i].Blue;
993             if( m_nAlphaIndex != -1 )
994                 pColors[m_nAlphaIndex] = rgbColor[i].Alpha;
995 
996             pColors += nComponentsPerPixel;
997         }
998     }
999     return aRes;
1000 }
1001 
1002 uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromPARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
1003 {
1004     vos::OGuard aGuard( Application::GetSolarMutex() );
1005 
1006     const sal_Size  nLen( rgbColor.getLength() );
1007     const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
1008 
1009     uno::Sequence< double > aRes(nLen*nComponentsPerPixel);
1010     double* pColors=aRes.getArray();
1011 
1012     if( m_bPalette )
1013     {
1014         for( sal_Size i=0; i<nLen; ++i )
1015         {
1016             const double nAlpha( rgbColor[i].Alpha );
1017             pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex(
1018                     BitmapColor(toByteColor(rgbColor[i].Red / nAlpha),
1019                                 toByteColor(rgbColor[i].Green / nAlpha),
1020                                 toByteColor(rgbColor[i].Blue / nAlpha)));
1021             if( m_nAlphaIndex != -1 )
1022                 pColors[m_nAlphaIndex] = nAlpha;
1023 
1024             pColors += nComponentsPerPixel;
1025         }
1026     }
1027     else
1028     {
1029         for( sal_Size i=0; i<nLen; ++i )
1030         {
1031             const double nAlpha( rgbColor[i].Alpha );
1032             pColors[m_nRedIndex]   = rgbColor[i].Red / nAlpha;
1033             pColors[m_nGreenIndex] = rgbColor[i].Green / nAlpha;
1034             pColors[m_nBlueIndex]  = rgbColor[i].Blue / nAlpha;
1035             if( m_nAlphaIndex != -1 )
1036                 pColors[m_nAlphaIndex] = nAlpha;
1037 
1038             pColors += nComponentsPerPixel;
1039         }
1040     }
1041     return aRes;
1042 }
1043 
1044 sal_Int32 SAL_CALL VclCanvasBitmap::getBitsPerPixel(  ) throw (uno::RuntimeException)
1045 {
1046     vos::OGuard aGuard( Application::GetSolarMutex() );
1047     return m_nBitsPerOutputPixel;
1048 }
1049 
1050 uno::Sequence< ::sal_Int32 > SAL_CALL VclCanvasBitmap::getComponentBitCounts(  ) throw (uno::RuntimeException)
1051 {
1052     vos::OGuard aGuard( Application::GetSolarMutex() );
1053     return m_aComponentBitCounts;
1054 }
1055 
1056 sal_Int8 SAL_CALL VclCanvasBitmap::getEndianness(  ) throw (uno::RuntimeException)
1057 {
1058     vos::OGuard aGuard( Application::GetSolarMutex() );
1059     return m_nEndianness;
1060 }
1061 
1062 uno::Sequence<double> SAL_CALL VclCanvasBitmap::convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
1063                                                                               const uno::Reference< ::rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,uno::RuntimeException)
1064 {
1065     if( dynamic_cast<VclCanvasBitmap*>(targetColorSpace.get()) )
1066     {
1067         vos::OGuard aGuard( Application::GetSolarMutex() );
1068 
1069         const sal_Size  nLen( deviceColor.getLength() );
1070         const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
1071         ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
1072                              "number of channels no multiple of pixel element count",
1073                              static_cast<rendering::XBitmapPalette*>(this), 01);
1074 
1075         uno::Sequence<double> aRes(nLen);
1076         double* pOut( aRes.getArray() );
1077 
1078         if( m_bPalette )
1079         {
1080             OSL_ENSURE(m_nIndexIndex != -1,
1081                        "Invalid color channel indices");
1082             ENSURE_OR_THROW(m_pBmpAcc,
1083                             "Unable to get BitmapAccess");
1084 
1085             for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
1086             {
1087                 const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
1088                     sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex]));
1089 
1090                 // TODO(F3): Convert result to sRGB color space
1091                 const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
1092                 *pOut++ = toDoubleColor(aCol.GetRed());
1093                 *pOut++ = toDoubleColor(aCol.GetGreen());
1094                 *pOut++ = toDoubleColor(aCol.GetBlue());
1095                 *pOut++ = nAlpha;
1096             }
1097         }
1098         else
1099         {
1100             OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
1101                        "Invalid color channel indices");
1102 
1103             for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
1104             {
1105                 // TODO(F3): Convert result to sRGB color space
1106                 const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
1107                 *pOut++ = deviceColor[i+m_nRedIndex];
1108                 *pOut++ = deviceColor[i+m_nGreenIndex];
1109                 *pOut++ = deviceColor[i+m_nBlueIndex];
1110                 *pOut++ = nAlpha;
1111             }
1112         }
1113 
1114         return aRes;
1115     }
1116     else
1117     {
1118         // TODO(P3): if we know anything about target
1119         // colorspace, this can be greatly sped up
1120         uno::Sequence<rendering::ARGBColor> aIntermediate(
1121             convertIntegerToARGB(deviceColor));
1122         return targetColorSpace->convertFromARGB(aIntermediate);
1123     }
1124 }
1125 
1126 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
1127                                                                                   const uno::Reference< ::rendering::XIntegerBitmapColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,uno::RuntimeException)
1128 {
1129     if( dynamic_cast<VclCanvasBitmap*>(targetColorSpace.get()) )
1130     {
1131         // it's us, so simply pass-through the data
1132         return deviceColor;
1133     }
1134     else
1135     {
1136         // TODO(P3): if we know anything about target
1137         // colorspace, this can be greatly sped up
1138         uno::Sequence<rendering::ARGBColor> aIntermediate(
1139             convertIntegerToARGB(deviceColor));
1140         return targetColorSpace->convertIntegerFromARGB(aIntermediate);
1141     }
1142 }
1143 
1144 uno::Sequence<rendering::RGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
1145 {
1146     vos::OGuard aGuard( Application::GetSolarMutex() );
1147 
1148     const sal_uInt8*     pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) );
1149     const sal_Size  nLen( deviceColor.getLength() );
1150     const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel);
1151 
1152     uno::Sequence< rendering::RGBColor > aRes(nNumColors);
1153     rendering::RGBColor* pOut( aRes.getArray() );
1154 
1155     ENSURE_OR_THROW(m_pBmpAcc,
1156                     "Unable to get BitmapAccess");
1157 
1158     if( m_aBmpEx.IsTransparent() )
1159     {
1160         const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8);
1161         for( sal_Size i=0; i<nLen; i+=nBytesPerPixel )
1162         {
1163             // if palette, index is guaranteed to be 8 bit
1164             const BitmapColor aCol =
1165                 m_bPalette ?
1166                 m_pBmpAcc->GetPaletteColor(*pIn) :
1167                 m_pBmpAcc->GetPixelFromData(pIn,0);
1168 
1169             // TODO(F3): Convert result to sRGB color space
1170             *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()),
1171                                           toDoubleColor(aCol.GetGreen()),
1172                                           toDoubleColor(aCol.GetBlue()));
1173             // skips alpha
1174             pIn += nBytesPerPixel;
1175         }
1176     }
1177     else
1178     {
1179         for( sal_Int32 i=0; i<nNumColors; ++i )
1180         {
1181             const BitmapColor aCol =
1182                 m_bPalette ?
1183                 m_pBmpAcc->GetPaletteColor(
1184                     sal::static_int_cast<sal_uInt16>(
1185                         m_pBmpAcc->GetPixelFromData(
1186                             pIn, i ))) :
1187                 m_pBmpAcc->GetPixelFromData(pIn, i);
1188 
1189             // TODO(F3): Convert result to sRGB color space
1190             *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()),
1191                                           toDoubleColor(aCol.GetGreen()),
1192                                           toDoubleColor(aCol.GetBlue()));
1193         }
1194     }
1195 
1196     return aRes;
1197 }
1198 
1199 uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
1200 {
1201     vos::OGuard aGuard( Application::GetSolarMutex() );
1202 
1203     const sal_uInt8*     pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) );
1204     const sal_Size  nLen( deviceColor.getLength() );
1205     const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel);
1206 
1207     uno::Sequence< rendering::ARGBColor > aRes(nNumColors);
1208     rendering::ARGBColor* pOut( aRes.getArray() );
1209 
1210     ENSURE_OR_THROW(m_pBmpAcc,
1211                     "Unable to get BitmapAccess");
1212 
1213     if( m_aBmpEx.IsTransparent() )
1214     {
1215         const long      nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
1216         const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8);
1217         const sal_uInt8 nAlphaFactor( m_aBmpEx.IsAlpha() ? 1 : 255 );
1218         for( sal_Size i=0; i<nLen; i+=nBytesPerPixel )
1219         {
1220             // if palette, index is guaranteed to be 8 bit
1221             const BitmapColor aCol =
1222                 m_bPalette ?
1223                 m_pBmpAcc->GetPaletteColor(*pIn) :
1224                 m_pBmpAcc->GetPixelFromData(pIn,0);
1225 
1226             // TODO(F3): Convert result to sRGB color space
1227             *pOut++ = rendering::ARGBColor(1.0 - toDoubleColor(nAlphaFactor*pIn[nNonAlphaBytes]),
1228                                            toDoubleColor(aCol.GetRed()),
1229                                            toDoubleColor(aCol.GetGreen()),
1230                                            toDoubleColor(aCol.GetBlue()));
1231             pIn += nBytesPerPixel;
1232         }
1233     }
1234     else
1235     {
1236         for( sal_Int32 i=0; i<nNumColors; ++i )
1237         {
1238             const BitmapColor aCol =
1239                 m_bPalette ?
1240                 m_pBmpAcc->GetPaletteColor(
1241                     sal::static_int_cast<sal_uInt16>(
1242                         m_pBmpAcc->GetPixelFromData(
1243                             pIn, i ))) :
1244                 m_pBmpAcc->GetPixelFromData(pIn, i);
1245 
1246             // TODO(F3): Convert result to sRGB color space
1247             *pOut++ = rendering::ARGBColor(1.0,
1248                                            toDoubleColor(aCol.GetRed()),
1249                                            toDoubleColor(aCol.GetGreen()),
1250                                            toDoubleColor(aCol.GetBlue()));
1251         }
1252     }
1253 
1254     return aRes;
1255 }
1256 
1257 uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
1258 {
1259     vos::OGuard aGuard( Application::GetSolarMutex() );
1260 
1261     const sal_uInt8*     pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) );
1262     const sal_Size  nLen( deviceColor.getLength() );
1263     const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel);
1264 
1265     uno::Sequence< rendering::ARGBColor > aRes(nNumColors);
1266     rendering::ARGBColor* pOut( aRes.getArray() );
1267 
1268     ENSURE_OR_THROW(m_pBmpAcc,
1269                     "Unable to get BitmapAccess");
1270 
1271     if( m_aBmpEx.IsTransparent() )
1272     {
1273         const long      nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
1274         const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8);
1275         const sal_uInt8 nAlphaFactor( m_aBmpEx.IsAlpha() ? 1 : 255 );
1276         for( sal_Size i=0; i<nLen; i+=nBytesPerPixel )
1277         {
1278             // if palette, index is guaranteed to be 8 bit
1279             const BitmapColor aCol =
1280                 m_bPalette ?
1281                 m_pBmpAcc->GetPaletteColor(*pIn) :
1282                 m_pBmpAcc->GetPixelFromData(pIn,0);
1283 
1284             // TODO(F3): Convert result to sRGB color space
1285             const double nAlpha( 1.0 - toDoubleColor(nAlphaFactor*pIn[nNonAlphaBytes]) );
1286             *pOut++ = rendering::ARGBColor(nAlpha,
1287                                            nAlpha*toDoubleColor(aCol.GetRed()),
1288                                            nAlpha*toDoubleColor(aCol.GetGreen()),
1289                                            nAlpha*toDoubleColor(aCol.GetBlue()));
1290             pIn += nBytesPerPixel;
1291         }
1292     }
1293     else
1294     {
1295         for( sal_Int32 i=0; i<nNumColors; ++i )
1296         {
1297             const BitmapColor aCol =
1298                 m_bPalette ?
1299                 m_pBmpAcc->GetPaletteColor(
1300                     sal::static_int_cast<sal_uInt16>(
1301                         m_pBmpAcc->GetPixelFromData(
1302                             pIn, i ))) :
1303                 m_pBmpAcc->GetPixelFromData(pIn, i);
1304 
1305             // TODO(F3): Convert result to sRGB color space
1306             *pOut++ = rendering::ARGBColor(1.0,
1307                                            toDoubleColor(aCol.GetRed()),
1308                                            toDoubleColor(aCol.GetGreen()),
1309                                            toDoubleColor(aCol.GetBlue()));
1310         }
1311     }
1312 
1313     return aRes;
1314 }
1315 
1316 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromRGB( const uno::Sequence<rendering::RGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
1317 {
1318     vos::OGuard aGuard( Application::GetSolarMutex() );
1319 
1320     const sal_Size  nLen( rgbColor.getLength() );
1321     const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8);
1322 
1323     uno::Sequence< sal_Int8 > aRes(nNumBytes);
1324     sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray());
1325 
1326     if( m_aBmpEx.IsTransparent() )
1327     {
1328         const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
1329         for( sal_Size i=0; i<nLen; ++i )
1330         {
1331             const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1332                                    toByteColor(rgbColor[i].Green),
1333                                    toByteColor(rgbColor[i].Blue));
1334             const BitmapColor aCol2 =
1335                 m_bPalette ?
1336                 BitmapColor(
1337                     sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1338                 aCol;
1339 
1340             m_pBmpAcc->SetPixelOnData(pColors,0,aCol2);
1341             pColors   += nNonAlphaBytes;
1342             *pColors++ = sal_uInt8(255);
1343         }
1344     }
1345     else
1346     {
1347         for( sal_Size i=0; i<nLen; ++i )
1348         {
1349             const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1350                                    toByteColor(rgbColor[i].Green),
1351                                    toByteColor(rgbColor[i].Blue));
1352             const BitmapColor aCol2 =
1353                 m_bPalette ?
1354                 BitmapColor(
1355                     sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1356                 aCol;
1357 
1358             m_pBmpAcc->SetPixelOnData(pColors,i,aCol2);
1359         }
1360     }
1361 
1362     return aRes;
1363 }
1364 
1365 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
1366 {
1367     vos::OGuard aGuard( Application::GetSolarMutex() );
1368 
1369     const sal_Size  nLen( rgbColor.getLength() );
1370     const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8);
1371 
1372     uno::Sequence< sal_Int8 > aRes(nNumBytes);
1373     sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray());
1374 
1375     if( m_aBmpEx.IsTransparent() )
1376     {
1377         const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
1378         for( sal_Size i=0; i<nLen; ++i )
1379         {
1380             const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1381                                    toByteColor(rgbColor[i].Green),
1382                                    toByteColor(rgbColor[i].Blue));
1383             const BitmapColor aCol2 =
1384                 m_bPalette ?
1385                 BitmapColor(
1386                     sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1387                 aCol;
1388 
1389             m_pBmpAcc->SetPixelOnData(pColors,0,aCol2);
1390             pColors   += nNonAlphaBytes;
1391             *pColors++ = 255 - toByteColor(rgbColor[i].Alpha);
1392         }
1393     }
1394     else
1395     {
1396         for( sal_Size i=0; i<nLen; ++i )
1397         {
1398             const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1399                                    toByteColor(rgbColor[i].Green),
1400                                    toByteColor(rgbColor[i].Blue));
1401             const BitmapColor aCol2 =
1402                 m_bPalette ?
1403                 BitmapColor(
1404                     sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1405                 aCol;
1406 
1407             m_pBmpAcc->SetPixelOnData(pColors,i,aCol2);
1408         }
1409     }
1410 
1411     return aRes;
1412 }
1413 
1414 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromPARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
1415 {
1416     vos::OGuard aGuard( Application::GetSolarMutex() );
1417 
1418     const sal_Size  nLen( rgbColor.getLength() );
1419     const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8);
1420 
1421     uno::Sequence< sal_Int8 > aRes(nNumBytes);
1422     sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray());
1423 
1424     if( m_aBmpEx.IsTransparent() )
1425     {
1426         const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
1427         for( sal_Size i=0; i<nLen; ++i )
1428         {
1429             const double nAlpha( rgbColor[i].Alpha );
1430             const BitmapColor aCol(toByteColor(rgbColor[i].Red / nAlpha),
1431                                    toByteColor(rgbColor[i].Green / nAlpha),
1432                                    toByteColor(rgbColor[i].Blue / nAlpha));
1433             const BitmapColor aCol2 =
1434                 m_bPalette ?
1435                 BitmapColor(
1436                     sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1437                 aCol;
1438 
1439             m_pBmpAcc->SetPixelOnData(pColors,0,aCol2);
1440             pColors   += nNonAlphaBytes;
1441             *pColors++ = 255 - toByteColor(nAlpha);
1442         }
1443     }
1444     else
1445     {
1446         for( sal_Size i=0; i<nLen; ++i )
1447         {
1448             const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1449                                    toByteColor(rgbColor[i].Green),
1450                                    toByteColor(rgbColor[i].Blue));
1451             const BitmapColor aCol2 =
1452                 m_bPalette ?
1453                 BitmapColor(
1454                     sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1455                 aCol;
1456 
1457             m_pBmpAcc->SetPixelOnData(pColors,i,aCol2);
1458         }
1459     }
1460 
1461     return aRes;
1462 }
1463 
1464 BitmapEx VclCanvasBitmap::getBitmapEx() const
1465 {
1466     return m_aBmpEx;
1467 }
1468