Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / source / gdi / impvect.cxx
blob0de467a03d389165112d2f703191fa920a648f55
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <stdlib.h>
21 #include <vcl/bitmapaccess.hxx>
22 #include <tools/poly.hxx>
23 #include <vcl/gdimtf.hxx>
24 #include <vcl/metaact.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/wrkwin.hxx>
27 #include <vcl/virdev.hxx>
28 #include <impvect.hxx>
29 #include <memory>
31 #define VECT_POLY_MAX 8192
33 #define VECT_FREE_INDEX 0
34 #define VECT_CONT_INDEX 1
35 #define VECT_DONE_INDEX 2
37 #define VECT_POLY_INLINE_INNER 1UL
38 #define VECT_POLY_INLINE_OUTER 2UL
39 #define VECT_POLY_OUTLINE_INNER 4UL
40 #define VECT_POLY_OUTLINE_OUTER 8UL
42 #define VECT_MAP( _def_pIn, _def_pOut, _def_nVal ) _def_pOut[_def_nVal]=(_def_pIn[_def_nVal]=((_def_nVal)*4)+1)+5;
43 #define BACK_MAP( _def_nVal ) ((((_def_nVal)+2)>>2)-1)
44 #define VECT_PROGRESS( _def_pProgress, _def_nVal ) \
45 if(_def_pProgress) \
46 (_def_pProgress->Call(_def_nVal));
48 class ImplVectMap;
49 class ImplChain;
51 namespace ImplVectorizer
53 ImplVectMap* ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor );
54 void ImplCalculate( ImplVectMap* pMap, tools::PolyPolygon& rPolyPoly, sal_uInt8 cReduce );
55 bool ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain );
56 bool ImplIsUp( ImplVectMap* pMap, long nY, long nX );
57 void ImplLimitPolyPoly( tools::PolyPolygon& rPolyPoly );
60 struct ChainMove { long nDX; long nDY; };
62 static const ChainMove aImplMove[ 8 ] = {
63 { 1, 0 },
64 { 0, -1 },
65 { -1, 0 },
66 { 0, 1 },
67 { 1, -1 },
68 { -1, -1 },
69 { -1, 1 },
70 { 1, 1 }
73 static const ChainMove aImplMoveInner[ 8 ] = {
74 { 0, 1 },
75 { 1, 0 },
76 { 0, -1 },
77 { -1, 0 },
78 { 0, 1 },
79 { 1, 0 },
80 { 0, -1 },
81 { -1, 0 }
84 static const ChainMove aImplMoveOuter[ 8 ] = {
85 { 0, -1 },
86 { -1, 0 },
87 { 0, 1 },
88 { 1, 0 },
89 { -1, 0 },
90 { 0, 1 },
91 { 1, 0 },
92 { 0, -1 }
95 struct ImplColorSet
97 BitmapColor maColor;
98 sal_uInt16 mnIndex;
99 bool mbSet;
102 extern "C" int SAL_CALL ImplColorSetCmpFnc( const void* p1, const void* p2 )
104 ImplColorSet const * pSet1 = static_cast<ImplColorSet const *>(p1);
105 ImplColorSet const * pSet2 = static_cast<ImplColorSet const *>(p2);
106 int nRet;
108 if( pSet1->mbSet && pSet2->mbSet )
110 const sal_uInt8 cLum1 = pSet1->maColor.GetLuminance();
111 const sal_uInt8 cLum2 = pSet2->maColor.GetLuminance();
112 nRet = ( ( cLum1 > cLum2 ) ? -1 : ( ( cLum1 == cLum2 ) ? 0 : 1 ) );
114 else if( pSet1->mbSet )
115 nRet = -1;
116 else if( pSet2->mbSet )
117 nRet = 1;
118 else
119 nRet = 0;
121 return nRet;
124 class ImplPointArray
126 Point* mpArray;
127 sal_uLong mnSize;
128 sal_uLong mnRealSize;
130 public:
132 ImplPointArray();
133 ~ImplPointArray();
135 void ImplSetSize( sal_uLong nSize );
136 sal_uLong ImplGetRealSize() const { return mnRealSize; }
137 void ImplSetRealSize( sal_uLong nRealSize ) { mnRealSize = nRealSize; }
138 void ImplCreatePoly( tools::Polygon& rPoly ) const;
140 inline Point& operator[]( sal_uLong nPos );
141 inline const Point& operator[]( sal_uLong nPos ) const;
145 ImplPointArray::ImplPointArray() :
146 mpArray ( nullptr ),
147 mnSize ( 0UL ),
148 mnRealSize ( 0UL )
153 ImplPointArray::~ImplPointArray()
155 if( mpArray )
156 rtl_freeMemory( mpArray );
159 void ImplPointArray::ImplSetSize( sal_uLong nSize )
161 const sal_uLong nTotal = nSize * sizeof( Point );
163 mnSize = nSize;
164 mnRealSize = 0UL;
166 if( mpArray )
167 rtl_freeMemory( mpArray );
169 mpArray = static_cast<Point*>(rtl_allocateMemory( nTotal ));
170 memset( mpArray, 0, nTotal );
173 inline Point& ImplPointArray::operator[]( sal_uLong nPos )
175 SAL_WARN_IF( nPos >= mnSize, "vcl", "ImplPointArray::operator[]: nPos out of range!" );
176 return mpArray[ nPos ];
179 inline const Point& ImplPointArray::operator[]( sal_uLong nPos ) const
181 SAL_WARN_IF( nPos >= mnSize, "vcl", "ImplPointArray::operator[]: nPos out of range!" );
182 return mpArray[ nPos ];
185 void ImplPointArray::ImplCreatePoly( tools::Polygon& rPoly ) const
187 rPoly = tools::Polygon( sal::static_int_cast<sal_uInt16>(mnRealSize), mpArray );
190 class ImplVectMap
192 private:
194 Scanline mpBuf;
195 Scanline* mpScan;
196 long mnWidth;
197 long mnHeight;
199 public:
201 ImplVectMap( long nWidth, long nHeight );
202 ~ImplVectMap();
204 long Width() const { return mnWidth; }
205 long Height() const { return mnHeight; }
207 inline void Set( long nY, long nX, sal_uInt8 cVal );
208 inline sal_uInt8 Get( long nY, long nX ) const;
210 inline bool IsFree( long nY, long nX ) const;
211 inline bool IsCont( long nY, long nX ) const;
212 inline bool IsDone( long nY, long nX ) const;
216 ImplVectMap::ImplVectMap( long nWidth, long nHeight ) :
217 mnWidth ( nWidth ),
218 mnHeight( nHeight )
220 const long nWidthAl = ( nWidth >> 2 ) + 1;
221 const long nSize = nWidthAl * nHeight;
222 Scanline pTmp = mpBuf = static_cast<Scanline>(rtl_allocateMemory( nSize ));
224 memset( mpBuf, 0, nSize );
225 mpScan = static_cast<Scanline*>(rtl_allocateMemory( nHeight * sizeof( Scanline ) ));
227 for( long nY = 0; nY < nHeight; pTmp += nWidthAl )
228 mpScan[ nY++ ] = pTmp;
231 ImplVectMap::~ImplVectMap()
233 rtl_freeMemory( mpBuf );
234 rtl_freeMemory( mpScan );
237 inline void ImplVectMap::Set( long nY, long nX, sal_uInt8 cVal )
239 const sal_uInt8 cShift = sal::static_int_cast<sal_uInt8>(6 - ( ( nX & 3 ) << 1 ));
240 ( ( mpScan[ nY ][ nX >> 2 ] ) &= ~( 3 << cShift ) ) |= ( cVal << cShift );
243 inline sal_uInt8 ImplVectMap::Get( long nY, long nX ) const
245 return sal::static_int_cast<sal_uInt8>( ( ( mpScan[ nY ][ nX >> 2 ] ) >> ( 6 - ( ( nX & 3 ) << 1 ) ) ) & 3 );
248 inline bool ImplVectMap::IsFree( long nY, long nX ) const
250 return( VECT_FREE_INDEX == Get( nY, nX ) );
253 inline bool ImplVectMap::IsCont( long nY, long nX ) const
255 return( VECT_CONT_INDEX == Get( nY, nX ) );
258 inline bool ImplVectMap::IsDone( long nY, long nX ) const
260 return( VECT_DONE_INDEX == Get( nY, nX ) );
263 class ImplChain
265 private:
267 tools::Polygon maPoly;
268 Point maStartPt;
269 sal_uLong mnArraySize;
270 sal_uLong mnCount;
271 std::unique_ptr<sal_uInt8[]>
272 mpCodes;
274 void ImplGetSpace();
276 void ImplPostProcess( const ImplPointArray& rArr );
278 ImplChain(const ImplChain&) = delete;
279 ImplChain& operator=(const ImplChain&) = delete;
281 public:
283 ImplChain();
285 void ImplBeginAdd( const Point& rStartPt );
286 inline void ImplAdd( sal_uInt8 nCode );
287 void ImplEndAdd( sal_uLong nTypeFlag );
289 const tools::Polygon& ImplGetPoly() const { return maPoly; }
292 ImplChain::ImplChain() :
293 mnArraySize ( 1024UL ),
294 mnCount ( 0UL )
296 mpCodes.reset( new sal_uInt8[ mnArraySize ] );
299 void ImplChain::ImplGetSpace()
301 const sal_uLong nOldArraySize = mnArraySize;
302 sal_uInt8* pNewCodes;
304 mnArraySize = mnArraySize << 1UL;
305 pNewCodes = new sal_uInt8[ mnArraySize ];
306 memcpy( pNewCodes, mpCodes.get(), nOldArraySize );
307 mpCodes.reset( pNewCodes );
310 void ImplChain::ImplBeginAdd( const Point& rStartPt )
312 maPoly = tools::Polygon();
313 maStartPt = rStartPt;
314 mnCount = 0UL;
317 inline void ImplChain::ImplAdd( sal_uInt8 nCode )
319 if( mnCount == mnArraySize )
320 ImplGetSpace();
322 mpCodes[ mnCount++ ] = nCode;
325 void ImplChain::ImplEndAdd( sal_uLong nFlag )
327 if( mnCount )
329 ImplPointArray aArr;
331 if( nFlag & VECT_POLY_INLINE_INNER )
333 long nFirstX, nFirstY;
334 long nLastX, nLastY;
336 nFirstX = nLastX = maStartPt.X();
337 nFirstY = nLastY = maStartPt.Y();
338 aArr.ImplSetSize( mnCount << 1 );
340 sal_uInt16 i, nPolyPos;
341 for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ )
343 const sal_uInt8 cMove = mpCodes[ i ];
344 const sal_uInt8 cNextMove = mpCodes[ i + 1 ];
345 const ChainMove& rMove = aImplMove[ cMove ];
346 const ChainMove& rMoveInner = aImplMoveInner[ cMove ];
347 // Point& rPt = aArr[ nPolyPos ];
348 bool bDone = true;
350 nLastX += rMove.nDX;
351 nLastY += rMove.nDY;
353 if( cMove < 4 )
355 if( ( cMove == 0 && cNextMove == 3 ) ||
356 ( cMove == 3 && cNextMove == 2 ) ||
357 ( cMove == 2 && cNextMove == 1 ) ||
358 ( cMove == 1 && cNextMove == 0 ) )
361 else if( cMove == 2 && cNextMove == 3 )
363 aArr[ nPolyPos ].X() = nLastX;
364 aArr[ nPolyPos++ ].Y() = nLastY - 1;
366 aArr[ nPolyPos ].X() = nLastX - 1;
367 aArr[ nPolyPos++ ].Y() = nLastY - 1;
369 aArr[ nPolyPos ].X() = nLastX - 1;
370 aArr[ nPolyPos++ ].Y() = nLastY;
372 else if( cMove == 3 && cNextMove == 0 )
374 aArr[ nPolyPos ].X() = nLastX - 1;
375 aArr[ nPolyPos++ ].Y() = nLastY;
377 aArr[ nPolyPos ].X() = nLastX - 1;
378 aArr[ nPolyPos++ ].Y() = nLastY + 1;
380 aArr[ nPolyPos ].X() = nLastX;
381 aArr[ nPolyPos++ ].Y() = nLastY + 1;
383 else if( cMove == 0 && cNextMove == 1 )
385 aArr[ nPolyPos ].X() = nLastX;
386 aArr[ nPolyPos++ ].Y() = nLastY + 1;
388 aArr[ nPolyPos ].X() = nLastX + 1;
389 aArr[ nPolyPos++ ].Y() = nLastY + 1;
391 aArr[ nPolyPos ].X() = nLastX + 1;
392 aArr[ nPolyPos++ ].Y() = nLastY;
394 else if( cMove == 1 && cNextMove == 2 )
396 aArr[ nPolyPos ].X() = nLastX + 1;
397 aArr[ nPolyPos++ ].Y() = nLastY + 1;
399 aArr[ nPolyPos ].X() = nLastX + 1;
400 aArr[ nPolyPos++ ].Y() = nLastY - 1;
402 aArr[ nPolyPos ].X() = nLastX;
403 aArr[ nPolyPos++ ].Y() = nLastY - 1;
405 else
406 bDone = false;
408 else if( cMove == 7 && cNextMove == 0 )
410 aArr[ nPolyPos ].X() = nLastX - 1;
411 aArr[ nPolyPos++ ].Y() = nLastY;
413 aArr[ nPolyPos ].X() = nLastX;
414 aArr[ nPolyPos++ ].Y() = nLastY + 1;
416 else if( cMove == 4 && cNextMove == 1 )
418 aArr[ nPolyPos ].X() = nLastX;
419 aArr[ nPolyPos++ ].Y() = nLastY + 1;
421 aArr[ nPolyPos ].X() = nLastX + 1;
422 aArr[ nPolyPos++ ].Y() = nLastY;
424 else
425 bDone = false;
427 if( !bDone )
429 aArr[ nPolyPos ].X() = nLastX + rMoveInner.nDX;
430 aArr[ nPolyPos++ ].Y() = nLastY + rMoveInner.nDY;
434 aArr[ nPolyPos ].X() = nFirstX + 1;
435 aArr[ nPolyPos++ ].Y() = nFirstY + 1;
436 aArr.ImplSetRealSize( nPolyPos );
438 else if( nFlag & VECT_POLY_INLINE_OUTER )
440 long nFirstX, nFirstY;
441 long nLastX, nLastY;
443 nFirstX = nLastX = maStartPt.X();
444 nFirstY = nLastY = maStartPt.Y();
445 aArr.ImplSetSize( mnCount << 1 );
447 sal_uInt16 i, nPolyPos;
448 for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ )
450 const sal_uInt8 cMove = mpCodes[ i ];
451 const sal_uInt8 cNextMove = mpCodes[ i + 1 ];
452 const ChainMove& rMove = aImplMove[ cMove ];
453 const ChainMove& rMoveOuter = aImplMoveOuter[ cMove ];
454 // Point& rPt = aArr[ nPolyPos ];
455 bool bDone = true;
457 nLastX += rMove.nDX;
458 nLastY += rMove.nDY;
460 if( cMove < 4 )
462 if( ( cMove == 0 && cNextMove == 1 ) ||
463 ( cMove == 1 && cNextMove == 2 ) ||
464 ( cMove == 2 && cNextMove == 3 ) ||
465 ( cMove == 3 && cNextMove == 0 ) )
468 else if( cMove == 0 && cNextMove == 3 )
470 aArr[ nPolyPos ].X() = nLastX;
471 aArr[ nPolyPos++ ].Y() = nLastY - 1;
473 aArr[ nPolyPos ].X() = nLastX + 1;
474 aArr[ nPolyPos++ ].Y() = nLastY - 1;
476 aArr[ nPolyPos ].X() = nLastX + 1;
477 aArr[ nPolyPos++ ].Y() = nLastY;
479 else if( cMove == 3 && cNextMove == 2 )
481 aArr[ nPolyPos ].X() = nLastX + 1;
482 aArr[ nPolyPos++ ].Y() = nLastY;
484 aArr[ nPolyPos ].X() = nLastX + 1;
485 aArr[ nPolyPos++ ].Y() = nLastY + 1;
487 aArr[ nPolyPos ].X() = nLastX;
488 aArr[ nPolyPos++ ].Y() = nLastY + 1;
490 else if( cMove == 2 && cNextMove == 1 )
492 aArr[ nPolyPos ].X() = nLastX;
493 aArr[ nPolyPos++ ].Y() = nLastY + 1;
495 aArr[ nPolyPos ].X() = nLastX - 1;
496 aArr[ nPolyPos++ ].Y() = nLastY + 1;
498 aArr[ nPolyPos ].X() = nLastX - 1;
499 aArr[ nPolyPos++ ].Y() = nLastY;
501 else if( cMove == 1 && cNextMove == 0 )
503 aArr[ nPolyPos ].X() = nLastX - 1;
504 aArr[ nPolyPos++ ].Y() = nLastY;
506 aArr[ nPolyPos ].X() = nLastX - 1;
507 aArr[ nPolyPos++ ].Y() = nLastY - 1;
509 aArr[ nPolyPos ].X() = nLastX;
510 aArr[ nPolyPos++ ].Y() = nLastY - 1;
512 else
513 bDone = false;
515 else if( cMove == 7 && cNextMove == 3 )
517 aArr[ nPolyPos ].X() = nLastX;
518 aArr[ nPolyPos++ ].Y() = nLastY - 1;
520 aArr[ nPolyPos ].X() = nLastX + 1;
521 aArr[ nPolyPos++ ].Y() = nLastY;
523 else if( cMove == 6 && cNextMove == 2 )
525 aArr[ nPolyPos ].X() = nLastX + 1;
526 aArr[ nPolyPos++ ].Y() = nLastY;
528 aArr[ nPolyPos ].X() = nLastX;
529 aArr[ nPolyPos++ ].Y() = nLastY + 1;
531 else
532 bDone = false;
534 if( !bDone )
536 aArr[ nPolyPos ].X() = nLastX + rMoveOuter.nDX;
537 aArr[ nPolyPos++ ].Y() = nLastY + rMoveOuter.nDY;
541 aArr[ nPolyPos ].X() = nFirstX - 1;
542 aArr[ nPolyPos++ ].Y() = nFirstY - 1;
543 aArr.ImplSetRealSize( nPolyPos );
545 else
547 long nLastX = maStartPt.X(), nLastY = maStartPt.Y();
549 aArr.ImplSetSize( mnCount + 1 );
550 aArr[ 0 ] = Point( nLastX, nLastY );
552 for( sal_uLong i = 0; i < mnCount; )
554 const ChainMove& rMove = aImplMove[ mpCodes[ i ] ];
555 aArr[ ++i ] = Point( nLastX += rMove.nDX, nLastY += rMove.nDY );
558 aArr.ImplSetRealSize( mnCount + 1 );
561 ImplPostProcess( aArr );
563 else
564 maPoly.SetSize( 0 );
567 void ImplChain::ImplPostProcess( const ImplPointArray& rArr )
569 ImplPointArray aNewArr1;
570 ImplPointArray aNewArr2;
571 Point* pLast;
572 Point* pLeast;
573 sal_uLong nNewPos;
574 sal_uLong nCount = rArr.ImplGetRealSize();
575 sal_uLong n;
577 // pass 1
578 aNewArr1.ImplSetSize( nCount );
579 pLast = &( aNewArr1[ 0 ] );
580 pLast->X() = BACK_MAP( rArr[ 0 ].X() );
581 pLast->Y() = BACK_MAP( rArr[ 0 ].Y() );
583 for( n = nNewPos = 1; n < nCount; )
585 const Point& rPt = rArr[ n++ ];
586 const long nX = BACK_MAP( rPt.X() );
587 const long nY = BACK_MAP( rPt.Y() );
589 if( nX != pLast->X() || nY != pLast->Y() )
591 pLast = pLeast = &( aNewArr1[ nNewPos++ ] );
592 pLeast->X() = nX;
593 pLeast->Y() = nY;
597 aNewArr1.ImplSetRealSize( nCount = nNewPos );
599 // pass 2
600 aNewArr2.ImplSetSize( nCount );
601 pLast = &( aNewArr2[ 0 ] );
602 *pLast = aNewArr1[ 0 ];
604 for( n = nNewPos = 1; n < nCount; )
606 pLeast = &( aNewArr1[ n++ ] );
608 if( pLeast->X() == pLast->X() )
610 while( n < nCount && aNewArr1[ n ].X() == pLast->X() )
611 pLeast = &( aNewArr1[ n++ ] );
613 else if( pLeast->Y() == pLast->Y() )
615 while( n < nCount && aNewArr1[ n ].Y() == pLast->Y() )
616 pLeast = &( aNewArr1[ n++ ] );
619 aNewArr2[ nNewPos++ ] = *( pLast = pLeast );
622 aNewArr2.ImplSetRealSize( nNewPos );
623 aNewArr2.ImplCreatePoly( maPoly );
626 namespace ImplVectorizer {
628 bool ImplVectorize( const Bitmap& rColorBmp, GDIMetaFile& rMtf,
629 sal_uInt8 cReduce, const Link<long,void>* pProgress )
631 bool bRet = false;
633 VECT_PROGRESS( pProgress, 0 );
635 std::unique_ptr<Bitmap> xBmp(new Bitmap( rColorBmp ));
636 Bitmap::ScopedReadAccess pRAcc(*xBmp);
638 if( pRAcc )
640 tools::PolyPolygon aPolyPoly;
641 double fPercent = 0.0;
642 double fPercentStep_2 = 0.0;
643 const long nWidth = pRAcc->Width();
644 const long nHeight = pRAcc->Height();
645 const sal_uInt16 nColorCount = pRAcc->GetPaletteEntryCount();
646 sal_uInt16 n;
647 ImplColorSet* pColorSet = reinterpret_cast<ImplColorSet*>(new sal_uInt8[ 256 * sizeof( ImplColorSet ) ]);
649 memset( pColorSet, 0, 256 * sizeof( ImplColorSet ) );
650 rMtf.Clear();
652 // get used palette colors and sort them from light to dark colors
653 for( n = 0; n < nColorCount; n++ )
655 pColorSet[ n ].mnIndex = n;
656 pColorSet[ n ].maColor = pRAcc->GetPaletteColor( n );
659 for( long nY = 0; nY < nHeight; nY++ )
660 for( long nX = 0; nX < nWidth; nX++ )
661 pColorSet[ pRAcc->GetPixel( nY, nX ).GetIndex() ].mbSet = true;
663 qsort( pColorSet, 256, sizeof( ImplColorSet ), ImplColorSetCmpFnc );
665 for( n = 0; n < 256; n++ )
666 if( !pColorSet[ n ].mbSet )
667 break;
669 if( n )
670 fPercentStep_2 = 45.0 / n;
672 VECT_PROGRESS( pProgress, FRound( fPercent += 10.0 ) );
674 for( sal_uInt16 i = 0; i < n; i++ )
676 const BitmapColor aBmpCol( pRAcc->GetPaletteColor( pColorSet[ i ].mnIndex ) );
677 const Color aFindColor( aBmpCol.GetRed(), aBmpCol.GetGreen(), aBmpCol.GetBlue() );
678 std::unique_ptr<ImplVectMap> xMap(ImplExpand( pRAcc.get(), aFindColor ));
680 VECT_PROGRESS( pProgress, FRound( fPercent += fPercentStep_2 ) );
682 if( xMap )
684 aPolyPoly.Clear();
685 ImplCalculate( xMap.get(), aPolyPoly, cReduce );
686 xMap.reset();
688 if( aPolyPoly.Count() )
690 ImplLimitPolyPoly( aPolyPoly );
692 aPolyPoly.Optimize( PolyOptimizeFlags::EDGES );
694 if( aPolyPoly.Count() )
696 rMtf.AddAction( new MetaLineColorAction( aFindColor, true ) );
697 rMtf.AddAction( new MetaFillColorAction( aFindColor, true ) );
698 rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) );
703 VECT_PROGRESS( pProgress, FRound( fPercent += fPercentStep_2 ) );
706 delete[] reinterpret_cast<sal_uInt8*>(pColorSet);
708 if( rMtf.GetActionSize() )
710 MapMode aMap( MapUnit::Map100thMM );
711 ScopedVclPtrInstance< VirtualDevice > aVDev;
712 const Size aLogSize1( aVDev->PixelToLogic( Size( 1, 1 ), aMap ) );
714 rMtf.SetPrefMapMode( aMap );
715 rMtf.SetPrefSize( Size( nWidth + 2, nHeight + 2 ) );
716 rMtf.Move( 1, 1 );
717 rMtf.Scale( aLogSize1.Width(), aLogSize1.Height() );
718 bRet = true;
722 pRAcc.reset();
723 xBmp.reset();
724 VECT_PROGRESS( pProgress, 100 );
726 return bRet;
729 void ImplLimitPolyPoly( tools::PolyPolygon& rPolyPoly )
731 if( rPolyPoly.Count() > VECT_POLY_MAX )
733 tools::PolyPolygon aNewPolyPoly;
734 long nReduce = 0;
735 sal_uInt16 nNewCount;
739 aNewPolyPoly.Clear();
740 nReduce++;
742 for( sal_uInt16 i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ )
744 const tools::Rectangle aBound( rPolyPoly[ i ].GetBoundRect() );
746 if( aBound.GetWidth() > nReduce && aBound.GetHeight() > nReduce )
748 if( rPolyPoly[ i ].GetSize() )
749 aNewPolyPoly.Insert( rPolyPoly[ i ] );
753 nNewCount = aNewPolyPoly.Count();
755 while( nNewCount > VECT_POLY_MAX );
757 rPolyPoly = aNewPolyPoly;
761 ImplVectMap* ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor )
763 ImplVectMap* pMap = nullptr;
765 if( pRAcc && pRAcc->Width() && pRAcc->Height() )
767 const long nOldWidth = pRAcc->Width();
768 const long nOldHeight = pRAcc->Height();
769 const long nNewWidth = ( nOldWidth << 2 ) + 4;
770 const long nNewHeight = ( nOldHeight << 2 ) + 4;
771 const BitmapColor aTest( pRAcc->GetBestMatchingColor( rColor ) );
772 std::unique_ptr<long[]> pMapIn(new long[ std::max( nOldWidth, nOldHeight ) ]);
773 std::unique_ptr<long[]> pMapOut(new long[ std::max( nOldWidth, nOldHeight ) ]);
774 long nX, nY, nTmpX, nTmpY;
776 pMap = new ImplVectMap( nNewWidth, nNewHeight );
778 for( nX = 0; nX < nOldWidth; nX++ )
779 VECT_MAP( pMapIn, pMapOut, nX );
781 for( nY = 0, nTmpY = 5; nY < nOldHeight; nY++, nTmpY += 4 )
783 for( nX = 0; nX < nOldWidth; )
785 if( pRAcc->GetPixel( nY, nX ) == aTest )
787 nTmpX = pMapIn[ nX++ ];
788 nTmpY -= 3;
790 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
791 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
792 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
793 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
795 while( nX < nOldWidth && pRAcc->GetPixel( nY, nX ) == aTest )
796 nX++;
798 nTmpX = pMapOut[ nX - 1 ];
799 nTmpY -= 3;
801 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
802 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
803 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
804 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
806 else
807 nX++;
811 for( nY = 0; nY < nOldHeight; nY++ )
812 VECT_MAP( pMapIn, pMapOut, nY );
814 for( nX = 0, nTmpX = 5; nX < nOldWidth; nX++, nTmpX += 4 )
816 for( nY = 0; nY < nOldHeight; )
818 if( pRAcc->GetPixel( nY, nX ) == aTest )
820 nTmpX -= 3;
821 nTmpY = pMapIn[ nY++ ];
823 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
824 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
825 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
826 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
828 while( nY < nOldHeight && pRAcc->GetPixel( nY, nX ) == aTest )
829 nY++;
831 nTmpX -= 3;
832 nTmpY = pMapOut[ nY - 1 ];
834 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
835 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
836 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
837 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
839 else
840 nY++;
845 return pMap;
848 void ImplCalculate( ImplVectMap* pMap, tools::PolyPolygon& rPolyPoly, sal_uInt8 cReduce )
850 const long nWidth = pMap->Width(), nHeight= pMap->Height();
852 for( long nY = 0; nY < nHeight; nY++ )
854 long nX = 0;
855 bool bInner = true;
857 while( nX < nWidth )
859 // skip free
860 while( ( nX < nWidth ) && pMap->IsFree( nY, nX ) )
861 nX++;
863 if( nX == nWidth )
864 break;
866 if( pMap->IsCont( nY, nX ) )
868 // new contour
869 ImplChain aChain;
870 const Point aStartPt( nX++, nY );
872 // get chain code
873 aChain.ImplBeginAdd( aStartPt );
874 ImplGetChain( pMap, aStartPt, aChain );
876 aChain.ImplEndAdd( bInner ? VECT_POLY_OUTLINE_INNER : VECT_POLY_OUTLINE_OUTER );
878 const tools::Polygon& rPoly = aChain.ImplGetPoly();
880 if( rPoly.GetSize() > 2 )
882 if( cReduce )
884 const tools::Rectangle aBound( rPoly.GetBoundRect() );
886 if( aBound.GetWidth() > cReduce && aBound.GetHeight() > cReduce )
887 rPolyPoly.Insert( rPoly );
889 else
890 rPolyPoly.Insert( rPoly );
893 // skip rest of detected contour
894 while( pMap->IsCont( nY, nX ) )
895 nX++;
897 else
899 // process done segment
900 const long nStartSegX = nX++;
902 while( pMap->IsDone( nY, nX ) )
903 nX++;
905 if( ( ( nX - nStartSegX ) == 1 ) || ( ImplIsUp( pMap, nY, nStartSegX ) != ImplIsUp( pMap, nY, nX - 1 ) ) )
906 bInner = !bInner;
912 bool ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain )
914 long nActX = rStartPt.X();
915 long nActY = rStartPt.Y();
916 sal_uLong nFound;
917 sal_uLong nLastDir = 0UL;
918 sal_uLong nDir;
922 nFound = 0UL;
924 // first try last direction
925 long nTryX = nActX + aImplMove[ nLastDir ].nDX;
926 long nTryY = nActY + aImplMove[ nLastDir ].nDY;
928 if( pMap->IsCont( nTryY, nTryX ) )
930 rChain.ImplAdd( (sal_uInt8) nLastDir );
931 pMap->Set( nActY = nTryY, nActX = nTryX, VECT_DONE_INDEX );
932 nFound = 1UL;
934 else
936 // try other directions
937 for( nDir = 0UL; nDir < 8UL; nDir++ )
939 // we already tried nLastDir
940 if( nDir != nLastDir )
942 nTryX = nActX + aImplMove[ nDir ].nDX;
943 nTryY = nActY + aImplMove[ nDir ].nDY;
945 if( pMap->IsCont( nTryY, nTryX ) )
947 rChain.ImplAdd( (sal_uInt8) nDir );
948 pMap->Set( nActY = nTryY, nActX = nTryX, VECT_DONE_INDEX );
949 nFound = 1UL;
950 nLastDir = nDir;
951 break;
957 while( nFound );
959 return true;
962 bool ImplIsUp( ImplVectMap* pMap, long nY, long nX )
964 if( pMap->IsDone( nY - 1, nX ) )
965 return true;
966 else if( pMap->IsDone( nY + 1, nX ) )
967 return false;
968 else if( pMap->IsDone( nY - 1, nX - 1 ) || pMap->IsDone( nY - 1, nX + 1 ) )
969 return true;
970 else
971 return false;
976 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */