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