update emoji autocorrect entries from po-files
[LibreOffice.git] / vcl / source / gdi / impvect.cxx
blob166f0be371489b888a24cab1df05f592bec97cec
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/bmpacc.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 <boost/scoped_array.hpp>
30 #include <memory>
32 #define VECT_POLY_MAX 8192
34 #define VECT_FREE_INDEX 0
35 #define VECT_CONT_INDEX 1
36 #define VECT_DONE_INDEX 2
38 #define VECT_POLY_INLINE_INNER 1UL
39 #define VECT_POLY_INLINE_OUTER 2UL
40 #define VECT_POLY_OUTLINE_INNER 4UL
41 #define VECT_POLY_OUTLINE_OUTER 8UL
43 #define VECT_MAP( _def_pIn, _def_pOut, _def_nVal ) _def_pOut[_def_nVal]=(_def_pIn[_def_nVal]=((_def_nVal)*4L)+1L)+5L;
44 #define BACK_MAP( _def_nVal ) ((((_def_nVal)+2)>>2)-1)
45 #define VECT_PROGRESS( _def_pProgress, _def_nVal ) \
46 if(_def_pProgress&&_def_pProgress->IsSet()) \
47 (_def_pProgress->Call(reinterpret_cast<void*>(_def_nVal)));
49 class ImplVectMap;
50 class ImplChain;
52 namespace ImplVectorizer
54 ImplVectMap* ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor );
55 void ImplCalculate( ImplVectMap* pMap, tools::PolyPolygon& rPolyPoly, sal_uInt8 cReduce, BmpVectorizeFlags nFlags );
56 bool ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain );
57 bool ImplIsUp( ImplVectMap* pMap, long nY, long nX );
58 void ImplLimitPolyPoly( tools::PolyPolygon& rPolyPoly );
61 struct ChainMove { long nDX; long nDY; };
63 static const ChainMove aImplMove[ 8 ] = {
64 { 1L, 0L },
65 { 0L, -1L },
66 { -1L, 0L },
67 { 0L, 1L },
68 { 1L, -1L },
69 { -1, -1L },
70 { -1L, 1L },
71 { 1L, 1L }
74 static const ChainMove aImplMoveInner[ 8 ] = {
75 { 0L, 1L },
76 { 1L, 0L },
77 { 0L, -1L },
78 { -1L, 0L },
79 { 0L, 1L },
80 { 1L, 0L },
81 { 0L, -1L },
82 { -1L, 0L }
85 static const ChainMove aImplMoveOuter[ 8 ] = {
86 { 0L, -1L },
87 { -1L, 0L },
88 { 0L, 1L },
89 { 1L, 0L },
90 { -1L, 0L },
91 { 0L, 1L },
92 { 1L, 0L },
93 { 0L, -1L }
96 struct ImplColorSet
98 BitmapColor maColor;
99 sal_uInt16 mnIndex;
100 bool mbSet;
103 extern "C" int SAL_CALL ImplColorSetCmpFnc( const void* p1, const void* p2 )
105 ImplColorSet const * pSet1 = static_cast<ImplColorSet const *>(p1);
106 ImplColorSet const * pSet2 = static_cast<ImplColorSet const *>(p2);
107 int nRet;
109 if( pSet1->mbSet && pSet2->mbSet )
111 const sal_uInt8 cLum1 = pSet1->maColor.GetLuminance();
112 const sal_uInt8 cLum2 = pSet2->maColor.GetLuminance();
113 nRet = ( ( cLum1 > cLum2 ) ? -1 : ( ( cLum1 == cLum2 ) ? 0 : 1 ) );
115 else if( pSet1->mbSet )
116 nRet = -1;
117 else if( pSet2->mbSet )
118 nRet = 1;
119 else
120 nRet = 0;
122 return nRet;
125 class ImplPointArray
127 Point* mpArray;
128 sal_uLong mnSize;
129 sal_uLong mnRealSize;
131 public:
133 ImplPointArray();
134 ~ImplPointArray();
136 void ImplSetSize( sal_uLong nSize );
138 sal_uLong ImplGetRealSize() const { return mnRealSize; }
139 void ImplSetRealSize( sal_uLong nRealSize ) { mnRealSize = nRealSize; }
141 inline Point& operator[]( sal_uLong nPos );
142 inline const Point& operator[]( sal_uLong nPos ) const;
144 void ImplCreatePoly( Polygon& rPoly ) const;
147 ImplPointArray::ImplPointArray() :
148 mpArray ( NULL ),
149 mnSize ( 0UL ),
150 mnRealSize ( 0UL )
155 ImplPointArray::~ImplPointArray()
157 if( mpArray )
158 rtl_freeMemory( mpArray );
161 void ImplPointArray::ImplSetSize( sal_uLong nSize )
163 const sal_uLong nTotal = nSize * sizeof( Point );
165 mnSize = nSize;
166 mnRealSize = 0UL;
168 if( mpArray )
169 rtl_freeMemory( mpArray );
171 mpArray = static_cast<Point*>(rtl_allocateMemory( nTotal ));
172 memset( mpArray, 0, nTotal );
175 inline Point& ImplPointArray::operator[]( sal_uLong nPos )
177 DBG_ASSERT( nPos < mnSize, "ImplPointArray::operator[]: nPos out of range!" );
178 return mpArray[ nPos ];
181 inline const Point& ImplPointArray::operator[]( sal_uLong nPos ) const
183 DBG_ASSERT( nPos < mnSize, "ImplPointArray::operator[]: nPos out of range!" );
184 return mpArray[ nPos ];
187 void ImplPointArray::ImplCreatePoly( Polygon& rPoly ) const
189 rPoly = Polygon( sal::static_int_cast<sal_uInt16>(mnRealSize), mpArray );
192 class ImplVectMap
194 private:
196 Scanline mpBuf;
197 Scanline* mpScan;
198 long mnWidth;
199 long mnHeight;
201 public:
203 ImplVectMap( long nWidth, long nHeight );
204 ~ImplVectMap();
206 inline long Width() const { return mnWidth; }
207 inline long Height() const { return mnHeight; }
209 inline void Set( long nY, long nX, sal_uInt8 cVal );
210 inline sal_uInt8 Get( long nY, long nX ) const;
212 inline bool IsFree( long nY, long nX ) const;
213 inline bool IsCont( long nY, long nX ) const;
214 inline bool IsDone( long nY, long nX ) const;
218 ImplVectMap::ImplVectMap( long nWidth, long nHeight ) :
219 mnWidth ( nWidth ),
220 mnHeight( nHeight )
222 const long nWidthAl = ( nWidth >> 2L ) + 1L;
223 const long nSize = nWidthAl * nHeight;
224 Scanline pTmp = mpBuf = static_cast<Scanline>(rtl_allocateMemory( nSize ));
226 memset( mpBuf, 0, nSize );
227 mpScan = static_cast<Scanline*>(rtl_allocateMemory( nHeight * sizeof( Scanline ) ));
229 for( long nY = 0L; nY < nHeight; pTmp += nWidthAl )
230 mpScan[ nY++ ] = pTmp;
233 ImplVectMap::~ImplVectMap()
235 rtl_freeMemory( mpBuf );
236 rtl_freeMemory( mpScan );
239 inline void ImplVectMap::Set( long nY, long nX, sal_uInt8 cVal )
241 const sal_uInt8 cShift = sal::static_int_cast<sal_uInt8>(6 - ( ( nX & 3 ) << 1 ));
242 ( ( mpScan[ nY ][ nX >> 2 ] ) &= ~( 3 << cShift ) ) |= ( cVal << cShift );
245 inline sal_uInt8 ImplVectMap::Get( long nY, long nX ) const
247 return sal::static_int_cast<sal_uInt8>( ( ( mpScan[ nY ][ nX >> 2 ] ) >> ( 6 - ( ( nX & 3 ) << 1 ) ) ) & 3 );
250 inline bool ImplVectMap::IsFree( long nY, long nX ) const
252 return( VECT_FREE_INDEX == Get( nY, nX ) );
255 inline bool ImplVectMap::IsCont( long nY, long nX ) const
257 return( VECT_CONT_INDEX == Get( nY, nX ) );
260 inline bool ImplVectMap::IsDone( long nY, long nX ) const
262 return( VECT_DONE_INDEX == Get( nY, nX ) );
265 class ImplChain
267 private:
269 Polygon maPoly;
270 Point maStartPt;
271 sal_uLong mnArraySize;
272 sal_uLong mnCount;
273 long mnResize;
274 sal_uInt8* mpCodes;
276 void ImplGetSpace();
278 void ImplPostProcess( const ImplPointArray& rArr );
280 public:
282 ImplChain( sal_uLong nInitCount = 1024UL, long nResize = -1L );
283 ~ImplChain();
285 void ImplBeginAdd( const Point& rStartPt );
286 inline void ImplAdd( sal_uInt8 nCode );
287 void ImplEndAdd( sal_uLong nTypeFlag );
289 const Polygon& ImplGetPoly() const { return maPoly; }
292 ImplChain::ImplChain( sal_uLong nInitCount, long nResize ) :
293 mnArraySize ( nInitCount ),
294 mnCount ( 0UL ),
295 mnResize ( nResize )
297 DBG_ASSERT( nInitCount && nResize, "ImplChain::ImplChain(): invalid parameters!" );
298 mpCodes = new sal_uInt8[ mnArraySize ];
301 ImplChain::~ImplChain()
303 delete[] mpCodes;
306 void ImplChain::ImplGetSpace()
308 const sal_uLong nOldArraySize = mnArraySize;
309 sal_uInt8* pNewCodes;
311 mnArraySize = ( mnResize < 0L ) ? ( mnArraySize << 1UL ) : ( mnArraySize + (sal_uLong) mnResize );
312 pNewCodes = new sal_uInt8[ mnArraySize ];
313 memcpy( pNewCodes, mpCodes, nOldArraySize );
314 delete[] mpCodes;
315 mpCodes = pNewCodes;
318 void ImplChain::ImplBeginAdd( const Point& rStartPt )
320 maPoly = Polygon();
321 maStartPt = rStartPt;
322 mnCount = 0UL;
325 inline void ImplChain::ImplAdd( sal_uInt8 nCode )
327 if( mnCount == mnArraySize )
328 ImplGetSpace();
330 mpCodes[ mnCount++ ] = nCode;
333 void ImplChain::ImplEndAdd( sal_uLong nFlag )
335 if( mnCount )
337 ImplPointArray aArr;
339 if( nFlag & VECT_POLY_INLINE_INNER )
341 long nFirstX, nFirstY;
342 long nLastX, nLastY;
344 nFirstX = nLastX = maStartPt.X();
345 nFirstY = nLastY = maStartPt.Y();
346 aArr.ImplSetSize( mnCount << 1 );
348 sal_uInt16 i, nPolyPos;
349 for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ )
351 const sal_uInt8 cMove = mpCodes[ i ];
352 const sal_uInt8 cNextMove = mpCodes[ i + 1 ];
353 const ChainMove& rMove = aImplMove[ cMove ];
354 const ChainMove& rMoveInner = aImplMoveInner[ cMove ];
355 // Point& rPt = aArr[ nPolyPos ];
356 bool bDone = true;
358 nLastX += rMove.nDX;
359 nLastY += rMove.nDY;
361 if( cMove < 4 )
363 if( ( cMove == 0 && cNextMove == 3 ) ||
364 ( cMove == 3 && cNextMove == 2 ) ||
365 ( cMove == 2 && cNextMove == 1 ) ||
366 ( cMove == 1 && cNextMove == 0 ) )
369 else if( cMove == 2 && cNextMove == 3 )
371 aArr[ nPolyPos ].X() = nLastX;
372 aArr[ nPolyPos++ ].Y() = nLastY - 1;
374 aArr[ nPolyPos ].X() = nLastX - 1;
375 aArr[ nPolyPos++ ].Y() = nLastY - 1;
377 aArr[ nPolyPos ].X() = nLastX - 1;
378 aArr[ nPolyPos++ ].Y() = nLastY;
380 else if( cMove == 3 && cNextMove == 0 )
382 aArr[ nPolyPos ].X() = nLastX - 1;
383 aArr[ nPolyPos++ ].Y() = nLastY;
385 aArr[ nPolyPos ].X() = nLastX - 1;
386 aArr[ nPolyPos++ ].Y() = nLastY + 1;
388 aArr[ nPolyPos ].X() = nLastX;
389 aArr[ nPolyPos++ ].Y() = nLastY + 1;
391 else if( cMove == 0 && cNextMove == 1 )
393 aArr[ nPolyPos ].X() = nLastX;
394 aArr[ nPolyPos++ ].Y() = nLastY + 1;
396 aArr[ nPolyPos ].X() = nLastX + 1;
397 aArr[ nPolyPos++ ].Y() = nLastY + 1;
399 aArr[ nPolyPos ].X() = nLastX + 1;
400 aArr[ nPolyPos++ ].Y() = nLastY;
402 else if( cMove == 1 && cNextMove == 2 )
404 aArr[ nPolyPos ].X() = nLastX + 1;
405 aArr[ nPolyPos++ ].Y() = nLastY + 1;
407 aArr[ nPolyPos ].X() = nLastX + 1;
408 aArr[ nPolyPos++ ].Y() = nLastY - 1;
410 aArr[ nPolyPos ].X() = nLastX;
411 aArr[ nPolyPos++ ].Y() = nLastY - 1;
413 else
414 bDone = false;
416 else if( cMove == 7 && cNextMove == 0 )
418 aArr[ nPolyPos ].X() = nLastX - 1;
419 aArr[ nPolyPos++ ].Y() = nLastY;
421 aArr[ nPolyPos ].X() = nLastX;
422 aArr[ nPolyPos++ ].Y() = nLastY + 1;
424 else if( cMove == 4 && cNextMove == 1 )
426 aArr[ nPolyPos ].X() = nLastX;
427 aArr[ nPolyPos++ ].Y() = nLastY + 1;
429 aArr[ nPolyPos ].X() = nLastX + 1;
430 aArr[ nPolyPos++ ].Y() = nLastY;
432 else
433 bDone = false;
435 if( !bDone )
437 aArr[ nPolyPos ].X() = nLastX + rMoveInner.nDX;
438 aArr[ nPolyPos++ ].Y() = nLastY + rMoveInner.nDY;
442 aArr[ nPolyPos ].X() = nFirstX + 1L;
443 aArr[ nPolyPos++ ].Y() = nFirstY + 1L;
444 aArr.ImplSetRealSize( nPolyPos );
446 else if( nFlag & VECT_POLY_INLINE_OUTER )
448 long nFirstX, nFirstY;
449 long nLastX, nLastY;
451 nFirstX = nLastX = maStartPt.X();
452 nFirstY = nLastY = maStartPt.Y();
453 aArr.ImplSetSize( mnCount << 1 );
455 sal_uInt16 i, nPolyPos;
456 for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ )
458 const sal_uInt8 cMove = mpCodes[ i ];
459 const sal_uInt8 cNextMove = mpCodes[ i + 1 ];
460 const ChainMove& rMove = aImplMove[ cMove ];
461 const ChainMove& rMoveOuter = aImplMoveOuter[ cMove ];
462 // Point& rPt = aArr[ nPolyPos ];
463 bool bDone = true;
465 nLastX += rMove.nDX;
466 nLastY += rMove.nDY;
468 if( cMove < 4 )
470 if( ( cMove == 0 && cNextMove == 1 ) ||
471 ( cMove == 1 && cNextMove == 2 ) ||
472 ( cMove == 2 && cNextMove == 3 ) ||
473 ( cMove == 3 && cNextMove == 0 ) )
476 else if( cMove == 0 && cNextMove == 3 )
478 aArr[ nPolyPos ].X() = nLastX;
479 aArr[ nPolyPos++ ].Y() = nLastY - 1;
481 aArr[ nPolyPos ].X() = nLastX + 1;
482 aArr[ nPolyPos++ ].Y() = nLastY - 1;
484 aArr[ nPolyPos ].X() = nLastX + 1;
485 aArr[ nPolyPos++ ].Y() = nLastY;
487 else if( cMove == 3 && cNextMove == 2 )
489 aArr[ nPolyPos ].X() = nLastX + 1;
490 aArr[ nPolyPos++ ].Y() = nLastY;
492 aArr[ nPolyPos ].X() = nLastX + 1;
493 aArr[ nPolyPos++ ].Y() = nLastY + 1;
495 aArr[ nPolyPos ].X() = nLastX;
496 aArr[ nPolyPos++ ].Y() = nLastY + 1;
498 else if( cMove == 2 && cNextMove == 1 )
500 aArr[ nPolyPos ].X() = nLastX;
501 aArr[ nPolyPos++ ].Y() = nLastY + 1;
503 aArr[ nPolyPos ].X() = nLastX - 1;
504 aArr[ nPolyPos++ ].Y() = nLastY + 1;
506 aArr[ nPolyPos ].X() = nLastX - 1;
507 aArr[ nPolyPos++ ].Y() = nLastY;
509 else if( cMove == 1 && cNextMove == 0 )
511 aArr[ nPolyPos ].X() = nLastX - 1;
512 aArr[ nPolyPos++ ].Y() = nLastY;
514 aArr[ nPolyPos ].X() = nLastX - 1;
515 aArr[ nPolyPos++ ].Y() = nLastY - 1;
517 aArr[ nPolyPos ].X() = nLastX;
518 aArr[ nPolyPos++ ].Y() = nLastY - 1;
520 else
521 bDone = false;
523 else if( cMove == 7 && cNextMove == 3 )
525 aArr[ nPolyPos ].X() = nLastX;
526 aArr[ nPolyPos++ ].Y() = nLastY - 1;
528 aArr[ nPolyPos ].X() = nLastX + 1;
529 aArr[ nPolyPos++ ].Y() = nLastY;
531 else if( cMove == 6 && cNextMove == 2 )
533 aArr[ nPolyPos ].X() = nLastX + 1;
534 aArr[ nPolyPos++ ].Y() = nLastY;
536 aArr[ nPolyPos ].X() = nLastX;
537 aArr[ nPolyPos++ ].Y() = nLastY + 1;
539 else
540 bDone = false;
542 if( !bDone )
544 aArr[ nPolyPos ].X() = nLastX + rMoveOuter.nDX;
545 aArr[ nPolyPos++ ].Y() = nLastY + rMoveOuter.nDY;
549 aArr[ nPolyPos ].X() = nFirstX - 1L;
550 aArr[ nPolyPos++ ].Y() = nFirstY - 1L;
551 aArr.ImplSetRealSize( nPolyPos );
553 else
555 long nLastX = maStartPt.X(), nLastY = maStartPt.Y();
557 aArr.ImplSetSize( mnCount + 1 );
558 aArr[ 0 ] = Point( nLastX, nLastY );
560 for( sal_uLong i = 0; i < mnCount; )
562 const ChainMove& rMove = aImplMove[ mpCodes[ i ] ];
563 aArr[ ++i ] = Point( nLastX += rMove.nDX, nLastY += rMove.nDY );
566 aArr.ImplSetRealSize( mnCount + 1 );
569 ImplPostProcess( aArr );
571 else
572 maPoly.SetSize( 0 );
575 void ImplChain::ImplPostProcess( const ImplPointArray& rArr )
577 ImplPointArray aNewArr1;
578 ImplPointArray aNewArr2;
579 Point* pLast;
580 Point* pLeast;
581 sal_uLong nNewPos;
582 sal_uLong nCount = rArr.ImplGetRealSize();
583 sal_uLong n;
585 // pass 1
586 aNewArr1.ImplSetSize( nCount );
587 pLast = &( aNewArr1[ 0 ] );
588 pLast->X() = BACK_MAP( rArr[ 0 ].X() );
589 pLast->Y() = BACK_MAP( rArr[ 0 ].Y() );
591 for( n = nNewPos = 1; n < nCount; )
593 const Point& rPt = rArr[ n++ ];
594 const long nX = BACK_MAP( rPt.X() );
595 const long nY = BACK_MAP( rPt.Y() );
597 if( nX != pLast->X() || nY != pLast->Y() )
599 pLast = pLeast = &( aNewArr1[ nNewPos++ ] );
600 pLeast->X() = nX;
601 pLeast->Y() = nY;
605 aNewArr1.ImplSetRealSize( nCount = nNewPos );
607 // pass 2
608 aNewArr2.ImplSetSize( nCount );
609 pLast = &( aNewArr2[ 0 ] );
610 *pLast = aNewArr1[ 0 ];
612 for( n = nNewPos = 1; n < nCount; )
614 pLeast = &( aNewArr1[ n++ ] );
616 if( pLeast->X() == pLast->X() )
618 while( n < nCount && aNewArr1[ n ].X() == pLast->X() )
619 pLeast = &( aNewArr1[ n++ ] );
621 else if( pLeast->Y() == pLast->Y() )
623 while( n < nCount && aNewArr1[ n ].Y() == pLast->Y() )
624 pLeast = &( aNewArr1[ n++ ] );
627 aNewArr2[ nNewPos++ ] = *( pLast = pLeast );
630 aNewArr2.ImplSetRealSize( nNewPos );
631 aNewArr2.ImplCreatePoly( maPoly );
634 namespace ImplVectorizer {
636 bool ImplVectorize( const Bitmap& rColorBmp, GDIMetaFile& rMtf,
637 sal_uInt8 cReduce, BmpVectorizeFlags nFlags, const Link<>* pProgress )
639 bool bRet = false;
641 VECT_PROGRESS( pProgress, 0 );
643 std::unique_ptr<Bitmap> xBmp(new Bitmap( rColorBmp ));
644 BitmapReadAccess* pRAcc = xBmp->AcquireReadAccess();
646 if( pRAcc )
648 tools::PolyPolygon aPolyPoly;
649 double fPercent = 0.0;
650 double fPercentStep_2 = 0.0;
651 const long nWidth = pRAcc->Width();
652 const long nHeight = pRAcc->Height();
653 const sal_uInt16 nColorCount = pRAcc->GetPaletteEntryCount();
654 sal_uInt16 n;
655 ImplColorSet* pColorSet = reinterpret_cast<ImplColorSet*>(new sal_uInt8[ 256 * sizeof( ImplColorSet ) ]);
657 memset( pColorSet, 0, 256 * sizeof( ImplColorSet ) );
658 rMtf.Clear();
660 // get used palette colors and sort them from light to dark colors
661 for( n = 0; n < nColorCount; n++ )
663 pColorSet[ n ].mnIndex = n;
664 pColorSet[ n ].maColor = pRAcc->GetPaletteColor( n );
667 for( long nY = 0L; nY < nHeight; nY++ )
668 for( long nX = 0L; nX < nWidth; nX++ )
669 pColorSet[ pRAcc->GetPixel( nY, nX ).GetIndex() ].mbSet = true;
671 qsort( pColorSet, 256, sizeof( ImplColorSet ), ImplColorSetCmpFnc );
673 for( n = 0; n < 256; n++ )
674 if( !pColorSet[ n ].mbSet )
675 break;
677 if( n )
678 fPercentStep_2 = 45.0 / n;
680 VECT_PROGRESS( pProgress, FRound( fPercent += 10.0 ) );
682 for( sal_uInt16 i = 0; i < n; i++ )
684 const BitmapColor aBmpCol( pRAcc->GetPaletteColor( pColorSet[ i ].mnIndex ) );
685 const Color aFindColor( aBmpCol.GetRed(), aBmpCol.GetGreen(), aBmpCol.GetBlue() );
686 std::unique_ptr<ImplVectMap> xMap(ImplExpand( pRAcc, aFindColor ));
688 VECT_PROGRESS( pProgress, FRound( fPercent += fPercentStep_2 ) );
690 if( xMap )
692 aPolyPoly.Clear();
693 ImplCalculate( xMap.get(), aPolyPoly, cReduce, nFlags );
694 xMap.reset();
696 if( aPolyPoly.Count() )
698 ImplLimitPolyPoly( aPolyPoly );
700 if( nFlags & BmpVectorizeFlags::ReduceEdges )
701 aPolyPoly.Optimize( PolyOptimizeFlags::EDGES );
703 if( aPolyPoly.Count() )
705 rMtf.AddAction( new MetaLineColorAction( aFindColor, true ) );
706 rMtf.AddAction( new MetaFillColorAction( aFindColor, true ) );
707 rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) );
712 VECT_PROGRESS( pProgress, FRound( fPercent += fPercentStep_2 ) );
715 delete[] reinterpret_cast<sal_uInt8*>(pColorSet);
717 if( rMtf.GetActionSize() )
719 MapMode aMap( MAP_100TH_MM );
720 ScopedVclPtrInstance< VirtualDevice > aVDev;
721 const Size aLogSize1( aVDev->PixelToLogic( Size( 1, 1 ), aMap ) );
723 rMtf.SetPrefMapMode( aMap );
724 rMtf.SetPrefSize( Size( nWidth + 2, nHeight + 2 ) );
725 rMtf.Move( 1, 1 );
726 rMtf.Scale( aLogSize1.Width(), aLogSize1.Height() );
727 bRet = true;
731 Bitmap::ReleaseAccess( pRAcc );
732 xBmp.reset();
733 VECT_PROGRESS( pProgress, 100 );
735 return bRet;
738 bool ImplVectorize( const Bitmap& rMonoBmp,
739 tools::PolyPolygon& rPolyPoly,
740 BmpVectorizeFlags nFlags, const Link<>* pProgress )
742 std::unique_ptr<Bitmap> xBmp(new Bitmap( rMonoBmp ));
743 BitmapReadAccess* pRAcc;
744 bool bRet = false;
746 VECT_PROGRESS( pProgress, 10 );
748 if( xBmp->GetBitCount() > 1 )
749 xBmp->Convert( BMP_CONVERSION_1BIT_THRESHOLD );
751 VECT_PROGRESS( pProgress, 30 );
753 pRAcc = xBmp->AcquireReadAccess();
754 std::unique_ptr <ImplVectMap> xMap(ImplExpand( pRAcc, COL_BLACK ));
755 Bitmap::ReleaseAccess( pRAcc );
756 xBmp.reset();
758 VECT_PROGRESS( pProgress, 60 );
760 if( xMap )
762 rPolyPoly.Clear();
763 ImplCalculate( xMap.get(), rPolyPoly, 0, nFlags );
764 xMap.reset();
765 ImplLimitPolyPoly( rPolyPoly );
767 if( nFlags & BmpVectorizeFlags::ReduceEdges )
768 rPolyPoly.Optimize( PolyOptimizeFlags::EDGES );
770 // #i14895#:setting the correct direction for polygons
771 // that represent holes and non-holes; non-hole polygons
772 // need to have a right orientation, holes need to have a
773 // left orientation in order to be treated correctly by
774 // several external tools like Flash viewers
775 sal_Int32 nFirstPoly = -1;
776 sal_uInt16 nCurPoly( 0 ), nCount( rPolyPoly.Count() );
778 for( ; nCurPoly < nCount; ++nCurPoly )
780 const Polygon& rPoly = rPolyPoly.GetObject( nCurPoly );
781 const sal_uInt16 nSize( rPoly.GetSize() );
782 sal_uInt16 nDepth( 0 ), i( 0 );
783 const bool bRight( rPoly.IsRightOrientated() );
785 for( ; i < nCount; ++i )
786 if( ( i != nCurPoly ) && rPolyPoly.GetObject( i ).IsInside( rPoly[ 0 ] ) )
787 ++nDepth;
789 const bool bHole( ( nDepth & 0x0001 ) == 1 );
791 if( nSize && ( ( !bRight && !bHole ) || ( bRight && bHole ) ) )
793 Polygon aNewPoly( nSize );
794 sal_uInt16 nPrim( 0 ), nSec( nSize - 1 );
796 if( rPoly.HasFlags() )
798 while( nPrim < nSize )
800 aNewPoly.SetPoint( rPoly.GetPoint( nSec ), nPrim );
801 aNewPoly.SetFlags( nPrim++, rPoly.GetFlags( nSec-- ) );
804 else
805 while( nPrim < nSize )
806 aNewPoly.SetPoint( rPoly.GetPoint( nSec-- ), nPrim++ );
808 rPolyPoly.Replace( aNewPoly, nCurPoly );
811 if( ( 0 == nDepth ) && ( -1 == nFirstPoly ) )
812 nFirstPoly = nCurPoly;
815 // put outmost polygon to the front
816 if( nFirstPoly > 0 )
818 const Polygon aFirst( rPolyPoly.GetObject( static_cast< sal_uInt16 >( nFirstPoly ) ) );
820 rPolyPoly.Remove( static_cast< sal_uInt16 >( nFirstPoly ) );
821 rPolyPoly.Insert( aFirst, 0 );
824 bRet = true;
827 VECT_PROGRESS( pProgress, 100 );
829 return bRet;
832 void ImplLimitPolyPoly( tools::PolyPolygon& rPolyPoly )
834 if( rPolyPoly.Count() > VECT_POLY_MAX )
836 tools::PolyPolygon aNewPolyPoly;
837 long nReduce = 0;
838 sal_uInt16 nNewCount;
842 aNewPolyPoly.Clear();
843 nReduce++;
845 for( sal_uInt16 i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ )
847 const Rectangle aBound( rPolyPoly[ i ].GetBoundRect() );
849 if( aBound.GetWidth() > nReduce && aBound.GetHeight() > nReduce )
851 if( rPolyPoly[ i ].GetSize() )
852 aNewPolyPoly.Insert( rPolyPoly[ i ] );
856 nNewCount = aNewPolyPoly.Count();
858 while( nNewCount > VECT_POLY_MAX );
860 rPolyPoly = aNewPolyPoly;
864 ImplVectMap* ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor )
866 ImplVectMap* pMap = NULL;
868 if( pRAcc && pRAcc->Width() && pRAcc->Height() )
870 const long nOldWidth = pRAcc->Width();
871 const long nOldHeight = pRAcc->Height();
872 const long nNewWidth = ( nOldWidth << 2L ) + 4L;
873 const long nNewHeight = ( nOldHeight << 2L ) + 4L;
874 const BitmapColor aTest( pRAcc->GetBestMatchingColor( rColor ) );
875 boost::scoped_array<long> pMapIn(new long[ std::max( nOldWidth, nOldHeight ) ]);
876 boost::scoped_array<long> pMapOut(new long[ std::max( nOldWidth, nOldHeight ) ]);
877 long nX, nY, nTmpX, nTmpY;
879 pMap = new ImplVectMap( nNewWidth, nNewHeight );
881 for( nX = 0L; nX < nOldWidth; nX++ )
882 VECT_MAP( pMapIn, pMapOut, nX );
884 for( nY = 0L, nTmpY = 5L; nY < nOldHeight; nY++, nTmpY += 4L )
886 for( nX = 0L; nX < nOldWidth; )
888 if( pRAcc->GetPixel( nY, nX ) == aTest )
890 nTmpX = pMapIn[ nX++ ];
891 nTmpY -= 3L;
893 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
894 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
895 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
896 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
898 while( nX < nOldWidth && pRAcc->GetPixel( nY, nX ) == aTest )
899 nX++;
901 nTmpX = pMapOut[ nX - 1L ];
902 nTmpY -= 3L;
904 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
905 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
906 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
907 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
909 else
910 nX++;
914 for( nY = 0L; nY < nOldHeight; nY++ )
915 VECT_MAP( pMapIn, pMapOut, nY );
917 for( nX = 0L, nTmpX = 5L; nX < nOldWidth; nX++, nTmpX += 4L )
919 for( nY = 0L; nY < nOldHeight; )
921 if( pRAcc->GetPixel( nY, nX ) == aTest )
923 nTmpX -= 3L;
924 nTmpY = pMapIn[ nY++ ];
926 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
927 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
928 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
929 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
931 while( nY < nOldHeight && pRAcc->GetPixel( nY, nX ) == aTest )
932 nY++;
934 nTmpX -= 3L;
935 nTmpY = pMapOut[ nY - 1L ];
937 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
938 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
939 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
940 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
942 else
943 nY++;
948 return pMap;
951 void ImplCalculate( ImplVectMap* pMap, tools::PolyPolygon& rPolyPoly, sal_uInt8 cReduce, BmpVectorizeFlags nFlags )
953 const long nWidth = pMap->Width(), nHeight= pMap->Height();
955 for( long nY = 0L; nY < nHeight; nY++ )
957 long nX = 0L;
958 bool bInner = true;
960 while( nX < nWidth )
962 // skip free
963 while( ( nX < nWidth ) && pMap->IsFree( nY, nX ) )
964 nX++;
966 if( nX == nWidth )
967 break;
969 if( pMap->IsCont( nY, nX ) )
971 // new contour
972 ImplChain aChain;
973 const Point aStartPt( nX++, nY );
975 // get chain code
976 aChain.ImplBeginAdd( aStartPt );
977 ImplGetChain( pMap, aStartPt, aChain );
979 if( nFlags & BmpVectorizeFlags::Inner )
980 aChain.ImplEndAdd( bInner ? VECT_POLY_INLINE_INNER : VECT_POLY_INLINE_OUTER );
981 else
982 aChain.ImplEndAdd( bInner ? VECT_POLY_OUTLINE_INNER : VECT_POLY_OUTLINE_OUTER );
984 const Polygon& rPoly = aChain.ImplGetPoly();
986 if( rPoly.GetSize() > 2 )
988 if( cReduce )
990 const Rectangle aBound( rPoly.GetBoundRect() );
992 if( aBound.GetWidth() > cReduce && aBound.GetHeight() > cReduce )
993 rPolyPoly.Insert( rPoly );
995 else
996 rPolyPoly.Insert( rPoly );
999 // skip rest of detected contour
1000 while( pMap->IsCont( nY, nX ) )
1001 nX++;
1003 else
1005 // process done segment
1006 const long nStartSegX = nX++;
1008 while( pMap->IsDone( nY, nX ) )
1009 nX++;
1011 if( ( ( nX - nStartSegX ) == 1L ) || ( ImplIsUp( pMap, nY, nStartSegX ) != ImplIsUp( pMap, nY, nX - 1L ) ) )
1012 bInner = !bInner;
1018 bool ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain )
1020 long nActX = rStartPt.X();
1021 long nActY = rStartPt.Y();
1022 sal_uLong nFound;
1023 sal_uLong nLastDir = 0UL;
1024 sal_uLong nDir;
1028 nFound = 0UL;
1030 // first try last direction
1031 long nTryX = nActX + aImplMove[ nLastDir ].nDX;
1032 long nTryY = nActY + aImplMove[ nLastDir ].nDY;
1034 if( pMap->IsCont( nTryY, nTryX ) )
1036 rChain.ImplAdd( (sal_uInt8) nLastDir );
1037 pMap->Set( nActY = nTryY, nActX = nTryX, VECT_DONE_INDEX );
1038 nFound = 1UL;
1040 else
1042 // try other directions
1043 for( nDir = 0UL; nDir < 8UL; nDir++ )
1045 // we already tried nLastDir
1046 if( nDir != nLastDir )
1048 nTryX = nActX + aImplMove[ nDir ].nDX;
1049 nTryY = nActY + aImplMove[ nDir ].nDY;
1051 if( pMap->IsCont( nTryY, nTryX ) )
1053 rChain.ImplAdd( (sal_uInt8) nDir );
1054 pMap->Set( nActY = nTryY, nActX = nTryX, VECT_DONE_INDEX );
1055 nFound = 1UL;
1056 nLastDir = nDir;
1057 break;
1063 while( nFound );
1065 return true;
1068 bool ImplIsUp( ImplVectMap* pMap, long nY, long nX )
1070 if( pMap->IsDone( nY - 1L, nX ) )
1071 return true;
1072 else if( pMap->IsDone( nY + 1L, nX ) )
1073 return false;
1074 else if( pMap->IsDone( nY - 1L, nX - 1L ) || pMap->IsDone( nY - 1L, nX + 1L ) )
1075 return true;
1076 else
1077 return false;
1082 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */