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