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