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 void impSmoothPoint(BitmapColor& rValue, const basegfx::B2DPoint& rSource, sal_Int32 nIntX, sal_Int32 nIntY, BitmapReadAccess& rRead) 841 { 842 double fDeltaX(rSource.getX() - nIntX); 843 double fDeltaY(rSource.getY() - nIntY); 844 sal_Int32 nIndX(0L); 845 sal_Int32 nIndY(0L); 846 847 if(fDeltaX > 0.0 && nIntX + 1L < rRead.Width()) 848 { 849 nIndX++; 850 } 851 else if(fDeltaX < 0.0 && nIntX >= 1L) 852 { 853 fDeltaX = -fDeltaX; 854 nIndX--; 855 } 856 857 if(fDeltaY > 0.0 && nIntY + 1L < rRead.Height()) 858 { 859 nIndY++; 860 } 861 else if(fDeltaY < 0.0 && nIntY >= 1L) 862 { 863 fDeltaY = -fDeltaY; 864 nIndY--; 865 } 866 867 if(nIndX || nIndY) 868 { 869 const double fColorToReal(1.0 / 255.0); 870 double fR(rValue.GetRed() * fColorToReal); 871 double fG(rValue.GetGreen() * fColorToReal); 872 double fB(rValue.GetBlue() * fColorToReal); 873 double fRBottom(0.0), fGBottom(0.0), fBBottom(0.0); 874 875 if(nIndX) 876 { 877 const double fMulA(fDeltaX * fColorToReal); 878 double fMulB(1.0 - fDeltaX); 879 const BitmapColor aTopPartner(rRead.GetColor(nIntY, nIntX + nIndX)); 880 881 fR = (fR * fMulB) + (aTopPartner.GetRed() * fMulA); 882 fG = (fG * fMulB) + (aTopPartner.GetGreen() * fMulA); 883 fB = (fB * fMulB) + (aTopPartner.GetBlue() * fMulA); 884 885 if(nIndY) 886 { 887 fMulB *= fColorToReal; 888 const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX)); 889 const BitmapColor aBottomPartner(rRead.GetColor(nIntY + nIndY, nIntX + nIndX)); 890 891 fRBottom = (aBottom.GetRed() * fMulB) + (aBottomPartner.GetRed() * fMulA); 892 fGBottom = (aBottom.GetGreen() * fMulB) + (aBottomPartner.GetGreen() * fMulA); 893 fBBottom = (aBottom.GetBlue() * fMulB) + (aBottomPartner.GetBlue() * fMulA); 894 } 895 } 896 897 if(nIndY) 898 { 899 if(!nIndX) 900 { 901 const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX)); 902 903 fRBottom = aBottom.GetRed() * fColorToReal; 904 fGBottom = aBottom.GetGreen() * fColorToReal; 905 fBBottom = aBottom.GetBlue() * fColorToReal; 906 } 907 908 const double fMulB(1.0 - fDeltaY); 909 910 fR = (fR * fMulB) + (fRBottom * fDeltaY); 911 fG = (fG * fMulB) + (fGBottom * fDeltaY); 912 fB = (fB * fMulB) + (fBBottom * fDeltaY); 913 } 914 915 rValue.SetRed((sal_uInt8)(fR * 255.0)); 916 rValue.SetGreen((sal_uInt8)(fG * 255.0)); 917 rValue.SetBlue((sal_uInt8)(fB * 255.0)); 918 } 919 } 920 921 Bitmap impTransformBitmap( 922 const Bitmap& rSource, 923 const Size aDestinationSize, 924 const basegfx::B2DHomMatrix& rTransform, 925 bool bSmooth) 926 { 927 Bitmap aDestination(aDestinationSize, 24); 928 BitmapWriteAccess* pWrite = aDestination.AcquireWriteAccess(); 929 930 if(pWrite) 931 { 932 const Size aContentSizePixel(rSource.GetSizePixel()); 933 BitmapReadAccess* pRead = (const_cast< Bitmap& >(rSource)).AcquireReadAccess(); 934 935 if(pRead) 936 { 937 const Size aDestinationSizePixel(aDestination.GetSizePixel()); 938 bool bWorkWithIndex(rSource.GetBitCount() <= 8); 939 BitmapColor aOutside(BitmapColor(0xff, 0xff, 0xff)); 940 941 for(sal_Int32 y(0L); y < aDestinationSizePixel.getHeight(); y++) 942 { 943 for(sal_Int32 x(0L); x < aDestinationSizePixel.getWidth(); x++) 944 { 945 const basegfx::B2DPoint aSourceCoor(rTransform * basegfx::B2DPoint(x, y)); 946 const sal_Int32 nIntX(basegfx::fround(aSourceCoor.getX())); 947 948 if(nIntX >= 0L && nIntX < aContentSizePixel.getWidth()) 949 { 950 const sal_Int32 nIntY(basegfx::fround(aSourceCoor.getY())); 951 952 if(nIntY >= 0L && nIntY < aContentSizePixel.getHeight()) 953 { 954 // inside pixel 955 BitmapColor aValue; 956 957 if(bWorkWithIndex) 958 { 959 aValue = pRead->GetPaletteColor(pRead->GetPixelIndex(nIntY, nIntX)); 960 } 961 else 962 { 963 aValue = pRead->GetPixel(nIntY, nIntX); 964 } 965 966 if(bSmooth) 967 { 968 impSmoothPoint(aValue, aSourceCoor, nIntX, nIntY, *pRead); 969 } 970 971 pWrite->SetPixel(y, x, aValue); 972 continue; 973 } 974 } 975 976 // here are outside pixels. Complete mask 977 if(bWorkWithIndex) 978 { 979 pWrite->SetPixel(y, x, aOutside); 980 } 981 } 982 } 983 984 delete pRead; 985 } 986 987 delete pWrite; 988 } 989 990 rSource.AdaptBitCount(aDestination); 991 992 return aDestination; 993 } 994 } // end of anonymous namespace 995 BitmapEx BitmapEx::TransformBitmapEx( 996 double fWidth, 997 double fHeight, 998 const basegfx::B2DHomMatrix& rTransformation) const 999 { 1000 if(fWidth <= 1 || fHeight <= 1) 1001 return BitmapEx(); 1002 1003 // force destination to 24 bit, we want to smooth output 1004 const Size aDestinationSize(basegfx::fround(fWidth), basegfx::fround(fHeight)); 1005 static bool bDoSmoothAtAll(true); 1006 const Bitmap aDestination(impTransformBitmap(GetBitmap(), aDestinationSize, rTransformation, bDoSmoothAtAll)); 1007 1008 // create mask 1009 if(IsTransparent()) 1010 { 1011 if(IsAlpha()) 1012 { 1013 const Bitmap aAlpha(impTransformBitmap(GetAlpha().GetBitmap(), aDestinationSize, rTransformation, bDoSmoothAtAll)); 1014 return BitmapEx(aDestination, AlphaMask(aAlpha)); 1015 } 1016 else 1017 { 1018 const Bitmap aMask(impTransformBitmap(GetMask(), aDestinationSize, rTransformation, false)); 1019 return BitmapEx(aDestination, aMask); 1020 } 1021 } 1022 1023 return BitmapEx(aDestination); 1024 } 1025 1026 // ------------------------------------------------------------------ 1027 1028 BitmapEx BitmapEx::getTransformed( 1029 const basegfx::B2DHomMatrix& rTransformation, 1030 double fMaximumArea) const 1031 { 1032 BitmapEx aRetval; 1033 1034 if(IsEmpty()) 1035 return aRetval; 1036 1037 const sal_uInt32 nSourceWidth(GetSizePixel().Width()); 1038 const sal_uInt32 nSourceHeight(GetSizePixel().Height()); 1039 1040 if(!nSourceWidth || !nSourceHeight) 1041 return aRetval; 1042 1043 // Get dest range 1044 basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0); 1045 aOutlineRange.transform(rTransformation); 1046 1047 // get target size 1048 double fWidth(aOutlineRange.getWidth()); 1049 double fHeight(aOutlineRange.getHeight()); 1050 1051 if(fWidth < 1.0 || fHeight < 1.0) 1052 return aRetval; 1053 1054 // test if discrete size (pixel) maybe too big and limit it 1055 const double fArea(fWidth * fHeight); 1056 const bool bNeedToReduce(fArea > fMaximumArea); 1057 double fReduceFactor(1.0); 1058 1059 if(bNeedToReduce) 1060 { 1061 fReduceFactor = sqrt(fMaximumArea / fArea); 1062 fWidth *= fReduceFactor; 1063 fHeight *= fReduceFactor; 1064 } 1065 1066 // Build complete transform from source pixels to target pixels. 1067 // Start by scaling from source pixel size to unit coordinates 1068 basegfx::B2DHomMatrix aTransform( 1069 basegfx::tools::createScaleB2DHomMatrix( 1070 1.0 / nSourceWidth, 1071 1.0 / nSourceHeight)); 1072 1073 // multiply with given transform which leads from unit coordinates inside 1074 // aOutlineRange 1075 aTransform = rTransformation * aTransform; 1076 1077 // substract top-left of aOutlineRange 1078 aTransform.translate(-aOutlineRange.getMinX(), -aOutlineRange.getMinY()); 1079 1080 // scale to target pixels (if needed) 1081 if(bNeedToReduce) 1082 { 1083 aTransform.scale(fReduceFactor, fReduceFactor); 1084 } 1085 1086 // invert to get transformation from target pixel coordiates to source pixels 1087 aTransform.invert(); 1088 1089 // create bitmap using source, destination and linear back-transformation 1090 aRetval = TransformBitmapEx(fWidth, fHeight, aTransform); 1091 1092 return aRetval; 1093 } 1094 1095 // ------------------------------------------------------------------ 1096 1097 BitmapEx BitmapEx::ModifyBitmapEx(const basegfx::BColorModifierStack& rBColorModifierStack) const 1098 { 1099 Bitmap aChangedBitmap(GetBitmap()); 1100 bool bDone(false); 1101 1102 for(sal_uInt32 a(rBColorModifierStack.count()); a && !bDone; ) 1103 { 1104 const basegfx::BColorModifier& rModifier = rBColorModifierStack.getBColorModifier(--a); 1105 1106 switch(rModifier.getMode()) 1107 { 1108 case basegfx::BCOLORMODIFYMODE_REPLACE : 1109 { 1110 // complete replace 1111 if(IsTransparent()) 1112 { 1113 // clear bitmap with dest color 1114 if(aChangedBitmap.GetBitCount() <= 8) 1115 { 1116 // do NOT use erase; for e.g. 8bit Bitmaps, the nearest color to the given 1117 // erase color is determined and used -> this may be different from what is 1118 // wanted here. Better create a new bitmap with the needed color explicitely 1119 BitmapReadAccess* pReadAccess = aChangedBitmap.AcquireReadAccess(); 1120 OSL_ENSURE(pReadAccess, "Got no Bitmap ReadAccess ?!?"); 1121 1122 if(pReadAccess) 1123 { 1124 BitmapPalette aNewPalette(pReadAccess->GetPalette()); 1125 aNewPalette[0] = BitmapColor(Color(rModifier.getBColor())); 1126 aChangedBitmap = Bitmap( 1127 aChangedBitmap.GetSizePixel(), 1128 aChangedBitmap.GetBitCount(), 1129 &aNewPalette); 1130 delete pReadAccess; 1131 } 1132 } 1133 else 1134 { 1135 aChangedBitmap.Erase(Color(rModifier.getBColor())); 1136 } 1137 } 1138 else 1139 { 1140 // erase bitmap, caller will know to paint direct 1141 aChangedBitmap.SetEmpty(); 1142 } 1143 1144 bDone = true; 1145 break; 1146 } 1147 1148 default : // BCOLORMODIFYMODE_INTERPOLATE, BCOLORMODIFYMODE_GRAY, BCOLORMODIFYMODE_BLACKANDWHITE 1149 { 1150 BitmapWriteAccess* pContent = aChangedBitmap.AcquireWriteAccess(); 1151 1152 if(pContent) 1153 { 1154 const double fConvertColor(1.0 / 255.0); 1155 1156 for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++) 1157 { 1158 for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++) 1159 { 1160 const BitmapColor aBMCol(pContent->GetColor(y, x)); 1161 const basegfx::BColor aBSource( 1162 (double)aBMCol.GetRed() * fConvertColor, 1163 (double)aBMCol.GetGreen() * fConvertColor, 1164 (double)aBMCol.GetBlue() * fConvertColor); 1165 const basegfx::BColor aBDest(rModifier.getModifiedColor(aBSource)); 1166 1167 pContent->SetPixel(y, x, BitmapColor(Color(aBDest))); 1168 } 1169 } 1170 1171 delete pContent; 1172 } 1173 1174 break; 1175 } 1176 } 1177 } 1178 1179 if(aChangedBitmap.IsEmpty()) 1180 { 1181 return BitmapEx(); 1182 } 1183 else 1184 { 1185 if(IsTransparent()) 1186 { 1187 if(IsAlpha()) 1188 { 1189 return BitmapEx(aChangedBitmap, GetAlpha()); 1190 } 1191 else 1192 { 1193 return BitmapEx(aChangedBitmap, GetMask()); 1194 } 1195 } 1196 else 1197 { 1198 return BitmapEx(aChangedBitmap); 1199 } 1200 } 1201 } 1202 1203 // ------------------------------------------------------------------ 1204 // eof 1205