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 OUString("bmp")
37 : #define FORMAT_GIF OUString("gif")
38 : #define FORMAT_JPG OUString("jpg")
39 : #define FORMAT_PNG OUString("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 : sal_uIntPtr nMirrorFlags = 0L;
51 :
52 0 : if( bHMirr )
53 0 : nMirrorFlags |= BMP_MIRROR_HORZ;
54 :
55 0 : if( bVMirr )
56 0 : nMirrorFlags |= BMP_MIRROR_VERT;
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 sal_uIntPtr nMirrorFlags )
82 : {
83 0 : Graphic aRetGraphic;
84 :
85 0 : if( nMirrorFlags )
86 : {
87 0 : if( rGraphic.IsAnimated() )
88 : {
89 0 : aRetGraphic = MirrorAnimation( rGraphic.GetAnimation(),
90 0 : ( nMirrorFlags & BMP_MIRROR_HORZ ) == BMP_MIRROR_HORZ,
91 0 : ( nMirrorFlags & BMP_MIRROR_VERT ) == BMP_MIRROR_VERT );
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 2 : 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 2 : if( rGraphic.GetType() != GRAPHIC_NONE )
122 : {
123 2 : INetURLObject aURL( rFileName );
124 4 : Graphic aGraphic;
125 4 : OUString aExt;
126 2 : GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
127 2 : sal_uInt16 nErr = GRFILTER_FILTERERROR, nFilter = GRFILTER_FORMAT_NOTFOUND;
128 2 : bool bTransparent = rGraphic.IsTransparent(), bAnimated = rGraphic.IsAnimated();
129 :
130 : DBG_ASSERT( aURL.GetProtocol() != INET_PROT_NOT_VALID, "XOutBitmap::WriteGraphic(...): invalid URL" );
131 :
132 : // calculate correct file name
133 2 : if( !( nFlags & XOUTBMP_DONT_EXPAND_FILENAME ) )
134 : {
135 2 : OUString aName( aURL.getBase() );
136 2 : aName += "_";
137 2 : aName += aURL.getExtension();
138 2 : aName += "_";
139 4 : OUString aStr( OUString::number( rGraphic.GetChecksum(), 16 ) );
140 2 : if ( aStr[0] == '-' )
141 0 : aStr = "m" + aStr.copy(1);
142 2 : aName += aStr;
143 4 : aURL.setBase( aName );
144 : }
145 :
146 : // #i121128# use shortcut to write SVG data in original form (if possible)
147 4 : const SvgDataPtr aSvgDataPtr(rGraphic.getSvgData());
148 :
149 4 : if(aSvgDataPtr.get()
150 0 : && aSvgDataPtr->getSvgDataArrayLength()
151 2 : && 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), STREAM_WRITE|STREAM_SHARE_DENYNONE|STREAM_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 2 : if( GRFILTER_OK != nErr )
175 : {
176 6 : if( ( nFlags & XOUTBMP_USE_NATIVE_IF_POSSIBLE ) &&
177 4 : !( nFlags & XOUTBMP_MIRROR_HORZ ) &&
178 4 : !( nFlags & XOUTBMP_MIRROR_VERT ) &&
179 6 : ( rGraphic.GetType() != GRAPHIC_GDIMETAFILE ) && rGraphic.IsLink() )
180 : {
181 : // try to write native link
182 2 : const GfxLink aGfxLink( ( (Graphic&) rGraphic ).GetLink() );
183 :
184 2 : 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 2 : 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 2 : if( !aExt.isEmpty() )
199 : {
200 2 : if( 0 == (nFlags & XOUTBMP_DONT_ADD_EXTENSION))
201 2 : aURL.setExtension( aExt );
202 2 : rFileName = aURL.GetMainURL( INetURLObject::NO_DECODE );
203 :
204 2 : SfxMedium aMedium(aURL.GetMainURL(INetURLObject::NO_DECODE), STREAM_WRITE | STREAM_SHARE_DENYNONE | STREAM_TRUNC);
205 2 : SvStream* pOStm = aMedium.GetOutStream();
206 :
207 2 : if( pOStm && aGfxLink.GetDataSize() && aGfxLink.GetData() )
208 : {
209 2 : pOStm->Write( aGfxLink.GetData(), aGfxLink.GetDataSize() );
210 2 : aMedium.Commit();
211 :
212 2 : if( !aMedium.GetError() )
213 2 : nErr = GRFILTER_OK;
214 2 : }
215 2 : }
216 : }
217 : }
218 :
219 2 : 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 : VirtualDevice aVDev;
254 0 : const Size aSize( aVDev.LogicToPixel( *pMtfSize_100TH_MM, MAP_100TH_MM ) );
255 :
256 0 : if( aVDev.SetOutputSizePixel( aSize ) )
257 : {
258 0 : const Wallpaper aWallpaper( aVDev.GetBackground() );
259 0 : const Point aPt;
260 :
261 0 : aVDev.SetBackground( Wallpaper( Color( COL_BLACK ) ) );
262 0 : aVDev.Erase();
263 0 : rGraphic.Draw( &aVDev, aPt, aSize );
264 :
265 0 : const Bitmap aBitmap( aVDev.GetBitmap( aPt, aSize ) );
266 :
267 0 : aVDev.SetBackground( aWallpaper );
268 0 : aVDev.Erase();
269 0 : rGraphic.Draw( &aVDev, aPt, aSize );
270 :
271 0 : aVDev.SetRasterOp( ROP_XOR );
272 0 : aVDev.DrawBitmap( aPt, aSize, aBitmap );
273 0 : aGraphic = BitmapEx( aBitmap, aVDev.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 : VirtualDevice aVDev;
287 0 : const Size aSize( aVDev.LogicToPixel( *pMtfSize_100TH_MM, MAP_100TH_MM ) );
288 :
289 0 : if( aVDev.SetOutputSizePixel( aSize ) )
290 : {
291 0 : rGraphic.Draw( &aVDev, Point(), aSize );
292 0 : aGraphic = aVDev.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 0 : aGraphic = MirrorGraphic( aGraphic, nFlags );
304 :
305 0 : if( ( GRFILTER_FORMAT_NOTFOUND != nFilter ) && ( aGraphic.GetType() != GRAPHIC_NONE ) )
306 : {
307 0 : if( 0 == (nFlags & XOUTBMP_DONT_ADD_EXTENSION))
308 0 : aURL.setExtension( aExt );
309 0 : rFileName = aURL.GetMainURL( INetURLObject::NO_DECODE );
310 0 : nErr = ExportGraphic( aGraphic, aURL, rFilter, nFilter, NULL );
311 : }
312 0 : }
313 : }
314 :
315 4 : return nErr;
316 : }
317 : else
318 : {
319 0 : return GRFILTER_OK;
320 : }
321 : }
322 :
323 6 : sal_uLong XOutBitmap::GraphicToBase64(const Graphic& rGraphic, OUString& rOUString)
324 : {
325 6 : SvMemoryStream aOStm;
326 12 : OUString aMimeType;
327 12 : GfxLink aLink = rGraphic.GetLink();
328 : sal_uLong aCvtType;
329 6 : switch( aLink.GetType() )
330 : {
331 : case( GFX_LINK_TYPE_NATIVE_JPG ):
332 0 : aCvtType = CVT_JPG;
333 0 : aMimeType = "image/jpeg";
334 0 : break;
335 : case( GFX_LINK_TYPE_NATIVE_PNG ):
336 6 : aCvtType = CVT_PNG;
337 6 : aMimeType = "image/png";
338 6 : break;
339 : case( GFX_LINK_TYPE_NATIVE_SVG ):
340 0 : aCvtType = CVT_SVG;
341 0 : aMimeType = "image/svg+xml";
342 0 : break;
343 : default:
344 : // save everything else (including gif) into png
345 0 : aCvtType = CVT_PNG;
346 0 : aMimeType = "image/png";
347 0 : break;
348 : }
349 6 : sal_uLong nErr = GraphicConverter::Export(aOStm,rGraphic,aCvtType);
350 6 : if ( nErr )
351 : {
352 : SAL_WARN("svx", "XOutBitmap::GraphicToBase64() invalid Graphic? error: " << nErr );
353 0 : return nErr;
354 : }
355 6 : aOStm.Seek(STREAM_SEEK_TO_END);
356 6 : css::uno::Sequence<sal_Int8> aOStmSeq( (sal_Int8*) aOStm.GetData(),aOStm.Tell() );
357 12 : OUStringBuffer aStrBuffer;
358 6 : ::sax::Converter::encodeBase64(aStrBuffer,aOStmSeq);
359 6 : rOUString = aMimeType + ";base64," + aStrBuffer.makeStringAndClear();
360 18 : return 0;
361 : }
362 :
363 0 : sal_uInt16 XOutBitmap::ExportGraphic( const Graphic& rGraphic, const INetURLObject& rURL,
364 : GraphicFilter& rFilter, const sal_uInt16 nFormat,
365 : const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >* pFilterData )
366 : {
367 : DBG_ASSERT( rURL.GetProtocol() != INET_PROT_NOT_VALID, "XOutBitmap::ExportGraphic(...): invalid URL" );
368 :
369 0 : SfxMedium aMedium( rURL.GetMainURL( INetURLObject::NO_DECODE ), STREAM_WRITE | STREAM_SHARE_DENYNONE | STREAM_TRUNC );
370 0 : SvStream* pOStm = aMedium.GetOutStream();
371 0 : sal_uInt16 nRet = GRFILTER_IOERROR;
372 :
373 0 : if( pOStm )
374 : {
375 0 : pGrfFilter = &rFilter;
376 :
377 0 : nRet = rFilter.ExportGraphic( rGraphic, rURL.GetMainURL( INetURLObject::NO_DECODE ), *pOStm, nFormat, pFilterData );
378 :
379 0 : pGrfFilter = NULL;
380 0 : aMedium.Commit();
381 :
382 0 : if( aMedium.GetError() && ( GRFILTER_OK == nRet ) )
383 0 : nRet = GRFILTER_IOERROR;
384 : }
385 :
386 0 : return nRet;
387 : }
388 :
389 0 : Bitmap XOutBitmap::DetectEdges( const Bitmap& rBmp, const sal_uInt8 cThreshold )
390 : {
391 0 : const Size aSize( rBmp.GetSizePixel() );
392 0 : Bitmap aRetBmp;
393 0 : bool bRet = false;
394 :
395 0 : if( ( aSize.Width() > 2L ) && ( aSize.Height() > 2L ) )
396 : {
397 0 : Bitmap aWorkBmp( rBmp );
398 :
399 0 : if( aWorkBmp.Convert( BMP_CONVERSION_8BIT_GREYS ) )
400 : {
401 0 : Bitmap aDstBmp( aSize, 1 );
402 0 : BitmapReadAccess* pReadAcc = aWorkBmp.AcquireReadAccess();
403 0 : BitmapWriteAccess* pWriteAcc = aDstBmp.AcquireWriteAccess();
404 :
405 0 : if( pReadAcc && pWriteAcc )
406 : {
407 0 : const long nWidth = aSize.Width();
408 0 : const long nWidth2 = nWidth - 2L;
409 0 : const long nHeight = aSize.Height();
410 0 : const long nHeight2 = nHeight - 2L;
411 0 : const long lThres2 = (long) cThreshold * cThreshold;
412 0 : const sal_uInt8 nWhitePalIdx(static_cast< sal_uInt8 >(pWriteAcc->GetBestPaletteIndex(Color(COL_WHITE))));
413 0 : const sal_uInt8 nBlackPalIdx(static_cast< sal_uInt8 >(pWriteAcc->GetBestPaletteIndex(Color(COL_BLACK))));
414 : long nSum1;
415 : long nSum2;
416 : long lGray;
417 :
418 : // initialize border with white pixels
419 0 : pWriteAcc->SetLineColor( Color( COL_WHITE) );
420 0 : pWriteAcc->DrawLine( Point(), Point( nWidth - 1L, 0L ) );
421 0 : pWriteAcc->DrawLine( Point( nWidth - 1L, 0L ), Point( nWidth - 1L, nHeight - 1L ) );
422 0 : pWriteAcc->DrawLine( Point( nWidth - 1L, nHeight - 1L ), Point( 0L, nHeight - 1L ) );
423 0 : pWriteAcc->DrawLine( Point( 0, nHeight - 1L ), Point() );
424 :
425 0 : for( long nY = 0L, nY1 = 1L, nY2 = 2; nY < nHeight2; nY++, nY1++, nY2++ )
426 : {
427 0 : for( long nX = 0L, nXDst = 1L, nXTmp; nX < nWidth2; nX++, nXDst++ )
428 : {
429 0 : nXTmp = nX;
430 :
431 0 : nSum1 = -( nSum2 = lGray = pReadAcc->GetPixelIndex( nY, nXTmp++ ) );
432 0 : nSum2 += ( (long) pReadAcc->GetPixelIndex( nY, nXTmp++ ) ) << 1;
433 0 : nSum1 += ( lGray = pReadAcc->GetPixelIndex( nY, nXTmp ) );
434 0 : nSum2 += lGray;
435 :
436 0 : nSum1 += ( (long) pReadAcc->GetPixelIndex( nY1, nXTmp ) ) << 1;
437 0 : nSum1 -= ( (long) pReadAcc->GetPixelIndex( nY1, nXTmp -= 2 ) ) << 1;
438 :
439 0 : nSum1 += ( lGray = -(long) pReadAcc->GetPixelIndex( nY2, nXTmp++ ) );
440 0 : nSum2 += lGray;
441 0 : nSum2 -= ( (long) pReadAcc->GetPixelIndex( nY2, nXTmp++ ) ) << 1;
442 0 : nSum1 += ( lGray = (long) pReadAcc->GetPixelIndex( nY2, nXTmp ) );
443 0 : nSum2 -= lGray;
444 :
445 0 : if( ( nSum1 * nSum1 + nSum2 * nSum2 ) < lThres2 )
446 0 : pWriteAcc->SetPixelIndex( nY1, nXDst, nWhitePalIdx );
447 : else
448 0 : pWriteAcc->SetPixelIndex( nY1, nXDst, nBlackPalIdx );
449 : }
450 : }
451 :
452 0 : bRet = true;
453 : }
454 :
455 0 : aWorkBmp.ReleaseAccess( pReadAcc );
456 0 : aDstBmp.ReleaseAccess( pWriteAcc );
457 :
458 0 : if( bRet )
459 0 : aRetBmp = aDstBmp;
460 0 : }
461 : }
462 :
463 0 : if( !aRetBmp )
464 0 : aRetBmp = rBmp;
465 : else
466 : {
467 0 : aRetBmp.SetPrefMapMode( rBmp.GetPrefMapMode() );
468 0 : aRetBmp.SetPrefSize( rBmp.GetPrefSize() );
469 : }
470 :
471 0 : return aRetBmp;
472 : };
473 :
474 0 : Polygon XOutBitmap::GetCountour( const Bitmap& rBmp, const sal_uIntPtr nFlags,
475 : const sal_uInt8 cEdgeDetectThreshold, const Rectangle* pWorkRectPixel )
476 : {
477 0 : Bitmap aWorkBmp;
478 0 : Polygon aRetPoly;
479 0 : Point aTmpPoint;
480 0 : Rectangle aWorkRect( aTmpPoint, rBmp.GetSizePixel() );
481 :
482 0 : if( pWorkRectPixel )
483 0 : aWorkRect.Intersection( *pWorkRectPixel );
484 :
485 0 : aWorkRect.Justify();
486 :
487 0 : if( ( aWorkRect.GetWidth() > 4 ) && ( aWorkRect.GetHeight() > 4 ) )
488 : {
489 : // if the flag is set, we need to detect edges
490 0 : if( nFlags & XOUTBMP_CONTOUR_EDGEDETECT )
491 0 : aWorkBmp = DetectEdges( rBmp, cEdgeDetectThreshold );
492 : else
493 0 : aWorkBmp = rBmp;
494 :
495 0 : BitmapReadAccess* pAcc = aWorkBmp.AcquireReadAccess();
496 :
497 0 : const long nWidth = pAcc ? pAcc->Width() : 0;
498 0 : const long nHeight = pAcc ? pAcc->Height() : 0;
499 :
500 0 : if (pAcc && nWidth && nHeight)
501 : {
502 0 : const Size& rPrefSize = aWorkBmp.GetPrefSize();
503 0 : const double fFactorX = (double) rPrefSize.Width() / nWidth;
504 0 : const double fFactorY = (double) rPrefSize.Height() / nHeight;
505 0 : const long nStartX1 = aWorkRect.Left() + 1L;
506 0 : const long nEndX1 = aWorkRect.Right();
507 0 : const long nStartX2 = nEndX1 - 1L;
508 0 : const long nStartY1 = aWorkRect.Top() + 1L;
509 0 : const long nEndY1 = aWorkRect.Bottom();
510 0 : const long nStartY2 = nEndY1 - 1L;
511 0 : boost::scoped_array<Point> pPoints1;
512 0 : boost::scoped_array<Point> pPoints2;
513 : long nX, nY;
514 0 : sal_uInt16 nPolyPos = 0;
515 0 : const BitmapColor aBlack = pAcc->GetBestMatchingColor( Color( COL_BLACK ) );
516 :
517 0 : if( nFlags & XOUTBMP_CONTOUR_VERT )
518 : {
519 0 : pPoints1.reset(new Point[ nWidth ]);
520 0 : pPoints2.reset(new Point[ nWidth ]);
521 :
522 0 : for( nX = nStartX1; nX < nEndX1; nX++ )
523 : {
524 0 : nY = nStartY1;
525 :
526 : // scan row from left to right
527 0 : while( nY < nEndY1 )
528 : {
529 0 : if( aBlack == pAcc->GetPixel( nY, nX ) )
530 : {
531 0 : pPoints1[ nPolyPos ] = Point( nX, nY );
532 0 : nY = nStartY2;
533 :
534 : // this loop always breaks eventually as there is at least one pixel
535 : while( true )
536 : {
537 0 : if( aBlack == pAcc->GetPixel( nY, nX ) )
538 : {
539 0 : pPoints2[ nPolyPos ] = Point( nX, nY );
540 0 : break;
541 : }
542 :
543 0 : nY--;
544 : }
545 :
546 0 : nPolyPos++;
547 0 : break;
548 : }
549 :
550 0 : nY++;
551 : }
552 : }
553 : }
554 : else
555 : {
556 0 : pPoints1.reset(new Point[ nHeight ]);
557 0 : pPoints2.reset(new Point[ nHeight ]);
558 :
559 0 : for ( nY = nStartY1; nY < nEndY1; nY++ )
560 : {
561 0 : nX = nStartX1;
562 :
563 : // scan row from left to right
564 0 : while( nX < nEndX1 )
565 : {
566 0 : if( aBlack == pAcc->GetPixel( nY, nX ) )
567 : {
568 0 : pPoints1[ nPolyPos ] = Point( nX, nY );
569 0 : nX = nStartX2;
570 :
571 : // this loop always breaks eventually as there is at least one pixel
572 : while( true )
573 : {
574 0 : if( aBlack == pAcc->GetPixel( nY, nX ) )
575 : {
576 0 : pPoints2[ nPolyPos ] = Point( nX, nY );
577 0 : break;
578 : }
579 :
580 0 : nX--;
581 : }
582 :
583 0 : nPolyPos++;
584 0 : break;
585 : }
586 :
587 0 : nX++;
588 : }
589 : }
590 : }
591 :
592 0 : const sal_uInt16 nNewSize1 = nPolyPos << 1;
593 :
594 0 : aRetPoly = Polygon( nPolyPos, pPoints1.get() );
595 0 : aRetPoly.SetSize( nNewSize1 + 1 );
596 0 : aRetPoly[ nNewSize1 ] = aRetPoly[ 0 ];
597 :
598 0 : for( sal_uInt16 j = nPolyPos; nPolyPos < nNewSize1; )
599 0 : aRetPoly[ nPolyPos++ ] = pPoints2[ --j ];
600 :
601 0 : if( ( fFactorX != 0. ) && ( fFactorY != 0. ) )
602 0 : aRetPoly.Scale( fFactorX, fFactorY );
603 : }
604 : }
605 :
606 0 : return aRetPoly;
607 : };
608 :
609 0 : bool DitherBitmap( Bitmap& rBitmap )
610 : {
611 0 : bool bRet = false;
612 :
613 0 : if( ( rBitmap.GetBitCount() >= 8 ) && ( Application::GetDefaultDevice()->GetColorCount() < 257 ) )
614 0 : bRet = rBitmap.Dither( BMP_DITHER_FLOYD );
615 : else
616 0 : bRet = false;
617 :
618 0 : return bRet;
619 651 : }
620 :
621 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|