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