Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / svx / source / xoutdev / _xoutbmp.cxx
blob1bb0b38e0e2127a90da261985fc9ba03659183eb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <sot/factory.hxx>
31 #include <tools/poly.hxx>
32 #include <vcl/bmpacc.hxx>
33 #include <vcl/virdev.hxx>
34 #include <vcl/wrkwin.hxx>
35 #include <svl/solar.hrc>
36 #include <sfx2/docfile.hxx>
37 #include <sfx2/app.hxx>
38 #include "svx/xoutbmp.hxx"
39 #include <svtools/FilterConfigItem.hxx>
40 #include <svtools/filter.hxx>
42 // -----------
43 // - Defines -
44 // -----------
46 #define FORMAT_BMP String(RTL_CONSTASCII_USTRINGPARAM("bmp"))
47 #define FORMAT_GIF String(RTL_CONSTASCII_USTRINGPARAM("gif"))
48 #define FORMAT_JPG String(RTL_CONSTASCII_USTRINGPARAM("jpg"))
49 #define FORMAT_PNG String(RTL_CONSTASCII_USTRINGPARAM("png"))
51 // --------------
52 // - XOutBitmap -
53 // --------------
55 GraphicFilter* XOutBitmap::pGrfFilter = NULL;
57 // ------------------------------------------------------------------------
59 Animation XOutBitmap::MirrorAnimation( const Animation& rAnimation, sal_Bool bHMirr, sal_Bool bVMirr )
61 Animation aNewAnim( rAnimation );
63 if( bHMirr || bVMirr )
65 const Size& rGlobalSize = aNewAnim.GetDisplaySizePixel();
66 sal_uIntPtr nMirrorFlags = 0L;
68 if( bHMirr )
69 nMirrorFlags |= BMP_MIRROR_HORZ;
71 if( bVMirr )
72 nMirrorFlags |= BMP_MIRROR_VERT;
74 for( sal_uInt16 i = 0, nCount = aNewAnim.Count(); i < nCount; i++ )
76 AnimationBitmap aAnimBmp( aNewAnim.Get( i ) );
78 // BitmapEx spiegeln
79 aAnimBmp.aBmpEx.Mirror( nMirrorFlags );
81 // Die Positionen innerhalb der Gesamtbitmap
82 // muessen natuerlich auch angepasst werden
83 if( bHMirr )
84 aAnimBmp.aPosPix.X() = rGlobalSize.Width() - aAnimBmp.aPosPix.X() -
85 aAnimBmp.aSizePix.Width();
87 if( bVMirr )
88 aAnimBmp.aPosPix.Y() = rGlobalSize.Height() - aAnimBmp.aPosPix.Y() -
89 aAnimBmp.aSizePix.Height();
91 aNewAnim.Replace( aAnimBmp, i );
95 return aNewAnim;
98 // ------------------------------------------------------------------------
100 Graphic XOutBitmap::MirrorGraphic( const Graphic& rGraphic, const sal_uIntPtr nMirrorFlags )
102 Graphic aRetGraphic;
104 if( nMirrorFlags )
106 if( rGraphic.IsAnimated() )
108 aRetGraphic = MirrorAnimation( rGraphic.GetAnimation(),
109 ( nMirrorFlags & BMP_MIRROR_HORZ ) == BMP_MIRROR_HORZ,
110 ( nMirrorFlags & BMP_MIRROR_VERT ) == BMP_MIRROR_VERT );
112 else
114 if( rGraphic.IsTransparent() )
116 BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
118 aBmpEx.Mirror( nMirrorFlags );
119 aRetGraphic = aBmpEx;
121 else
123 Bitmap aBmp( rGraphic.GetBitmap() );
125 aBmp.Mirror( nMirrorFlags );
126 aRetGraphic = aBmp;
130 else
131 aRetGraphic = rGraphic;
133 return aRetGraphic;
136 // ------------------------------------------------------------------------
138 sal_uInt16 XOutBitmap::WriteGraphic( const Graphic& rGraphic, String& rFileName,
139 const String& rFilterName, const sal_uIntPtr nFlags,
140 const Size* pMtfSize_100TH_MM )
142 if( rGraphic.GetType() != GRAPHIC_NONE )
144 INetURLObject aURL( rFileName );
145 Graphic aGraphic;
146 String aExt;
147 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
148 sal_uInt16 nErr = GRFILTER_FILTERERROR, nFilter = GRFILTER_FORMAT_NOTFOUND;
149 sal_Bool bTransparent = rGraphic.IsTransparent(), bAnimated = rGraphic.IsAnimated();
151 DBG_ASSERT( aURL.GetProtocol() != INET_PROT_NOT_VALID, "XOutBitmap::WriteGraphic(...): invalid URL" );
153 // calculate correct file name
154 if( !( nFlags & XOUTBMP_DONT_EXPAND_FILENAME ) )
156 String aName( aURL.getBase() );
157 aName += '_';
158 aName += String(aURL.getExtension());
159 aName += '_';
160 String aStr( String::CreateFromInt32( rGraphic.GetChecksum(), 16 ) );
161 if ( aStr.GetChar(0) == '-' )
162 aStr.SetChar(0,'m');
163 aName += aStr;
164 aURL.setBase( aName );
167 if( ( nFlags & XOUTBMP_USE_NATIVE_IF_POSSIBLE ) &&
168 !( nFlags & XOUTBMP_MIRROR_HORZ ) &&
169 !( nFlags & XOUTBMP_MIRROR_VERT ) &&
170 ( rGraphic.GetType() != GRAPHIC_GDIMETAFILE ) && rGraphic.IsLink() )
172 // try to write native link
173 const GfxLink aGfxLink( ( (Graphic&) rGraphic ).GetLink() );
175 switch( aGfxLink.GetType() )
177 case( GFX_LINK_TYPE_NATIVE_GIF ): aExt = FORMAT_GIF; break;
178 case( GFX_LINK_TYPE_NATIVE_JPG ): aExt = FORMAT_JPG; break;
179 case( GFX_LINK_TYPE_NATIVE_PNG ): aExt = FORMAT_PNG; break;
181 default:
182 break;
185 if( aExt.Len() )
187 if( 0 == (nFlags & XOUTBMP_DONT_ADD_EXTENSION))
188 aURL.setExtension( aExt );
189 rFileName = aURL.GetMainURL( INetURLObject::NO_DECODE );
191 SfxMedium aMedium( aURL.GetMainURL( INetURLObject::NO_DECODE ), STREAM_WRITE | STREAM_SHARE_DENYNONE | STREAM_TRUNC );
192 SvStream* pOStm = aMedium.GetOutStream();
194 if( pOStm && aGfxLink.GetDataSize() && aGfxLink.GetData() )
196 pOStm->Write( aGfxLink.GetData(), aGfxLink.GetDataSize() );
197 aMedium.Commit();
199 if( !aMedium.GetError() )
200 nErr = GRFILTER_OK;
205 if( GRFILTER_OK != nErr )
207 String aFilter( rFilterName );
208 sal_Bool bWriteTransGrf = ( aFilter.EqualsIgnoreCaseAscii( "transgrf" ) ) ||
209 ( aFilter.EqualsIgnoreCaseAscii( "gif" ) ) ||
210 ( nFlags & XOUTBMP_USE_GIF_IF_POSSIBLE ) ||
211 ( ( nFlags & XOUTBMP_USE_GIF_IF_SENSIBLE ) && ( bAnimated || bTransparent ) );
213 // get filter and extension
214 if( bWriteTransGrf )
215 aFilter = FORMAT_GIF;
217 nFilter = rFilter.GetExportFormatNumberForShortName( aFilter );
219 if( GRFILTER_FORMAT_NOTFOUND == nFilter )
221 nFilter = rFilter.GetExportFormatNumberForShortName( FORMAT_JPG );
223 if( GRFILTER_FORMAT_NOTFOUND == nFilter )
224 nFilter = rFilter.GetExportFormatNumberForShortName( FORMAT_BMP );
227 if( GRFILTER_FORMAT_NOTFOUND != nFilter )
229 aExt = rFilter.GetExportFormatShortName( nFilter ).ToLowerAscii();
231 if( bWriteTransGrf )
233 if( bAnimated )
234 aGraphic = rGraphic;
235 else
237 if( pMtfSize_100TH_MM && ( rGraphic.GetType() != GRAPHIC_BITMAP ) )
239 VirtualDevice aVDev;
240 const Size aSize( aVDev.LogicToPixel( *pMtfSize_100TH_MM, MAP_100TH_MM ) );
242 if( aVDev.SetOutputSizePixel( aSize ) )
244 const Wallpaper aWallpaper( aVDev.GetBackground() );
245 const Point aPt;
247 aVDev.SetBackground( Wallpaper( Color( COL_BLACK ) ) );
248 aVDev.Erase();
249 rGraphic.Draw( &aVDev, aPt, aSize );
251 const Bitmap aBitmap( aVDev.GetBitmap( aPt, aSize ) );
253 aVDev.SetBackground( aWallpaper );
254 aVDev.Erase();
255 rGraphic.Draw( &aVDev, aPt, aSize );
257 aVDev.SetRasterOp( ROP_XOR );
258 aVDev.DrawBitmap( aPt, aSize, aBitmap );
259 aGraphic = BitmapEx( aBitmap, aVDev.GetBitmap( aPt, aSize ) );
261 else
262 aGraphic = rGraphic.GetBitmapEx();
264 else
265 aGraphic = rGraphic.GetBitmapEx();
268 else
270 if( pMtfSize_100TH_MM && ( rGraphic.GetType() != GRAPHIC_BITMAP ) )
272 VirtualDevice aVDev;
273 const Size aSize( aVDev.LogicToPixel( *pMtfSize_100TH_MM, MAP_100TH_MM ) );
275 if( aVDev.SetOutputSizePixel( aSize ) )
277 rGraphic.Draw( &aVDev, Point(), aSize );
278 aGraphic = aVDev.GetBitmap( Point(), aSize );
280 else
281 aGraphic = rGraphic.GetBitmap();
283 else
284 aGraphic = rGraphic.GetBitmap();
287 // mirror?
288 if( ( nFlags & XOUTBMP_MIRROR_HORZ ) || ( nFlags & XOUTBMP_MIRROR_VERT ) )
289 aGraphic = MirrorGraphic( aGraphic, nFlags );
291 if( ( GRFILTER_FORMAT_NOTFOUND != nFilter ) && ( aGraphic.GetType() != GRAPHIC_NONE ) )
293 if( 0 == (nFlags & XOUTBMP_DONT_ADD_EXTENSION))
294 aURL.setExtension( aExt );
295 rFileName = aURL.GetMainURL( INetURLObject::NO_DECODE );
296 nErr = ExportGraphic( aGraphic, aURL, rFilter, nFilter, NULL );
301 return nErr;
303 else
305 return GRFILTER_OK;
309 // ------------------------------------------------------------------------
311 #ifdef _MSC_VER
312 #pragma optimize ( "", off )
313 #endif
315 sal_uInt16 XOutBitmap::ExportGraphic( const Graphic& rGraphic, const INetURLObject& rURL,
316 GraphicFilter& rFilter, const sal_uInt16 nFormat,
317 const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >* pFilterData )
319 DBG_ASSERT( rURL.GetProtocol() != INET_PROT_NOT_VALID, "XOutBitmap::ExportGraphic(...): invalid URL" );
321 SfxMedium aMedium( rURL.GetMainURL( INetURLObject::NO_DECODE ), STREAM_WRITE | STREAM_SHARE_DENYNONE | STREAM_TRUNC );
322 SvStream* pOStm = aMedium.GetOutStream();
323 sal_uInt16 nRet = GRFILTER_IOERROR;
325 if( pOStm )
327 pGrfFilter = &rFilter;
329 nRet = rFilter.ExportGraphic( rGraphic, rURL.GetMainURL( INetURLObject::NO_DECODE ), *pOStm, nFormat, pFilterData );
331 pGrfFilter = NULL;
332 aMedium.Commit();
334 if( aMedium.GetError() && ( GRFILTER_OK == nRet ) )
335 nRet = GRFILTER_IOERROR;
338 return nRet;
341 #ifdef _MSC_VER
342 #pragma optimize ( "", on )
343 #endif
345 // ------------------------------------------------------------------------
347 Bitmap XOutBitmap::DetectEdges( const Bitmap& rBmp, const sal_uInt8 cThreshold )
349 const Size aSize( rBmp.GetSizePixel() );
350 Bitmap aRetBmp;
351 sal_Bool bRet = sal_False;
353 if( ( aSize.Width() > 2L ) && ( aSize.Height() > 2L ) )
355 Bitmap aWorkBmp( rBmp );
357 if( aWorkBmp.Convert( BMP_CONVERSION_8BIT_GREYS ) )
359 Bitmap aDstBmp( aSize, 1 );
360 BitmapReadAccess* pReadAcc = aWorkBmp.AcquireReadAccess();
361 BitmapWriteAccess* pWriteAcc = aDstBmp.AcquireWriteAccess();
363 if( pReadAcc && pWriteAcc )
365 const long nWidth = aSize.Width();
366 const long nWidth2 = nWidth - 2L;
367 const long nHeight = aSize.Height();
368 const long nHeight2 = nHeight - 2L;
369 const long lThres2 = (long) cThreshold * cThreshold;
370 const BitmapColor aWhite = (sal_uInt8) pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) );
371 const BitmapColor aBlack = (sal_uInt8) pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) );
372 long nSum1;
373 long nSum2;
374 long lGray;
376 // Rand mit Weiss init.
377 pWriteAcc->SetLineColor( Color( COL_WHITE) );
378 pWriteAcc->DrawLine( Point(), Point( nWidth - 1L, 0L ) );
379 pWriteAcc->DrawLine( Point( nWidth - 1L, 0L ), Point( nWidth - 1L, nHeight - 1L ) );
380 pWriteAcc->DrawLine( Point( nWidth - 1L, nHeight - 1L ), Point( 0L, nHeight - 1L ) );
381 pWriteAcc->DrawLine( Point( 0, nHeight - 1L ), Point() );
383 for( long nY = 0L, nY1 = 1L, nY2 = 2; nY < nHeight2; nY++, nY1++, nY2++ )
385 for( long nX = 0L, nXDst = 1L, nXTmp; nX < nWidth2; nX++, nXDst++ )
387 nXTmp = nX;
389 nSum1 = -( nSum2 = lGray = (sal_uInt8) pReadAcc->GetPixel( nY, nXTmp++ ) );
390 nSum2 += ( (long) (sal_uInt8) pReadAcc->GetPixel( nY, nXTmp++ ) ) << 1;
391 nSum1 += ( lGray = pReadAcc->GetPixel( nY, nXTmp ) );
392 nSum2 += lGray;
394 nSum1 += ( (long) (sal_uInt8) pReadAcc->GetPixel( nY1, nXTmp ) ) << 1;
395 nSum1 -= ( (long) (sal_uInt8) pReadAcc->GetPixel( nY1, nXTmp -= 2 ) ) << 1;
397 nSum1 += ( lGray = -(long) (sal_uInt8) pReadAcc->GetPixel( nY2, nXTmp++ ) );
398 nSum2 += lGray;
399 nSum2 -= ( (long) (sal_uInt8) pReadAcc->GetPixel( nY2, nXTmp++ ) ) << 1;
400 nSum1 += ( lGray = (long) (sal_uInt8) pReadAcc->GetPixel( nY2, nXTmp ) );
401 nSum2 -= lGray;
403 if( ( nSum1 * nSum1 + nSum2 * nSum2 ) < lThres2 )
404 pWriteAcc->SetPixel( nY1, nXDst, aWhite );
405 else
406 pWriteAcc->SetPixel( nY1, nXDst, aBlack );
410 bRet = sal_True;
413 aWorkBmp.ReleaseAccess( pReadAcc );
414 aDstBmp.ReleaseAccess( pWriteAcc );
416 if( bRet )
417 aRetBmp = aDstBmp;
421 if( !aRetBmp )
422 aRetBmp = rBmp;
423 else
425 aRetBmp.SetPrefMapMode( rBmp.GetPrefMapMode() );
426 aRetBmp.SetPrefSize( rBmp.GetPrefSize() );
429 return aRetBmp;
432 // ------------------------------------------------------------------------
434 Polygon XOutBitmap::GetCountour( const Bitmap& rBmp, const sal_uIntPtr nFlags,
435 const sal_uInt8 cEdgeDetectThreshold, const Rectangle* pWorkRectPixel )
437 Bitmap aWorkBmp;
438 Polygon aRetPoly;
439 Point aTmpPoint;
440 Rectangle aWorkRect( aTmpPoint, rBmp.GetSizePixel() );
442 if( pWorkRectPixel )
443 aWorkRect.Intersection( *pWorkRectPixel );
445 aWorkRect.Justify();
447 if( ( aWorkRect.GetWidth() > 4 ) && ( aWorkRect.GetHeight() > 4 ) )
449 // falls Flag gesetzt, muessen wir Kanten detektieren
450 if( nFlags & XOUTBMP_CONTOUR_EDGEDETECT )
451 aWorkBmp = DetectEdges( rBmp, cEdgeDetectThreshold );
452 else
453 aWorkBmp = rBmp;
455 BitmapReadAccess* pAcc = aWorkBmp.AcquireReadAccess();
457 if( pAcc )
459 const Size& rPrefSize = aWorkBmp.GetPrefSize();
460 const long nWidth = pAcc->Width();
461 const long nHeight = pAcc->Height();
462 const double fFactorX = (double) rPrefSize.Width() / nWidth;
463 const double fFactorY = (double) rPrefSize.Height() / nHeight;
464 const long nStartX1 = aWorkRect.Left() + 1L;
465 const long nEndX1 = aWorkRect.Right();
466 const long nStartX2 = nEndX1 - 1L;
467 // const long nEndX2 = nStartX1 - 1L;
468 const long nStartY1 = aWorkRect.Top() + 1L;
469 const long nEndY1 = aWorkRect.Bottom();
470 const long nStartY2 = nEndY1 - 1L;
471 // const long nEndY2 = nStartY1 - 1L;
472 Point* pPoints1 = NULL;
473 Point* pPoints2 = NULL;
474 long nX, nY;
475 sal_uInt16 nPolyPos = 0;
476 const BitmapColor aBlack = pAcc->GetBestMatchingColor( Color( COL_BLACK ) );
478 if( nFlags & XOUTBMP_CONTOUR_VERT )
480 pPoints1 = new Point[ nWidth ];
481 pPoints2 = new Point[ nWidth ];
483 for( nX = nStartX1; nX < nEndX1; nX++ )
485 nY = nStartY1;
487 // zunaechst Zeile von Links nach Rechts durchlaufen
488 while( nY < nEndY1 )
490 if( aBlack == pAcc->GetPixel( nY, nX ) )
492 pPoints1[ nPolyPos ] = Point( nX, nY );
493 nY = nStartY2;
495 // diese Schleife wird immer gebreaked da hier ja min. ein Pixel ist
496 while( sal_True )
498 if( aBlack == pAcc->GetPixel( nY, nX ) )
500 pPoints2[ nPolyPos ] = Point( nX, nY );
501 break;
504 nY--;
507 nPolyPos++;
508 break;
511 nY++;
515 else
517 pPoints1 = new Point[ nHeight ];
518 pPoints2 = new Point[ nHeight ];
520 for ( nY = nStartY1; nY < nEndY1; nY++ )
522 nX = nStartX1;
524 // zunaechst Zeile von Links nach Rechts durchlaufen
525 while( nX < nEndX1 )
527 if( aBlack == pAcc->GetPixel( nY, nX ) )
529 pPoints1[ nPolyPos ] = Point( nX, nY );
530 nX = nStartX2;
532 // diese Schleife wird immer gebreaked da hier ja min. ein Pixel ist
533 while( sal_True )
535 if( aBlack == pAcc->GetPixel( nY, nX ) )
537 pPoints2[ nPolyPos ] = Point( nX, nY );
538 break;
541 nX--;
544 nPolyPos++;
545 break;
548 nX++;
553 const sal_uInt16 nNewSize1 = nPolyPos << 1;
555 aRetPoly = Polygon( nPolyPos, pPoints1 );
556 aRetPoly.SetSize( nNewSize1 + 1 );
557 aRetPoly[ nNewSize1 ] = aRetPoly[ 0 ];
559 for( sal_uInt16 j = nPolyPos; nPolyPos < nNewSize1; )
560 aRetPoly[ nPolyPos++ ] = pPoints2[ --j ];
562 if( ( fFactorX != 0. ) && ( fFactorY != 0. ) )
563 aRetPoly.Scale( fFactorX, fFactorY );
565 delete[] pPoints1;
566 delete[] pPoints2;
570 return aRetPoly;
573 // ----------------
574 // - DitherBitmap -
575 // ----------------
577 sal_Bool DitherBitmap( Bitmap& rBitmap )
579 sal_Bool bRet = sal_False;
581 if( ( rBitmap.GetBitCount() >= 8 ) && ( Application::GetDefaultDevice()->GetColorCount() < 257 ) )
582 bRet = rBitmap.Dither( BMP_DITHER_FLOYD );
583 else
584 bRet = sal_False;
586 return bRet;
589 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */