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 <ctype.h> 28 #include <rtl/crc.h> 29 #include <tools/stream.hxx> 30 #include <tools/debug.hxx> 31 #include <tools/rc.h> 32 #include <vcl/salbtype.hxx> 33 #include <vcl/outdev.hxx> 34 #include <vcl/alpha.hxx> 35 #include <vcl/bitmapex.hxx> 36 #include <vcl/pngread.hxx> 37 #include <vcl/svapp.hxx> 38 #include <vcl/bmpacc.hxx> 39 #include <vcl/dibtools.hxx> 40 #include <image.h> 41 #include <impimagetree.hxx> 42 #include <basegfx/matrix/b2dhommatrixtools.hxx> 43 44 // ------------ 45 // - BitmapEx - 46 // ------------ 47 48 BitmapEx::BitmapEx() : 49 eTransparent( TRANSPARENT_NONE ), 50 bAlpha ( sal_False ) 51 { 52 } 53 54 // ------------------------------------------------------------------ 55 56 BitmapEx::BitmapEx( const BitmapEx& rBitmapEx ) : 57 aBitmap ( rBitmapEx.aBitmap ), 58 aMask ( rBitmapEx.aMask ), 59 aBitmapSize ( rBitmapEx.aBitmapSize ), 60 aTransparentColor ( rBitmapEx.aTransparentColor ), 61 eTransparent ( rBitmapEx.eTransparent ), 62 bAlpha ( rBitmapEx.bAlpha ) 63 { 64 } 65 66 BitmapEx::BitmapEx( const BitmapEx& rBitmapEx, Point aSrc, Size aSize ) : 67 eTransparent( TRANSPARENT_NONE ), 68 bAlpha ( sal_False ) 69 { 70 if( rBitmapEx.IsEmpty() ) 71 return; 72 73 aBitmap = Bitmap( aSize, rBitmapEx.aBitmap.GetBitCount() ); 74 aBitmapSize = aSize; 75 if( rBitmapEx.IsAlpha() ) 76 { 77 bAlpha = sal_True; 78 aMask = AlphaMask( aSize ).ImplGetBitmap(); 79 } 80 else if( rBitmapEx.IsTransparent() ) 81 aMask = Bitmap( aSize, rBitmapEx.aMask.GetBitCount() ); 82 83 Rectangle aDestRect( Point( 0, 0 ), aSize ); 84 Rectangle aSrcRect( aSrc, aSize ); 85 CopyPixel( aDestRect, aSrcRect, &rBitmapEx ); 86 } 87 88 // ------------------------------------------------------------------ 89 90 BitmapEx::BitmapEx( const ResId& rResId ) : 91 eTransparent( TRANSPARENT_NONE ), 92 bAlpha ( sal_False ) 93 { 94 static ImplImageTreeSingletonRef aImageTree; 95 ResMgr* pResMgr = NULL; 96 97 ResMgr::GetResourceSkipHeader( rResId.SetRT( RSC_BITMAP ), &pResMgr ); 98 pResMgr->ReadLong(); 99 pResMgr->ReadLong(); 100 101 const String aFileName( pResMgr->ReadString() ); 102 ::rtl::OUString aCurrentSymbolsStyle = Application::GetSettings().GetStyleSettings().GetCurrentSymbolsStyleName(); 103 104 if( !aImageTree->loadImage( aFileName, aCurrentSymbolsStyle, *this ) ) 105 { 106 #ifdef DBG_UTIL 107 ByteString aErrorStr( "BitmapEx::BitmapEx( const ResId& rResId ): could not load image <" ); 108 DBG_ERROR( ( ( aErrorStr += ByteString( aFileName, RTL_TEXTENCODING_ASCII_US ) ) += '>' ).GetBuffer() ); 109 #endif 110 } 111 } 112 113 // ------------------------------------------------------------------ 114 115 BitmapEx::BitmapEx( const Bitmap& rBmp ) : 116 aBitmap ( rBmp ), 117 aBitmapSize ( aBitmap.GetSizePixel() ), 118 eTransparent( TRANSPARENT_NONE ), 119 bAlpha ( sal_False ) 120 { 121 } 122 123 // ------------------------------------------------------------------ 124 125 BitmapEx::BitmapEx( const Bitmap& rBmp, const Bitmap& rMask ) : 126 aBitmap ( rBmp ), 127 aMask ( rMask ), 128 aBitmapSize ( aBitmap.GetSizePixel() ), 129 eTransparent ( !rMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP ), 130 bAlpha ( sal_False ) 131 { 132 if(!!aBitmap && !!aMask && aBitmap.GetSizePixel() != aMask.GetSizePixel()) 133 { 134 OSL_ENSURE(false, "Mask size differs from Bitmap size, corrected Mask (!)"); 135 aMask.Scale(aBitmap.GetSizePixel()); 136 } 137 138 // #105489# Ensure a mask is exactly one bit deep 139 if( !!aMask && aMask.GetBitCount() != 1 ) 140 { 141 OSL_TRACE("BitmapEx: forced mask to monochrome"); 142 aMask.ImplMakeMono( 255 ); 143 } 144 } 145 146 // ------------------------------------------------------------------ 147 148 BitmapEx::BitmapEx( const Bitmap& rBmp, const AlphaMask& rAlphaMask ) : 149 aBitmap ( rBmp ), 150 aMask ( rAlphaMask.ImplGetBitmap() ), 151 aBitmapSize ( aBitmap.GetSizePixel() ), 152 eTransparent ( !rAlphaMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP ), 153 bAlpha ( !rAlphaMask ? sal_False : sal_True ) 154 { 155 if(!!aBitmap && !!aMask && aBitmap.GetSizePixel() != aMask.GetSizePixel()) 156 { 157 OSL_ENSURE(false, "Alpha size differs from Bitmap size, corrected Mask (!)"); 158 aMask.Scale(rBmp.GetSizePixel()); 159 } 160 161 // #i75531# the workaround below can go when 162 // X11SalGraphics::drawAlphaBitmap()'s render acceleration 163 // can handle the bitmap depth mismatch directly 164 if( aBitmap.GetBitCount() < aMask.GetBitCount() ) 165 aBitmap.Convert( BMP_CONVERSION_24BIT ); 166 } 167 168 // ------------------------------------------------------------------ 169 170 BitmapEx::BitmapEx( const Bitmap& rBmp, const Color& rTransparentColor ) : 171 aBitmap ( rBmp ), 172 aBitmapSize ( aBitmap.GetSizePixel() ), 173 aTransparentColor ( rTransparentColor ), 174 eTransparent ( TRANSPARENT_BITMAP ), 175 bAlpha ( sal_False ) 176 { 177 aMask = aBitmap.CreateMask( aTransparentColor ); 178 179 DBG_ASSERT( rBmp.GetSizePixel() == aMask.GetSizePixel(), 180 "BitmapEx::BitmapEx(): size mismatch for bitmap and alpha mask." ); 181 } 182 183 // ------------------------------------------------------------------ 184 185 BitmapEx::~BitmapEx() 186 { 187 } 188 189 // ------------------------------------------------------------------ 190 191 // ------------------------------------------------------------------ 192 193 BitmapEx& BitmapEx::operator=( const BitmapEx& rBitmapEx ) 194 { 195 if( &rBitmapEx != this ) 196 { 197 aBitmap = rBitmapEx.aBitmap; 198 aMask = rBitmapEx.aMask; 199 aBitmapSize = rBitmapEx.aBitmapSize; 200 aTransparentColor = rBitmapEx.aTransparentColor; 201 eTransparent = rBitmapEx.eTransparent; 202 bAlpha = rBitmapEx.bAlpha; 203 } 204 205 return *this; 206 } 207 208 // ------------------------------------------------------------------ 209 210 sal_Bool BitmapEx::operator==( const BitmapEx& rBitmapEx ) const 211 { 212 if( eTransparent != rBitmapEx.eTransparent ) 213 return sal_False; 214 215 if( aBitmap != rBitmapEx.aBitmap ) 216 return sal_False; 217 218 if( aBitmapSize != rBitmapEx.aBitmapSize ) 219 return sal_False; 220 221 if( eTransparent == TRANSPARENT_NONE ) 222 return sal_True; 223 224 if( eTransparent == TRANSPARENT_COLOR ) 225 return aTransparentColor == rBitmapEx.aTransparentColor; 226 227 return( ( aMask == rBitmapEx.aMask ) && ( bAlpha == rBitmapEx.bAlpha ) ); 228 } 229 230 // ------------------------------------------------------------------ 231 232 sal_Bool BitmapEx::IsEqual( const BitmapEx& rBmpEx ) const 233 { 234 return( rBmpEx.eTransparent == eTransparent && 235 rBmpEx.bAlpha == bAlpha && 236 rBmpEx.aBitmap.IsEqual( aBitmap ) && 237 rBmpEx.aMask.IsEqual( aMask ) ); 238 } 239 240 // ------------------------------------------------------------------ 241 242 sal_Bool BitmapEx::IsEmpty() const 243 { 244 return( aBitmap.IsEmpty() && aMask.IsEmpty() ); 245 } 246 247 // ------------------------------------------------------------------ 248 249 void BitmapEx::SetEmpty() 250 { 251 aBitmap.SetEmpty(); 252 aMask.SetEmpty(); 253 eTransparent = TRANSPARENT_NONE; 254 bAlpha = sal_False; 255 } 256 257 // ------------------------------------------------------------------ 258 259 void BitmapEx::Clear() 260 { 261 SetEmpty(); 262 } 263 264 // ------------------------------------------------------------------ 265 266 sal_Bool BitmapEx::IsTransparent() const 267 { 268 return( eTransparent != TRANSPARENT_NONE ); 269 } 270 271 // ------------------------------------------------------------------ 272 273 sal_Bool BitmapEx::IsAlpha() const 274 { 275 return( IsTransparent() && bAlpha ); 276 } 277 278 // ------------------------------------------------------------------ 279 280 Bitmap BitmapEx::GetBitmap( const Color* pTransReplaceColor ) const 281 { 282 Bitmap aRetBmp( aBitmap ); 283 284 if( pTransReplaceColor && ( eTransparent != TRANSPARENT_NONE ) ) 285 { 286 Bitmap aTempMask; 287 288 if( eTransparent == TRANSPARENT_COLOR ) 289 aTempMask = aBitmap.CreateMask( aTransparentColor ); 290 else 291 aTempMask = aMask; 292 293 if( !IsAlpha() ) 294 aRetBmp.Replace( aTempMask, *pTransReplaceColor ); 295 else 296 aRetBmp.Replace( GetAlpha(), *pTransReplaceColor ); 297 } 298 299 return aRetBmp; 300 } 301 302 // ------------------------------------------------------------------ 303 304 BitmapEx BitmapEx::GetColorTransformedBitmapEx( BmpColorMode eColorMode ) const 305 { 306 BitmapEx aRet; 307 308 if( BMP_COLOR_HIGHCONTRAST == eColorMode ) 309 { 310 aRet = *this; 311 aRet.aBitmap = aBitmap.GetColorTransformedBitmap( eColorMode ); 312 } 313 else if( BMP_COLOR_MONOCHROME_BLACK == eColorMode || 314 BMP_COLOR_MONOCHROME_WHITE == eColorMode ) 315 { 316 aRet = *this; 317 aRet.aBitmap = aRet.aBitmap.GetColorTransformedBitmap( eColorMode ); 318 319 if( !aRet.aMask.IsEmpty() ) 320 { 321 aRet.aMask.CombineSimple( aRet.aBitmap, BMP_COMBINE_OR ); 322 aRet.aBitmap.Erase( ( BMP_COLOR_MONOCHROME_BLACK == eColorMode ) ? COL_BLACK : COL_WHITE ); 323 324 DBG_ASSERT( aRet.aBitmap.GetSizePixel() == aRet.aMask.GetSizePixel(), 325 "BitmapEx::GetColorTransformedBitmapEx(): size mismatch for bitmap and alpha mask." ); 326 } 327 } 328 329 return aRet; 330 } 331 332 // ------------------------------------------------------------------ 333 334 Bitmap BitmapEx::GetMask() const 335 { 336 Bitmap aRet( aMask ); 337 338 if( IsAlpha() ) 339 aRet.ImplMakeMono( 255 ); 340 341 return aRet; 342 } 343 344 // ------------------------------------------------------------------ 345 346 AlphaMask BitmapEx::GetAlpha() const 347 { 348 AlphaMask aAlpha; 349 350 if( IsAlpha() ) 351 aAlpha.ImplSetBitmap( aMask ); 352 else 353 aAlpha = aMask; 354 355 return aAlpha; 356 } 357 358 // ------------------------------------------------------------------ 359 360 sal_uLong BitmapEx::GetSizeBytes() const 361 { 362 sal_uLong nSizeBytes = aBitmap.GetSizeBytes(); 363 364 if( eTransparent == TRANSPARENT_BITMAP ) 365 nSizeBytes += aMask.GetSizeBytes(); 366 367 return nSizeBytes; 368 } 369 370 // ------------------------------------------------------------------ 371 372 sal_uLong BitmapEx::GetChecksum() const 373 { 374 sal_uInt32 nCrc = aBitmap.GetChecksum(); 375 SVBT32 aBT32; 376 377 UInt32ToSVBT32( (long) eTransparent, aBT32 ); 378 nCrc = rtl_crc32( nCrc, aBT32, 4 ); 379 380 UInt32ToSVBT32( (long) bAlpha, aBT32 ); 381 nCrc = rtl_crc32( nCrc, aBT32, 4 ); 382 383 if( ( TRANSPARENT_BITMAP == eTransparent ) && !aMask.IsEmpty() ) 384 { 385 UInt32ToSVBT32( aMask.GetChecksum(), aBT32 ); 386 nCrc = rtl_crc32( nCrc, aBT32, 4 ); 387 } 388 389 return nCrc; 390 } 391 392 // ------------------------------------------------------------------ 393 394 void BitmapEx::SetSizePixel( const Size& rNewSize, sal_uInt32 nScaleFlag ) 395 { 396 if(GetSizePixel() != rNewSize) 397 { 398 Scale( rNewSize, nScaleFlag ); 399 } 400 } 401 402 // ------------------------------------------------------------------ 403 404 sal_Bool BitmapEx::Invert() 405 { 406 sal_Bool bRet = sal_False; 407 408 if( !!aBitmap ) 409 { 410 bRet = aBitmap.Invert(); 411 412 if( bRet && ( eTransparent == TRANSPARENT_COLOR ) ) 413 aTransparentColor = BitmapColor( aTransparentColor ).Invert(); 414 } 415 416 return bRet; 417 } 418 419 // ------------------------------------------------------------------ 420 421 sal_Bool BitmapEx::Mirror( sal_uLong nMirrorFlags ) 422 { 423 sal_Bool bRet = sal_False; 424 425 if( !!aBitmap ) 426 { 427 bRet = aBitmap.Mirror( nMirrorFlags ); 428 429 if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask ) 430 aMask.Mirror( nMirrorFlags ); 431 } 432 433 return bRet; 434 } 435 436 // ------------------------------------------------------------------ 437 438 sal_Bool BitmapEx::Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag ) 439 { 440 sal_Bool bRet = sal_False; 441 442 if( !!aBitmap ) 443 { 444 bRet = aBitmap.Scale( rScaleX, rScaleY, nScaleFlag ); 445 446 if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask ) 447 { 448 aMask.Scale( rScaleX, rScaleY, nScaleFlag ); 449 } 450 451 aBitmapSize = aBitmap.GetSizePixel(); 452 453 DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(), 454 "BitmapEx::Scale(): size mismatch for bitmap and alpha mask." ); 455 } 456 457 return bRet; 458 } 459 460 // ------------------------------------------------------------------------ 461 462 sal_Bool BitmapEx::Scale( const Size& rNewSize, sal_uInt32 nScaleFlag ) 463 { 464 sal_Bool bRet; 465 466 if( aBitmapSize.Width() && aBitmapSize.Height() ) 467 { 468 bRet = Scale( (double) rNewSize.Width() / aBitmapSize.Width(), 469 (double) rNewSize.Height() / aBitmapSize.Height(), 470 nScaleFlag ); 471 } 472 else 473 bRet = sal_True; 474 475 return bRet; 476 } 477 478 // ------------------------------------------------------------------ 479 480 sal_Bool BitmapEx::Rotate( long nAngle10, const Color& rFillColor ) 481 { 482 sal_Bool bRet = sal_False; 483 484 if( !!aBitmap ) 485 { 486 const sal_Bool bTransRotate = ( Color( COL_TRANSPARENT ) == rFillColor ); 487 488 if( bTransRotate ) 489 { 490 if( eTransparent == TRANSPARENT_COLOR ) 491 bRet = aBitmap.Rotate( nAngle10, aTransparentColor ); 492 else 493 { 494 bRet = aBitmap.Rotate( nAngle10, COL_BLACK ); 495 496 if( eTransparent == TRANSPARENT_NONE ) 497 { 498 aMask = Bitmap( aBitmapSize, 1 ); 499 aMask.Erase( COL_BLACK ); 500 eTransparent = TRANSPARENT_BITMAP; 501 } 502 503 if( bRet && !!aMask ) 504 aMask.Rotate( nAngle10, COL_WHITE ); 505 } 506 } 507 else 508 { 509 bRet = aBitmap.Rotate( nAngle10, rFillColor ); 510 511 if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask ) 512 aMask.Rotate( nAngle10, COL_WHITE ); 513 } 514 515 aBitmapSize = aBitmap.GetSizePixel(); 516 517 DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(), 518 "BitmapEx::Rotate(): size mismatch for bitmap and alpha mask." ); 519 } 520 521 return bRet; 522 } 523 524 // ------------------------------------------------------------------ 525 526 sal_Bool BitmapEx::Crop( const Rectangle& rRectPixel ) 527 { 528 sal_Bool bRet = sal_False; 529 530 if( !!aBitmap ) 531 { 532 bRet = aBitmap.Crop( rRectPixel ); 533 534 if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask ) 535 aMask.Crop( rRectPixel ); 536 537 aBitmapSize = aBitmap.GetSizePixel(); 538 539 DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(), 540 "BitmapEx::Crop(): size mismatch for bitmap and alpha mask." ); 541 } 542 543 return bRet; 544 } 545 546 // ------------------------------------------------------------------ 547 548 sal_Bool BitmapEx::Convert( BmpConversion eConversion ) 549 { 550 return( !!aBitmap ? aBitmap.Convert( eConversion ) : sal_False ); 551 } 552 553 // ------------------------------------------------------------------ 554 555 sal_Bool BitmapEx::ReduceColors( sal_uInt16 nNewColorCount, BmpReduce eReduce ) 556 { 557 return( !!aBitmap ? aBitmap.ReduceColors( nNewColorCount, eReduce ) : sal_False ); 558 } 559 560 // ------------------------------------------------------------------ 561 562 sal_Bool BitmapEx::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor, sal_Bool bExpandTransparent ) 563 { 564 sal_Bool bRet = sal_False; 565 566 if( !!aBitmap ) 567 { 568 bRet = aBitmap.Expand( nDX, nDY, pInitColor ); 569 570 if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask ) 571 { 572 Color aColor( bExpandTransparent ? COL_WHITE : COL_BLACK ); 573 aMask.Expand( nDX, nDY, &aColor ); 574 } 575 576 aBitmapSize = aBitmap.GetSizePixel(); 577 578 DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(), 579 "BitmapEx::Expand(): size mismatch for bitmap and alpha mask." ); 580 } 581 582 return bRet; 583 } 584 585 // ------------------------------------------------------------------ 586 587 sal_Bool BitmapEx::CopyPixel( const Rectangle& rRectDst, const Rectangle& rRectSrc, 588 const BitmapEx* pBmpExSrc ) 589 { 590 sal_Bool bRet = sal_False; 591 592 if( !pBmpExSrc || pBmpExSrc->IsEmpty() ) 593 { 594 if( !aBitmap.IsEmpty() ) 595 { 596 bRet = aBitmap.CopyPixel( rRectDst, rRectSrc ); 597 598 if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask ) 599 aMask.CopyPixel( rRectDst, rRectSrc ); 600 } 601 } 602 else 603 { 604 if( !aBitmap.IsEmpty() ) 605 { 606 bRet = aBitmap.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aBitmap ); 607 608 if( bRet ) 609 { 610 if( pBmpExSrc->IsAlpha() ) 611 { 612 if( IsAlpha() ) 613 // cast to use the optimized AlphaMask::CopyPixel 614 ((AlphaMask*) &aMask)->CopyPixel( rRectDst, rRectSrc, (AlphaMask*)&pBmpExSrc->aMask ); 615 else if( IsTransparent() ) 616 { 617 AlphaMask* pAlpha = new AlphaMask( aMask ); 618 619 aMask = pAlpha->ImplGetBitmap(); 620 delete pAlpha; 621 bAlpha = sal_True; 622 aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask ); 623 } 624 else 625 { 626 sal_uInt8 cBlack = 0; 627 AlphaMask* pAlpha = new AlphaMask( GetSizePixel(), &cBlack ); 628 629 aMask = pAlpha->ImplGetBitmap(); 630 delete pAlpha; 631 eTransparent = TRANSPARENT_BITMAP; 632 bAlpha = sal_True; 633 aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask ); 634 } 635 } 636 else if( pBmpExSrc->IsTransparent() ) 637 { 638 if( IsAlpha() ) 639 { 640 AlphaMask aAlpha( pBmpExSrc->aMask ); 641 aMask.CopyPixel( rRectDst, rRectSrc, &aAlpha.ImplGetBitmap() ); 642 } 643 else if( IsTransparent() ) 644 aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask ); 645 else 646 { 647 aMask = Bitmap( GetSizePixel(), 1 ); 648 aMask.Erase( Color( COL_BLACK ) ); 649 eTransparent = TRANSPARENT_BITMAP; 650 aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask ); 651 } 652 } 653 else if( IsAlpha() ) 654 { 655 sal_uInt8 cBlack = 0; 656 const AlphaMask aAlphaSrc( pBmpExSrc->GetSizePixel(), &cBlack ); 657 658 aMask.CopyPixel( rRectDst, rRectSrc, &aAlphaSrc.ImplGetBitmap() ); 659 } 660 else if( IsTransparent() ) 661 { 662 Bitmap aMaskSrc( pBmpExSrc->GetSizePixel(), 1 ); 663 664 aMaskSrc.Erase( Color( COL_BLACK ) ); 665 aMask.CopyPixel( rRectDst, rRectSrc, &aMaskSrc ); 666 } 667 } 668 } 669 } 670 671 return bRet; 672 } 673 674 // ------------------------------------------------------------------ 675 676 sal_Bool BitmapEx::Erase( const Color& rFillColor ) 677 { 678 sal_Bool bRet = sal_False; 679 680 if( !!aBitmap ) 681 { 682 bRet = aBitmap.Erase( rFillColor ); 683 684 if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask ) 685 { 686 // #104416# Respect transparency on fill color 687 if( rFillColor.GetTransparency() ) 688 { 689 const Color aFill( rFillColor.GetTransparency(), rFillColor.GetTransparency(), rFillColor.GetTransparency() ); 690 aMask.Erase( aFill ); 691 } 692 else 693 { 694 const Color aBlack( COL_BLACK ); 695 aMask.Erase( aBlack ); 696 } 697 } 698 } 699 700 return bRet; 701 } 702 703 // ------------------------------------------------------------------ 704 705 sal_Bool BitmapEx::Dither( sal_uLong nDitherFlags ) 706 { 707 return( !!aBitmap ? aBitmap.Dither( nDitherFlags ) : sal_False ); 708 } 709 710 // ------------------------------------------------------------------ 711 712 sal_Bool BitmapEx::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol ) 713 { 714 return( !!aBitmap ? aBitmap.Replace( rSearchColor, rReplaceColor, nTol ) : sal_False ); 715 } 716 717 // ------------------------------------------------------------------ 718 719 sal_Bool BitmapEx::Replace( const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount, const sal_uLong* pTols ) 720 { 721 return( !!aBitmap ? aBitmap.Replace( pSearchColors, pReplaceColors, nColorCount, (sal_uLong*) pTols ) : sal_False ); 722 } 723 724 // ------------------------------------------------------------------ 725 726 sal_Bool BitmapEx::Adjust( short nLuminancePercent, short nContrastPercent, 727 short nChannelRPercent, short nChannelGPercent, short nChannelBPercent, 728 double fGamma, sal_Bool bInvert ) 729 { 730 return( !!aBitmap ? aBitmap.Adjust( nLuminancePercent, nContrastPercent, 731 nChannelRPercent, nChannelGPercent, nChannelBPercent, 732 fGamma, bInvert ) : sal_False ); 733 } 734 735 // ------------------------------------------------------------------ 736 737 sal_Bool BitmapEx::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress ) 738 { 739 return( !!aBitmap ? aBitmap.Filter( eFilter, pFilterParam, pProgress ) : sal_False ); 740 } 741 742 // ------------------------------------------------------------------ 743 744 void BitmapEx::Draw( OutputDevice* pOutDev, const Point& rDestPt ) const 745 { 746 pOutDev->DrawBitmapEx( rDestPt, *this ); 747 } 748 749 // ------------------------------------------------------------------ 750 751 void BitmapEx::Draw( OutputDevice* pOutDev, 752 const Point& rDestPt, const Size& rDestSize ) const 753 { 754 pOutDev->DrawBitmapEx( rDestPt, rDestSize, *this ); 755 } 756 757 // ------------------------------------------------------------------ 758 759 void BitmapEx::Draw( OutputDevice* pOutDev, 760 const Point& rDestPt, const Size& rDestSize, 761 const Point& rSrcPtPixel, const Size& rSrcSizePixel ) const 762 { 763 pOutDev->DrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, *this ); 764 } 765 766 // ------------------------------------------------------------------ 767 768 sal_uInt8 BitmapEx::GetTransparency(sal_Int32 nX, sal_Int32 nY) const 769 { 770 sal_uInt8 nTransparency(0xff); 771 772 if(!aBitmap.IsEmpty()) 773 { 774 if(nX >= 0 && nX < aBitmapSize.Width() && nY >= 0 && nY < aBitmapSize.Height()) 775 { 776 switch(eTransparent) 777 { 778 case TRANSPARENT_NONE: 779 { 780 // not transparent, ergo all covered 781 nTransparency = 0x00; 782 break; 783 } 784 case TRANSPARENT_COLOR: 785 { 786 Bitmap aTestBitmap(aBitmap); 787 BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess(); 788 789 if(pRead) 790 { 791 const Color aColor = pRead->GetColor(nY, nX); 792 793 // if color is not equal to TransparentColor, we are not transparent 794 if(aColor != aTransparentColor) 795 { 796 nTransparency = 0x00; 797 } 798 799 aTestBitmap.ReleaseAccess(pRead); 800 } 801 break; 802 } 803 case TRANSPARENT_BITMAP: 804 { 805 if(!aMask.IsEmpty()) 806 { 807 Bitmap aTestBitmap(aMask); 808 BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess(); 809 810 if(pRead) 811 { 812 const BitmapColor aBitmapColor(pRead->GetPixel(nY, nX)); 813 814 if(bAlpha) 815 { 816 nTransparency = aBitmapColor.GetIndex(); 817 } 818 else 819 { 820 if(0x00 == aBitmapColor.GetIndex()) 821 { 822 nTransparency = 0x00; 823 } 824 } 825 826 aTestBitmap.ReleaseAccess(pRead); 827 } 828 } 829 break; 830 } 831 } 832 } 833 } 834 835 return nTransparency; 836 } 837 838 // ------------------------------------------------------------------ 839 840 namespace 841 { 842 Bitmap impTransformBitmap( 843 const Bitmap& rSource, 844 const Size aDestinationSize, 845 const basegfx::B2DHomMatrix& rTransform, 846 bool bSmooth) 847 { 848 Bitmap aDestination(aDestinationSize, 24); 849 BitmapWriteAccess* pWrite = aDestination.AcquireWriteAccess(); 850 851 if(pWrite) 852 { 853 //const Size aContentSizePixel(rSource.GetSizePixel()); 854 BitmapReadAccess* pRead = (const_cast< Bitmap& >(rSource)).AcquireReadAccess(); 855 856 if(pRead) 857 { 858 const Size aDestinationSizePixel(aDestination.GetSizePixel()); 859 const BitmapColor aOutside(BitmapColor(0xff, 0xff, 0xff)); 860 861 for(sal_Int32 y(0L); y < aDestinationSizePixel.getHeight(); y++) 862 { 863 for(sal_Int32 x(0L); x < aDestinationSizePixel.getWidth(); x++) 864 { 865 const basegfx::B2DPoint aSourceCoor(rTransform * basegfx::B2DPoint(x, y)); 866 867 if(bSmooth) 868 { 869 pWrite->SetPixel( 870 y, 871 x, 872 pRead->GetInterpolatedColorWithFallback( 873 aSourceCoor.getY(), 874 aSourceCoor.getX(), 875 aOutside)); 876 } 877 else 878 { 879 // this version does the correct <= 0.0 checks, so no need 880 // to do the static_cast< sal_Int32 > self and make an error 881 pWrite->SetPixel( 882 y, 883 x, 884 pRead->GetColorWithFallback( 885 aSourceCoor.getY(), 886 aSourceCoor.getX(), 887 aOutside)); 888 } 889 } 890 } 891 892 delete pRead; 893 } 894 895 delete pWrite; 896 } 897 898 rSource.AdaptBitCount(aDestination); 899 900 return aDestination; 901 } 902 } // end of anonymous namespace 903 904 BitmapEx BitmapEx::TransformBitmapEx( 905 double fWidth, 906 double fHeight, 907 const basegfx::B2DHomMatrix& rTransformation, 908 bool bSmooth) const 909 { 910 if(fWidth <= 1 || fHeight <= 1) 911 return BitmapEx(); 912 913 // force destination to 24 bit, we want to smooth output 914 const Size aDestinationSize(basegfx::fround(fWidth), basegfx::fround(fHeight)); 915 const Bitmap aDestination(impTransformBitmap(GetBitmap(), aDestinationSize, rTransformation, bSmooth)); 916 917 // create mask 918 if(IsTransparent()) 919 { 920 if(IsAlpha()) 921 { 922 const Bitmap aAlpha(impTransformBitmap(GetAlpha().GetBitmap(), aDestinationSize, rTransformation, bSmooth)); 923 return BitmapEx(aDestination, AlphaMask(aAlpha)); 924 } 925 else 926 { 927 const Bitmap aMask(impTransformBitmap(GetMask(), aDestinationSize, rTransformation, false)); 928 return BitmapEx(aDestination, aMask); 929 } 930 } 931 932 return BitmapEx(aDestination); 933 } 934 935 // ------------------------------------------------------------------ 936 937 BitmapEx BitmapEx::getTransformed( 938 const basegfx::B2DHomMatrix& rTransformation, 939 const basegfx::B2DRange& rVisibleRange, 940 double fMaximumArea, 941 bool bSmooth) const 942 { 943 BitmapEx aRetval; 944 945 if(IsEmpty()) 946 return aRetval; 947 948 const sal_uInt32 nSourceWidth(GetSizePixel().Width()); 949 const sal_uInt32 nSourceHeight(GetSizePixel().Height()); 950 951 if(!nSourceWidth || !nSourceHeight) 952 return aRetval; 953 954 // Get aOutlineRange 955 basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0); 956 957 aOutlineRange.transform(rTransformation); 958 959 // create visible range from it by moving from relative to absolute 960 basegfx::B2DRange aVisibleRange(rVisibleRange); 961 962 aVisibleRange.transform( 963 basegfx::tools::createScaleTranslateB2DHomMatrix( 964 aOutlineRange.getRange(), 965 aOutlineRange.getMinimum())); 966 967 // get target size (which is visible range's size) 968 double fWidth(aVisibleRange.getWidth()); 969 double fHeight(aVisibleRange.getHeight()); 970 971 if(fWidth < 1.0 || fHeight < 1.0) 972 { 973 return aRetval; 974 } 975 976 // test if discrete size (pixel) maybe too big and limit it 977 const double fArea(fWidth * fHeight); 978 const bool bNeedToReduce(basegfx::fTools::more(fArea, fMaximumArea)); 979 double fReduceFactor(1.0); 980 981 if(bNeedToReduce) 982 { 983 fReduceFactor = sqrt(fMaximumArea / fArea); 984 fWidth *= fReduceFactor; 985 fHeight *= fReduceFactor; 986 } 987 988 // Build complete transform from source pixels to target pixels. 989 // Start by scaling from source pixel size to unit coordinates 990 basegfx::B2DHomMatrix aTransform( 991 basegfx::tools::createScaleB2DHomMatrix( 992 1.0 / nSourceWidth, 993 1.0 / nSourceHeight)); 994 995 // multiply with given transform which leads from unit coordinates inside 996 // aOutlineRange 997 aTransform = rTransformation * aTransform; 998 999 // subtract top-left of absolute VisibleRange 1000 aTransform.translate( 1001 -aVisibleRange.getMinX(), 1002 -aVisibleRange.getMinY()); 1003 1004 // scale to target pixels (if needed) 1005 if(bNeedToReduce) 1006 { 1007 aTransform.scale(fReduceFactor, fReduceFactor); 1008 } 1009 1010 // invert to get transformation from target pixel coordinates to source pixels 1011 aTransform.invert(); 1012 1013 // create bitmap using source, destination and linear back-transformation 1014 aRetval = TransformBitmapEx(fWidth, fHeight, aTransform, bSmooth); 1015 1016 return aRetval; 1017 } 1018 1019 // ------------------------------------------------------------------ 1020 1021 BitmapEx BitmapEx::ModifyBitmapEx(const basegfx::BColorModifierStack& rBColorModifierStack) const 1022 { 1023 Bitmap aChangedBitmap(GetBitmap()); 1024 bool bDone(false); 1025 1026 for(sal_uInt32 a(rBColorModifierStack.count()); a && !bDone; ) 1027 { 1028 const basegfx::BColorModifierSharedPtr& rModifier = rBColorModifierStack.getBColorModifier(--a); 1029 const basegfx::BColorModifier_replace* pReplace = dynamic_cast< const basegfx::BColorModifier_replace* >(rModifier.get()); 1030 1031 if(pReplace) 1032 { 1033 // complete replace 1034 if(IsTransparent()) 1035 { 1036 // clear bitmap with dest color 1037 if(aChangedBitmap.GetBitCount() <= 8) 1038 { 1039 // do NOT use erase; for e.g. 8bit Bitmaps, the nearest color to the given 1040 // erase color is determined and used -> this may be different from what is 1041 // wanted here. Better create a new bitmap with the needed color explicitly 1042 BitmapReadAccess* pReadAccess = aChangedBitmap.AcquireReadAccess(); 1043 OSL_ENSURE(pReadAccess, "Got no Bitmap ReadAccess ?!?"); 1044 1045 if(pReadAccess) 1046 { 1047 BitmapPalette aNewPalette(pReadAccess->GetPalette()); 1048 aNewPalette[0] = BitmapColor(Color(pReplace->getBColor())); 1049 aChangedBitmap = Bitmap( 1050 aChangedBitmap.GetSizePixel(), 1051 aChangedBitmap.GetBitCount(), 1052 &aNewPalette); 1053 delete pReadAccess; 1054 } 1055 } 1056 else 1057 { 1058 aChangedBitmap.Erase(Color(pReplace->getBColor())); 1059 } 1060 } 1061 else 1062 { 1063 // erase bitmap, caller will know to paint direct 1064 aChangedBitmap.SetEmpty(); 1065 } 1066 1067 bDone = true; 1068 } 1069 else 1070 { 1071 BitmapWriteAccess* pContent = aChangedBitmap.AcquireWriteAccess(); 1072 1073 if(pContent) 1074 { 1075 const double fConvertColor(1.0 / 255.0); 1076 1077 if(pContent->HasPalette()) 1078 { 1079 const sal_uInt16 nCount(pContent->GetPaletteEntryCount()); 1080 1081 for(sal_uInt16 a(0); a < nCount; a++) 1082 { 1083 const BitmapColor& rCol = pContent->GetPaletteColor(a); 1084 const basegfx::BColor aBSource( 1085 rCol.GetRed() * fConvertColor, 1086 rCol.GetGreen() * fConvertColor, 1087 rCol.GetBlue() * fConvertColor); 1088 const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource)); 1089 pContent->SetPaletteColor(a, BitmapColor(Color(aBDest))); 1090 } 1091 } 1092 else if(BMP_FORMAT_24BIT_TC_BGR == pContent->GetScanlineFormat()) 1093 { 1094 for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++) 1095 { 1096 Scanline pScan = pContent->GetScanline(y); 1097 1098 for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++) 1099 { 1100 const basegfx::BColor aBSource( 1101 *(pScan + 2)* fConvertColor, 1102 *(pScan + 1) * fConvertColor, 1103 *pScan * fConvertColor); 1104 const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource)); 1105 *pScan++ = static_cast< sal_uInt8 >(aBDest.getBlue() * 255.0); 1106 *pScan++ = static_cast< sal_uInt8 >(aBDest.getGreen() * 255.0); 1107 *pScan++ = static_cast< sal_uInt8 >(aBDest.getRed() * 255.0); 1108 } 1109 } 1110 } 1111 else if(BMP_FORMAT_24BIT_TC_RGB == pContent->GetScanlineFormat()) 1112 { 1113 for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++) 1114 { 1115 Scanline pScan = pContent->GetScanline(y); 1116 1117 for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++) 1118 { 1119 const basegfx::BColor aBSource( 1120 *pScan * fConvertColor, 1121 *(pScan + 1) * fConvertColor, 1122 *(pScan + 2) * fConvertColor); 1123 const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource)); 1124 *pScan++ = static_cast< sal_uInt8 >(aBDest.getRed() * 255.0); 1125 *pScan++ = static_cast< sal_uInt8 >(aBDest.getGreen() * 255.0); 1126 *pScan++ = static_cast< sal_uInt8 >(aBDest.getBlue() * 255.0); 1127 } 1128 } 1129 } 1130 else 1131 { 1132 for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++) 1133 { 1134 for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++) 1135 { 1136 const BitmapColor aBMCol(pContent->GetColor(y, x)); 1137 const basegfx::BColor aBSource( 1138 (double)aBMCol.GetRed() * fConvertColor, 1139 (double)aBMCol.GetGreen() * fConvertColor, 1140 (double)aBMCol.GetBlue() * fConvertColor); 1141 const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource)); 1142 1143 pContent->SetPixel(y, x, BitmapColor(Color(aBDest))); 1144 } 1145 } 1146 } 1147 1148 delete pContent; 1149 } 1150 } 1151 } 1152 1153 if(aChangedBitmap.IsEmpty()) 1154 { 1155 return BitmapEx(); 1156 } 1157 else 1158 { 1159 if(IsTransparent()) 1160 { 1161 if(IsAlpha()) 1162 { 1163 return BitmapEx(aChangedBitmap, GetAlpha()); 1164 } 1165 else 1166 { 1167 return BitmapEx(aChangedBitmap, GetMask()); 1168 } 1169 } 1170 else 1171 { 1172 return BitmapEx(aChangedBitmap); 1173 } 1174 } 1175 } 1176 1177 // ----------------------------------------------------------------------------- 1178 1179 BitmapEx VCL_DLLPUBLIC createBlendFrame( 1180 const Size& rSize, 1181 sal_uInt8 nAlpha, 1182 Color aColorTopLeft, 1183 Color aColorBottomRight) 1184 { 1185 const sal_uInt32 nW(rSize.Width()); 1186 const sal_uInt32 nH(rSize.Height()); 1187 1188 if(nW || nH) 1189 { 1190 Color aColTopRight(aColorTopLeft); 1191 Color aColBottomLeft(aColorTopLeft); 1192 const sal_uInt32 nDE(nW + nH); 1193 1194 aColTopRight.Merge(aColorBottomRight, 255 - sal_uInt8((nW * 255) / nDE)); 1195 aColBottomLeft.Merge(aColorBottomRight, 255 - sal_uInt8((nH * 255) / nDE)); 1196 1197 return createBlendFrame(rSize, nAlpha, aColorTopLeft, aColTopRight, aColorBottomRight, aColBottomLeft); 1198 } 1199 1200 return BitmapEx(); 1201 } 1202 1203 BitmapEx VCL_DLLPUBLIC createBlendFrame( 1204 const Size& rSize, 1205 sal_uInt8 nAlpha, 1206 Color aColorTopLeft, 1207 Color aColorTopRight, 1208 Color aColorBottomRight, 1209 Color aColorBottomLeft) 1210 { 1211 static Size aLastSize(0, 0); 1212 static sal_uInt8 nLastAlpha(0); 1213 static Color aLastColorTopLeft(COL_BLACK); 1214 static Color aLastColorTopRight(COL_BLACK); 1215 static Color aLastColorBottomRight(COL_BLACK); 1216 static Color aLastColorBottomLeft(COL_BLACK); 1217 static BitmapEx aLastResult; 1218 1219 if(aLastSize == rSize 1220 && nLastAlpha == nAlpha 1221 && aLastColorTopLeft == aColorTopLeft 1222 && aLastColorTopRight == aColorTopRight 1223 && aLastColorBottomRight == aColorBottomRight 1224 && aLastColorBottomLeft == aColorBottomLeft) 1225 { 1226 return aLastResult; 1227 } 1228 1229 aLastSize = rSize; 1230 nLastAlpha = nAlpha; 1231 aLastColorTopLeft = aColorTopLeft; 1232 aLastColorTopRight = aColorTopRight; 1233 aLastColorBottomRight = aColorBottomRight; 1234 aLastColorBottomLeft = aColorBottomLeft; 1235 aLastResult.Clear(); 1236 1237 const long nW(rSize.Width()); 1238 const long nH(rSize.Height()); 1239 1240 if(nW && nH) 1241 { 1242 sal_uInt8 aEraseTrans(0xff); 1243 Bitmap aContent(rSize, 24); 1244 AlphaMask aAlpha(rSize, &aEraseTrans); 1245 1246 aContent.Erase(COL_BLACK); 1247 1248 BitmapWriteAccess* pContent = aContent.AcquireWriteAccess(); 1249 BitmapWriteAccess* pAlpha = aAlpha.AcquireWriteAccess(); 1250 1251 if(pContent && pAlpha) 1252 { 1253 long x(0); 1254 long y(0); 1255 1256 // x == 0, y == 0, top-left corner 1257 pContent->SetPixel(0, 0, aColorTopLeft); 1258 pAlpha->SetPixelIndex(0, 0, nAlpha); 1259 1260 // y == 0, top line left to right 1261 for(x = 1; x < nW - 1; x++) 1262 { 1263 Color aMix(aColorTopLeft); 1264 1265 aMix.Merge(aColorTopRight, 255 - sal_uInt8((x * 255) / nW)); 1266 pContent->SetPixel(0, x, aMix); 1267 pAlpha->SetPixelIndex(0, x, nAlpha); 1268 } 1269 1270 // x == nW - 1, y == 0, top-right corner 1271 // #123690# Caution! When nW is 1, x == nW is possible (!) 1272 if(x < nW) 1273 { 1274 pContent->SetPixel(0, x, aColorTopRight); 1275 pAlpha->SetPixelIndex(0, x, nAlpha); 1276 } 1277 1278 // x == 0 and nW - 1, left and right line top-down 1279 for(y = 1; y < nH - 1; y++) 1280 { 1281 Color aMixA(aColorTopLeft); 1282 1283 aMixA.Merge(aColorBottomLeft, 255 - sal_uInt8((y * 255) / nH)); 1284 pContent->SetPixel(y, 0, aMixA); 1285 pAlpha->SetPixelIndex(y, 0, nAlpha); 1286 1287 // #123690# Caution! When nW is 1, x == nW is possible (!) 1288 if(x < nW) 1289 { 1290 Color aMixB(aColorTopRight); 1291 1292 aMixB.Merge(aColorBottomRight, 255 - sal_uInt8((y * 255) / nH)); 1293 pContent->SetPixel(y, x, aMixB); 1294 pAlpha->SetPixelIndex(y, x, nAlpha); 1295 } 1296 } 1297 1298 // #123690# Caution! When nH is 1, y == nH is possible (!) 1299 if(y < nH) 1300 { 1301 // x == 0, y == nH - 1, bottom-left corner 1302 pContent->SetPixel(y, 0, aColorBottomLeft); 1303 pAlpha->SetPixelIndex(y, 0, nAlpha); 1304 1305 // y == nH - 1, bottom line left to right 1306 for(x = 1; x < nW - 1; x++) 1307 { 1308 Color aMix(aColorBottomLeft); 1309 1310 aMix.Merge(aColorBottomRight, 255 - sal_uInt8(((x - 0)* 255) / nW)); 1311 pContent->SetPixel(y, x, aMix); 1312 pAlpha->SetPixelIndex(y, x, nAlpha); 1313 } 1314 1315 // x == nW - 1, y == nH - 1, bottom-right corner 1316 // #123690# Caution! When nW is 1, x == nW is possible (!) 1317 if(x < nW) 1318 { 1319 pContent->SetPixel(y, x, aColorBottomRight); 1320 pAlpha->SetPixelIndex(y, x, nAlpha); 1321 } 1322 } 1323 1324 aContent.ReleaseAccess(pContent); 1325 aAlpha.ReleaseAccess(pAlpha); 1326 1327 aLastResult = BitmapEx(aContent, aAlpha); 1328 } 1329 else 1330 { 1331 if(pContent) 1332 { 1333 aContent.ReleaseAccess(pContent); 1334 } 1335 1336 if(pAlpha) 1337 { 1338 aAlpha.ReleaseAccess(pAlpha); 1339 } 1340 } 1341 } 1342 1343 return aLastResult; 1344 } 1345 1346 /* vim: set noet sw=4 ts=4: */ 1347