Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <sot/factory.hxx>
21 : #include <tools/poly.hxx>
22 : #include <vcl/bmpacc.hxx>
23 : #include <vcl/virdev.hxx>
24 : #include <vcl/wrkwin.hxx>
25 : #include <svl/solar.hrc>
26 : #include <sfx2/docfile.hxx>
27 : #include <sfx2/app.hxx>
28 : #include "svx/xoutbmp.hxx"
29 : #include <vcl/dibtools.hxx>
30 : #include <vcl/FilterConfigItem.hxx>
31 : #include <vcl/graphicfilter.hxx>
32 : #include <vcl/cvtgrf.hxx>
33 : #include <sax/tools/converter.hxx>
34 : #include <boost/scoped_array.hpp>
35 :
36 : #define FORMAT_BMP "bmp"
37 : #define FORMAT_GIF "gif"
38 : #define FORMAT_JPG "jpg"
39 : #define FORMAT_PNG "png"
40 :
41 : GraphicFilter* XOutBitmap::pGrfFilter = NULL;
42 :
43 0 : Animation XOutBitmap::MirrorAnimation( const Animation& rAnimation, bool bHMirr, bool bVMirr )
44 : {
45 0 : Animation aNewAnim( rAnimation );
46 :
47 0 : if( bHMirr || bVMirr )
48 : {
49 0 : const Size& rGlobalSize = aNewAnim.GetDisplaySizePixel();
50 0 : BmpMirrorFlags nMirrorFlags = BmpMirrorFlags::NONE;
51 :
52 0 : if( bHMirr )
53 0 : nMirrorFlags |= BmpMirrorFlags::Horizontal;
54 :
55 0 : if( bVMirr )
56 0 : nMirrorFlags |= BmpMirrorFlags::Vertical;
57 :
58 0 : for( sal_uInt16 i = 0, nCount = aNewAnim.Count(); i < nCount; i++ )
59 : {
60 0 : AnimationBitmap aAnimBmp( aNewAnim.Get( i ) );
61 :
62 : // mirror the BitmapEx
63 0 : aAnimBmp.aBmpEx.Mirror( nMirrorFlags );
64 :
65 : // Adjust the positions inside the whole bitmap
66 0 : if( bHMirr )
67 0 : aAnimBmp.aPosPix.X() = rGlobalSize.Width() - aAnimBmp.aPosPix.X() -
68 0 : aAnimBmp.aSizePix.Width();
69 :
70 0 : if( bVMirr )
71 0 : aAnimBmp.aPosPix.Y() = rGlobalSize.Height() - aAnimBmp.aPosPix.Y() -
72 0 : aAnimBmp.aSizePix.Height();
73 :
74 0 : aNewAnim.Replace( aAnimBmp, i );
75 0 : }
76 : }
77 :
78 0 : return aNewAnim;
79 : }
80 :
81 0 : Graphic XOutBitmap::MirrorGraphic( const Graphic& rGraphic, const BmpMirrorFlags nMirrorFlags )
82 : {
83 0 : Graphic aRetGraphic;
84 :
85 0 : if( nMirrorFlags != BmpMirrorFlags::NONE )
86 : {
87 0 : if( rGraphic.IsAnimated() )
88 : {
89 0 : aRetGraphic = MirrorAnimation( rGraphic.GetAnimation(),
90 0 : bool( nMirrorFlags & BmpMirrorFlags::Horizontal ),
91 0 : bool( nMirrorFlags & BmpMirrorFlags::Vertical ) );
92 : }
93 : else
94 : {
95 0 : if( rGraphic.IsTransparent() )
96 : {
97 0 : BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
98 :
99 0 : aBmpEx.Mirror( nMirrorFlags );
100 0 : aRetGraphic = aBmpEx;
101 : }
102 : else
103 : {
104 0 : Bitmap aBmp( rGraphic.GetBitmap() );
105 :
106 0 : aBmp.Mirror( nMirrorFlags );
107 0 : aRetGraphic = aBmp;
108 : }
109 : }
110 : }
111 : else
112 0 : aRetGraphic = rGraphic;
113 :
114 0 : return aRetGraphic;
115 : }
116 :
117 1 : sal_uInt16 XOutBitmap::WriteGraphic( const Graphic& rGraphic, OUString& rFileName,
118 : const OUString& rFilterName, const sal_uIntPtr nFlags,
119 : const Size* pMtfSize_100TH_MM )
120 : {
121 1 : if( rGraphic.GetType() != GRAPHIC_NONE )
122 : {
123 1 : INetURLObject aURL( rFileName );
124 2 : Graphic aGraphic;
125 2 : OUString aExt;
126 1 : GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
127 1 : sal_uInt16 nErr = GRFILTER_FILTERERROR, nFilter = GRFILTER_FORMAT_NOTFOUND;
128 1 : bool bTransparent = rGraphic.IsTransparent(), bAnimated = rGraphic.IsAnimated();
129 :
130 : DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "XOutBitmap::WriteGraphic(...): invalid URL" );
131 :
132 : // calculate correct file name
133 1 : if( !( nFlags & XOUTBMP_DONT_EXPAND_FILENAME ) )
134 : {
135 1 : OUString aName( aURL.getBase() );
136 1 : aName += "_";
137 1 : aName += aURL.getExtension();
138 1 : aName += "_";
139 2 : OUString aStr( OUString::number( rGraphic.GetChecksum(), 16 ) );
140 1 : if ( aStr[0] == '-' )
141 0 : aStr = "m" + aStr.copy(1);
142 1 : aName += aStr;
143 2 : aURL.setBase( aName );
144 : }
145 :
146 : // #i121128# use shortcut to write SVG data in original form (if possible)
147 2 : const SvgDataPtr aSvgDataPtr(rGraphic.getSvgData());
148 :
149 2 : if(aSvgDataPtr.get()
150 0 : && aSvgDataPtr->getSvgDataArrayLength()
151 1 : && rFilterName.equalsIgnoreAsciiCase("svg"))
152 : {
153 0 : if(!(nFlags & XOUTBMP_DONT_ADD_EXTENSION))
154 : {
155 0 : aURL.setExtension(rFilterName);
156 : }
157 :
158 0 : rFileName = aURL.GetMainURL(INetURLObject::NO_DECODE);
159 0 : SfxMedium aMedium(aURL.GetMainURL(INetURLObject::NO_DECODE), StreamMode::WRITE|StreamMode::SHARE_DENYNONE|StreamMode::TRUNC);
160 0 : SvStream* pOStm = aMedium.GetOutStream();
161 :
162 0 : if(pOStm)
163 : {
164 0 : pOStm->Write(aSvgDataPtr->getSvgDataArray().get(), aSvgDataPtr->getSvgDataArrayLength());
165 0 : aMedium.Commit();
166 :
167 0 : if(!aMedium.GetError())
168 : {
169 0 : nErr = GRFILTER_OK;
170 : }
171 0 : }
172 : }
173 :
174 1 : if( GRFILTER_OK != nErr )
175 : {
176 3 : if( ( nFlags & XOUTBMP_USE_NATIVE_IF_POSSIBLE ) &&
177 2 : !( nFlags & XOUTBMP_MIRROR_HORZ ) &&
178 2 : !( nFlags & XOUTBMP_MIRROR_VERT ) &&
179 3 : ( rGraphic.GetType() != GRAPHIC_GDIMETAFILE ) && rGraphic.IsLink() )
180 : {
181 : // try to write native link
182 1 : const GfxLink aGfxLink( ( (Graphic&) rGraphic ).GetLink() );
183 :
184 1 : switch( aGfxLink.GetType() )
185 : {
186 0 : case( GFX_LINK_TYPE_NATIVE_GIF ): aExt = FORMAT_GIF; break;
187 :
188 : // #i15508# added BMP type for better exports (no call/trigger found, prob used in HTML export)
189 0 : case( GFX_LINK_TYPE_NATIVE_BMP ): aExt = FORMAT_BMP; break;
190 :
191 1 : case( GFX_LINK_TYPE_NATIVE_JPG ): aExt = FORMAT_JPG; break;
192 0 : case( GFX_LINK_TYPE_NATIVE_PNG ): aExt = FORMAT_PNG; break;
193 :
194 : default:
195 0 : break;
196 : }
197 :
198 1 : if( !aExt.isEmpty() )
199 : {
200 1 : if( 0 == (nFlags & XOUTBMP_DONT_ADD_EXTENSION))
201 1 : aURL.setExtension( aExt );
202 1 : rFileName = aURL.GetMainURL( INetURLObject::NO_DECODE );
203 :
204 1 : SfxMedium aMedium(aURL.GetMainURL(INetURLObject::NO_DECODE), StreamMode::WRITE | StreamMode::SHARE_DENYNONE | StreamMode::TRUNC);
205 1 : SvStream* pOStm = aMedium.GetOutStream();
206 :
207 1 : if( pOStm && aGfxLink.GetDataSize() && aGfxLink.GetData() )
208 : {
209 1 : pOStm->Write( aGfxLink.GetData(), aGfxLink.GetDataSize() );
210 1 : aMedium.Commit();
211 :
212 1 : if( !aMedium.GetError() )
213 1 : nErr = GRFILTER_OK;
214 1 : }
215 1 : }
216 : }
217 : }
218 :
219 1 : if( GRFILTER_OK != nErr )
220 : {
221 0 : OUString aFilter( rFilterName );
222 0 : bool bWriteTransGrf = ( aFilter.equalsIgnoreAsciiCase( "transgrf" ) ) ||
223 0 : ( aFilter.equalsIgnoreAsciiCase( "gif" ) ) ||
224 0 : ( nFlags & XOUTBMP_USE_GIF_IF_POSSIBLE ) ||
225 0 : ( ( nFlags & XOUTBMP_USE_GIF_IF_SENSIBLE ) && ( bAnimated || bTransparent ) );
226 :
227 : // get filter and extension
228 0 : if( bWriteTransGrf )
229 0 : aFilter = FORMAT_GIF;
230 :
231 0 : nFilter = rFilter.GetExportFormatNumberForShortName( aFilter );
232 :
233 0 : if( GRFILTER_FORMAT_NOTFOUND == nFilter )
234 : {
235 0 : nFilter = rFilter.GetExportFormatNumberForShortName( FORMAT_PNG );
236 :
237 0 : if( GRFILTER_FORMAT_NOTFOUND == nFilter )
238 0 : nFilter = rFilter.GetExportFormatNumberForShortName( FORMAT_BMP );
239 : }
240 :
241 0 : if( GRFILTER_FORMAT_NOTFOUND != nFilter )
242 : {
243 0 : aExt = rFilter.GetExportFormatShortName( nFilter ).toAsciiLowerCase();
244 :
245 0 : if( bWriteTransGrf )
246 : {
247 0 : if( bAnimated )
248 0 : aGraphic = rGraphic;
249 : else
250 : {
251 0 : if( pMtfSize_100TH_MM && ( rGraphic.GetType() != GRAPHIC_BITMAP ) )
252 : {
253 0 : ScopedVclPtrInstance< VirtualDevice > pVDev;
254 0 : const Size aSize( pVDev->LogicToPixel( *pMtfSize_100TH_MM, MAP_100TH_MM ) );
255 :
256 0 : if( pVDev->SetOutputSizePixel( aSize ) )
257 : {
258 0 : const Wallpaper aWallpaper( pVDev->GetBackground() );
259 0 : const Point aPt;
260 :
261 0 : pVDev->SetBackground( Wallpaper( Color( COL_BLACK ) ) );
262 0 : pVDev->Erase();
263 0 : rGraphic.Draw( pVDev.get(), aPt, aSize );
264 :
265 0 : const Bitmap aBitmap( pVDev->GetBitmap( aPt, aSize ) );
266 :
267 0 : pVDev->SetBackground( aWallpaper );
268 0 : pVDev->Erase();
269 0 : rGraphic.Draw( pVDev.get(), aPt, aSize );
270 :
271 0 : pVDev->SetRasterOp( ROP_XOR );
272 0 : pVDev->DrawBitmap( aPt, aSize, aBitmap );
273 0 : aGraphic = BitmapEx( aBitmap, pVDev->GetBitmap( aPt, aSize ) );
274 : }
275 : else
276 0 : aGraphic = rGraphic.GetBitmapEx();
277 : }
278 : else
279 0 : aGraphic = rGraphic.GetBitmapEx();
280 : }
281 : }
282 : else
283 : {
284 0 : if( pMtfSize_100TH_MM && ( rGraphic.GetType() != GRAPHIC_BITMAP ) )
285 : {
286 0 : ScopedVclPtrInstance< VirtualDevice > pVDev;
287 0 : const Size aSize( pVDev->LogicToPixel( *pMtfSize_100TH_MM, MAP_100TH_MM ) );
288 :
289 0 : if( pVDev->SetOutputSizePixel( aSize ) )
290 : {
291 0 : rGraphic.Draw( pVDev.get(), Point(), aSize );
292 0 : aGraphic = pVDev->GetBitmap( Point(), aSize );
293 : }
294 : else
295 0 : aGraphic = rGraphic.GetBitmap();
296 : }
297 : else
298 0 : aGraphic = rGraphic.GetBitmap();
299 : }
300 :
301 : // mirror?
302 0 : if( ( nFlags & XOUTBMP_MIRROR_HORZ ) || ( nFlags & XOUTBMP_MIRROR_VERT ) )
303 : {
304 0 : BmpMirrorFlags nBmpMirrorFlags = BmpMirrorFlags::NONE;
305 0 : if( nFlags & XOUTBMP_MIRROR_HORZ )
306 0 : nBmpMirrorFlags |= BmpMirrorFlags::Horizontal;
307 0 : if( nFlags & XOUTBMP_MIRROR_VERT )
308 0 : nBmpMirrorFlags |= BmpMirrorFlags::Vertical;
309 0 : aGraphic = MirrorGraphic( aGraphic, nBmpMirrorFlags );
310 : }
311 :
312 0 : if( ( GRFILTER_FORMAT_NOTFOUND != nFilter ) && ( aGraphic.GetType() != GRAPHIC_NONE ) )
313 : {
314 0 : if( 0 == (nFlags & XOUTBMP_DONT_ADD_EXTENSION))
315 0 : aURL.setExtension( aExt );
316 0 : rFileName = aURL.GetMainURL( INetURLObject::NO_DECODE );
317 0 : nErr = ExportGraphic( aGraphic, aURL, rFilter, nFilter, NULL );
318 : }
319 0 : }
320 : }
321 :
322 2 : return nErr;
323 : }
324 : else
325 : {
326 0 : return GRFILTER_OK;
327 : }
328 : }
329 :
330 3 : sal_uLong XOutBitmap::GraphicToBase64(const Graphic& rGraphic, OUString& rOUString)
331 : {
332 3 : SvMemoryStream aOStm;
333 6 : OUString aMimeType;
334 6 : GfxLink aLink = rGraphic.GetLink();
335 : ConvertDataFormat aCvtType;
336 3 : switch( aLink.GetType() )
337 : {
338 : case( GFX_LINK_TYPE_NATIVE_JPG ):
339 0 : aCvtType = ConvertDataFormat::JPG;
340 0 : aMimeType = "image/jpeg";
341 0 : break;
342 : case( GFX_LINK_TYPE_NATIVE_PNG ):
343 3 : aCvtType = ConvertDataFormat::PNG;
344 3 : aMimeType = "image/png";
345 3 : break;
346 : case( GFX_LINK_TYPE_NATIVE_SVG ):
347 0 : aCvtType = ConvertDataFormat::SVG;
348 0 : aMimeType = "image/svg+xml";
349 0 : break;
350 : default:
351 : // save everything else (including gif) into png
352 0 : aCvtType = ConvertDataFormat::PNG;
353 0 : aMimeType = "image/png";
354 0 : break;
355 : }
356 3 : sal_uLong nErr = GraphicConverter::Export(aOStm,rGraphic,aCvtType);
357 3 : if ( nErr )
358 : {
359 : SAL_WARN("svx", "XOutBitmap::GraphicToBase64() invalid Graphic? error: " << nErr );
360 0 : return nErr;
361 : }
362 3 : aOStm.Seek(STREAM_SEEK_TO_END);
363 3 : css::uno::Sequence<sal_Int8> aOStmSeq( static_cast<sal_Int8 const *>(aOStm.GetData()),aOStm.Tell() );
364 6 : OUStringBuffer aStrBuffer;
365 3 : ::sax::Converter::encodeBase64(aStrBuffer,aOStmSeq);
366 3 : rOUString = aMimeType + ";base64," + aStrBuffer.makeStringAndClear();
367 9 : return 0;
368 : }
369 :
370 0 : sal_uInt16 XOutBitmap::ExportGraphic( const Graphic& rGraphic, const INetURLObject& rURL,
371 : GraphicFilter& rFilter, const sal_uInt16 nFormat,
372 : const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >* pFilterData )
373 : {
374 : DBG_ASSERT( rURL.GetProtocol() != INetProtocol::NotValid, "XOutBitmap::ExportGraphic(...): invalid URL" );
375 :
376 0 : SfxMedium aMedium( rURL.GetMainURL( INetURLObject::NO_DECODE ), StreamMode::WRITE | StreamMode::SHARE_DENYNONE | StreamMode::TRUNC );
377 0 : SvStream* pOStm = aMedium.GetOutStream();
378 0 : sal_uInt16 nRet = GRFILTER_IOERROR;
379 :
380 0 : if( pOStm )
381 : {
382 0 : pGrfFilter = &rFilter;
383 :
384 0 : nRet = rFilter.ExportGraphic( rGraphic, rURL.GetMainURL( INetURLObject::NO_DECODE ), *pOStm, nFormat, pFilterData );
385 :
386 0 : pGrfFilter = NULL;
387 0 : aMedium.Commit();
388 :
389 0 : if( aMedium.GetError() && ( GRFILTER_OK == nRet ) )
390 0 : nRet = GRFILTER_IOERROR;
391 : }
392 :
393 0 : return nRet;
394 : }
395 :
396 0 : Bitmap XOutBitmap::DetectEdges( const Bitmap& rBmp, const sal_uInt8 cThreshold )
397 : {
398 0 : const Size aSize( rBmp.GetSizePixel() );
399 0 : Bitmap aRetBmp;
400 :
401 0 : if( ( aSize.Width() > 2L ) && ( aSize.Height() > 2L ) )
402 : {
403 0 : Bitmap aWorkBmp( rBmp );
404 :
405 0 : if( aWorkBmp.Convert( BMP_CONVERSION_8BIT_GREYS ) )
406 : {
407 0 : bool bRet = false;
408 :
409 0 : Bitmap aDstBmp( aSize, 1 );
410 0 : BitmapReadAccess* pReadAcc = aWorkBmp.AcquireReadAccess();
411 0 : BitmapWriteAccess* pWriteAcc = aDstBmp.AcquireWriteAccess();
412 :
413 0 : if( pReadAcc && pWriteAcc )
414 : {
415 0 : const long nWidth = aSize.Width();
416 0 : const long nWidth2 = nWidth - 2L;
417 0 : const long nHeight = aSize.Height();
418 0 : const long nHeight2 = nHeight - 2L;
419 0 : const long lThres2 = (long) cThreshold * cThreshold;
420 0 : const sal_uInt8 nWhitePalIdx(static_cast< sal_uInt8 >(pWriteAcc->GetBestPaletteIndex(Color(COL_WHITE))));
421 0 : const sal_uInt8 nBlackPalIdx(static_cast< sal_uInt8 >(pWriteAcc->GetBestPaletteIndex(Color(COL_BLACK))));
422 : long nSum1;
423 : long nSum2;
424 : long lGray;
425 :
426 : // initialize border with white pixels
427 0 : pWriteAcc->SetLineColor( Color( COL_WHITE) );
428 0 : pWriteAcc->DrawLine( Point(), Point( nWidth - 1L, 0L ) );
429 0 : pWriteAcc->DrawLine( Point( nWidth - 1L, 0L ), Point( nWidth - 1L, nHeight - 1L ) );
430 0 : pWriteAcc->DrawLine( Point( nWidth - 1L, nHeight - 1L ), Point( 0L, nHeight - 1L ) );
431 0 : pWriteAcc->DrawLine( Point( 0, nHeight - 1L ), Point() );
432 :
433 0 : for( long nY = 0L, nY1 = 1L, nY2 = 2; nY < nHeight2; nY++, nY1++, nY2++ )
434 : {
435 0 : for( long nX = 0L, nXDst = 1L, nXTmp; nX < nWidth2; nX++, nXDst++ )
436 : {
437 0 : nXTmp = nX;
438 :
439 0 : nSum1 = -( nSum2 = lGray = pReadAcc->GetPixelIndex( nY, nXTmp++ ) );
440 0 : nSum2 += ( (long) pReadAcc->GetPixelIndex( nY, nXTmp++ ) ) << 1;
441 0 : nSum1 += ( lGray = pReadAcc->GetPixelIndex( nY, nXTmp ) );
442 0 : nSum2 += lGray;
443 :
444 0 : nSum1 += ( (long) pReadAcc->GetPixelIndex( nY1, nXTmp ) ) << 1;
445 0 : nSum1 -= ( (long) pReadAcc->GetPixelIndex( nY1, nXTmp -= 2 ) ) << 1;
446 :
447 0 : nSum1 += ( lGray = -(long) pReadAcc->GetPixelIndex( nY2, nXTmp++ ) );
448 0 : nSum2 += lGray;
449 0 : nSum2 -= ( (long) pReadAcc->GetPixelIndex( nY2, nXTmp++ ) ) << 1;
450 0 : nSum1 += ( lGray = (long) pReadAcc->GetPixelIndex( nY2, nXTmp ) );
451 0 : nSum2 -= lGray;
452 :
453 0 : if( ( nSum1 * nSum1 + nSum2 * nSum2 ) < lThres2 )
454 0 : pWriteAcc->SetPixelIndex( nY1, nXDst, nWhitePalIdx );
455 : else
456 0 : pWriteAcc->SetPixelIndex( nY1, nXDst, nBlackPalIdx );
457 : }
458 : }
459 :
460 0 : bRet = true;
461 : }
462 :
463 0 : Bitmap::ReleaseAccess( pReadAcc );
464 0 : Bitmap::ReleaseAccess( pWriteAcc );
465 :
466 0 : if( bRet )
467 0 : aRetBmp = aDstBmp;
468 0 : }
469 : }
470 :
471 0 : if( !aRetBmp )
472 0 : aRetBmp = rBmp;
473 : else
474 : {
475 0 : aRetBmp.SetPrefMapMode( rBmp.GetPrefMapMode() );
476 0 : aRetBmp.SetPrefSize( rBmp.GetPrefSize() );
477 : }
478 :
479 0 : return aRetBmp;
480 : };
481 :
482 0 : Polygon XOutBitmap::GetCountour( const Bitmap& rBmp, const sal_uIntPtr nFlags,
483 : const sal_uInt8 cEdgeDetectThreshold, const Rectangle* pWorkRectPixel )
484 : {
485 0 : Bitmap aWorkBmp;
486 0 : Polygon aRetPoly;
487 0 : Point aTmpPoint;
488 0 : Rectangle aWorkRect( aTmpPoint, rBmp.GetSizePixel() );
489 :
490 0 : if( pWorkRectPixel )
491 0 : aWorkRect.Intersection( *pWorkRectPixel );
492 :
493 0 : aWorkRect.Justify();
494 :
495 0 : if( ( aWorkRect.GetWidth() > 4 ) && ( aWorkRect.GetHeight() > 4 ) )
496 : {
497 : // if the flag is set, we need to detect edges
498 0 : if( nFlags & XOUTBMP_CONTOUR_EDGEDETECT )
499 0 : aWorkBmp = DetectEdges( rBmp, cEdgeDetectThreshold );
500 : else
501 0 : aWorkBmp = rBmp;
502 :
503 0 : BitmapReadAccess* pAcc = aWorkBmp.AcquireReadAccess();
504 :
505 0 : const long nWidth = pAcc ? pAcc->Width() : 0;
506 0 : const long nHeight = pAcc ? pAcc->Height() : 0;
507 :
508 0 : if (pAcc && nWidth && nHeight)
509 : {
510 0 : const Size& rPrefSize = aWorkBmp.GetPrefSize();
511 0 : const double fFactorX = (double) rPrefSize.Width() / nWidth;
512 0 : const double fFactorY = (double) rPrefSize.Height() / nHeight;
513 0 : const long nStartX1 = aWorkRect.Left() + 1L;
514 0 : const long nEndX1 = aWorkRect.Right();
515 0 : const long nStartX2 = nEndX1 - 1L;
516 0 : const long nStartY1 = aWorkRect.Top() + 1L;
517 0 : const long nEndY1 = aWorkRect.Bottom();
518 0 : const long nStartY2 = nEndY1 - 1L;
519 0 : boost::scoped_array<Point> pPoints1;
520 0 : boost::scoped_array<Point> pPoints2;
521 : long nX, nY;
522 0 : sal_uInt16 nPolyPos = 0;
523 0 : const BitmapColor aBlack = pAcc->GetBestMatchingColor( Color( COL_BLACK ) );
524 :
525 0 : if( nFlags & XOUTBMP_CONTOUR_VERT )
526 : {
527 0 : pPoints1.reset(new Point[ nWidth ]);
528 0 : pPoints2.reset(new Point[ nWidth ]);
529 :
530 0 : for( nX = nStartX1; nX < nEndX1; nX++ )
531 : {
532 0 : nY = nStartY1;
533 :
534 : // scan row from left to right
535 0 : while( nY < nEndY1 )
536 : {
537 0 : if( aBlack == pAcc->GetPixel( nY, nX ) )
538 : {
539 0 : pPoints1[ nPolyPos ] = Point( nX, nY );
540 0 : nY = nStartY2;
541 :
542 : // this loop always breaks eventually as there is at least one pixel
543 : while( true )
544 : {
545 0 : if( aBlack == pAcc->GetPixel( nY, nX ) )
546 : {
547 0 : pPoints2[ nPolyPos ] = Point( nX, nY );
548 0 : break;
549 : }
550 :
551 0 : nY--;
552 : }
553 :
554 0 : nPolyPos++;
555 0 : break;
556 : }
557 :
558 0 : nY++;
559 : }
560 : }
561 : }
562 : else
563 : {
564 0 : pPoints1.reset(new Point[ nHeight ]);
565 0 : pPoints2.reset(new Point[ nHeight ]);
566 :
567 0 : for ( nY = nStartY1; nY < nEndY1; nY++ )
568 : {
569 0 : nX = nStartX1;
570 :
571 : // scan row from left to right
572 0 : while( nX < nEndX1 )
573 : {
574 0 : if( aBlack == pAcc->GetPixel( nY, nX ) )
575 : {
576 0 : pPoints1[ nPolyPos ] = Point( nX, nY );
577 0 : nX = nStartX2;
578 :
579 : // this loop always breaks eventually as there is at least one pixel
580 : while( true )
581 : {
582 0 : if( aBlack == pAcc->GetPixel( nY, nX ) )
583 : {
584 0 : pPoints2[ nPolyPos ] = Point( nX, nY );
585 0 : break;
586 : }
587 :
588 0 : nX--;
589 : }
590 :
591 0 : nPolyPos++;
592 0 : break;
593 : }
594 :
595 0 : nX++;
596 : }
597 : }
598 : }
599 :
600 0 : const sal_uInt16 nNewSize1 = nPolyPos << 1;
601 :
602 0 : aRetPoly = Polygon( nPolyPos, pPoints1.get() );
603 0 : aRetPoly.SetSize( nNewSize1 + 1 );
604 0 : aRetPoly[ nNewSize1 ] = aRetPoly[ 0 ];
605 :
606 0 : for( sal_uInt16 j = nPolyPos; nPolyPos < nNewSize1; )
607 0 : aRetPoly[ nPolyPos++ ] = pPoints2[ --j ];
608 :
609 0 : if( ( fFactorX != 0. ) && ( fFactorY != 0. ) )
610 0 : aRetPoly.Scale( fFactorX, fFactorY );
611 : }
612 : }
613 :
614 0 : return aRetPoly;
615 : };
616 :
617 0 : bool DitherBitmap( Bitmap& rBitmap )
618 : {
619 0 : bool bRet = false;
620 :
621 0 : if( ( rBitmap.GetBitCount() >= 8 ) && ( Application::GetDefaultDevice()->GetColorCount() < 257 ) )
622 0 : bRet = rBitmap.Dither( BmpDitherFlags::Floyd );
623 : else
624 0 : bRet = false;
625 :
626 0 : return bRet;
627 435 : }
628 :
629 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|