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() throw (uno::RuntimeException) 443 { 444 vos::OGuard aGuard( Application::GetSolarMutex() ); 445 return integerSize2DFromSize( m_aBitmap.GetSizePixel() ); 446 } 447 448 ::sal_Bool SAL_CALL VclCanvasBitmap::hasAlpha() throw (uno::RuntimeException) 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 ) throw (uno::RuntimeException) 456 { 457 vos::OGuard aGuard( Application::GetSolarMutex() ); 458 459 BitmapEx aNewBmp( m_aBitmap ); 460 aNewBmp.Scale( sizeFromRealSize2D( newSize ), beFast ? BMP_SCALE_FAST : 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 ) throw( lang::IndexOutOfBoundsException, 467 rendering::VolatileContentDestroyedException, 468 uno::RuntimeException) 469 { 470 vos::OGuard aGuard( Application::GetSolarMutex() ); 471 472 bitmapLayout = getMemoryLayout(); 473 474 const ::Rectangle aRequestedArea( vcl::unotools::rectangleFromIntegerRectangle2D(rect) ); 475 if( aRequestedArea.IsEmpty() ) 476 return uno::Sequence< sal_Int8 >(); 477 478 // Invalid/empty bitmap: no data available 479 if( !m_pBmpAcc ) 480 throw lang::IndexOutOfBoundsException(); 481 if( m_aBmpEx.IsTransparent() && !m_pAlphaAcc ) 482 throw lang::IndexOutOfBoundsException(); 483 484 if( aRequestedArea.Left() < 0 || aRequestedArea.Top() < 0 || 485 aRequestedArea.Right() > m_pBmpAcc->Width() || 486 aRequestedArea.Bottom() > m_pBmpAcc->Height() ) 487 { 488 throw lang::IndexOutOfBoundsException(); 489 } 490 491 uno::Sequence< sal_Int8 > aRet; 492 Rectangle aRequestedBytes( aRequestedArea ); 493 494 // adapt to byte boundaries 495 aRequestedBytes.Left() = aRequestedArea.Left()*m_nBitsPerOutputPixel/8; 496 aRequestedBytes.Right() = (aRequestedArea.Right()*m_nBitsPerOutputPixel + 7)/8; 497 498 // copy stuff to output sequence 499 aRet.realloc(aRequestedBytes.getWidth()*aRequestedBytes.getHeight()); 500 sal_Int8* pOutBuf = aRet.getArray(); 501 502 bitmapLayout.ScanLines = aRequestedBytes.getHeight(); 503 bitmapLayout.ScanLineBytes = 504 bitmapLayout.ScanLineStride= aRequestedBytes.getWidth(); 505 506 sal_Int32 nScanlineStride=bitmapLayout.ScanLineStride; 507 if( !(m_pBmpAcc->GetScanlineFormat() & BMP_FORMAT_TOP_DOWN) ) 508 { 509 pOutBuf += bitmapLayout.ScanLineStride*(aRequestedBytes.getHeight()-1); 510 nScanlineStride *= -1; 511 } 512 513 if( !m_aBmpEx.IsTransparent() ) 514 { 515 OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access"); 516 517 // can return bitmap data as-is 518 for( long y=aRequestedBytes.Top(); y<aRequestedBytes.Bottom(); ++y ) 519 { 520 Scanline pScan = m_pBmpAcc->GetScanline(y); 521 rtl_copyMemory(pOutBuf, pScan+aRequestedBytes.Left(), aRequestedBytes.getWidth()); 522 pOutBuf += nScanlineStride; 523 } 524 } 525 else 526 { 527 OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access"); 528 OSL_ENSURE(m_pAlphaAcc,"Invalid alpha read access"); 529 530 // interleave alpha with bitmap data - note, bitcount is 531 // always integer multiple of 8 532 OSL_ENSURE((m_nBitsPerOutputPixel & 0x07) == 0, 533 "Transparent bitmap bitcount not integer multiple of 8" ); 534 535 for( long y=aRequestedArea.Top(); y<aRequestedArea.Bottom(); ++y ) 536 { 537 sal_Int8* pOutScan = pOutBuf; 538 539 if( m_nBitsPerInputPixel < 8 ) 540 { 541 // input less than a byte - copy via GetPixel() 542 for( long x=aRequestedArea.Left(); x<aRequestedArea.Right(); ++x ) 543 { 544 *pOutScan++ = m_pBmpAcc->GetPixel(y,x); 545 *pOutScan++ = m_pAlphaAcc->GetPixel(y,x); 546 } 547 } 548 else 549 { 550 const long nNonAlphaBytes( m_nBitsPerInputPixel/8 ); 551 const long nScanlineOffsetLeft(aRequestedArea.Left()*nNonAlphaBytes); 552 Scanline pScan = m_pBmpAcc->GetScanline(y) + nScanlineOffsetLeft; 553 554 // input integer multiple of byte - copy directly 555 for( long x=aRequestedArea.Left(); x<aRequestedArea.Right(); ++x ) 556 { 557 for( long i=0; i<nNonAlphaBytes; ++i ) 558 *pOutScan++ = *pScan++; 559 *pOutScan++ = m_pAlphaAcc->GetPixel(y,x); 560 } 561 } 562 563 pOutBuf += nScanlineStride; 564 } 565 } 566 567 return aRet; 568 } 569 570 uno::Sequence< sal_Int8 > SAL_CALL VclCanvasBitmap::getPixel( rendering::IntegerBitmapLayout& bitmapLayout, 571 const geometry::IntegerPoint2D& pos ) throw (lang::IndexOutOfBoundsException, 572 rendering::VolatileContentDestroyedException, 573 uno::RuntimeException) 574 { 575 vos::OGuard aGuard( Application::GetSolarMutex() ); 576 577 bitmapLayout = getMemoryLayout(); 578 579 // Invalid/empty bitmap: no data available 580 if( !m_pBmpAcc ) 581 throw lang::IndexOutOfBoundsException(); 582 if( m_aBmpEx.IsTransparent() && !m_pAlphaAcc ) 583 throw lang::IndexOutOfBoundsException(); 584 585 if( pos.X < 0 || pos.Y < 0 || 586 pos.X > m_pBmpAcc->Width() || pos.Y > m_pBmpAcc->Height() ) 587 { 588 throw lang::IndexOutOfBoundsException(); 589 } 590 591 uno::Sequence< sal_Int8 > aRet((m_nBitsPerOutputPixel + 7)/8); 592 sal_Int8* pOutBuf = aRet.getArray(); 593 594 // copy stuff to output sequence 595 bitmapLayout.ScanLines = 1; 596 bitmapLayout.ScanLineBytes = 597 bitmapLayout.ScanLineStride= aRet.getLength(); 598 599 const long nScanlineLeftOffset( pos.X*m_nBitsPerInputPixel/8 ); 600 if( !m_aBmpEx.IsTransparent() ) 601 { 602 OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access"); 603 604 // can return bitmap data as-is 605 Scanline pScan = m_pBmpAcc->GetScanline(pos.Y); 606 rtl_copyMemory(pOutBuf, pScan+nScanlineLeftOffset, aRet.getLength() ); 607 } 608 else 609 { 610 OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access"); 611 OSL_ENSURE(m_pAlphaAcc,"Invalid alpha read access"); 612 613 // interleave alpha with bitmap data - note, bitcount is 614 // always integer multiple of 8 615 OSL_ENSURE((m_nBitsPerOutputPixel & 0x07) == 0, 616 "Transparent bitmap bitcount not integer multiple of 8" ); 617 618 if( m_nBitsPerInputPixel < 8 ) 619 { 620 // input less than a byte - copy via GetPixel() 621 *pOutBuf++ = m_pBmpAcc->GetPixel(pos.Y,pos.X); 622 *pOutBuf = m_pAlphaAcc->GetPixel(pos.Y,pos.X); 623 } 624 else 625 { 626 const long nNonAlphaBytes( m_nBitsPerInputPixel/8 ); 627 Scanline pScan = m_pBmpAcc->GetScanline(pos.Y); 628 629 // input integer multiple of byte - copy directly 630 rtl_copyMemory(pOutBuf, pScan+nScanlineLeftOffset, nNonAlphaBytes ); 631 pOutBuf += nNonAlphaBytes; 632 *pOutBuf++ = m_pAlphaAcc->GetPixel(pos.Y,pos.X); 633 } 634 } 635 636 return aRet; 637 } 638 639 uno::Reference< rendering::XBitmapPalette > SAL_CALL VclCanvasBitmap::getPalette() throw (uno::RuntimeException) 640 { 641 vos::OGuard aGuard( Application::GetSolarMutex() ); 642 643 uno::Reference< XBitmapPalette > aRet; 644 if( m_bPalette ) 645 aRet.set(this); 646 647 return aRet; 648 } 649 650 rendering::IntegerBitmapLayout SAL_CALL VclCanvasBitmap::getMemoryLayout() throw (uno::RuntimeException) 651 { 652 vos::OGuard aGuard( Application::GetSolarMutex() ); 653 654 rendering::IntegerBitmapLayout aLayout( m_aLayout ); 655 656 // only set references to self on separate copy of 657 // IntegerBitmapLayout - if we'd set that on m_aLayout, we'd have 658 // a circular reference! 659 if( m_bPalette ) 660 aLayout.Palette.set( this ); 661 662 aLayout.ColorSpace.set( this ); 663 664 return aLayout; 665 } 666 667 sal_Int32 SAL_CALL VclCanvasBitmap::getNumberOfEntries() throw (uno::RuntimeException) 668 { 669 vos::OGuard aGuard( Application::GetSolarMutex() ); 670 671 if( !m_pBmpAcc ) 672 return 0; 673 674 return m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ; 675 } 676 677 sal_Bool SAL_CALL VclCanvasBitmap::getIndex( uno::Sequence< double >& o_entry, sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 678 { 679 vos::OGuard aGuard( Application::GetSolarMutex() ); 680 681 const sal_uInt16 nCount( m_pBmpAcc ? 682 (m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ) : 0 ); 683 OSL_ENSURE(nIndex >= 0 && nIndex < nCount,"Palette index out of range"); 684 if( nIndex < 0 || nIndex >= nCount ) 685 throw lang::IndexOutOfBoundsException(::rtl::OUString::createFromAscii("Palette index out of range"), 686 static_cast<rendering::XBitmapPalette*>(this)); 687 688 const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(sal::static_int_cast<sal_uInt16>(nIndex)); 689 o_entry.realloc(3); 690 double* pColor=o_entry.getArray(); 691 pColor[0] = aCol.GetRed(); 692 pColor[1] = aCol.GetGreen(); 693 pColor[2] = aCol.GetBlue(); 694 695 return sal_True; // no palette transparency here. 696 } 697 698 sal_Bool SAL_CALL VclCanvasBitmap::setIndex( const uno::Sequence< double >&, sal_Bool, sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException) 699 { 700 vos::OGuard aGuard( Application::GetSolarMutex() ); 701 702 const sal_uInt16 nCount( m_pBmpAcc ? 703 (m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ) : 0 ); 704 705 OSL_ENSURE(nIndex >= 0 && nIndex < nCount,"Palette index out of range"); 706 if( nIndex < 0 || nIndex >= nCount ) 707 throw lang::IndexOutOfBoundsException(::rtl::OUString::createFromAscii("Palette index out of range"), 708 static_cast<rendering::XBitmapPalette*>(this)); 709 710 return sal_False; // read-only implementation 711 } 712 713 namespace 714 { 715 struct PaletteColorSpaceHolder: public rtl::StaticWithInit<uno::Reference<rendering::XColorSpace>, 716 PaletteColorSpaceHolder> 717 { 718 uno::Reference<rendering::XColorSpace> operator()() 719 { 720 return vcl::unotools::createStandardColorSpace(); 721 } 722 }; 723 } 724 725 uno::Reference< rendering::XColorSpace > SAL_CALL VclCanvasBitmap::getColorSpace( ) throw (uno::RuntimeException) 726 { 727 // this is the method from XBitmapPalette. Return palette color 728 // space here 729 return PaletteColorSpaceHolder::get(); 730 } 731 732 sal_Int8 SAL_CALL VclCanvasBitmap::getType( ) throw (uno::RuntimeException) 733 { 734 return rendering::ColorSpaceType::RGB; 735 } 736 737 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::getComponentTags( ) throw (uno::RuntimeException) 738 { 739 vos::OGuard aGuard( Application::GetSolarMutex() ); 740 return m_aComponentTags; 741 } 742 743 sal_Int8 SAL_CALL VclCanvasBitmap::getRenderingIntent( ) throw (uno::RuntimeException) 744 { 745 return rendering::RenderingIntent::PERCEPTUAL; 746 } 747 748 uno::Sequence< ::beans::PropertyValue > SAL_CALL VclCanvasBitmap::getProperties( ) throw (uno::RuntimeException) 749 { 750 return uno::Sequence< ::beans::PropertyValue >(); 751 } 752 753 uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertColorSpace( const uno::Sequence< double >& deviceColor, 754 const uno::Reference< ::rendering::XColorSpace >& targetColorSpace ) throw (uno::RuntimeException) 755 { 756 // TODO(P3): if we know anything about target 757 // colorspace, this can be greatly sped up 758 uno::Sequence<rendering::ARGBColor> aIntermediate( 759 convertToARGB(deviceColor)); 760 return targetColorSpace->convertFromARGB(aIntermediate); 761 } 762 763 uno::Sequence<rendering::RGBColor> SAL_CALL VclCanvasBitmap::convertToRGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException) 764 { 765 vos::OGuard aGuard( Application::GetSolarMutex() ); 766 767 const sal_Size nLen( deviceColor.getLength() ); 768 const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength()); 769 ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0, 770 "number of channels no multiple of pixel element count", 771 static_cast<rendering::XBitmapPalette*>(this), 01); 772 773 uno::Sequence< rendering::RGBColor > aRes(nLen/nComponentsPerPixel); 774 rendering::RGBColor* pOut( aRes.getArray() ); 775 776 if( m_bPalette ) 777 { 778 OSL_ENSURE(m_nIndexIndex != -1, 779 "Invalid color channel indices"); 780 ENSURE_OR_THROW(m_pBmpAcc, 781 "Unable to get BitmapAccess"); 782 783 for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel ) 784 { 785 const BitmapColor aCol = m_pBmpAcc->GetPaletteColor( 786 sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex])); 787 788 // TODO(F3): Convert result to sRGB color space 789 *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()), 790 toDoubleColor(aCol.GetGreen()), 791 toDoubleColor(aCol.GetBlue())); 792 } 793 } 794 else 795 { 796 OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1, 797 "Invalid color channel indices"); 798 799 for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel ) 800 { 801 // TODO(F3): Convert result to sRGB color space 802 *pOut++ = rendering::RGBColor( 803 deviceColor[i+m_nRedIndex], 804 deviceColor[i+m_nGreenIndex], 805 deviceColor[i+m_nBlueIndex]); 806 } 807 } 808 809 return aRes; 810 } 811 812 uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertToARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException) 813 { 814 vos::OGuard aGuard( Application::GetSolarMutex() ); 815 816 const sal_Size nLen( deviceColor.getLength() ); 817 const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength()); 818 ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0, 819 "number of channels no multiple of pixel element count", 820 static_cast<rendering::XBitmapPalette*>(this), 01); 821 822 uno::Sequence< rendering::ARGBColor > aRes(nLen/nComponentsPerPixel); 823 rendering::ARGBColor* pOut( aRes.getArray() ); 824 825 if( m_bPalette ) 826 { 827 OSL_ENSURE(m_nIndexIndex != -1, 828 "Invalid color channel indices"); 829 ENSURE_OR_THROW(m_pBmpAcc, 830 "Unable to get BitmapAccess"); 831 832 for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel ) 833 { 834 const BitmapColor aCol = m_pBmpAcc->GetPaletteColor( 835 sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex])); 836 837 // TODO(F3): Convert result to sRGB color space 838 const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 ); 839 *pOut++ = rendering::ARGBColor(nAlpha, 840 toDoubleColor(aCol.GetRed()), 841 toDoubleColor(aCol.GetGreen()), 842 toDoubleColor(aCol.GetBlue())); 843 } 844 } 845 else 846 { 847 OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1, 848 "Invalid color channel indices"); 849 850 for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel ) 851 { 852 // TODO(F3): Convert result to sRGB color space 853 const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 ); 854 *pOut++ = rendering::ARGBColor( 855 nAlpha, 856 deviceColor[i+m_nRedIndex], 857 deviceColor[i+m_nGreenIndex], 858 deviceColor[i+m_nBlueIndex]); 859 } 860 } 861 862 return aRes; 863 } 864 865 uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertToPARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException) 866 { 867 vos::OGuard aGuard( Application::GetSolarMutex() ); 868 869 const sal_Size nLen( deviceColor.getLength() ); 870 const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength()); 871 ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0, 872 "number of channels no multiple of pixel element count", 873 static_cast<rendering::XBitmapPalette*>(this), 01); 874 875 uno::Sequence< rendering::ARGBColor > aRes(nLen/nComponentsPerPixel); 876 rendering::ARGBColor* pOut( aRes.getArray() ); 877 878 if( m_bPalette ) 879 { 880 OSL_ENSURE(m_nIndexIndex != -1, 881 "Invalid color channel indices"); 882 ENSURE_OR_THROW(m_pBmpAcc, 883 "Unable to get BitmapAccess"); 884 885 for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel ) 886 { 887 const BitmapColor aCol = m_pBmpAcc->GetPaletteColor( 888 sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex])); 889 890 // TODO(F3): Convert result to sRGB color space 891 const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 ); 892 *pOut++ = rendering::ARGBColor(nAlpha, 893 nAlpha*toDoubleColor(aCol.GetRed()), 894 nAlpha*toDoubleColor(aCol.GetGreen()), 895 nAlpha*toDoubleColor(aCol.GetBlue())); 896 } 897 } 898 else 899 { 900 OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1, 901 "Invalid color channel indices"); 902 903 for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel ) 904 { 905 // TODO(F3): Convert result to sRGB color space 906 const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 ); 907 *pOut++ = rendering::ARGBColor( 908 nAlpha, 909 nAlpha*deviceColor[i+m_nRedIndex], 910 nAlpha*deviceColor[i+m_nGreenIndex], 911 nAlpha*deviceColor[i+m_nBlueIndex]); 912 } 913 } 914 915 return aRes; 916 } 917 918 uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromRGB( const uno::Sequence<rendering::RGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException) 919 { 920 vos::OGuard aGuard( Application::GetSolarMutex() ); 921 922 const sal_Size nLen( rgbColor.getLength() ); 923 const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength()); 924 925 uno::Sequence< double > aRes(nLen*nComponentsPerPixel); 926 double* pColors=aRes.getArray(); 927 928 if( m_bPalette ) 929 { 930 for( sal_Size i=0; i<nLen; ++i ) 931 { 932 pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex( 933 BitmapColor(toByteColor(rgbColor[i].Red), 934 toByteColor(rgbColor[i].Green), 935 toByteColor(rgbColor[i].Blue))); 936 if( m_nAlphaIndex != -1 ) 937 pColors[m_nAlphaIndex] = 1.0; 938 939 pColors += nComponentsPerPixel; 940 } 941 } 942 else 943 { 944 for( sal_Size i=0; i<nLen; ++i ) 945 { 946 pColors[m_nRedIndex] = rgbColor[i].Red; 947 pColors[m_nGreenIndex] = rgbColor[i].Green; 948 pColors[m_nBlueIndex] = rgbColor[i].Blue; 949 if( m_nAlphaIndex != -1 ) 950 pColors[m_nAlphaIndex] = 1.0; 951 952 pColors += nComponentsPerPixel; 953 } 954 } 955 return aRes; 956 } 957 958 uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException) 959 { 960 vos::OGuard aGuard( Application::GetSolarMutex() ); 961 962 const sal_Size nLen( rgbColor.getLength() ); 963 const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength()); 964 965 uno::Sequence< double > aRes(nLen*nComponentsPerPixel); 966 double* pColors=aRes.getArray(); 967 968 if( m_bPalette ) 969 { 970 for( sal_Size i=0; i<nLen; ++i ) 971 { 972 pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex( 973 BitmapColor(toByteColor(rgbColor[i].Red), 974 toByteColor(rgbColor[i].Green), 975 toByteColor(rgbColor[i].Blue))); 976 if( m_nAlphaIndex != -1 ) 977 pColors[m_nAlphaIndex] = rgbColor[i].Alpha; 978 979 pColors += nComponentsPerPixel; 980 } 981 } 982 else 983 { 984 for( sal_Size i=0; i<nLen; ++i ) 985 { 986 pColors[m_nRedIndex] = rgbColor[i].Red; 987 pColors[m_nGreenIndex] = rgbColor[i].Green; 988 pColors[m_nBlueIndex] = rgbColor[i].Blue; 989 if( m_nAlphaIndex != -1 ) 990 pColors[m_nAlphaIndex] = rgbColor[i].Alpha; 991 992 pColors += nComponentsPerPixel; 993 } 994 } 995 return aRes; 996 } 997 998 uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromPARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException) 999 { 1000 vos::OGuard aGuard( Application::GetSolarMutex() ); 1001 1002 const sal_Size nLen( rgbColor.getLength() ); 1003 const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength()); 1004 1005 uno::Sequence< double > aRes(nLen*nComponentsPerPixel); 1006 double* pColors=aRes.getArray(); 1007 1008 if( m_bPalette ) 1009 { 1010 for( sal_Size i=0; i<nLen; ++i ) 1011 { 1012 const double nAlpha( rgbColor[i].Alpha ); 1013 pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex( 1014 BitmapColor(toByteColor(rgbColor[i].Red / nAlpha), 1015 toByteColor(rgbColor[i].Green / nAlpha), 1016 toByteColor(rgbColor[i].Blue / nAlpha))); 1017 if( m_nAlphaIndex != -1 ) 1018 pColors[m_nAlphaIndex] = nAlpha; 1019 1020 pColors += nComponentsPerPixel; 1021 } 1022 } 1023 else 1024 { 1025 for( sal_Size i=0; i<nLen; ++i ) 1026 { 1027 const double nAlpha( rgbColor[i].Alpha ); 1028 pColors[m_nRedIndex] = rgbColor[i].Red / nAlpha; 1029 pColors[m_nGreenIndex] = rgbColor[i].Green / nAlpha; 1030 pColors[m_nBlueIndex] = rgbColor[i].Blue / nAlpha; 1031 if( m_nAlphaIndex != -1 ) 1032 pColors[m_nAlphaIndex] = nAlpha; 1033 1034 pColors += nComponentsPerPixel; 1035 } 1036 } 1037 return aRes; 1038 } 1039 1040 sal_Int32 SAL_CALL VclCanvasBitmap::getBitsPerPixel( ) throw (uno::RuntimeException) 1041 { 1042 vos::OGuard aGuard( Application::GetSolarMutex() ); 1043 return m_nBitsPerOutputPixel; 1044 } 1045 1046 uno::Sequence< ::sal_Int32 > SAL_CALL VclCanvasBitmap::getComponentBitCounts( ) throw (uno::RuntimeException) 1047 { 1048 vos::OGuard aGuard( Application::GetSolarMutex() ); 1049 return m_aComponentBitCounts; 1050 } 1051 1052 sal_Int8 SAL_CALL VclCanvasBitmap::getEndianness( ) throw (uno::RuntimeException) 1053 { 1054 vos::OGuard aGuard( Application::GetSolarMutex() ); 1055 return m_nEndianness; 1056 } 1057 1058 uno::Sequence<double> SAL_CALL VclCanvasBitmap::convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor, 1059 const uno::Reference< ::rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,uno::RuntimeException) 1060 { 1061 if( dynamic_cast<VclCanvasBitmap*>(targetColorSpace.get()) ) 1062 { 1063 vos::OGuard aGuard( Application::GetSolarMutex() ); 1064 1065 const sal_Size nLen( deviceColor.getLength() ); 1066 const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength()); 1067 ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0, 1068 "number of channels no multiple of pixel element count", 1069 static_cast<rendering::XBitmapPalette*>(this), 01); 1070 1071 uno::Sequence<double> aRes(nLen); 1072 double* pOut( aRes.getArray() ); 1073 1074 if( m_bPalette ) 1075 { 1076 OSL_ENSURE(m_nIndexIndex != -1, 1077 "Invalid color channel indices"); 1078 ENSURE_OR_THROW(m_pBmpAcc, 1079 "Unable to get BitmapAccess"); 1080 1081 for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel ) 1082 { 1083 const BitmapColor aCol = m_pBmpAcc->GetPaletteColor( 1084 sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex])); 1085 1086 // TODO(F3): Convert result to sRGB color space 1087 const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 ); 1088 *pOut++ = toDoubleColor(aCol.GetRed()); 1089 *pOut++ = toDoubleColor(aCol.GetGreen()); 1090 *pOut++ = toDoubleColor(aCol.GetBlue()); 1091 *pOut++ = nAlpha; 1092 } 1093 } 1094 else 1095 { 1096 OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1, 1097 "Invalid color channel indices"); 1098 1099 for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel ) 1100 { 1101 // TODO(F3): Convert result to sRGB color space 1102 const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 ); 1103 *pOut++ = deviceColor[i+m_nRedIndex]; 1104 *pOut++ = deviceColor[i+m_nGreenIndex]; 1105 *pOut++ = deviceColor[i+m_nBlueIndex]; 1106 *pOut++ = nAlpha; 1107 } 1108 } 1109 1110 return aRes; 1111 } 1112 else 1113 { 1114 // TODO(P3): if we know anything about target 1115 // colorspace, this can be greatly sped up 1116 uno::Sequence<rendering::ARGBColor> aIntermediate( 1117 convertIntegerToARGB(deviceColor)); 1118 return targetColorSpace->convertFromARGB(aIntermediate); 1119 } 1120 } 1121 1122 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor, 1123 const uno::Reference< ::rendering::XIntegerBitmapColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,uno::RuntimeException) 1124 { 1125 if( dynamic_cast<VclCanvasBitmap*>(targetColorSpace.get()) ) 1126 { 1127 // it's us, so simply pass-through the data 1128 return deviceColor; 1129 } 1130 else 1131 { 1132 // TODO(P3): if we know anything about target 1133 // colorspace, this can be greatly sped up 1134 uno::Sequence<rendering::ARGBColor> aIntermediate( 1135 convertIntegerToARGB(deviceColor)); 1136 return targetColorSpace->convertIntegerFromARGB(aIntermediate); 1137 } 1138 } 1139 1140 uno::Sequence<rendering::RGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException) 1141 { 1142 vos::OGuard aGuard( Application::GetSolarMutex() ); 1143 1144 const sal_uInt8* pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) ); 1145 const sal_Size nLen( deviceColor.getLength() ); 1146 const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel); 1147 1148 uno::Sequence< rendering::RGBColor > aRes(nNumColors); 1149 rendering::RGBColor* pOut( aRes.getArray() ); 1150 1151 ENSURE_OR_THROW(m_pBmpAcc, 1152 "Unable to get BitmapAccess"); 1153 1154 if( m_aBmpEx.IsTransparent() ) 1155 { 1156 const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8); 1157 for( sal_Size i=0; i<nLen; i+=nBytesPerPixel ) 1158 { 1159 // if palette, index is guaranteed to be 8 bit 1160 const BitmapColor aCol = 1161 m_bPalette ? 1162 m_pBmpAcc->GetPaletteColor(*pIn) : 1163 m_pBmpAcc->GetPixelFromData(pIn,0); 1164 1165 // TODO(F3): Convert result to sRGB color space 1166 *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()), 1167 toDoubleColor(aCol.GetGreen()), 1168 toDoubleColor(aCol.GetBlue())); 1169 // skips alpha 1170 pIn += nBytesPerPixel; 1171 } 1172 } 1173 else 1174 { 1175 for( sal_Int32 i=0; i<nNumColors; ++i ) 1176 { 1177 const BitmapColor aCol = 1178 m_bPalette ? 1179 m_pBmpAcc->GetPaletteColor( 1180 sal::static_int_cast<sal_uInt16>( 1181 m_pBmpAcc->GetPixelFromData( 1182 pIn, i ))) : 1183 m_pBmpAcc->GetPixelFromData(pIn, i); 1184 1185 // TODO(F3): Convert result to sRGB color space 1186 *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()), 1187 toDoubleColor(aCol.GetGreen()), 1188 toDoubleColor(aCol.GetBlue())); 1189 } 1190 } 1191 1192 return aRes; 1193 } 1194 1195 uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException) 1196 { 1197 vos::OGuard aGuard( Application::GetSolarMutex() ); 1198 1199 const sal_uInt8* pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) ); 1200 const sal_Size nLen( deviceColor.getLength() ); 1201 const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel); 1202 1203 uno::Sequence< rendering::ARGBColor > aRes(nNumColors); 1204 rendering::ARGBColor* pOut( aRes.getArray() ); 1205 1206 ENSURE_OR_THROW(m_pBmpAcc, 1207 "Unable to get BitmapAccess"); 1208 1209 if( m_aBmpEx.IsTransparent() ) 1210 { 1211 const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 ); 1212 const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8); 1213 const sal_uInt8 nAlphaFactor( m_aBmpEx.IsAlpha() ? 1 : 255 ); 1214 for( sal_Size i=0; i<nLen; i+=nBytesPerPixel ) 1215 { 1216 // if palette, index is guaranteed to be 8 bit 1217 const BitmapColor aCol = 1218 m_bPalette ? 1219 m_pBmpAcc->GetPaletteColor(*pIn) : 1220 m_pBmpAcc->GetPixelFromData(pIn,0); 1221 1222 // TODO(F3): Convert result to sRGB color space 1223 *pOut++ = rendering::ARGBColor(1.0 - toDoubleColor(nAlphaFactor*pIn[nNonAlphaBytes]), 1224 toDoubleColor(aCol.GetRed()), 1225 toDoubleColor(aCol.GetGreen()), 1226 toDoubleColor(aCol.GetBlue())); 1227 pIn += nBytesPerPixel; 1228 } 1229 } 1230 else 1231 { 1232 for( sal_Int32 i=0; i<nNumColors; ++i ) 1233 { 1234 const BitmapColor aCol = 1235 m_bPalette ? 1236 m_pBmpAcc->GetPaletteColor( 1237 sal::static_int_cast<sal_uInt16>( 1238 m_pBmpAcc->GetPixelFromData( 1239 pIn, i ))) : 1240 m_pBmpAcc->GetPixelFromData(pIn, i); 1241 1242 // TODO(F3): Convert result to sRGB color space 1243 *pOut++ = rendering::ARGBColor(1.0, 1244 toDoubleColor(aCol.GetRed()), 1245 toDoubleColor(aCol.GetGreen()), 1246 toDoubleColor(aCol.GetBlue())); 1247 } 1248 } 1249 1250 return aRes; 1251 } 1252 1253 uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException) 1254 { 1255 vos::OGuard aGuard( Application::GetSolarMutex() ); 1256 1257 const sal_uInt8* pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) ); 1258 const sal_Size nLen( deviceColor.getLength() ); 1259 const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel); 1260 1261 uno::Sequence< rendering::ARGBColor > aRes(nNumColors); 1262 rendering::ARGBColor* pOut( aRes.getArray() ); 1263 1264 ENSURE_OR_THROW(m_pBmpAcc, 1265 "Unable to get BitmapAccess"); 1266 1267 if( m_aBmpEx.IsTransparent() ) 1268 { 1269 const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 ); 1270 const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8); 1271 const sal_uInt8 nAlphaFactor( m_aBmpEx.IsAlpha() ? 1 : 255 ); 1272 for( sal_Size i=0; i<nLen; i+=nBytesPerPixel ) 1273 { 1274 // if palette, index is guaranteed to be 8 bit 1275 const BitmapColor aCol = 1276 m_bPalette ? 1277 m_pBmpAcc->GetPaletteColor(*pIn) : 1278 m_pBmpAcc->GetPixelFromData(pIn,0); 1279 1280 // TODO(F3): Convert result to sRGB color space 1281 const double nAlpha( 1.0 - toDoubleColor(nAlphaFactor*pIn[nNonAlphaBytes]) ); 1282 *pOut++ = rendering::ARGBColor(nAlpha, 1283 nAlpha*toDoubleColor(aCol.GetRed()), 1284 nAlpha*toDoubleColor(aCol.GetGreen()), 1285 nAlpha*toDoubleColor(aCol.GetBlue())); 1286 pIn += nBytesPerPixel; 1287 } 1288 } 1289 else 1290 { 1291 for( sal_Int32 i=0; i<nNumColors; ++i ) 1292 { 1293 const BitmapColor aCol = 1294 m_bPalette ? 1295 m_pBmpAcc->GetPaletteColor( 1296 sal::static_int_cast<sal_uInt16>( 1297 m_pBmpAcc->GetPixelFromData( 1298 pIn, i ))) : 1299 m_pBmpAcc->GetPixelFromData(pIn, i); 1300 1301 // TODO(F3): Convert result to sRGB color space 1302 *pOut++ = rendering::ARGBColor(1.0, 1303 toDoubleColor(aCol.GetRed()), 1304 toDoubleColor(aCol.GetGreen()), 1305 toDoubleColor(aCol.GetBlue())); 1306 } 1307 } 1308 1309 return aRes; 1310 } 1311 1312 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromRGB( const uno::Sequence<rendering::RGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException) 1313 { 1314 vos::OGuard aGuard( Application::GetSolarMutex() ); 1315 1316 const sal_Size nLen( rgbColor.getLength() ); 1317 const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8); 1318 1319 uno::Sequence< sal_Int8 > aRes(nNumBytes); 1320 sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray()); 1321 1322 if( m_aBmpEx.IsTransparent() ) 1323 { 1324 const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 ); 1325 for( sal_Size i=0; i<nLen; ++i ) 1326 { 1327 const BitmapColor aCol(toByteColor(rgbColor[i].Red), 1328 toByteColor(rgbColor[i].Green), 1329 toByteColor(rgbColor[i].Blue)); 1330 const BitmapColor aCol2 = 1331 m_bPalette ? 1332 BitmapColor( 1333 sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) : 1334 aCol; 1335 1336 m_pBmpAcc->SetPixelOnData(pColors,0,aCol2); 1337 pColors += nNonAlphaBytes; 1338 *pColors++ = sal_uInt8(255); 1339 } 1340 } 1341 else 1342 { 1343 for( sal_Size i=0; i<nLen; ++i ) 1344 { 1345 const BitmapColor aCol(toByteColor(rgbColor[i].Red), 1346 toByteColor(rgbColor[i].Green), 1347 toByteColor(rgbColor[i].Blue)); 1348 const BitmapColor aCol2 = 1349 m_bPalette ? 1350 BitmapColor( 1351 sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) : 1352 aCol; 1353 1354 m_pBmpAcc->SetPixelOnData(pColors,i,aCol2); 1355 } 1356 } 1357 1358 return aRes; 1359 } 1360 1361 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException) 1362 { 1363 vos::OGuard aGuard( Application::GetSolarMutex() ); 1364 1365 const sal_Size nLen( rgbColor.getLength() ); 1366 const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8); 1367 1368 uno::Sequence< sal_Int8 > aRes(nNumBytes); 1369 sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray()); 1370 1371 if( m_aBmpEx.IsTransparent() ) 1372 { 1373 const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 ); 1374 for( sal_Size i=0; i<nLen; ++i ) 1375 { 1376 const BitmapColor aCol(toByteColor(rgbColor[i].Red), 1377 toByteColor(rgbColor[i].Green), 1378 toByteColor(rgbColor[i].Blue)); 1379 const BitmapColor aCol2 = 1380 m_bPalette ? 1381 BitmapColor( 1382 sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) : 1383 aCol; 1384 1385 m_pBmpAcc->SetPixelOnData(pColors,0,aCol2); 1386 pColors += nNonAlphaBytes; 1387 *pColors++ = 255 - toByteColor(rgbColor[i].Alpha); 1388 } 1389 } 1390 else 1391 { 1392 for( sal_Size i=0; i<nLen; ++i ) 1393 { 1394 const BitmapColor aCol(toByteColor(rgbColor[i].Red), 1395 toByteColor(rgbColor[i].Green), 1396 toByteColor(rgbColor[i].Blue)); 1397 const BitmapColor aCol2 = 1398 m_bPalette ? 1399 BitmapColor( 1400 sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) : 1401 aCol; 1402 1403 m_pBmpAcc->SetPixelOnData(pColors,i,aCol2); 1404 } 1405 } 1406 1407 return aRes; 1408 } 1409 1410 uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromPARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException) 1411 { 1412 vos::OGuard aGuard( Application::GetSolarMutex() ); 1413 1414 const sal_Size nLen( rgbColor.getLength() ); 1415 const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8); 1416 1417 uno::Sequence< sal_Int8 > aRes(nNumBytes); 1418 sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray()); 1419 1420 if( m_aBmpEx.IsTransparent() ) 1421 { 1422 const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 ); 1423 for( sal_Size i=0; i<nLen; ++i ) 1424 { 1425 const double nAlpha( rgbColor[i].Alpha ); 1426 const BitmapColor aCol(toByteColor(rgbColor[i].Red / nAlpha), 1427 toByteColor(rgbColor[i].Green / nAlpha), 1428 toByteColor(rgbColor[i].Blue / nAlpha)); 1429 const BitmapColor aCol2 = 1430 m_bPalette ? 1431 BitmapColor( 1432 sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) : 1433 aCol; 1434 1435 m_pBmpAcc->SetPixelOnData(pColors,0,aCol2); 1436 pColors += nNonAlphaBytes; 1437 *pColors++ = 255 - toByteColor(nAlpha); 1438 } 1439 } 1440 else 1441 { 1442 for( sal_Size i=0; i<nLen; ++i ) 1443 { 1444 const BitmapColor aCol(toByteColor(rgbColor[i].Red), 1445 toByteColor(rgbColor[i].Green), 1446 toByteColor(rgbColor[i].Blue)); 1447 const BitmapColor aCol2 = 1448 m_bPalette ? 1449 BitmapColor( 1450 sal::static_int_cast<sal_uInt8>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) : 1451 aCol; 1452 1453 m_pBmpAcc->SetPixelOnData(pColors,i,aCol2); 1454 } 1455 } 1456 1457 return aRes; 1458 } 1459 1460 BitmapEx VclCanvasBitmap::getBitmapEx() const 1461 { 1462 return m_aBmpEx; 1463 } 1464