bump product version to 6.4.0.3
[LibreOffice.git] / vcl / source / gdi / impvect.cxx
blob5ecfb6aedbd1b69c1c42769f646c2b5d601fc990
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 <sal/log.hxx>
21 #include <vcl/bitmapaccess.hxx>
22 #include <tools/link.hxx>
23 #include <tools/poly.hxx>
24 #include <tools/helpers.hxx>
25 #include <vcl/gdimtf.hxx>
26 #include <vcl/metaact.hxx>
27 #include <vcl/virdev.hxx>
28 #include "impvect.hxx"
29 #include <array>
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 static void VECT_MAP( const std::unique_ptr<long []> & pMapIn, const std::unique_ptr<long []>& pMapOut, long nVal )
45 pMapIn[nVal] = (nVal * 4) + 1;
46 pMapOut[nVal] = pMapIn[nVal] + 5;
48 static constexpr long BACK_MAP( long _def_nVal )
50 return ((_def_nVal + 2) >> 2) - 1;
52 static void VECT_PROGRESS( const Link<long, void>* pProgress, long _def_nVal )
54 if(pProgress)
55 pProgress->Call(_def_nVal);
58 class ImplVectMap;
59 class ImplChain;
61 namespace ImplVectorizer
63 static ImplVectMap* ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor );
64 static void ImplCalculate( ImplVectMap* pMap, tools::PolyPolygon& rPolyPoly, sal_uInt8 cReduce );
65 static bool ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain );
66 static bool ImplIsUp( ImplVectMap const * pMap, long nY, long nX );
67 static void ImplLimitPolyPoly( tools::PolyPolygon& rPolyPoly );
70 struct ChainMove { long nDX; long nDY; };
72 static const ChainMove aImplMove[ 8 ] = {
73 { 1, 0 },
74 { 0, -1 },
75 { -1, 0 },
76 { 0, 1 },
77 { 1, -1 },
78 { -1, -1 },
79 { -1, 1 },
80 { 1, 1 }
83 static const ChainMove aImplMoveInner[ 8 ] = {
84 { 0, 1 },
85 { 1, 0 },
86 { 0, -1 },
87 { -1, 0 },
88 { 0, 1 },
89 { 1, 0 },
90 { 0, -1 },
91 { -1, 0 }
94 static const ChainMove aImplMoveOuter[ 8 ] = {
95 { 0, -1 },
96 { -1, 0 },
97 { 0, 1 },
98 { 1, 0 },
99 { -1, 0 },
100 { 0, 1 },
101 { 1, 0 },
102 { 0, -1 }
105 struct ImplColorSet
107 BitmapColor maColor;
108 sal_uInt16 mnIndex = 0;
109 bool mbSet = false;
112 static bool ImplColorSetCmpFnc( const ImplColorSet& lhs, const ImplColorSet& rhs)
114 if( lhs.mbSet && rhs.mbSet )
116 const sal_uInt8 cLum1 = lhs.maColor.GetLuminance();
117 const sal_uInt8 cLum2 = rhs.maColor.GetLuminance();
118 return cLum1 < cLum2;
120 return lhs.mbSet < rhs.mbSet;
123 class ImplPointArray
125 std::unique_ptr<Point[]> mpArray;
126 sal_uLong mnSize;
127 sal_uLong mnRealSize;
129 public:
131 ImplPointArray();
133 void ImplSetSize( sal_uLong nSize );
134 sal_uLong ImplGetRealSize() const { return mnRealSize; }
135 void ImplSetRealSize( sal_uLong nRealSize ) { mnRealSize = nRealSize; }
136 void ImplCreatePoly( tools::Polygon& rPoly ) const;
138 inline Point& operator[]( sal_uLong nPos );
139 inline const Point& operator[]( sal_uLong nPos ) const;
143 ImplPointArray::ImplPointArray() :
144 mnSize ( 0 ),
145 mnRealSize ( 0 )
150 void ImplPointArray::ImplSetSize( sal_uLong nSize )
152 const sal_uLong nTotal = nSize * sizeof( Point );
154 mnSize = nSize;
155 mnRealSize = 0;
157 mpArray = std::make_unique<Point[]>( nTotal );
160 inline Point& ImplPointArray::operator[]( sal_uLong nPos )
162 SAL_WARN_IF( nPos >= mnSize, "vcl", "ImplPointArray::operator[]: nPos out of range!" );
163 return mpArray[ nPos ];
166 inline const Point& ImplPointArray::operator[]( sal_uLong nPos ) const
168 SAL_WARN_IF( nPos >= mnSize, "vcl", "ImplPointArray::operator[]: nPos out of range!" );
169 return mpArray[ nPos ];
172 void ImplPointArray::ImplCreatePoly( tools::Polygon& rPoly ) const
174 rPoly = tools::Polygon( sal::static_int_cast<sal_uInt16>(mnRealSize), mpArray.get() );
177 class ImplVectMap
179 private:
181 Scanline const mpBuf;
182 Scanline* mpScan;
183 long const mnWidth;
184 long const mnHeight;
186 public:
188 ImplVectMap( long nWidth, long nHeight );
189 ~ImplVectMap();
191 long Width() const { return mnWidth; }
192 long Height() const { return mnHeight; }
194 inline void Set( long nY, long nX, sal_uInt8 cVal );
195 inline sal_uInt8 Get( long nY, long nX ) const;
197 inline bool IsFree( long nY, long nX ) const;
198 inline bool IsCont( long nY, long nX ) const;
199 inline bool IsDone( long nY, long nX ) const;
203 ImplVectMap::ImplVectMap( long nWidth, long nHeight ) :
204 mpBuf ( static_cast<Scanline>(rtl_allocateZeroMemory(nWidth * nHeight)) ),
205 mpScan ( static_cast<Scanline*>(std::malloc(nHeight * sizeof(Scanline))) ),
206 mnWidth ( nWidth ),
207 mnHeight( nHeight )
209 const long nWidthAl = ( nWidth >> 2 ) + 1;
210 Scanline pTmp = mpBuf;
212 for( long nY = 0; nY < nHeight; pTmp += nWidthAl )
213 mpScan[ nY++ ] = pTmp;
216 ImplVectMap::~ImplVectMap()
218 std::free( mpBuf );
219 std::free( mpScan );
222 inline void ImplVectMap::Set( long nY, long nX, sal_uInt8 cVal )
224 const sal_uInt8 cShift = sal::static_int_cast<sal_uInt8>(6 - ( ( nX & 3 ) << 1 ));
225 auto & rPixel = mpScan[ nY ][ nX >> 2 ];
226 rPixel = (rPixel & ~( 3 << cShift ) ) | ( cVal << cShift );
229 inline sal_uInt8 ImplVectMap::Get( long nY, long nX ) const
231 return sal::static_int_cast<sal_uInt8>( ( ( mpScan[ nY ][ nX >> 2 ] ) >> ( 6 - ( ( nX & 3 ) << 1 ) ) ) & 3 );
234 inline bool ImplVectMap::IsFree( long nY, long nX ) const
236 return( VECT_FREE_INDEX == Get( nY, nX ) );
239 inline bool ImplVectMap::IsCont( long nY, long nX ) const
241 return( VECT_CONT_INDEX == Get( nY, nX ) );
244 inline bool ImplVectMap::IsDone( long nY, long nX ) const
246 return( VECT_DONE_INDEX == Get( nY, nX ) );
249 class ImplChain
251 private:
253 tools::Polygon maPoly;
254 Point maStartPt;
255 sal_uLong mnArraySize;
256 sal_uLong mnCount;
257 std::unique_ptr<sal_uInt8[]>
258 mpCodes;
260 void ImplGetSpace();
262 void ImplPostProcess( const ImplPointArray& rArr );
264 ImplChain(const ImplChain&) = delete;
265 ImplChain& operator=(const ImplChain&) = delete;
267 public:
269 ImplChain();
271 void ImplBeginAdd( const Point& rStartPt );
272 inline void ImplAdd( sal_uInt8 nCode );
273 void ImplEndAdd( sal_uLong nTypeFlag );
275 const tools::Polygon& ImplGetPoly() const { return maPoly; }
278 ImplChain::ImplChain() :
279 mnArraySize ( 1024 ),
280 mnCount ( 0 ),
281 mpCodes ( new sal_uInt8[mnArraySize] )
285 void ImplChain::ImplGetSpace()
287 const sal_uLong nOldArraySize = mnArraySize;
288 sal_uInt8* pNewCodes;
290 mnArraySize = mnArraySize << 1;
291 pNewCodes = new sal_uInt8[ mnArraySize ];
292 memcpy( pNewCodes, mpCodes.get(), nOldArraySize );
293 mpCodes.reset( pNewCodes );
296 void ImplChain::ImplBeginAdd( const Point& rStartPt )
298 maPoly = tools::Polygon();
299 maStartPt = rStartPt;
300 mnCount = 0;
303 inline void ImplChain::ImplAdd( sal_uInt8 nCode )
305 if( mnCount == mnArraySize )
306 ImplGetSpace();
308 mpCodes[ mnCount++ ] = nCode;
311 void ImplChain::ImplEndAdd( sal_uLong nFlag )
313 if( mnCount )
315 ImplPointArray aArr;
317 if( nFlag & VECT_POLY_INLINE_INNER )
319 long nFirstX, nFirstY;
320 long nLastX, nLastY;
322 nFirstX = nLastX = maStartPt.X();
323 nFirstY = nLastY = maStartPt.Y();
324 aArr.ImplSetSize( mnCount << 1 );
326 sal_uInt16 nPolyPos;
327 sal_uLong i;
328 for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ )
330 const sal_uInt8 cMove = mpCodes[ i ];
331 const sal_uInt8 cNextMove = mpCodes[ i + 1 ];
332 const ChainMove& rMove = aImplMove[ cMove ];
333 const ChainMove& rMoveInner = aImplMoveInner[ cMove ];
334 // Point& rPt = aArr[ nPolyPos ];
335 bool bDone = true;
337 nLastX += rMove.nDX;
338 nLastY += rMove.nDY;
340 if( cMove < 4 )
342 if( ( cMove == 0 && cNextMove == 3 ) ||
343 ( cMove == 3 && cNextMove == 2 ) ||
344 ( cMove == 2 && cNextMove == 1 ) ||
345 ( cMove == 1 && cNextMove == 0 ) )
348 else if( cMove == 2 && cNextMove == 3 )
350 aArr[ nPolyPos ].setX( nLastX );
351 aArr[ nPolyPos++ ].setY( nLastY - 1 );
353 aArr[ nPolyPos ].setX( nLastX - 1 );
354 aArr[ nPolyPos++ ].setY( nLastY - 1 );
356 aArr[ nPolyPos ].setX( nLastX - 1 );
357 aArr[ nPolyPos++ ].setY( nLastY );
359 else if( cMove == 3 && cNextMove == 0 )
361 aArr[ nPolyPos ].setX( nLastX - 1 );
362 aArr[ nPolyPos++ ].setY( nLastY );
364 aArr[ nPolyPos ].setX( nLastX - 1 );
365 aArr[ nPolyPos++ ].setY( nLastY + 1 );
367 aArr[ nPolyPos ].setX( nLastX );
368 aArr[ nPolyPos++ ].setY( nLastY + 1 );
370 else if( cMove == 0 && cNextMove == 1 )
372 aArr[ nPolyPos ].setX( nLastX );
373 aArr[ nPolyPos++ ].setY( nLastY + 1 );
375 aArr[ nPolyPos ].setX( nLastX + 1 );
376 aArr[ nPolyPos++ ].setY( nLastY + 1 );
378 aArr[ nPolyPos ].setX( nLastX + 1 );
379 aArr[ nPolyPos++ ].setY( nLastY );
381 else if( cMove == 1 && cNextMove == 2 )
383 aArr[ nPolyPos ].setX( nLastX + 1 );
384 aArr[ nPolyPos++ ].setY( nLastY + 1 );
386 aArr[ nPolyPos ].setX( nLastX + 1 );
387 aArr[ nPolyPos++ ].setY( nLastY - 1 );
389 aArr[ nPolyPos ].setX( nLastX );
390 aArr[ nPolyPos++ ].setY( nLastY - 1 );
392 else
393 bDone = false;
395 else if( cMove == 7 && cNextMove == 0 )
397 aArr[ nPolyPos ].setX( nLastX - 1 );
398 aArr[ nPolyPos++ ].setY( nLastY );
400 aArr[ nPolyPos ].setX( nLastX );
401 aArr[ nPolyPos++ ].setY( nLastY + 1 );
403 else if( cMove == 4 && cNextMove == 1 )
405 aArr[ nPolyPos ].setX( nLastX );
406 aArr[ nPolyPos++ ].setY( nLastY + 1 );
408 aArr[ nPolyPos ].setX( nLastX + 1 );
409 aArr[ nPolyPos++ ].setY( nLastY );
411 else
412 bDone = false;
414 if( !bDone )
416 aArr[ nPolyPos ].setX( nLastX + rMoveInner.nDX );
417 aArr[ nPolyPos++ ].setY( nLastY + rMoveInner.nDY );
421 aArr[ nPolyPos ].setX( nFirstX + 1 );
422 aArr[ nPolyPos++ ].setY( nFirstY + 1 );
423 aArr.ImplSetRealSize( nPolyPos );
425 else if( nFlag & VECT_POLY_INLINE_OUTER )
427 long nFirstX, nFirstY;
428 long nLastX, nLastY;
430 nFirstX = nLastX = maStartPt.X();
431 nFirstY = nLastY = maStartPt.Y();
432 aArr.ImplSetSize( mnCount << 1 );
434 sal_uInt16 nPolyPos;
435 sal_uLong i;
436 for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ )
438 const sal_uInt8 cMove = mpCodes[ i ];
439 const sal_uInt8 cNextMove = mpCodes[ i + 1 ];
440 const ChainMove& rMove = aImplMove[ cMove ];
441 const ChainMove& rMoveOuter = aImplMoveOuter[ cMove ];
442 // Point& rPt = aArr[ nPolyPos ];
443 bool bDone = true;
445 nLastX += rMove.nDX;
446 nLastY += rMove.nDY;
448 if( cMove < 4 )
450 if( ( cMove == 0 && cNextMove == 1 ) ||
451 ( cMove == 1 && cNextMove == 2 ) ||
452 ( cMove == 2 && cNextMove == 3 ) ||
453 ( cMove == 3 && cNextMove == 0 ) )
456 else if( cMove == 0 && cNextMove == 3 )
458 aArr[ nPolyPos ].setX( nLastX );
459 aArr[ nPolyPos++ ].setY( nLastY - 1 );
461 aArr[ nPolyPos ].setX( nLastX + 1 );
462 aArr[ nPolyPos++ ].setY( nLastY - 1 );
464 aArr[ nPolyPos ].setX( nLastX + 1 );
465 aArr[ nPolyPos++ ].setY( nLastY );
467 else if( cMove == 3 && cNextMove == 2 )
469 aArr[ nPolyPos ].setX( nLastX + 1 );
470 aArr[ nPolyPos++ ].setY( nLastY );
472 aArr[ nPolyPos ].setX( nLastX + 1 );
473 aArr[ nPolyPos++ ].setY( nLastY + 1 );
475 aArr[ nPolyPos ].setX( nLastX );
476 aArr[ nPolyPos++ ].setY( nLastY + 1 );
478 else if( cMove == 2 && cNextMove == 1 )
480 aArr[ nPolyPos ].setX( nLastX );
481 aArr[ nPolyPos++ ].setY( nLastY + 1 );
483 aArr[ nPolyPos ].setX( nLastX - 1 );
484 aArr[ nPolyPos++ ].setY( nLastY + 1 );
486 aArr[ nPolyPos ].setX( nLastX - 1 );
487 aArr[ nPolyPos++ ].setY( nLastY );
489 else if( cMove == 1 && cNextMove == 0 )
491 aArr[ nPolyPos ].setX( nLastX - 1 );
492 aArr[ nPolyPos++ ].setY( nLastY );
494 aArr[ nPolyPos ].setX( nLastX - 1 );
495 aArr[ nPolyPos++ ].setY( nLastY - 1 );
497 aArr[ nPolyPos ].setX( nLastX );
498 aArr[ nPolyPos++ ].setY( nLastY - 1 );
500 else
501 bDone = false;
503 else if( cMove == 7 && cNextMove == 3 )
505 aArr[ nPolyPos ].setX( nLastX );
506 aArr[ nPolyPos++ ].setY( nLastY - 1 );
508 aArr[ nPolyPos ].setX( nLastX + 1 );
509 aArr[ nPolyPos++ ].setY( nLastY );
511 else if( cMove == 6 && cNextMove == 2 )
513 aArr[ nPolyPos ].setX( nLastX + 1 );
514 aArr[ nPolyPos++ ].setY( nLastY );
516 aArr[ nPolyPos ].setX( nLastX );
517 aArr[ nPolyPos++ ].setY( nLastY + 1 );
519 else
520 bDone = false;
522 if( !bDone )
524 aArr[ nPolyPos ].setX( nLastX + rMoveOuter.nDX );
525 aArr[ nPolyPos++ ].setY( nLastY + rMoveOuter.nDY );
529 aArr[ nPolyPos ].setX( nFirstX - 1 );
530 aArr[ nPolyPos++ ].setY( nFirstY - 1 );
531 aArr.ImplSetRealSize( nPolyPos );
533 else
535 long nLastX = maStartPt.X(), nLastY = maStartPt.Y();
537 aArr.ImplSetSize( mnCount + 1 );
538 aArr[ 0 ] = Point( nLastX, nLastY );
540 for( sal_uLong i = 0; i < mnCount; )
542 const ChainMove& rMove = aImplMove[ mpCodes[ i ] ];
543 aArr[ ++i ] = Point( nLastX += rMove.nDX, nLastY += rMove.nDY );
546 aArr.ImplSetRealSize( mnCount + 1 );
549 ImplPostProcess( aArr );
551 else
552 maPoly.SetSize( 0 );
555 void ImplChain::ImplPostProcess( const ImplPointArray& rArr )
557 ImplPointArray aNewArr1;
558 ImplPointArray aNewArr2;
559 Point* pLast;
560 Point* pLeast;
561 sal_uLong nNewPos;
562 sal_uLong nCount = rArr.ImplGetRealSize();
563 sal_uLong n;
565 // pass 1
566 aNewArr1.ImplSetSize( nCount );
567 pLast = &( aNewArr1[ 0 ] );
568 pLast->setX( BACK_MAP( rArr[ 0 ].X() ) );
569 pLast->setY( BACK_MAP( rArr[ 0 ].Y() ) );
571 for( n = nNewPos = 1; n < nCount; )
573 const Point& rPt = rArr[ n++ ];
574 const long nX = BACK_MAP( rPt.X() );
575 const long nY = BACK_MAP( rPt.Y() );
577 if( nX != pLast->X() || nY != pLast->Y() )
579 pLast = pLeast = &( aNewArr1[ nNewPos++ ] );
580 pLeast->setX( nX );
581 pLeast->setY( nY );
585 nCount = nNewPos;
586 aNewArr1.ImplSetRealSize( nCount );
588 // pass 2
589 aNewArr2.ImplSetSize( nCount );
590 pLast = &( aNewArr2[ 0 ] );
591 *pLast = aNewArr1[ 0 ];
593 for( n = nNewPos = 1; n < nCount; )
595 pLeast = &( aNewArr1[ n++ ] );
597 if( pLeast->X() == pLast->X() )
599 while( n < nCount && aNewArr1[ n ].X() == pLast->X() )
600 pLeast = &( aNewArr1[ n++ ] );
602 else if( pLeast->Y() == pLast->Y() )
604 while( n < nCount && aNewArr1[ n ].Y() == pLast->Y() )
605 pLeast = &( aNewArr1[ n++ ] );
608 pLast = pLeast;
609 aNewArr2[ nNewPos++ ] = *pLast;
612 aNewArr2.ImplSetRealSize( nNewPos );
613 aNewArr2.ImplCreatePoly( maPoly );
616 namespace ImplVectorizer {
618 bool ImplVectorize( const Bitmap& rColorBmp, GDIMetaFile& rMtf,
619 sal_uInt8 cReduce, const Link<long,void>* pProgress )
621 bool bRet = false;
623 VECT_PROGRESS( pProgress, 0 );
625 std::unique_ptr<Bitmap> xBmp(new Bitmap( rColorBmp ));
626 Bitmap::ScopedReadAccess pRAcc(*xBmp);
628 if( pRAcc )
630 tools::PolyPolygon aPolyPoly;
631 double fPercent = 0.0;
632 double fPercentStep_2 = 0.0;
633 const long nWidth = pRAcc->Width();
634 const long nHeight = pRAcc->Height();
635 const sal_uInt16 nColorCount = pRAcc->GetPaletteEntryCount();
636 sal_uInt16 n;
637 std::array<ImplColorSet, 256> aColorSet;
639 rMtf.Clear();
641 // get used palette colors and sort them from light to dark colors
642 for( n = 0; n < nColorCount; n++ )
644 aColorSet[ n ].mnIndex = n;
645 aColorSet[ n ].maColor = pRAcc->GetPaletteColor( n );
648 for( long nY = 0; nY < nHeight; nY++ )
650 Scanline pScanlineRead = pRAcc->GetScanline( nY );
651 for( long nX = 0; nX < nWidth; nX++ )
652 aColorSet[ pRAcc->GetIndexFromData( pScanlineRead, nX ) ].mbSet = true;
655 std::sort( aColorSet.begin(), aColorSet.end(), ImplColorSetCmpFnc );
657 for( n = 0; n < 256; n++ )
658 if( !aColorSet[ n ].mbSet )
659 break;
661 if( n )
662 fPercentStep_2 = 45.0 / n;
664 fPercent += 10.0;
665 VECT_PROGRESS( pProgress, FRound( fPercent ) );
667 for( sal_uInt16 i = 0; i < n; i++ )
669 const BitmapColor aBmpCol( pRAcc->GetPaletteColor( aColorSet[ i ].mnIndex ) );
670 const Color aFindColor( aBmpCol.GetRed(), aBmpCol.GetGreen(), aBmpCol.GetBlue() );
671 std::unique_ptr<ImplVectMap> xMap(ImplExpand( pRAcc.get(), aFindColor ));
673 fPercent += fPercentStep_2;
674 VECT_PROGRESS( pProgress, FRound( fPercent ) );
676 if( xMap )
678 aPolyPoly.Clear();
679 ImplCalculate( xMap.get(), aPolyPoly, cReduce );
680 xMap.reset();
682 if( aPolyPoly.Count() )
684 ImplLimitPolyPoly( aPolyPoly );
686 aPolyPoly.Optimize( PolyOptimizeFlags::EDGES );
688 if( aPolyPoly.Count() )
690 rMtf.AddAction( new MetaLineColorAction( aFindColor, true ) );
691 rMtf.AddAction( new MetaFillColorAction( aFindColor, true ) );
692 rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) );
697 fPercent += fPercentStep_2;
698 VECT_PROGRESS( pProgress, FRound( fPercent ) );
701 if( rMtf.GetActionSize() )
703 MapMode aMap( MapUnit::Map100thMM );
704 ScopedVclPtrInstance< VirtualDevice > aVDev;
705 const Size aLogSize1( aVDev->PixelToLogic( Size( 1, 1 ), aMap ) );
707 rMtf.SetPrefMapMode( aMap );
708 rMtf.SetPrefSize( Size( nWidth + 2, nHeight + 2 ) );
709 rMtf.Move( 1, 1 );
710 rMtf.Scale( aLogSize1.Width(), aLogSize1.Height() );
711 bRet = true;
715 pRAcc.reset();
716 xBmp.reset();
717 VECT_PROGRESS( pProgress, 100 );
719 return bRet;
722 void ImplLimitPolyPoly( tools::PolyPolygon& rPolyPoly )
724 if( rPolyPoly.Count() > VECT_POLY_MAX )
726 tools::PolyPolygon aNewPolyPoly;
727 long nReduce = 0;
728 sal_uInt16 nNewCount;
732 aNewPolyPoly.Clear();
733 nReduce++;
735 for( sal_uInt16 i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ )
737 const tools::Rectangle aBound( rPolyPoly[ i ].GetBoundRect() );
739 if( aBound.GetWidth() > nReduce && aBound.GetHeight() > nReduce )
741 if( rPolyPoly[ i ].GetSize() )
742 aNewPolyPoly.Insert( rPolyPoly[ i ] );
746 nNewCount = aNewPolyPoly.Count();
748 while( nNewCount > VECT_POLY_MAX );
750 rPolyPoly = aNewPolyPoly;
754 ImplVectMap* ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor )
756 ImplVectMap* pMap = nullptr;
758 if( pRAcc && pRAcc->Width() && pRAcc->Height() )
760 const long nOldWidth = pRAcc->Width();
761 const long nOldHeight = pRAcc->Height();
762 const long nNewWidth = ( nOldWidth << 2 ) + 4;
763 const long nNewHeight = ( nOldHeight << 2 ) + 4;
764 const BitmapColor aTest( pRAcc->GetBestMatchingColor( rColor ) );
765 std::unique_ptr<long[]> pMapIn(new long[ std::max( nOldWidth, nOldHeight ) ]);
766 std::unique_ptr<long[]> pMapOut(new long[ std::max( nOldWidth, nOldHeight ) ]);
767 long nX, nY, nTmpX, nTmpY;
769 pMap = new ImplVectMap( nNewWidth, nNewHeight );
771 for( nX = 0; nX < nOldWidth; nX++ )
772 VECT_MAP( pMapIn, pMapOut, nX );
774 for( nY = 0, nTmpY = 5; nY < nOldHeight; nY++, nTmpY += 4 )
776 Scanline pScanlineRead = pRAcc->GetScanline( nY );
777 for( nX = 0; nX < nOldWidth; )
779 if( pRAcc->GetPixelFromData( pScanlineRead, nX ) == aTest )
781 nTmpX = pMapIn[ nX++ ];
782 nTmpY -= 3;
784 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
785 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
786 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
787 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
789 while( nX < nOldWidth && pRAcc->GetPixelFromData( pScanlineRead, nX ) == aTest )
790 nX++;
792 nTmpX = pMapOut[ nX - 1 ];
793 nTmpY -= 3;
795 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
796 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
797 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
798 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
800 else
801 nX++;
805 for( nY = 0; nY < nOldHeight; nY++ )
806 VECT_MAP( pMapIn, pMapOut, nY );
808 for( nX = 0, nTmpX = 5; nX < nOldWidth; nX++, nTmpX += 4 )
810 for( nY = 0; nY < nOldHeight; )
812 if( pRAcc->GetPixel( nY, nX ) == aTest )
814 nTmpX -= 3;
815 nTmpY = pMapIn[ nY++ ];
817 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
818 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
819 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
820 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
822 while( nY < nOldHeight && pRAcc->GetPixel( nY, nX ) == aTest )
823 nY++;
825 nTmpX -= 3;
826 nTmpY = pMapOut[ nY - 1 ];
828 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
829 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
830 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
831 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
833 else
834 nY++;
839 return pMap;
842 void ImplCalculate( ImplVectMap* pMap, tools::PolyPolygon& rPolyPoly, sal_uInt8 cReduce )
844 const long nWidth = pMap->Width(), nHeight= pMap->Height();
846 for( long nY = 0; nY < nHeight; nY++ )
848 long nX = 0;
849 bool bInner = true;
851 while( nX < nWidth )
853 // skip free
854 while( ( nX < nWidth ) && pMap->IsFree( nY, nX ) )
855 nX++;
857 if( nX == nWidth )
858 break;
860 if( pMap->IsCont( nY, nX ) )
862 // new contour
863 ImplChain aChain;
864 const Point aStartPt( nX++, nY );
866 // get chain code
867 aChain.ImplBeginAdd( aStartPt );
868 ImplGetChain( pMap, aStartPt, aChain );
870 aChain.ImplEndAdd( bInner ? VECT_POLY_OUTLINE_INNER : VECT_POLY_OUTLINE_OUTER );
872 const tools::Polygon& rPoly = aChain.ImplGetPoly();
874 if( rPoly.GetSize() > 2 )
876 if( cReduce )
878 const tools::Rectangle aBound( rPoly.GetBoundRect() );
880 if( aBound.GetWidth() > cReduce && aBound.GetHeight() > cReduce )
881 rPolyPoly.Insert( rPoly );
883 else
884 rPolyPoly.Insert( rPoly );
887 // skip rest of detected contour
888 while( pMap->IsCont( nY, nX ) )
889 nX++;
891 else
893 // process done segment
894 const long nStartSegX = nX++;
896 while( pMap->IsDone( nY, nX ) )
897 nX++;
899 if( ( ( nX - nStartSegX ) == 1 ) || ( ImplIsUp( pMap, nY, nStartSegX ) != ImplIsUp( pMap, nY, nX - 1 ) ) )
900 bInner = !bInner;
906 bool ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain )
908 long nActX = rStartPt.X();
909 long nActY = rStartPt.Y();
910 sal_uLong nFound;
911 sal_uLong nLastDir = 0;
912 sal_uLong nDir;
916 nFound = 0;
918 // first try last direction
919 long nTryX = nActX + aImplMove[ nLastDir ].nDX;
920 long nTryY = nActY + aImplMove[ nLastDir ].nDY;
922 if( pMap->IsCont( nTryY, nTryX ) )
924 rChain.ImplAdd( static_cast<sal_uInt8>(nLastDir) );
925 nActY = nTryY;
926 nActX = nTryX;
927 pMap->Set( nActY, nActX, VECT_DONE_INDEX );
928 nFound = 1;
930 else
932 // try other directions
933 for( nDir = 0; nDir < 8; nDir++ )
935 // we already tried nLastDir
936 if( nDir != nLastDir )
938 nTryX = nActX + aImplMove[ nDir ].nDX;
939 nTryY = nActY + aImplMove[ nDir ].nDY;
941 if( pMap->IsCont( nTryY, nTryX ) )
943 rChain.ImplAdd( static_cast<sal_uInt8>(nDir) );
944 nActY = nTryY;
945 nActX = nTryX;
946 pMap->Set( nActY, nActX, VECT_DONE_INDEX );
947 nFound = 1;
948 nLastDir = nDir;
949 break;
955 while( nFound );
957 return true;
960 bool ImplIsUp( ImplVectMap const * pMap, long nY, long nX )
962 if( pMap->IsDone( nY - 1, nX ) )
963 return true;
964 else if( pMap->IsDone( nY + 1, nX ) )
965 return false;
966 else if( pMap->IsDone( nY - 1, nX - 1 ) || pMap->IsDone( nY - 1, nX + 1 ) )
967 return true;
968 else
969 return false;
974 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */