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()
443 {
444 vos::OGuard aGuard( Application::GetSolarMutex() );
445 return integerSize2DFromSize( m_aBitmap.GetSizePixel() );
446 }
447
hasAlpha()448 ::sal_Bool SAL_CALL VclCanvasBitmap::hasAlpha()
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 )
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 )
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
getPixel(rendering::IntegerBitmapLayout & bitmapLayout,const geometry::IntegerPoint2D & pos)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
getPalette()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
getMemoryLayout()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
getNumberOfEntries()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
getIndex(uno::Sequence<double> & o_entry,sal_Int32 nIndex)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
setIndex(const uno::Sequence<double> &,sal_Bool,sal_Int32 nIndex)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 {
operator ()__anon32d059b30211::PaletteColorSpaceHolder714 uno::Reference<rendering::XColorSpace> operator()()
715 {
716 return vcl::unotools::createStandardColorSpace();
717 }
718 };
719 }
720
getColorSpace()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
getType()728 sal_Int8 SAL_CALL VclCanvasBitmap::getType( )
729 {
730 return rendering::ColorSpaceType::RGB;
731 }
732
getComponentTags()733 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::getComponentTags( )
734 {
735 vos::OGuard aGuard( Application::GetSolarMutex() );
736 return m_aComponentTags;
737 }
738
getRenderingIntent()739 sal_Int8 SAL_CALL VclCanvasBitmap::getRenderingIntent( )
740 {
741 return rendering::RenderingIntent::PERCEPTUAL;
742 }
743
getProperties()744 uno::Sequence< ::beans::PropertyValue > SAL_CALL VclCanvasBitmap::getProperties( )
745 {
746 return uno::Sequence< ::beans::PropertyValue >();
747 }
748
convertColorSpace(const uno::Sequence<double> & deviceColor,const uno::Reference<::rendering::XColorSpace> & targetColorSpace)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
convertToRGB(const uno::Sequence<double> & deviceColor)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
convertToARGB(const uno::Sequence<double> & deviceColor)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
convertToPARGB(const uno::Sequence<double> & deviceColor)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
convertFromRGB(const uno::Sequence<rendering::RGBColor> & rgbColor)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
convertFromARGB(const uno::Sequence<rendering::ARGBColor> & rgbColor)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
convertFromPARGB(const uno::Sequence<rendering::ARGBColor> & rgbColor)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
getBitsPerPixel()1036 sal_Int32 SAL_CALL VclCanvasBitmap::getBitsPerPixel( )
1037 {
1038 vos::OGuard aGuard( Application::GetSolarMutex() );
1039 return m_nBitsPerOutputPixel;
1040 }
1041
getComponentBitCounts()1042 uno::Sequence< ::sal_Int32 > SAL_CALL VclCanvasBitmap::getComponentBitCounts( )
1043 {
1044 vos::OGuard aGuard( Application::GetSolarMutex() );
1045 return m_aComponentBitCounts;
1046 }
1047
getEndianness()1048 sal_Int8 SAL_CALL VclCanvasBitmap::getEndianness( )
1049 {
1050 vos::OGuard aGuard( Application::GetSolarMutex() );
1051 return m_nEndianness;
1052 }
1053
convertFromIntegerColorSpace(const uno::Sequence<::sal_Int8> & deviceColor,const uno::Reference<::rendering::XColorSpace> & targetColorSpace)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
convertToIntegerColorSpace(const uno::Sequence<::sal_Int8> & deviceColor,const uno::Reference<::rendering::XIntegerBitmapColorSpace> & targetColorSpace)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
convertIntegerToRGB(const uno::Sequence<::sal_Int8> & deviceColor)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
convertIntegerToARGB(const uno::Sequence<::sal_Int8> & deviceColor)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
convertIntegerToPARGB(const uno::Sequence<::sal_Int8> & deviceColor)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
convertIntegerFromRGB(const uno::Sequence<rendering::RGBColor> & rgbColor)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
convertIntegerFromARGB(const uno::Sequence<rendering::ARGBColor> & rgbColor)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
convertIntegerFromPARGB(const uno::Sequence<rendering::ARGBColor> & rgbColor)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
getBitmapEx() const1447 BitmapEx VclCanvasBitmap::getBitmapEx() const
1448 {
1449 return m_aBmpEx;
1450 }
1451