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