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
bitcount(sal_uInt32 val)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
setComponentInfo(sal_uLong redShift,sal_uLong greenShift,sal_uLong blueShift)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
VclCanvasBitmap(const BitmapEx & rBitmap)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
~VclCanvasBitmap()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
getSize()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
hasAlpha()448 ::sal_Bool SAL_CALL VclCanvasBitmap::hasAlpha() throw (uno::RuntimeException)
449 {
450 vos::OGuard aGuard( Application::GetSolarMutex() );
451 return m_aBmpEx.IsTransparent();
452 }
453
getScaledBitmap(const geometry::RealSize2D & newSize,sal_Bool beFast)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_FASTESTINTERPOLATE : BMP_SCALE_INTERPOLATE );
461 return uno::Reference<rendering::XBitmap>( new VclCanvasBitmap( aNewBmp ) );
462 }
463
464 // XIntegerReadOnlyBitmap
getData(rendering::IntegerBitmapLayout & bitmapLayout,const geometry::IntegerRectangle2D & rect)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->GetPixelIndex(y,x);
545 *pOutScan++ = m_pAlphaAcc->GetPixelIndex(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->GetPixelIndex( y, x );
560 }
561 }
562
563 pOutBuf += nScanlineStride;
564 }
565 }
566
567 return aRet;
568 }
569
getPixel(rendering::IntegerBitmapLayout & bitmapLayout,const geometry::IntegerPoint2D & pos)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->GetPixelIndex(pos.Y,pos.X);
622 *pOutBuf = m_pAlphaAcc->GetPixelIndex(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->GetPixelIndex(pos.Y,pos.X);
633 }
634 }
635
636 return aRet;
637 }
638
getPalette()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
getMemoryLayout()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
getNumberOfEntries()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
getIndex(uno::Sequence<double> & o_entry,sal_Int32 nIndex)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
setIndex(const uno::Sequence<double> &,sal_Bool,sal_Int32 nIndex)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 {
operator ()__anonc5bfbaf40211::PaletteColorSpaceHolder718 uno::Reference<rendering::XColorSpace> operator()()
719 {
720 return vcl::unotools::createStandardColorSpace();
721 }
722 };
723 }
724
getColorSpace()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
getType()732 sal_Int8 SAL_CALL VclCanvasBitmap::getType( ) throw (uno::RuntimeException)
733 {
734 return rendering::ColorSpaceType::RGB;
735 }
736
getComponentTags()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
getRenderingIntent()743 sal_Int8 SAL_CALL VclCanvasBitmap::getRenderingIntent( ) throw (uno::RuntimeException)
744 {
745 return rendering::RenderingIntent::PERCEPTUAL;
746 }
747
getProperties()748 uno::Sequence< ::beans::PropertyValue > SAL_CALL VclCanvasBitmap::getProperties( ) throw (uno::RuntimeException)
749 {
750 return uno::Sequence< ::beans::PropertyValue >();
751 }
752
convertColorSpace(const uno::Sequence<double> & deviceColor,const uno::Reference<::rendering::XColorSpace> & targetColorSpace)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
convertToRGB(const uno::Sequence<double> & deviceColor)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
convertToARGB(const uno::Sequence<double> & deviceColor)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
convertToPARGB(const uno::Sequence<double> & deviceColor)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
convertFromRGB(const uno::Sequence<rendering::RGBColor> & rgbColor)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
convertFromARGB(const uno::Sequence<rendering::ARGBColor> & rgbColor)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
convertFromPARGB(const uno::Sequence<rendering::ARGBColor> & rgbColor)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
getBitsPerPixel()1040 sal_Int32 SAL_CALL VclCanvasBitmap::getBitsPerPixel( ) throw (uno::RuntimeException)
1041 {
1042 vos::OGuard aGuard( Application::GetSolarMutex() );
1043 return m_nBitsPerOutputPixel;
1044 }
1045
getComponentBitCounts()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
getEndianness()1052 sal_Int8 SAL_CALL VclCanvasBitmap::getEndianness( ) throw (uno::RuntimeException)
1053 {
1054 vos::OGuard aGuard( Application::GetSolarMutex() );
1055 return m_nEndianness;
1056 }
1057
convertFromIntegerColorSpace(const uno::Sequence<::sal_Int8> & deviceColor,const uno::Reference<::rendering::XColorSpace> & targetColorSpace)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
convertToIntegerColorSpace(const uno::Sequence<::sal_Int8> & deviceColor,const uno::Reference<::rendering::XIntegerBitmapColorSpace> & targetColorSpace)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
convertIntegerToRGB(const uno::Sequence<::sal_Int8> & deviceColor)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( m_pBmpAcc->GetPixelFromData( pIn, i ).GetIndex()) :
1180 m_pBmpAcc->GetPixelFromData(pIn, i);
1181
1182 // TODO(F3): Convert result to sRGB color space
1183 *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()),
1184 toDoubleColor(aCol.GetGreen()),
1185 toDoubleColor(aCol.GetBlue()));
1186 }
1187 }
1188
1189 return aRes;
1190 }
1191
convertIntegerToARGB(const uno::Sequence<::sal_Int8> & deviceColor)1192 uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
1193 {
1194 vos::OGuard aGuard( Application::GetSolarMutex() );
1195
1196 const sal_uInt8* pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) );
1197 const sal_Size nLen( deviceColor.getLength() );
1198 const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel);
1199
1200 uno::Sequence< rendering::ARGBColor > aRes(nNumColors);
1201 rendering::ARGBColor* pOut( aRes.getArray() );
1202
1203 ENSURE_OR_THROW(m_pBmpAcc,
1204 "Unable to get BitmapAccess");
1205
1206 if( m_aBmpEx.IsTransparent() )
1207 {
1208 const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
1209 const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8);
1210 const sal_uInt8 nAlphaFactor( m_aBmpEx.IsAlpha() ? 1 : 255 );
1211 for( sal_Size i=0; i<nLen; i+=nBytesPerPixel )
1212 {
1213 // if palette, index is guaranteed to be 8 bit
1214 const BitmapColor aCol =
1215 m_bPalette ?
1216 m_pBmpAcc->GetPaletteColor(*pIn) :
1217 m_pBmpAcc->GetPixelFromData(pIn,0);
1218
1219 // TODO(F3): Convert result to sRGB color space
1220 *pOut++ = rendering::ARGBColor(1.0 - toDoubleColor(nAlphaFactor*pIn[nNonAlphaBytes]),
1221 toDoubleColor(aCol.GetRed()),
1222 toDoubleColor(aCol.GetGreen()),
1223 toDoubleColor(aCol.GetBlue()));
1224 pIn += nBytesPerPixel;
1225 }
1226 }
1227 else
1228 {
1229 for( sal_Int32 i=0; i<nNumColors; ++i )
1230 {
1231 const BitmapColor aCol =
1232 m_bPalette ?
1233 m_pBmpAcc->GetPaletteColor( m_pBmpAcc->GetPixelFromData( pIn, i ).GetIndex() ) :
1234 m_pBmpAcc->GetPixelFromData(pIn, i);
1235
1236 // TODO(F3): Convert result to sRGB color space
1237 *pOut++ = rendering::ARGBColor(1.0,
1238 toDoubleColor(aCol.GetRed()),
1239 toDoubleColor(aCol.GetGreen()),
1240 toDoubleColor(aCol.GetBlue()));
1241 }
1242 }
1243
1244 return aRes;
1245 }
1246
convertIntegerToPARGB(const uno::Sequence<::sal_Int8> & deviceColor)1247 uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
1248 {
1249 vos::OGuard aGuard( Application::GetSolarMutex() );
1250
1251 const sal_uInt8* pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) );
1252 const sal_Size nLen( deviceColor.getLength() );
1253 const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel);
1254
1255 uno::Sequence< rendering::ARGBColor > aRes(nNumColors);
1256 rendering::ARGBColor* pOut( aRes.getArray() );
1257
1258 ENSURE_OR_THROW(m_pBmpAcc,
1259 "Unable to get BitmapAccess");
1260
1261 if( m_aBmpEx.IsTransparent() )
1262 {
1263 const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
1264 const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8);
1265 const sal_uInt8 nAlphaFactor( m_aBmpEx.IsAlpha() ? 1 : 255 );
1266 for( sal_Size i=0; i<nLen; i+=nBytesPerPixel )
1267 {
1268 // if palette, index is guaranteed to be 8 bit
1269 const BitmapColor aCol =
1270 m_bPalette ?
1271 m_pBmpAcc->GetPaletteColor(*pIn) :
1272 m_pBmpAcc->GetPixelFromData(pIn,0);
1273
1274 // TODO(F3): Convert result to sRGB color space
1275 const double nAlpha( 1.0 - toDoubleColor(nAlphaFactor*pIn[nNonAlphaBytes]) );
1276 *pOut++ = rendering::ARGBColor(nAlpha,
1277 nAlpha*toDoubleColor(aCol.GetRed()),
1278 nAlpha*toDoubleColor(aCol.GetGreen()),
1279 nAlpha*toDoubleColor(aCol.GetBlue()));
1280 pIn += nBytesPerPixel;
1281 }
1282 }
1283 else
1284 {
1285 for( sal_Int32 i=0; i<nNumColors; ++i )
1286 {
1287 const BitmapColor aCol =
1288 m_bPalette ?
1289 m_pBmpAcc->GetPaletteColor( m_pBmpAcc->GetPixelFromData( pIn, i ).GetIndex() ) :
1290 m_pBmpAcc->GetPixelFromData(pIn, i);
1291
1292 // TODO(F3): Convert result to sRGB color space
1293 *pOut++ = rendering::ARGBColor(1.0,
1294 toDoubleColor(aCol.GetRed()),
1295 toDoubleColor(aCol.GetGreen()),
1296 toDoubleColor(aCol.GetBlue()));
1297 }
1298 }
1299
1300 return aRes;
1301 }
1302
convertIntegerFromRGB(const uno::Sequence<rendering::RGBColor> & rgbColor)1303 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromRGB( const uno::Sequence<rendering::RGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
1304 {
1305 vos::OGuard aGuard( Application::GetSolarMutex() );
1306
1307 const sal_Size nLen( rgbColor.getLength() );
1308 const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8);
1309
1310 uno::Sequence< sal_Int8 > aRes(nNumBytes);
1311 sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray());
1312
1313 if( m_aBmpEx.IsTransparent() )
1314 {
1315 const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
1316 for( sal_Size i=0; i<nLen; ++i )
1317 {
1318 const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1319 toByteColor(rgbColor[i].Green),
1320 toByteColor(rgbColor[i].Blue));
1321 const BitmapColor aCol2 =
1322 m_bPalette ?
1323 BitmapColor(
1324 sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1325 aCol;
1326
1327 m_pBmpAcc->SetPixelOnData(pColors,0,aCol2);
1328 pColors += nNonAlphaBytes;
1329 *pColors++ = sal_uInt8(255);
1330 }
1331 }
1332 else
1333 {
1334 for( sal_Size i=0; i<nLen; ++i )
1335 {
1336 const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1337 toByteColor(rgbColor[i].Green),
1338 toByteColor(rgbColor[i].Blue));
1339 const BitmapColor aCol2 =
1340 m_bPalette ?
1341 BitmapColor(
1342 sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1343 aCol;
1344
1345 m_pBmpAcc->SetPixelOnData(pColors,i,aCol2);
1346 }
1347 }
1348
1349 return aRes;
1350 }
1351
convertIntegerFromARGB(const uno::Sequence<rendering::ARGBColor> & rgbColor)1352 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
1353 {
1354 vos::OGuard aGuard( Application::GetSolarMutex() );
1355
1356 const sal_Size nLen( rgbColor.getLength() );
1357 const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8);
1358
1359 uno::Sequence< sal_Int8 > aRes(nNumBytes);
1360 sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray());
1361
1362 if( m_aBmpEx.IsTransparent() )
1363 {
1364 const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
1365 for( sal_Size i=0; i<nLen; ++i )
1366 {
1367 const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1368 toByteColor(rgbColor[i].Green),
1369 toByteColor(rgbColor[i].Blue));
1370 const BitmapColor aCol2 =
1371 m_bPalette ?
1372 BitmapColor(
1373 sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1374 aCol;
1375
1376 m_pBmpAcc->SetPixelOnData(pColors,0,aCol2);
1377 pColors += nNonAlphaBytes;
1378 *pColors++ = 255 - toByteColor(rgbColor[i].Alpha);
1379 }
1380 }
1381 else
1382 {
1383 for( sal_Size i=0; i<nLen; ++i )
1384 {
1385 const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1386 toByteColor(rgbColor[i].Green),
1387 toByteColor(rgbColor[i].Blue));
1388 const BitmapColor aCol2 =
1389 m_bPalette ?
1390 BitmapColor(
1391 sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1392 aCol;
1393
1394 m_pBmpAcc->SetPixelOnData(pColors,i,aCol2);
1395 }
1396 }
1397
1398 return aRes;
1399 }
1400
convertIntegerFromPARGB(const uno::Sequence<rendering::ARGBColor> & rgbColor)1401 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromPARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
1402 {
1403 vos::OGuard aGuard( Application::GetSolarMutex() );
1404
1405 const sal_Size nLen( rgbColor.getLength() );
1406 const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8);
1407
1408 uno::Sequence< sal_Int8 > aRes(nNumBytes);
1409 sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray());
1410
1411 if( m_aBmpEx.IsTransparent() )
1412 {
1413 const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
1414 for( sal_Size i=0; i<nLen; ++i )
1415 {
1416 const double nAlpha( rgbColor[i].Alpha );
1417 const BitmapColor aCol(toByteColor(rgbColor[i].Red / nAlpha),
1418 toByteColor(rgbColor[i].Green / nAlpha),
1419 toByteColor(rgbColor[i].Blue / nAlpha));
1420 const BitmapColor aCol2 =
1421 m_bPalette ?
1422 BitmapColor(
1423 sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1424 aCol;
1425
1426 m_pBmpAcc->SetPixelOnData(pColors,0,aCol2);
1427 pColors += nNonAlphaBytes;
1428 *pColors++ = 255 - toByteColor(nAlpha);
1429 }
1430 }
1431 else
1432 {
1433 for( sal_Size i=0; i<nLen; ++i )
1434 {
1435 const BitmapColor aCol(toByteColor(rgbColor[i].Red),
1436 toByteColor(rgbColor[i].Green),
1437 toByteColor(rgbColor[i].Blue));
1438 const BitmapColor aCol2 =
1439 m_bPalette ?
1440 BitmapColor(
1441 sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
1442 aCol;
1443
1444 m_pBmpAcc->SetPixelOnData(pColors,i,aCol2);
1445 }
1446 }
1447
1448 return aRes;
1449 }
1450
getBitmapEx() const1451 BitmapEx VclCanvasBitmap::getBitmapEx() const
1452 {
1453 return m_aBmpEx;
1454 }
1455