xref: /trunk/main/vcl/source/helper/canvasbitmap.cxx (revision 45c5a00162811bd03b87fcb4fe9996782f2b59ec)
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()
443 {
444     vos::OGuard aGuard( Application::GetSolarMutex() );
445     return integerSize2DFromSize( m_aBitmap.GetSizePixel() );
446 }
447 
448 ::sal_Bool SAL_CALL VclCanvasBitmap::hasAlpha()
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 )
456 {
457     vos::OGuard aGuard( Application::GetSolarMutex() );
458 
459     BitmapEx aNewBmp( m_aBitmap );
460     aNewBmp.Scale( sizeFromRealSize2D( newSize ), beFast ? BMP_SCALE_FASTESTINTERPOLATE : 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 )
467 {
468     vos::OGuard aGuard( Application::GetSolarMutex() );
469 
470     bitmapLayout = getMemoryLayout();
471 
472     const ::Rectangle aRequestedArea( vcl::unotools::rectangleFromIntegerRectangle2D(rect) );
473     if( aRequestedArea.IsEmpty() )
474         return uno::Sequence< sal_Int8 >();
475 
476     // Invalid/empty bitmap: no data available
477     if( !m_pBmpAcc )
478         throw lang::IndexOutOfBoundsException();
479     if( m_aBmpEx.IsTransparent() && !m_pAlphaAcc )
480         throw lang::IndexOutOfBoundsException();
481 
482     if( aRequestedArea.Left() < 0 || aRequestedArea.Top() < 0 ||
483         aRequestedArea.Right() > m_pBmpAcc->Width() ||
484         aRequestedArea.Bottom() > m_pBmpAcc->Height() )
485     {
486         throw lang::IndexOutOfBoundsException();
487     }
488 
489     uno::Sequence< sal_Int8 > aRet;
490     Rectangle aRequestedBytes( aRequestedArea );
491 
492     // adapt to byte boundaries
493     aRequestedBytes.Left()  = aRequestedArea.Left()*m_nBitsPerOutputPixel/8;
494     aRequestedBytes.Right() = (aRequestedArea.Right()*m_nBitsPerOutputPixel + 7)/8;
495 
496     // copy stuff to output sequence
497     aRet.realloc(aRequestedBytes.getWidth()*aRequestedBytes.getHeight());
498     sal_Int8* pOutBuf = aRet.getArray();
499 
500     bitmapLayout.ScanLines     = aRequestedBytes.getHeight();
501     bitmapLayout.ScanLineBytes =
502     bitmapLayout.ScanLineStride= aRequestedBytes.getWidth();
503 
504     sal_Int32 nScanlineStride=bitmapLayout.ScanLineStride;
505     if( !(m_pBmpAcc->GetScanlineFormat() & BMP_FORMAT_TOP_DOWN) )
506     {
507         pOutBuf += bitmapLayout.ScanLineStride*(aRequestedBytes.getHeight()-1);
508         nScanlineStride *= -1;
509     }
510 
511     if( !m_aBmpEx.IsTransparent() )
512     {
513         OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access");
514 
515         // can return bitmap data as-is
516         for( long y=aRequestedBytes.Top(); y<aRequestedBytes.Bottom(); ++y )
517         {
518             Scanline pScan = m_pBmpAcc->GetScanline(y);
519             rtl_copyMemory(pOutBuf, pScan+aRequestedBytes.Left(), aRequestedBytes.getWidth());
520             pOutBuf += nScanlineStride;
521         }
522     }
523     else
524     {
525         OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access");
526         OSL_ENSURE(m_pAlphaAcc,"Invalid alpha read access");
527 
528         // interleave alpha with bitmap data - note, bitcount is
529         // always integer multiple of 8
530         OSL_ENSURE((m_nBitsPerOutputPixel & 0x07) == 0,
531                    "Transparent bitmap bitcount not integer multiple of 8" );
532 
533         for( long y=aRequestedArea.Top(); y<aRequestedArea.Bottom(); ++y )
534         {
535             sal_Int8* pOutScan = pOutBuf;
536 
537             if( m_nBitsPerInputPixel < 8 )
538             {
539                 // input less than a byte - copy via GetPixel()
540                 for( long x=aRequestedArea.Left(); x<aRequestedArea.Right(); ++x )
541                 {
542                     *pOutScan++ = m_pBmpAcc->GetPixelIndex(y,x);
543                     *pOutScan++ = m_pAlphaAcc->GetPixelIndex(y,x);
544                 }
545             }
546             else
547             {
548                 const long nNonAlphaBytes( m_nBitsPerInputPixel/8 );
549                 const long nScanlineOffsetLeft(aRequestedArea.Left()*nNonAlphaBytes);
550                 Scanline  pScan = m_pBmpAcc->GetScanline(y) + nScanlineOffsetLeft;
551 
552                 // input integer multiple of byte - copy directly
553                 for( long x=aRequestedArea.Left(); x<aRequestedArea.Right(); ++x )
554                 {
555                     for( long i=0; i<nNonAlphaBytes; ++i )
556                         *pOutScan++ = *pScan++;
557                     *pOutScan++ = m_pAlphaAcc->GetPixelIndex( y, x );
558                 }
559             }
560 
561             pOutBuf += nScanlineStride;
562         }
563     }
564 
565     return aRet;
566 }
567 
568 uno::Sequence< sal_Int8 > SAL_CALL VclCanvasBitmap::getPixel( rendering::IntegerBitmapLayout&   bitmapLayout,
569                                                               const geometry::IntegerPoint2D&   pos )
570 {
571     vos::OGuard aGuard( Application::GetSolarMutex() );
572 
573     bitmapLayout = getMemoryLayout();
574 
575     // Invalid/empty bitmap: no data available
576     if( !m_pBmpAcc )
577         throw lang::IndexOutOfBoundsException();
578     if( m_aBmpEx.IsTransparent() && !m_pAlphaAcc )
579         throw lang::IndexOutOfBoundsException();
580 
581     if( pos.X < 0 || pos.Y < 0 ||
582         pos.X > m_pBmpAcc->Width() || pos.Y > m_pBmpAcc->Height() )
583     {
584         throw lang::IndexOutOfBoundsException();
585     }
586 
587     uno::Sequence< sal_Int8 > aRet((m_nBitsPerOutputPixel + 7)/8);
588     sal_Int8* pOutBuf = aRet.getArray();
589 
590     // copy stuff to output sequence
591     bitmapLayout.ScanLines     = 1;
592     bitmapLayout.ScanLineBytes =
593     bitmapLayout.ScanLineStride= aRet.getLength();
594 
595     const long nScanlineLeftOffset( pos.X*m_nBitsPerInputPixel/8 );
596     if( !m_aBmpEx.IsTransparent() )
597     {
598         OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access");
599 
600         // can return bitmap data as-is
601         Scanline pScan = m_pBmpAcc->GetScanline(pos.Y);
602         rtl_copyMemory(pOutBuf, pScan+nScanlineLeftOffset, aRet.getLength() );
603     }
604     else
605     {
606         OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access");
607         OSL_ENSURE(m_pAlphaAcc,"Invalid alpha read access");
608 
609         // interleave alpha with bitmap data - note, bitcount is
610         // always integer multiple of 8
611         OSL_ENSURE((m_nBitsPerOutputPixel & 0x07) == 0,
612                    "Transparent bitmap bitcount not integer multiple of 8" );
613 
614         if( m_nBitsPerInputPixel < 8 )
615         {
616             // input less than a byte - copy via GetPixel()
617             *pOutBuf++ = m_pBmpAcc->GetPixelIndex(pos.Y,pos.X);
618             *pOutBuf   = m_pAlphaAcc->GetPixelIndex(pos.Y,pos.X);
619         }
620         else
621         {
622             const long nNonAlphaBytes( m_nBitsPerInputPixel/8 );
623             Scanline  pScan = m_pBmpAcc->GetScanline(pos.Y);
624 
625             // input integer multiple of byte - copy directly
626             rtl_copyMemory(pOutBuf, pScan+nScanlineLeftOffset, nNonAlphaBytes );
627             pOutBuf += nNonAlphaBytes;
628             *pOutBuf++ = m_pAlphaAcc->GetPixelIndex(pos.Y,pos.X);
629         }
630     }
631 
632     return aRet;
633 }
634 
635 uno::Reference< rendering::XBitmapPalette > SAL_CALL VclCanvasBitmap::getPalette()
636 {
637     vos::OGuard aGuard( Application::GetSolarMutex() );
638 
639     uno::Reference< XBitmapPalette > aRet;
640     if( m_bPalette )
641         aRet.set(this);
642 
643     return aRet;
644 }
645 
646 rendering::IntegerBitmapLayout SAL_CALL VclCanvasBitmap::getMemoryLayout()
647 {
648     vos::OGuard aGuard( Application::GetSolarMutex() );
649 
650     rendering::IntegerBitmapLayout aLayout( m_aLayout );
651 
652     // only set references to self on separate copy of
653     // IntegerBitmapLayout - if we'd set that on m_aLayout, we'd have
654     // a circular reference!
655     if( m_bPalette )
656         aLayout.Palette.set( this );
657 
658     aLayout.ColorSpace.set( this );
659 
660     return aLayout;
661 }
662 
663 sal_Int32 SAL_CALL VclCanvasBitmap::getNumberOfEntries()
664 {
665     vos::OGuard aGuard( Application::GetSolarMutex() );
666 
667     if( !m_pBmpAcc )
668         return 0;
669 
670     return m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ;
671 }
672 
673 sal_Bool SAL_CALL VclCanvasBitmap::getIndex( uno::Sequence< double >& o_entry, sal_Int32 nIndex )
674 {
675     vos::OGuard aGuard( Application::GetSolarMutex() );
676 
677     const sal_uInt16 nCount( m_pBmpAcc ?
678                          (m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ) : 0 );
679     OSL_ENSURE(nIndex >= 0 && nIndex < nCount,"Palette index out of range");
680     if( nIndex < 0 || nIndex >= nCount )
681         throw lang::IndexOutOfBoundsException(::rtl::OUString::createFromAscii("Palette index out of range"),
682                                               static_cast<rendering::XBitmapPalette*>(this));
683 
684     const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(sal::static_int_cast<sal_uInt16>(nIndex));
685     o_entry.realloc(3);
686     double* pColor=o_entry.getArray();
687     pColor[0] = aCol.GetRed();
688     pColor[1] = aCol.GetGreen();
689     pColor[2] = aCol.GetBlue();
690 
691     return sal_True; // no palette transparency here.
692 }
693 
694 sal_Bool SAL_CALL VclCanvasBitmap::setIndex( const uno::Sequence< double >&, sal_Bool, sal_Int32 nIndex )
695 {
696     vos::OGuard aGuard( Application::GetSolarMutex() );
697 
698     const sal_uInt16 nCount( m_pBmpAcc ?
699                          (m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ) : 0 );
700 
701     OSL_ENSURE(nIndex >= 0 && nIndex < nCount,"Palette index out of range");
702     if( nIndex < 0 || nIndex >= nCount )
703         throw lang::IndexOutOfBoundsException(::rtl::OUString::createFromAscii("Palette index out of range"),
704                                               static_cast<rendering::XBitmapPalette*>(this));
705 
706     return sal_False; // read-only implementation
707 }
708 
709 namespace
710 {
711     struct PaletteColorSpaceHolder: public rtl::StaticWithInit<uno::Reference<rendering::XColorSpace>,
712                                                                PaletteColorSpaceHolder>
713     {
714         uno::Reference<rendering::XColorSpace> operator()()
715         {
716             return vcl::unotools::createStandardColorSpace();
717         }
718     };
719 }
720 
721 uno::Reference< rendering::XColorSpace > SAL_CALL VclCanvasBitmap::getColorSpace(  )
722 {
723     // this is the method from XBitmapPalette. Return palette color
724     // space here
725     return PaletteColorSpaceHolder::get();
726 }
727 
728 sal_Int8 SAL_CALL VclCanvasBitmap::getType(  )
729 {
730     return rendering::ColorSpaceType::RGB;
731 }
732 
733 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::getComponentTags(  )
734 {
735     vos::OGuard aGuard( Application::GetSolarMutex() );
736     return m_aComponentTags;
737 }
738 
739 sal_Int8 SAL_CALL VclCanvasBitmap::getRenderingIntent(  )
740 {
741     return rendering::RenderingIntent::PERCEPTUAL;
742 }
743 
744 uno::Sequence< ::beans::PropertyValue > SAL_CALL VclCanvasBitmap::getProperties(  )
745 {
746     return uno::Sequence< ::beans::PropertyValue >();
747 }
748 
749 uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertColorSpace( const uno::Sequence< double >& deviceColor,
750                                                                      const uno::Reference< ::rendering::XColorSpace >& targetColorSpace )
751 {
752     // TODO(P3): if we know anything about target
753     // colorspace, this can be greatly sped up
754     uno::Sequence<rendering::ARGBColor> aIntermediate(
755         convertToARGB(deviceColor));
756     return targetColorSpace->convertFromARGB(aIntermediate);
757 }
758 
759 uno::Sequence<rendering::RGBColor> SAL_CALL VclCanvasBitmap::convertToRGB( const uno::Sequence< double >& deviceColor )
760 {
761     vos::OGuard aGuard( Application::GetSolarMutex() );
762 
763     const sal_Size  nLen( deviceColor.getLength() );
764     const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
765     ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
766                          "number of channels no multiple of pixel element count",
767                          static_cast<rendering::XBitmapPalette*>(this), 01);
768 
769     uno::Sequence< rendering::RGBColor > aRes(nLen/nComponentsPerPixel);
770     rendering::RGBColor* pOut( aRes.getArray() );
771 
772     if( m_bPalette )
773     {
774         OSL_ENSURE(m_nIndexIndex != -1,
775                    "Invalid color channel indices");
776         ENSURE_OR_THROW(m_pBmpAcc,
777                         "Unable to get BitmapAccess");
778 
779         for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
780         {
781             const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
782                 sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex]));
783 
784             // TODO(F3): Convert result to sRGB color space
785             *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()),
786                                           toDoubleColor(aCol.GetGreen()),
787                                           toDoubleColor(aCol.GetBlue()));
788         }
789     }
790     else
791     {
792         OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
793                    "Invalid color channel indices");
794 
795         for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
796         {
797             // TODO(F3): Convert result to sRGB color space
798             *pOut++ = rendering::RGBColor(
799                 deviceColor[i+m_nRedIndex],
800                 deviceColor[i+m_nGreenIndex],
801                 deviceColor[i+m_nBlueIndex]);
802         }
803     }
804 
805     return aRes;
806 }
807 
808 uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertToARGB( const uno::Sequence< double >& deviceColor )
809 {
810     vos::OGuard aGuard( Application::GetSolarMutex() );
811 
812     const sal_Size  nLen( deviceColor.getLength() );
813     const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
814     ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
815                          "number of channels no multiple of pixel element count",
816                          static_cast<rendering::XBitmapPalette*>(this), 01);
817 
818     uno::Sequence< rendering::ARGBColor > aRes(nLen/nComponentsPerPixel);
819     rendering::ARGBColor* pOut( aRes.getArray() );
820 
821     if( m_bPalette )
822     {
823         OSL_ENSURE(m_nIndexIndex != -1,
824                    "Invalid color channel indices");
825         ENSURE_OR_THROW(m_pBmpAcc,
826                         "Unable to get BitmapAccess");
827 
828         for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
829         {
830             const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
831                 sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex]));
832 
833             // TODO(F3): Convert result to sRGB color space
834             const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
835             *pOut++ = rendering::ARGBColor(nAlpha,
836                                            toDoubleColor(aCol.GetRed()),
837                                            toDoubleColor(aCol.GetGreen()),
838                                            toDoubleColor(aCol.GetBlue()));
839         }
840     }
841     else
842     {
843         OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
844                    "Invalid color channel indices");
845 
846         for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
847         {
848             // TODO(F3): Convert result to sRGB color space
849             const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
850             *pOut++ = rendering::ARGBColor(
851                 nAlpha,
852                 deviceColor[i+m_nRedIndex],
853                 deviceColor[i+m_nGreenIndex],
854                 deviceColor[i+m_nBlueIndex]);
855         }
856     }
857 
858     return aRes;
859 }
860 
861 uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertToPARGB( const uno::Sequence< double >& deviceColor )
862 {
863     vos::OGuard aGuard( Application::GetSolarMutex() );
864 
865     const sal_Size  nLen( deviceColor.getLength() );
866     const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
867     ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
868                          "number of channels no multiple of pixel element count",
869                          static_cast<rendering::XBitmapPalette*>(this), 01);
870 
871     uno::Sequence< rendering::ARGBColor > aRes(nLen/nComponentsPerPixel);
872     rendering::ARGBColor* pOut( aRes.getArray() );
873 
874     if( m_bPalette )
875     {
876         OSL_ENSURE(m_nIndexIndex != -1,
877                    "Invalid color channel indices");
878         ENSURE_OR_THROW(m_pBmpAcc,
879                         "Unable to get BitmapAccess");
880 
881         for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
882         {
883             const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
884                 sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex]));
885 
886             // TODO(F3): Convert result to sRGB color space
887             const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
888             *pOut++ = rendering::ARGBColor(nAlpha,
889                                            nAlpha*toDoubleColor(aCol.GetRed()),
890                                            nAlpha*toDoubleColor(aCol.GetGreen()),
891                                            nAlpha*toDoubleColor(aCol.GetBlue()));
892         }
893     }
894     else
895     {
896         OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
897                    "Invalid color channel indices");
898 
899         for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
900         {
901             // TODO(F3): Convert result to sRGB color space
902             const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
903             *pOut++ = rendering::ARGBColor(
904                 nAlpha,
905                 nAlpha*deviceColor[i+m_nRedIndex],
906                 nAlpha*deviceColor[i+m_nGreenIndex],
907                 nAlpha*deviceColor[i+m_nBlueIndex]);
908         }
909     }
910 
911     return aRes;
912 }
913 
914 uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromRGB( const uno::Sequence<rendering::RGBColor>& rgbColor )
915 {
916     vos::OGuard aGuard( Application::GetSolarMutex() );
917 
918     const sal_Size  nLen( rgbColor.getLength() );
919     const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
920 
921     uno::Sequence< double > aRes(nLen*nComponentsPerPixel);
922     double* pColors=aRes.getArray();
923 
924     if( m_bPalette )
925     {
926         for( sal_Size i=0; i<nLen; ++i )
927         {
928             pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex(
929                     BitmapColor(toByteColor(rgbColor[i].Red),
930                                 toByteColor(rgbColor[i].Green),
931                                 toByteColor(rgbColor[i].Blue)));
932             if( m_nAlphaIndex != -1 )
933                 pColors[m_nAlphaIndex] = 1.0;
934 
935             pColors += nComponentsPerPixel;
936         }
937     }
938     else
939     {
940         for( sal_Size i=0; i<nLen; ++i )
941         {
942             pColors[m_nRedIndex]   = rgbColor[i].Red;
943             pColors[m_nGreenIndex] = rgbColor[i].Green;
944             pColors[m_nBlueIndex]  = rgbColor[i].Blue;
945             if( m_nAlphaIndex != -1 )
946                 pColors[m_nAlphaIndex] = 1.0;
947 
948             pColors += nComponentsPerPixel;
949         }
950     }
951     return aRes;
952 }
953 
954 uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor )
955 {
956     vos::OGuard aGuard( Application::GetSolarMutex() );
957 
958     const sal_Size  nLen( rgbColor.getLength() );
959     const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
960 
961     uno::Sequence< double > aRes(nLen*nComponentsPerPixel);
962     double* pColors=aRes.getArray();
963 
964     if( m_bPalette )
965     {
966         for( sal_Size i=0; i<nLen; ++i )
967         {
968             pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex(
969                     BitmapColor(toByteColor(rgbColor[i].Red),
970                                 toByteColor(rgbColor[i].Green),
971                                 toByteColor(rgbColor[i].Blue)));
972             if( m_nAlphaIndex != -1 )
973                 pColors[m_nAlphaIndex] = rgbColor[i].Alpha;
974 
975             pColors += nComponentsPerPixel;
976         }
977     }
978     else
979     {
980         for( sal_Size i=0; i<nLen; ++i )
981         {
982             pColors[m_nRedIndex]   = rgbColor[i].Red;
983             pColors[m_nGreenIndex] = rgbColor[i].Green;
984             pColors[m_nBlueIndex]  = rgbColor[i].Blue;
985             if( m_nAlphaIndex != -1 )
986                 pColors[m_nAlphaIndex] = rgbColor[i].Alpha;
987 
988             pColors += nComponentsPerPixel;
989         }
990     }
991     return aRes;
992 }
993 
994 uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromPARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor )
995 {
996     vos::OGuard aGuard( Application::GetSolarMutex() );
997 
998     const sal_Size  nLen( rgbColor.getLength() );
999     const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
1000 
1001     uno::Sequence< double > aRes(nLen*nComponentsPerPixel);
1002     double* pColors=aRes.getArray();
1003 
1004     if( m_bPalette )
1005     {
1006         for( sal_Size i=0; i<nLen; ++i )
1007         {
1008             const double nAlpha( rgbColor[i].Alpha );
1009             pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex(
1010                     BitmapColor(toByteColor(rgbColor[i].Red / nAlpha),
1011                                 toByteColor(rgbColor[i].Green / nAlpha),
1012                                 toByteColor(rgbColor[i].Blue / nAlpha)));
1013             if( m_nAlphaIndex != -1 )
1014                 pColors[m_nAlphaIndex] = nAlpha;
1015 
1016             pColors += nComponentsPerPixel;
1017         }
1018     }
1019     else
1020     {
1021         for( sal_Size i=0; i<nLen; ++i )
1022         {
1023             const double nAlpha( rgbColor[i].Alpha );
1024             pColors[m_nRedIndex]   = rgbColor[i].Red / nAlpha;
1025             pColors[m_nGreenIndex] = rgbColor[i].Green / nAlpha;
1026             pColors[m_nBlueIndex]  = rgbColor[i].Blue / nAlpha;
1027             if( m_nAlphaIndex != -1 )
1028                 pColors[m_nAlphaIndex] = nAlpha;
1029 
1030             pColors += nComponentsPerPixel;
1031         }
1032     }
1033     return aRes;
1034 }
1035 
1036 sal_Int32 SAL_CALL VclCanvasBitmap::getBitsPerPixel(  )
1037 {
1038     vos::OGuard aGuard( Application::GetSolarMutex() );
1039     return m_nBitsPerOutputPixel;
1040 }
1041 
1042 uno::Sequence< ::sal_Int32 > SAL_CALL VclCanvasBitmap::getComponentBitCounts(  )
1043 {
1044     vos::OGuard aGuard( Application::GetSolarMutex() );
1045     return m_aComponentBitCounts;
1046 }
1047 
1048 sal_Int8 SAL_CALL VclCanvasBitmap::getEndianness(  )
1049 {
1050     vos::OGuard aGuard( Application::GetSolarMutex() );
1051     return m_nEndianness;
1052 }
1053 
1054 uno::Sequence<double> SAL_CALL VclCanvasBitmap::convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
1055                                                                               const uno::Reference< ::rendering::XColorSpace >& targetColorSpace )
1056 {
1057     if( dynamic_cast<VclCanvasBitmap*>(targetColorSpace.get()) )
1058     {
1059         vos::OGuard aGuard( Application::GetSolarMutex() );
1060 
1061         const sal_Size  nLen( deviceColor.getLength() );
1062         const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
1063         ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
1064                              "number of channels no multiple of pixel element count",
1065                              static_cast<rendering::XBitmapPalette*>(this), 01);
1066 
1067         uno::Sequence<double> aRes(nLen);
1068         double* pOut( aRes.getArray() );
1069 
1070         if( m_bPalette )
1071         {
1072             OSL_ENSURE(m_nIndexIndex != -1,
1073                        "Invalid color channel indices");
1074             ENSURE_OR_THROW(m_pBmpAcc,
1075                             "Unable to get BitmapAccess");
1076 
1077             for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
1078             {
1079                 const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
1080                     sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex]));
1081 
1082                 // TODO(F3): Convert result to sRGB color space
1083                 const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
1084                 *pOut++ = toDoubleColor(aCol.GetRed());
1085                 *pOut++ = toDoubleColor(aCol.GetGreen());
1086                 *pOut++ = toDoubleColor(aCol.GetBlue());
1087                 *pOut++ = nAlpha;
1088             }
1089         }
1090         else
1091         {
1092             OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
1093                        "Invalid color channel indices");
1094 
1095             for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
1096             {
1097                 // TODO(F3): Convert result to sRGB color space
1098                 const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
1099                 *pOut++ = deviceColor[i+m_nRedIndex];
1100                 *pOut++ = deviceColor[i+m_nGreenIndex];
1101                 *pOut++ = deviceColor[i+m_nBlueIndex];
1102                 *pOut++ = nAlpha;
1103             }
1104         }
1105 
1106         return aRes;
1107     }
1108     else
1109     {
1110         // TODO(P3): if we know anything about target
1111         // colorspace, this can be greatly sped up
1112         uno::Sequence<rendering::ARGBColor> aIntermediate(
1113             convertIntegerToARGB(deviceColor));
1114         return targetColorSpace->convertFromARGB(aIntermediate);
1115     }
1116 }
1117 
1118 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
1119                                                                                   const uno::Reference< ::rendering::XIntegerBitmapColorSpace >& targetColorSpace )
1120 {
1121     if( dynamic_cast<VclCanvasBitmap*>(targetColorSpace.get()) )
1122     {
1123         // it's us, so simply pass-through the data
1124         return deviceColor;
1125     }
1126     else
1127     {
1128         // TODO(P3): if we know anything about target
1129         // colorspace, this can be greatly sped up
1130         uno::Sequence<rendering::ARGBColor> aIntermediate(
1131             convertIntegerToARGB(deviceColor));
1132         return targetColorSpace->convertIntegerFromARGB(aIntermediate);
1133     }
1134 }
1135 
1136 uno::Sequence<rendering::RGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor )
1137 {
1138     vos::OGuard aGuard( Application::GetSolarMutex() );
1139 
1140     const sal_uInt8*     pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) );
1141     const sal_Size  nLen( deviceColor.getLength() );
1142     const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel);
1143 
1144     uno::Sequence< rendering::RGBColor > aRes(nNumColors);
1145     rendering::RGBColor* pOut( aRes.getArray() );
1146 
1147     ENSURE_OR_THROW(m_pBmpAcc,
1148                     "Unable to get BitmapAccess");
1149 
1150     if( m_aBmpEx.IsTransparent() )
1151     {
1152         const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8);
1153         for( sal_Size i=0; i<nLen; i+=nBytesPerPixel )
1154         {
1155             // if palette, index is guaranteed to be 8 bit
1156             const BitmapColor aCol =
1157                 m_bPalette ?
1158                 m_pBmpAcc->GetPaletteColor(*pIn) :
1159                 m_pBmpAcc->GetPixelFromData(pIn,0);
1160 
1161             // TODO(F3): Convert result to sRGB color space
1162             *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()),
1163                                           toDoubleColor(aCol.GetGreen()),
1164                                           toDoubleColor(aCol.GetBlue()));
1165             // skips alpha
1166             pIn += nBytesPerPixel;
1167         }
1168     }
1169     else
1170     {
1171         for( sal_Int32 i=0; i<nNumColors; ++i )
1172         {
1173             const BitmapColor aCol =
1174                 m_bPalette ?
1175                 m_pBmpAcc->GetPaletteColor( m_pBmpAcc->GetPixelFromData( pIn, i ).GetIndex()) :
1176                 m_pBmpAcc->GetPixelFromData(pIn, i);
1177 
1178             // TODO(F3): Convert result to sRGB color space
1179             *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()),
1180                                           toDoubleColor(aCol.GetGreen()),
1181                                           toDoubleColor(aCol.GetBlue()));
1182         }
1183     }
1184 
1185     return aRes;
1186 }
1187 
1188 uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor )
1189 {
1190     vos::OGuard aGuard( Application::GetSolarMutex() );
1191 
1192     const sal_uInt8*     pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) );
1193     const sal_Size  nLen( deviceColor.getLength() );
1194     const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel);
1195 
1196     uno::Sequence< rendering::ARGBColor > aRes(nNumColors);
1197     rendering::ARGBColor* pOut( aRes.getArray() );
1198 
1199     ENSURE_OR_THROW(m_pBmpAcc,
1200                     "Unable to get BitmapAccess");
1201 
1202     if( m_aBmpEx.IsTransparent() )
1203     {
1204         const long      nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
1205         const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8);
1206         const sal_uInt8 nAlphaFactor( m_aBmpEx.IsAlpha() ? 1 : 255 );
1207         for( sal_Size i=0; i<nLen; i+=nBytesPerPixel )
1208         {
1209             // if palette, index is guaranteed to be 8 bit
1210             const BitmapColor aCol =
1211                 m_bPalette ?
1212                 m_pBmpAcc->GetPaletteColor(*pIn) :
1213                 m_pBmpAcc->GetPixelFromData(pIn,0);
1214 
1215             // TODO(F3): Convert result to sRGB color space
1216             *pOut++ = rendering::ARGBColor(1.0 - toDoubleColor(nAlphaFactor*pIn[nNonAlphaBytes]),
1217                                            toDoubleColor(aCol.GetRed()),
1218                                            toDoubleColor(aCol.GetGreen()),
1219                                            toDoubleColor(aCol.GetBlue()));
1220             pIn += nBytesPerPixel;
1221         }
1222     }
1223     else
1224     {
1225         for( sal_Int32 i=0; i<nNumColors; ++i )
1226         {
1227             const BitmapColor aCol =
1228                 m_bPalette ?
1229                 m_pBmpAcc->GetPaletteColor( m_pBmpAcc->GetPixelFromData( pIn, i ).GetIndex() ) :
1230                 m_pBmpAcc->GetPixelFromData(pIn, i);
1231 
1232             // TODO(F3): Convert result to sRGB color space
1233             *pOut++ = rendering::ARGBColor(1.0,
1234                                            toDoubleColor(aCol.GetRed()),
1235                                            toDoubleColor(aCol.GetGreen()),
1236                                            toDoubleColor(aCol.GetBlue()));
1237         }
1238     }
1239 
1240     return aRes;
1241 }
1242 
1243 uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor )
1244 {
1245     vos::OGuard aGuard( Application::GetSolarMutex() );
1246 
1247     const sal_uInt8*     pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) );
1248     const sal_Size  nLen( deviceColor.getLength() );
1249     const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel);
1250 
1251     uno::Sequence< rendering::ARGBColor > aRes(nNumColors);
1252     rendering::ARGBColor* pOut( aRes.getArray() );
1253 
1254     ENSURE_OR_THROW(m_pBmpAcc,
1255                     "Unable to get BitmapAccess");
1256 
1257     if( m_aBmpEx.IsTransparent() )
1258     {
1259         const long      nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
1260         const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8);
1261         const sal_uInt8 nAlphaFactor( m_aBmpEx.IsAlpha() ? 1 : 255 );
1262         for( sal_Size i=0; i<nLen; i+=nBytesPerPixel )
1263         {
1264             // if palette, index is guaranteed to be 8 bit
1265             const BitmapColor aCol =
1266                 m_bPalette ?
1267                 m_pBmpAcc->GetPaletteColor(*pIn) :
1268                 m_pBmpAcc->GetPixelFromData(pIn,0);
1269 
1270             // TODO(F3): Convert result to sRGB color space
1271             const double nAlpha( 1.0 - toDoubleColor(nAlphaFactor*pIn[nNonAlphaBytes]) );
1272             *pOut++ = rendering::ARGBColor(nAlpha,
1273                                            nAlpha*toDoubleColor(aCol.GetRed()),
1274                                            nAlpha*toDoubleColor(aCol.GetGreen()),
1275                                            nAlpha*toDoubleColor(aCol.GetBlue()));
1276             pIn += nBytesPerPixel;
1277         }
1278     }
1279     else
1280     {
1281         for( sal_Int32 i=0; i<nNumColors; ++i )
1282         {
1283             const BitmapColor aCol =
1284                 m_bPalette ?
1285                 m_pBmpAcc->GetPaletteColor( m_pBmpAcc->GetPixelFromData( pIn, i ).GetIndex() ) :
1286                 m_pBmpAcc->GetPixelFromData(pIn, i);
1287 
1288             // TODO(F3): Convert result to sRGB color space
1289             *pOut++ = rendering::ARGBColor(1.0,
1290                                            toDoubleColor(aCol.GetRed()),
1291                                            toDoubleColor(aCol.GetGreen()),
1292                                            toDoubleColor(aCol.GetBlue()));
1293         }
1294     }
1295 
1296     return aRes;
1297 }
1298 
1299 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromRGB( const uno::Sequence<rendering::RGBColor>& rgbColor )
1300 {
1301     vos::OGuard aGuard( Application::GetSolarMutex() );
1302 
1303     const sal_Size  nLen( rgbColor.getLength() );
1304     const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8);
1305 
1306     uno::Sequence< sal_Int8 > aRes(nNumBytes);
1307     sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray());
1308 
1309     if( m_aBmpEx.IsTransparent() )
1310     {
1311         const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
1312         for( sal_Size i=0; i<nLen; ++i )
1313         {
1314             const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1315                                    toByteColor(rgbColor[i].Green),
1316                                    toByteColor(rgbColor[i].Blue));
1317             const BitmapColor aCol2 =
1318                 m_bPalette ?
1319                 BitmapColor(
1320                     sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1321                 aCol;
1322 
1323             m_pBmpAcc->SetPixelOnData(pColors,0,aCol2);
1324             pColors   += nNonAlphaBytes;
1325             *pColors++ = sal_uInt8(255);
1326         }
1327     }
1328     else
1329     {
1330         for( sal_Size i=0; i<nLen; ++i )
1331         {
1332             const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1333                                    toByteColor(rgbColor[i].Green),
1334                                    toByteColor(rgbColor[i].Blue));
1335             const BitmapColor aCol2 =
1336                 m_bPalette ?
1337                 BitmapColor(
1338                     sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1339                 aCol;
1340 
1341             m_pBmpAcc->SetPixelOnData(pColors,i,aCol2);
1342         }
1343     }
1344 
1345     return aRes;
1346 }
1347 
1348 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor )
1349 {
1350     vos::OGuard aGuard( Application::GetSolarMutex() );
1351 
1352     const sal_Size  nLen( rgbColor.getLength() );
1353     const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8);
1354 
1355     uno::Sequence< sal_Int8 > aRes(nNumBytes);
1356     sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray());
1357 
1358     if( m_aBmpEx.IsTransparent() )
1359     {
1360         const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
1361         for( sal_Size i=0; i<nLen; ++i )
1362         {
1363             const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1364                                    toByteColor(rgbColor[i].Green),
1365                                    toByteColor(rgbColor[i].Blue));
1366             const BitmapColor aCol2 =
1367                 m_bPalette ?
1368                 BitmapColor(
1369                     sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1370                 aCol;
1371 
1372             m_pBmpAcc->SetPixelOnData(pColors,0,aCol2);
1373             pColors   += nNonAlphaBytes;
1374             *pColors++ = 255 - toByteColor(rgbColor[i].Alpha);
1375         }
1376     }
1377     else
1378     {
1379         for( sal_Size i=0; i<nLen; ++i )
1380         {
1381             const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1382                                    toByteColor(rgbColor[i].Green),
1383                                    toByteColor(rgbColor[i].Blue));
1384             const BitmapColor aCol2 =
1385                 m_bPalette ?
1386                 BitmapColor(
1387                     sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1388                 aCol;
1389 
1390             m_pBmpAcc->SetPixelOnData(pColors,i,aCol2);
1391         }
1392     }
1393 
1394     return aRes;
1395 }
1396 
1397 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromPARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor )
1398 {
1399     vos::OGuard aGuard( Application::GetSolarMutex() );
1400 
1401     const sal_Size  nLen( rgbColor.getLength() );
1402     const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8);
1403 
1404     uno::Sequence< sal_Int8 > aRes(nNumBytes);
1405     sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray());
1406 
1407     if( m_aBmpEx.IsTransparent() )
1408     {
1409         const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
1410         for( sal_Size i=0; i<nLen; ++i )
1411         {
1412             const double nAlpha( rgbColor[i].Alpha );
1413             const BitmapColor aCol(toByteColor(rgbColor[i].Red / nAlpha),
1414                                    toByteColor(rgbColor[i].Green / nAlpha),
1415                                    toByteColor(rgbColor[i].Blue / nAlpha));
1416             const BitmapColor aCol2 =
1417                 m_bPalette ?
1418                 BitmapColor(
1419                     sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1420                 aCol;
1421 
1422             m_pBmpAcc->SetPixelOnData(pColors,0,aCol2);
1423             pColors   += nNonAlphaBytes;
1424             *pColors++ = 255 - toByteColor(nAlpha);
1425         }
1426     }
1427     else
1428     {
1429         for( sal_Size i=0; i<nLen; ++i )
1430         {
1431             const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1432                                    toByteColor(rgbColor[i].Green),
1433                                    toByteColor(rgbColor[i].Blue));
1434             const BitmapColor aCol2 =
1435                 m_bPalette ?
1436                 BitmapColor(
1437                     sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1438                 aCol;
1439 
1440             m_pBmpAcc->SetPixelOnData(pColors,i,aCol2);
1441         }
1442     }
1443 
1444     return aRes;
1445 }
1446 
1447 BitmapEx VclCanvasBitmap::getBitmapEx() const
1448 {
1449     return m_aBmpEx;
1450 }
1451