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