1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_svx.hxx" 30 31 #include <sot/factory.hxx> 32 #include <tools/urlobj.hxx> 33 #include <unotools/ucbstreamhelper.hxx> 34 #include <vcl/bmpacc.hxx> 35 #include <tools/poly.hxx> 36 #include <vcl/virdev.hxx> 37 #include <vcl/wrkwin.hxx> 38 #include <svl/solar.hrc> 39 #include <sfx2/docfile.hxx> 40 #include <sfx2/app.hxx> 41 #include "svx/xoutbmp.hxx" 42 #include <svtools/FilterConfigItem.hxx> 43 #include <svtools/filter.hxx> 44 45 // ----------- 46 // - Defines - 47 // ----------- 48 49 #define FORMAT_BMP String(RTL_CONSTASCII_USTRINGPARAM("bmp")) 50 #define FORMAT_GIF String(RTL_CONSTASCII_USTRINGPARAM("gif")) 51 #define FORMAT_JPG String(RTL_CONSTASCII_USTRINGPARAM("jpg")) 52 #define FORMAT_PNG String(RTL_CONSTASCII_USTRINGPARAM("png")) 53 54 // -------------- 55 // - XOutBitmap - 56 // -------------- 57 58 GraphicFilter* XOutBitmap::pGrfFilter = NULL; 59 60 // ----------------------------------------------------------------------------- 61 62 BitmapEx XOutBitmap::CreateQuickDrawBitmapEx( const Graphic& rGraphic, const OutputDevice& rCompDev, 63 const MapMode& rMapMode, const Size& rLogSize, 64 const Point& rPoint, const Size& rSize ) 65 { 66 BitmapEx aRetBmp; 67 68 if( rGraphic.IsAlpha() ) 69 aRetBmp = rGraphic.GetBitmapEx(); 70 else 71 { 72 VirtualDevice aVDev( rCompDev ); 73 MapMode aMap( rMapMode ); 74 75 aMap.SetOrigin( Point() ); 76 aVDev.SetMapMode( aMap ); 77 78 Point aPoint( aVDev.LogicToPixel( rPoint ) ); 79 Size aOldSize( aVDev.LogicToPixel( rSize ) ); 80 Size aAbsSize( aOldSize ); 81 Size aQSizePix( aVDev.LogicToPixel( rLogSize ) ); 82 83 aVDev.SetMapMode( MapMode() ); 84 85 if( aOldSize.Width() < 0 ) 86 aAbsSize.Width() = -aAbsSize.Width(); 87 88 if( aOldSize.Height() < 0 ) 89 aAbsSize.Height() = -aAbsSize.Height(); 90 91 if( aVDev.SetOutputSizePixel( aAbsSize ) ) 92 { 93 Point aNewOrg( -aPoint.X(), -aPoint.Y() ); 94 const Point aNullPoint; 95 96 // horizontale Spiegelung ggf. beruecksichtigen 97 if( aOldSize.Width() < 0 ) 98 { 99 aNewOrg.X() -= aOldSize.Width(); 100 101 // und jetzt noch einen abziehen 102 aNewOrg.X()--; 103 } 104 105 // vertikale Spiegelung ggf. beruecksichtigen 106 if( rSize.Height() < 0 ) 107 { 108 aNewOrg.Y() -= aOldSize.Height(); 109 110 // und jetzt noch einen abziehen 111 aNewOrg.Y()--; 112 } 113 114 if( rGraphic.GetType() != GRAPHIC_BITMAP ) 115 { 116 rGraphic.Draw( &aVDev, aNewOrg, aQSizePix ); 117 118 const Bitmap aBmp( aVDev.GetBitmap( aNullPoint, aAbsSize ) ); 119 Bitmap aMask; 120 121 Graphic( rGraphic.GetGDIMetaFile().GetMonochromeMtf( COL_BLACK ) ).Draw( &aVDev, aNewOrg, aQSizePix ); 122 aMask = aVDev.GetBitmap( aNullPoint, aAbsSize ); 123 aRetBmp = BitmapEx( aBmp, aMask ); 124 } 125 else 126 { 127 Bitmap aBmp( rGraphic.GetBitmap() ); 128 129 // UNX has got problems with 1x1 bitmaps which are transparent (KA 02.11.1998) 130 #ifdef UNX 131 const Size aBmpSize( aBmp.GetSizePixel() ); 132 sal_Bool bFullTrans = sal_False; 133 134 if( aBmpSize.Width() == 1 && aBmpSize.Height() == 1 && rGraphic.IsTransparent() ) 135 { 136 Bitmap aTrans( rGraphic.GetBitmapEx().GetMask() ); 137 BitmapReadAccess* pMAcc = aBmp.AcquireReadAccess(); 138 139 if( pMAcc ) 140 { 141 if( pMAcc->GetColor( 0, 0 ) == BitmapColor( Color( COL_WHITE ) ) ) 142 bFullTrans = sal_True; 143 144 aTrans.ReleaseAccess( pMAcc ); 145 } 146 } 147 148 if( !bFullTrans ) 149 #endif // UNX 150 151 { 152 DitherBitmap( aBmp ); 153 aVDev.DrawBitmap( aNewOrg, aQSizePix, aBmp ); 154 aBmp = aVDev.GetBitmap( aNullPoint, aAbsSize ); 155 156 if( !rGraphic.IsTransparent() ) 157 aRetBmp = BitmapEx( aBmp ); 158 else 159 { 160 Bitmap aTrans( rGraphic.GetBitmapEx().GetMask() ); 161 162 if( !aTrans ) 163 aRetBmp = BitmapEx( aBmp, rGraphic.GetBitmapEx().GetTransparentColor() ); 164 else 165 { 166 aVDev.DrawBitmap( aNewOrg, aQSizePix, aTrans ); 167 aRetBmp = BitmapEx( aBmp, aVDev.GetBitmap( Point(), aAbsSize ) ); 168 } 169 } 170 } 171 } 172 } 173 } 174 175 return aRetBmp; 176 } 177 178 // ------------------------------------------------------------------------ 179 180 void XOutBitmap::DrawQuickDrawBitmapEx( OutputDevice* pOutDev, const Point& rPt, 181 const Size& rSize, const BitmapEx& rBmpEx ) 182 { 183 const Size aBmpSizePix( rBmpEx.GetSizePixel() ); 184 const Size aSizePix( pOutDev->LogicToPixel( rSize ) ); 185 186 if ( ( aSizePix.Width() - aBmpSizePix.Width() ) || ( aSizePix.Height() - aBmpSizePix.Height() ) ) 187 rBmpEx.Draw( pOutDev, rPt, rSize ); 188 else 189 rBmpEx.Draw( pOutDev, rPt ); 190 } 191 192 // ------------------------------------------------------------------------ 193 194 void XOutBitmap::DrawTiledBitmapEx( OutputDevice* pOutDev, 195 const Point& rStartPt, const Size& rGrfSize, 196 const Rectangle& rTileRect, const BitmapEx& rBmpEx ) 197 { 198 Rectangle aClipRect( pOutDev->LogicToPixel( pOutDev->GetClipRegion().GetBoundRect() ) ); 199 Rectangle aPixRect( pOutDev->LogicToPixel( rTileRect ) ); 200 const Size aPixSize( pOutDev->LogicToPixel( rGrfSize ) ); 201 const Point aPixPoint( pOutDev->LogicToPixel( rStartPt ) ); 202 Point aOrg; 203 const long nWidth = aPixSize.Width(); 204 const long nHeight = aPixSize.Height(); 205 long nXPos = aPixPoint.X() + ( ( aPixRect.Left() - aPixPoint.X() ) / nWidth ) * nWidth; 206 long nYPos = aPixPoint.Y() + ( ( aPixRect.Top() - aPixPoint.Y() ) / nHeight ) * nHeight; 207 const long nBottom = aPixRect.Bottom(); 208 const long nRight = aPixRect.Right(); 209 const long nLeft = nXPos; 210 const sal_Bool bNoSize = ( aPixSize == rBmpEx.GetSizePixel() ); 211 212 pOutDev->Push(); 213 pOutDev->SetMapMode( MapMode() ); 214 215 // ggf. neue ClipRegion berechnen und setzen 216 if ( pOutDev->IsClipRegion() ) 217 aPixRect.Intersection( aClipRect ); 218 219 pOutDev->SetClipRegion( aPixRect ); 220 221 while( nYPos <= nBottom ) 222 { 223 while( nXPos <= nRight ) 224 { 225 if ( bNoSize ) 226 rBmpEx.Draw( pOutDev, Point( nXPos, nYPos ) ); 227 else 228 rBmpEx.Draw( pOutDev, Point( nXPos, nYPos ), aPixSize ); 229 230 nXPos += nWidth; 231 } 232 233 nXPos = nLeft; 234 nYPos += nHeight; 235 } 236 237 pOutDev->Pop(); 238 } 239 240 // ------------------------------------------------------------------------ 241 242 Animation XOutBitmap::MirrorAnimation( const Animation& rAnimation, sal_Bool bHMirr, sal_Bool bVMirr ) 243 { 244 Animation aNewAnim( rAnimation ); 245 246 if( bHMirr || bVMirr ) 247 { 248 const Size& rGlobalSize = aNewAnim.GetDisplaySizePixel(); 249 sal_uIntPtr nMirrorFlags = 0L; 250 251 if( bHMirr ) 252 nMirrorFlags |= BMP_MIRROR_HORZ; 253 254 if( bVMirr ) 255 nMirrorFlags |= BMP_MIRROR_VERT; 256 257 for( sal_uInt16 i = 0, nCount = aNewAnim.Count(); i < nCount; i++ ) 258 { 259 AnimationBitmap aAnimBmp( aNewAnim.Get( i ) ); 260 261 // BitmapEx spiegeln 262 aAnimBmp.aBmpEx.Mirror( nMirrorFlags ); 263 264 // Die Positionen innerhalb der Gesamtbitmap 265 // muessen natuerlich auch angepasst werden 266 if( bHMirr ) 267 aAnimBmp.aPosPix.X() = rGlobalSize.Width() - aAnimBmp.aPosPix.X() - 268 aAnimBmp.aSizePix.Width(); 269 270 if( bVMirr ) 271 aAnimBmp.aPosPix.Y() = rGlobalSize.Height() - aAnimBmp.aPosPix.Y() - 272 aAnimBmp.aSizePix.Height(); 273 274 aNewAnim.Replace( aAnimBmp, i ); 275 } 276 } 277 278 return aNewAnim; 279 } 280 281 // ------------------------------------------------------------------------ 282 283 Graphic XOutBitmap::MirrorGraphic( const Graphic& rGraphic, const sal_uIntPtr nMirrorFlags ) 284 { 285 Graphic aRetGraphic; 286 287 if( nMirrorFlags ) 288 { 289 if( rGraphic.IsAnimated() ) 290 { 291 aRetGraphic = MirrorAnimation( rGraphic.GetAnimation(), 292 ( nMirrorFlags & BMP_MIRROR_HORZ ) == BMP_MIRROR_HORZ, 293 ( nMirrorFlags & BMP_MIRROR_VERT ) == BMP_MIRROR_VERT ); 294 } 295 else 296 { 297 if( rGraphic.IsTransparent() ) 298 { 299 BitmapEx aBmpEx( rGraphic.GetBitmapEx() ); 300 301 aBmpEx.Mirror( nMirrorFlags ); 302 aRetGraphic = aBmpEx; 303 } 304 else 305 { 306 Bitmap aBmp( rGraphic.GetBitmap() ); 307 308 aBmp.Mirror( nMirrorFlags ); 309 aRetGraphic = aBmp; 310 } 311 } 312 } 313 else 314 aRetGraphic = rGraphic; 315 316 return aRetGraphic; 317 } 318 319 // ------------------------------------------------------------------------ 320 321 sal_uInt16 XOutBitmap::WriteGraphic( const Graphic& rGraphic, String& rFileName, 322 const String& rFilterName, const sal_uIntPtr nFlags, 323 const Size* pMtfSize_100TH_MM ) 324 { 325 if( rGraphic.GetType() != GRAPHIC_NONE ) 326 { 327 INetURLObject aURL( rFileName ); 328 Graphic aGraphic; 329 String aExt; 330 GraphicFilter* pFilter = GraphicFilter::GetGraphicFilter(); 331 sal_uInt16 nErr = GRFILTER_FILTERERROR, nFilter = GRFILTER_FORMAT_NOTFOUND; 332 sal_Bool bTransparent = rGraphic.IsTransparent(), bAnimated = rGraphic.IsAnimated(); 333 334 DBG_ASSERT( aURL.GetProtocol() != INET_PROT_NOT_VALID, "XOutBitmap::WriteGraphic(...): invalid URL" ); 335 336 // calculate correct file name 337 if( !( nFlags & XOUTBMP_DONT_EXPAND_FILENAME ) ) 338 { 339 String aName( aURL.getBase() ); 340 aName += '_'; 341 aName += String(aURL.getExtension()); 342 aName += '_'; 343 String aStr( String::CreateFromInt32( rGraphic.GetChecksum(), 16 ) ); 344 if ( aStr.GetChar(0) == '-' ) 345 aStr.SetChar(0,'m'); 346 aName += aStr; 347 aURL.setBase( aName ); 348 } 349 350 if( ( nFlags & XOUTBMP_USE_NATIVE_IF_POSSIBLE ) && 351 !( nFlags & XOUTBMP_MIRROR_HORZ ) && 352 !( nFlags & XOUTBMP_MIRROR_VERT ) && 353 ( rGraphic.GetType() != GRAPHIC_GDIMETAFILE ) && rGraphic.IsLink() ) 354 { 355 // try to write native link 356 const GfxLink aGfxLink( ( (Graphic&) rGraphic ).GetLink() ); 357 358 switch( aGfxLink.GetType() ) 359 { 360 case( GFX_LINK_TYPE_NATIVE_GIF ): aExt = FORMAT_GIF; break; 361 case( GFX_LINK_TYPE_NATIVE_JPG ): aExt = FORMAT_JPG; break; 362 case( GFX_LINK_TYPE_NATIVE_PNG ): aExt = FORMAT_PNG; break; 363 364 default: 365 break; 366 } 367 368 if( aExt.Len() ) 369 { 370 if( 0 == (nFlags & XOUTBMP_DONT_ADD_EXTENSION)) 371 aURL.setExtension( aExt ); 372 rFileName = aURL.GetMainURL( INetURLObject::NO_DECODE ); 373 374 SfxMedium aMedium( aURL.GetMainURL( INetURLObject::NO_DECODE ), STREAM_WRITE | STREAM_SHARE_DENYNONE | STREAM_TRUNC, sal_True ); 375 SvStream* pOStm = aMedium.GetOutStream(); 376 377 if( pOStm && aGfxLink.GetDataSize() && aGfxLink.GetData() ) 378 { 379 pOStm->Write( aGfxLink.GetData(), aGfxLink.GetDataSize() ); 380 aMedium.Commit(); 381 382 if( !aMedium.GetError() ) 383 nErr = GRFILTER_OK; 384 } 385 } 386 } 387 388 if( GRFILTER_OK != nErr ) 389 { 390 String aFilter( rFilterName ); 391 sal_Bool bWriteTransGrf = ( aFilter.EqualsIgnoreCaseAscii( "transgrf" ) ) || 392 ( aFilter.EqualsIgnoreCaseAscii( "gif" ) ) || 393 ( nFlags & XOUTBMP_USE_GIF_IF_POSSIBLE ) || 394 ( ( nFlags & XOUTBMP_USE_GIF_IF_SENSIBLE ) && ( bAnimated || bTransparent ) ); 395 396 // get filter and extension 397 if( bWriteTransGrf ) 398 aFilter = FORMAT_GIF; 399 400 nFilter = pFilter->GetExportFormatNumberForShortName( aFilter ); 401 402 if( GRFILTER_FORMAT_NOTFOUND == nFilter ) 403 { 404 nFilter = pFilter->GetExportFormatNumberForShortName( FORMAT_JPG ); 405 406 if( GRFILTER_FORMAT_NOTFOUND == nFilter ) 407 nFilter = pFilter->GetExportFormatNumberForShortName( FORMAT_BMP ); 408 } 409 410 if( GRFILTER_FORMAT_NOTFOUND != nFilter ) 411 { 412 aExt = pFilter->GetExportFormatShortName( nFilter ).ToLowerAscii(); 413 414 if( bWriteTransGrf ) 415 { 416 if( bAnimated ) 417 aGraphic = rGraphic; 418 else 419 { 420 if( pMtfSize_100TH_MM && ( rGraphic.GetType() != GRAPHIC_BITMAP ) ) 421 { 422 VirtualDevice aVDev; 423 const Size aSize( aVDev.LogicToPixel( *pMtfSize_100TH_MM, MAP_100TH_MM ) ); 424 425 if( aVDev.SetOutputSizePixel( aSize ) ) 426 { 427 const Wallpaper aWallpaper( aVDev.GetBackground() ); 428 const Point aPt; 429 430 aVDev.SetBackground( Wallpaper( Color( COL_BLACK ) ) ); 431 aVDev.Erase(); 432 rGraphic.Draw( &aVDev, aPt, aSize ); 433 434 const Bitmap aBitmap( aVDev.GetBitmap( aPt, aSize ) ); 435 436 aVDev.SetBackground( aWallpaper ); 437 aVDev.Erase(); 438 rGraphic.Draw( &aVDev, aPt, aSize ); 439 440 aVDev.SetRasterOp( ROP_XOR ); 441 aVDev.DrawBitmap( aPt, aSize, aBitmap ); 442 aGraphic = BitmapEx( aBitmap, aVDev.GetBitmap( aPt, aSize ) ); 443 } 444 else 445 aGraphic = rGraphic.GetBitmapEx(); 446 } 447 else 448 aGraphic = rGraphic.GetBitmapEx(); 449 } 450 } 451 else 452 { 453 if( pMtfSize_100TH_MM && ( rGraphic.GetType() != GRAPHIC_BITMAP ) ) 454 { 455 VirtualDevice aVDev; 456 const Size aSize( aVDev.LogicToPixel( *pMtfSize_100TH_MM, MAP_100TH_MM ) ); 457 458 if( aVDev.SetOutputSizePixel( aSize ) ) 459 { 460 rGraphic.Draw( &aVDev, Point(), aSize ); 461 aGraphic = aVDev.GetBitmap( Point(), aSize ); 462 } 463 else 464 aGraphic = rGraphic.GetBitmap(); 465 } 466 else 467 aGraphic = rGraphic.GetBitmap(); 468 } 469 470 // mirror? 471 if( ( nFlags & XOUTBMP_MIRROR_HORZ ) || ( nFlags & XOUTBMP_MIRROR_VERT ) ) 472 aGraphic = MirrorGraphic( aGraphic, nFlags ); 473 474 if( ( GRFILTER_FORMAT_NOTFOUND != nFilter ) && ( aGraphic.GetType() != GRAPHIC_NONE ) ) 475 { 476 if( 0 == (nFlags & XOUTBMP_DONT_ADD_EXTENSION)) 477 aURL.setExtension( aExt ); 478 rFileName = aURL.GetMainURL( INetURLObject::NO_DECODE ); 479 nErr = ExportGraphic( aGraphic, aURL, *pFilter, nFilter, NULL ); 480 } 481 } 482 } 483 484 return nErr; 485 } 486 else 487 { 488 return GRFILTER_OK; 489 } 490 } 491 492 // ------------------------------------------------------------------------ 493 494 #ifdef _MSC_VER 495 #pragma optimize ( "", off ) 496 #endif 497 498 sal_uInt16 XOutBitmap::ExportGraphic( const Graphic& rGraphic, const INetURLObject& rURL, 499 GraphicFilter& rFilter, const sal_uInt16 nFormat, 500 const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >* pFilterData ) 501 { 502 DBG_ASSERT( rURL.GetProtocol() != INET_PROT_NOT_VALID, "XOutBitmap::ExportGraphic(...): invalid URL" ); 503 504 SfxMedium aMedium( rURL.GetMainURL( INetURLObject::NO_DECODE ), STREAM_WRITE | STREAM_SHARE_DENYNONE | STREAM_TRUNC, sal_True ); 505 SvStream* pOStm = aMedium.GetOutStream(); 506 sal_uInt16 nRet = GRFILTER_IOERROR; 507 508 if( pOStm ) 509 { 510 pGrfFilter = &rFilter; 511 512 nRet = rFilter.ExportGraphic( rGraphic, rURL.GetMainURL( INetURLObject::NO_DECODE ), *pOStm, nFormat, pFilterData ); 513 514 pGrfFilter = NULL; 515 aMedium.Commit(); 516 517 if( aMedium.GetError() && ( GRFILTER_OK == nRet ) ) 518 nRet = GRFILTER_IOERROR; 519 } 520 521 return nRet; 522 } 523 524 #ifdef _MSC_VER 525 #pragma optimize ( "", on ) 526 #endif 527 528 // ------------------------------------------------------------------------ 529 530 Bitmap XOutBitmap::DetectEdges( const Bitmap& rBmp, const sal_uInt8 cThreshold ) 531 { 532 const Size aSize( rBmp.GetSizePixel() ); 533 Bitmap aRetBmp; 534 sal_Bool bRet = sal_False; 535 536 if( ( aSize.Width() > 2L ) && ( aSize.Height() > 2L ) ) 537 { 538 Bitmap aWorkBmp( rBmp ); 539 540 if( aWorkBmp.Convert( BMP_CONVERSION_8BIT_GREYS ) ) 541 { 542 Bitmap aDstBmp( aSize, 1 ); 543 BitmapReadAccess* pReadAcc = aWorkBmp.AcquireReadAccess(); 544 BitmapWriteAccess* pWriteAcc = aDstBmp.AcquireWriteAccess(); 545 546 if( pReadAcc && pWriteAcc ) 547 { 548 const long nWidth = aSize.Width(); 549 const long nWidth2 = nWidth - 2L; 550 const long nHeight = aSize.Height(); 551 const long nHeight2 = nHeight - 2L; 552 const long lThres2 = (long) cThreshold * cThreshold; 553 const BitmapColor aWhite = (sal_uInt8) pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ); 554 const BitmapColor aBlack = (sal_uInt8) pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ); 555 long nSum1; 556 long nSum2; 557 long lGray; 558 559 // Rand mit Weiss init. 560 pWriteAcc->SetLineColor( Color( COL_WHITE) ); 561 pWriteAcc->DrawLine( Point(), Point( nWidth - 1L, 0L ) ); 562 pWriteAcc->DrawLine( Point( nWidth - 1L, 0L ), Point( nWidth - 1L, nHeight - 1L ) ); 563 pWriteAcc->DrawLine( Point( nWidth - 1L, nHeight - 1L ), Point( 0L, nHeight - 1L ) ); 564 pWriteAcc->DrawLine( Point( 0, nHeight - 1L ), Point() ); 565 566 for( long nY = 0L, nY1 = 1L, nY2 = 2; nY < nHeight2; nY++, nY1++, nY2++ ) 567 { 568 for( long nX = 0L, nXDst = 1L, nXTmp; nX < nWidth2; nX++, nXDst++ ) 569 { 570 nXTmp = nX; 571 572 nSum1 = -( nSum2 = lGray = (sal_uInt8) pReadAcc->GetPixel( nY, nXTmp++ ) ); 573 nSum2 += ( (long) (sal_uInt8) pReadAcc->GetPixel( nY, nXTmp++ ) ) << 1; 574 nSum1 += ( lGray = pReadAcc->GetPixel( nY, nXTmp ) ); 575 nSum2 += lGray; 576 577 nSum1 += ( (long) (sal_uInt8) pReadAcc->GetPixel( nY1, nXTmp ) ) << 1; 578 nSum1 -= ( (long) (sal_uInt8) pReadAcc->GetPixel( nY1, nXTmp -= 2 ) ) << 1; 579 580 nSum1 += ( lGray = -(long) (sal_uInt8) pReadAcc->GetPixel( nY2, nXTmp++ ) ); 581 nSum2 += lGray; 582 nSum2 -= ( (long) (sal_uInt8) pReadAcc->GetPixel( nY2, nXTmp++ ) ) << 1; 583 nSum1 += ( lGray = (long) (sal_uInt8) pReadAcc->GetPixel( nY2, nXTmp ) ); 584 nSum2 -= lGray; 585 586 if( ( nSum1 * nSum1 + nSum2 * nSum2 ) < lThres2 ) 587 pWriteAcc->SetPixel( nY1, nXDst, aWhite ); 588 else 589 pWriteAcc->SetPixel( nY1, nXDst, aBlack ); 590 } 591 } 592 593 bRet = sal_True; 594 } 595 596 aWorkBmp.ReleaseAccess( pReadAcc ); 597 aDstBmp.ReleaseAccess( pWriteAcc ); 598 599 if( bRet ) 600 aRetBmp = aDstBmp; 601 } 602 } 603 604 if( !aRetBmp ) 605 aRetBmp = rBmp; 606 else 607 { 608 aRetBmp.SetPrefMapMode( rBmp.GetPrefMapMode() ); 609 aRetBmp.SetPrefSize( rBmp.GetPrefSize() ); 610 } 611 612 return aRetBmp; 613 }; 614 615 // ------------------------------------------------------------------------ 616 617 Polygon XOutBitmap::GetCountour( const Bitmap& rBmp, const sal_uIntPtr nFlags, 618 const sal_uInt8 cEdgeDetectThreshold, const Rectangle* pWorkRectPixel ) 619 { 620 Bitmap aWorkBmp; 621 Polygon aRetPoly; 622 Point aTmpPoint; 623 Rectangle aWorkRect( aTmpPoint, rBmp.GetSizePixel() ); 624 625 if( pWorkRectPixel ) 626 aWorkRect.Intersection( *pWorkRectPixel ); 627 628 aWorkRect.Justify(); 629 630 if( ( aWorkRect.GetWidth() > 4 ) && ( aWorkRect.GetHeight() > 4 ) ) 631 { 632 // falls Flag gesetzt, muessen wir Kanten detektieren 633 if( nFlags & XOUTBMP_CONTOUR_EDGEDETECT ) 634 aWorkBmp = DetectEdges( rBmp, cEdgeDetectThreshold ); 635 else 636 aWorkBmp = rBmp; 637 638 BitmapReadAccess* pAcc = aWorkBmp.AcquireReadAccess(); 639 640 if( pAcc ) 641 { 642 const Size& rPrefSize = aWorkBmp.GetPrefSize(); 643 const long nWidth = pAcc->Width(); 644 const long nHeight = pAcc->Height(); 645 const double fFactorX = (double) rPrefSize.Width() / nWidth; 646 const double fFactorY = (double) rPrefSize.Height() / nHeight; 647 const long nStartX1 = aWorkRect.Left() + 1L; 648 const long nEndX1 = aWorkRect.Right(); 649 const long nStartX2 = nEndX1 - 1L; 650 // const long nEndX2 = nStartX1 - 1L; 651 const long nStartY1 = aWorkRect.Top() + 1L; 652 const long nEndY1 = aWorkRect.Bottom(); 653 const long nStartY2 = nEndY1 - 1L; 654 // const long nEndY2 = nStartY1 - 1L; 655 Point* pPoints1 = NULL; 656 Point* pPoints2 = NULL; 657 long nX, nY; 658 sal_uInt16 nPolyPos = 0; 659 const BitmapColor aBlack = pAcc->GetBestMatchingColor( Color( COL_BLACK ) ); 660 661 if( nFlags & XOUTBMP_CONTOUR_VERT ) 662 { 663 pPoints1 = new Point[ nWidth ]; 664 pPoints2 = new Point[ nWidth ]; 665 666 for( nX = nStartX1; nX < nEndX1; nX++ ) 667 { 668 nY = nStartY1; 669 670 // zunaechst Zeile von Links nach Rechts durchlaufen 671 while( nY < nEndY1 ) 672 { 673 if( aBlack == pAcc->GetPixel( nY, nX ) ) 674 { 675 pPoints1[ nPolyPos ] = Point( nX, nY ); 676 nY = nStartY2; 677 678 // diese Schleife wird immer gebreaked da hier ja min. ein Pixel ist 679 while( sal_True ) 680 { 681 if( aBlack == pAcc->GetPixel( nY, nX ) ) 682 { 683 pPoints2[ nPolyPos ] = Point( nX, nY ); 684 break; 685 } 686 687 nY--; 688 } 689 690 nPolyPos++; 691 break; 692 } 693 694 nY++; 695 } 696 } 697 } 698 else 699 { 700 pPoints1 = new Point[ nHeight ]; 701 pPoints2 = new Point[ nHeight ]; 702 703 for ( nY = nStartY1; nY < nEndY1; nY++ ) 704 { 705 nX = nStartX1; 706 707 // zunaechst Zeile von Links nach Rechts durchlaufen 708 while( nX < nEndX1 ) 709 { 710 if( aBlack == pAcc->GetPixel( nY, nX ) ) 711 { 712 pPoints1[ nPolyPos ] = Point( nX, nY ); 713 nX = nStartX2; 714 715 // diese Schleife wird immer gebreaked da hier ja min. ein Pixel ist 716 while( sal_True ) 717 { 718 if( aBlack == pAcc->GetPixel( nY, nX ) ) 719 { 720 pPoints2[ nPolyPos ] = Point( nX, nY ); 721 break; 722 } 723 724 nX--; 725 } 726 727 nPolyPos++; 728 break; 729 } 730 731 nX++; 732 } 733 } 734 } 735 736 const sal_uInt16 nNewSize1 = nPolyPos << 1; 737 738 aRetPoly = Polygon( nPolyPos, pPoints1 ); 739 aRetPoly.SetSize( nNewSize1 + 1 ); 740 aRetPoly[ nNewSize1 ] = aRetPoly[ 0 ]; 741 742 for( sal_uInt16 j = nPolyPos; nPolyPos < nNewSize1; ) 743 aRetPoly[ nPolyPos++ ] = pPoints2[ --j ]; 744 745 if( ( fFactorX != 0. ) && ( fFactorY != 0. ) ) 746 aRetPoly.Scale( fFactorX, fFactorY ); 747 748 delete[] pPoints1; 749 delete[] pPoints2; 750 } 751 } 752 753 return aRetPoly; 754 }; 755 756 // ---------------- 757 // - DitherBitmap - 758 // ---------------- 759 760 sal_Bool DitherBitmap( Bitmap& rBitmap ) 761 { 762 sal_Bool bRet = sal_False; 763 764 if( ( rBitmap.GetBitCount() >= 8 ) && ( Application::GetDefaultDevice()->GetColorCount() < 257 ) ) 765 bRet = rBitmap.Dither( BMP_DITHER_FLOYD ); 766 else 767 bRet = sal_False; 768 769 return bRet; 770 } 771