1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/BitmapReadAccess.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"
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
<tools::Long
[]> & pMapIn
, const std::unique_ptr
<tools::Long
[]>& pMapOut
, tools::Long nVal
)
45 pMapIn
[nVal
] = (nVal
* 4) + 1;
46 pMapOut
[nVal
] = pMapIn
[nVal
] + 5;
48 static constexpr tools::Long
BACK_MAP( tools::Long _def_nVal
)
50 return ((_def_nVal
+ 2) >> 2) - 1;
52 static void VECT_PROGRESS( const Link
<tools::Long
, void>* pProgress
, tools::Long _def_nVal
)
55 pProgress
->Call(_def_nVal
);
65 namespace ImplVectorizer
67 static ImplVectMap
* ImplExpand( BitmapReadAccess
* pRAcc
, const Color
& rColor
);
68 static void ImplCalculate( ImplVectMap
* pMap
, tools::PolyPolygon
& rPolyPoly
, sal_uInt8 cReduce
);
69 static bool ImplGetChain( ImplVectMap
* pMap
, const Point
& rStartPt
, ImplChain
& rChain
);
70 static bool ImplIsUp( ImplVectMap
const * pMap
, tools::Long nY
, tools::Long nX
);
71 static void ImplLimitPolyPoly( tools::PolyPolygon
& rPolyPoly
);
76 struct ChainMove
{ tools::Long nDX
; tools::Long nDY
; };
80 const ChainMove aImplMove
[ 8 ] = {
91 const ChainMove aImplMoveInner
[ 8 ] = {
102 const ChainMove aImplMoveOuter
[ 8 ] = {
118 sal_uInt16 mnIndex
= 0;
124 static bool ImplColorSetCmpFnc( const ImplColorSet
& lhs
, const ImplColorSet
& rhs
)
126 if( lhs
.mbSet
&& rhs
.mbSet
)
128 const sal_uInt8 cLum1
= lhs
.maColor
.GetLuminance();
129 const sal_uInt8 cLum2
= rhs
.maColor
.GetLuminance();
130 return cLum1
< cLum2
;
132 return lhs
.mbSet
> rhs
.mbSet
;
139 std::unique_ptr
<Point
[]> mpArray
;
141 sal_uLong mnRealSize
;
147 void ImplSetSize( sal_uLong nSize
);
148 sal_uLong
ImplGetRealSize() const { return mnRealSize
; }
149 void ImplSetRealSize( sal_uLong nRealSize
) { mnRealSize
= nRealSize
; }
150 void ImplCreatePoly( tools::Polygon
& rPoly
) const;
152 inline Point
& operator[]( sal_uLong nPos
);
153 inline const Point
& operator[]( sal_uLong nPos
) const;
159 ImplPointArray::ImplPointArray() :
166 void ImplPointArray::ImplSetSize( sal_uLong nSize
)
168 const sal_uLong nTotal
= nSize
* sizeof( Point
);
173 mpArray
= std::make_unique
<Point
[]>( nTotal
);
176 inline Point
& ImplPointArray::operator[]( sal_uLong nPos
)
178 SAL_WARN_IF( nPos
>= mnSize
, "vcl", "ImplPointArray::operator[]: nPos out of range!" );
179 return mpArray
[ nPos
];
182 inline const Point
& ImplPointArray::operator[]( sal_uLong nPos
) const
184 SAL_WARN_IF( nPos
>= mnSize
, "vcl", "ImplPointArray::operator[]: nPos out of range!" );
185 return mpArray
[ nPos
];
188 void ImplPointArray::ImplCreatePoly( tools::Polygon
& rPoly
) const
190 rPoly
= tools::Polygon( sal::static_int_cast
<sal_uInt16
>(mnRealSize
), mpArray
.get() );
202 tools::Long mnHeight
;
206 ImplVectMap( tools::Long nWidth
, tools::Long nHeight
);
209 tools::Long
Width() const { return mnWidth
; }
210 tools::Long
Height() const { return mnHeight
; }
212 inline void Set( tools::Long nY
, tools::Long nX
, sal_uInt8 cVal
);
213 inline sal_uInt8
Get( tools::Long nY
, tools::Long nX
) const;
215 inline bool IsFree( tools::Long nY
, tools::Long nX
) const;
216 inline bool IsCont( tools::Long nY
, tools::Long nX
) const;
217 inline bool IsDone( tools::Long nY
, tools::Long nX
) const;
223 ImplVectMap::ImplVectMap( tools::Long nWidth
, tools::Long nHeight
) :
224 mpBuf ( static_cast<Scanline
>(rtl_allocateZeroMemory(nWidth
* nHeight
)) ),
225 mpScan ( static_cast<Scanline
*>(std::malloc(nHeight
* sizeof(Scanline
))) ),
229 const tools::Long nWidthAl
= ( nWidth
>> 2 ) + 1;
230 Scanline pTmp
= mpBuf
;
232 for( tools::Long nY
= 0; nY
< nHeight
; pTmp
+= nWidthAl
)
233 mpScan
[ nY
++ ] = pTmp
;
236 ImplVectMap::~ImplVectMap()
242 inline void ImplVectMap::Set( tools::Long nY
, tools::Long nX
, sal_uInt8 cVal
)
244 const sal_uInt8 cShift
= sal::static_int_cast
<sal_uInt8
>(6 - ( ( nX
& 3 ) << 1 ));
245 auto & rPixel
= mpScan
[ nY
][ nX
>> 2 ];
246 rPixel
= (rPixel
& ~( 3 << cShift
) ) | ( cVal
<< cShift
);
249 inline sal_uInt8
ImplVectMap::Get( tools::Long nY
, tools::Long nX
) const
251 return sal::static_int_cast
<sal_uInt8
>( ( ( mpScan
[ nY
][ nX
>> 2 ] ) >> ( 6 - ( ( nX
& 3 ) << 1 ) ) ) & 3 );
254 inline bool ImplVectMap::IsFree( tools::Long nY
, tools::Long nX
) const
256 return( VECT_FREE_INDEX
== Get( nY
, nX
) );
259 inline bool ImplVectMap::IsCont( tools::Long nY
, tools::Long nX
) const
261 return( VECT_CONT_INDEX
== Get( nY
, nX
) );
264 inline bool ImplVectMap::IsDone( tools::Long nY
, tools::Long nX
) const
266 return( VECT_DONE_INDEX
== Get( nY
, nX
) );
275 tools::Polygon maPoly
;
277 sal_uLong mnArraySize
;
279 std::unique_ptr
<sal_uInt8
[]>
284 void ImplPostProcess( const ImplPointArray
& rArr
);
286 ImplChain(const ImplChain
&) = delete;
287 ImplChain
& operator=(const ImplChain
&) = delete;
293 void ImplBeginAdd( const Point
& rStartPt
);
294 inline void ImplAdd( sal_uInt8 nCode
);
295 void ImplEndAdd( sal_uLong nTypeFlag
);
297 const tools::Polygon
& ImplGetPoly() const { return maPoly
; }
302 ImplChain::ImplChain() :
303 mnArraySize ( 1024 ),
305 mpCodes ( new sal_uInt8
[mnArraySize
] )
309 void ImplChain::ImplGetSpace()
311 const sal_uLong nOldArraySize
= mnArraySize
;
312 sal_uInt8
* pNewCodes
;
314 mnArraySize
= mnArraySize
<< 1;
315 pNewCodes
= new sal_uInt8
[ mnArraySize
];
316 memcpy( pNewCodes
, mpCodes
.get(), nOldArraySize
);
317 mpCodes
.reset( pNewCodes
);
320 void ImplChain::ImplBeginAdd( const Point
& rStartPt
)
322 maPoly
= tools::Polygon();
323 maStartPt
= rStartPt
;
327 inline void ImplChain::ImplAdd( sal_uInt8 nCode
)
329 if( mnCount
== mnArraySize
)
332 mpCodes
[ mnCount
++ ] = nCode
;
335 void ImplChain::ImplEndAdd( sal_uLong nFlag
)
341 if( nFlag
& VECT_POLY_INLINE_INNER
)
343 tools::Long nFirstX
, nFirstY
;
344 tools::Long nLastX
, nLastY
;
346 nFirstX
= nLastX
= maStartPt
.X();
347 nFirstY
= nLastY
= maStartPt
.Y();
348 aArr
.ImplSetSize( mnCount
<< 1 );
352 for( i
= 0, nPolyPos
= 0; i
< ( mnCount
- 1 ); i
++ )
354 const sal_uInt8 cMove
= mpCodes
[ i
];
355 const sal_uInt8 cNextMove
= mpCodes
[ i
+ 1 ];
356 const ChainMove
& rMove
= aImplMove
[ cMove
];
357 const ChainMove
& rMoveInner
= aImplMoveInner
[ cMove
];
358 // Point& rPt = aArr[ nPolyPos ];
366 if( ( cMove
== 0 && cNextMove
== 3 ) ||
367 ( cMove
== 3 && cNextMove
== 2 ) ||
368 ( cMove
== 2 && cNextMove
== 1 ) ||
369 ( cMove
== 1 && cNextMove
== 0 ) )
372 else if( cMove
== 2 && cNextMove
== 3 )
374 aArr
[ nPolyPos
].setX( nLastX
);
375 aArr
[ nPolyPos
++ ].setY( nLastY
- 1 );
377 aArr
[ nPolyPos
].setX( nLastX
- 1 );
378 aArr
[ nPolyPos
++ ].setY( nLastY
- 1 );
380 aArr
[ nPolyPos
].setX( nLastX
- 1 );
381 aArr
[ nPolyPos
++ ].setY( nLastY
);
383 else if( cMove
== 3 && cNextMove
== 0 )
385 aArr
[ nPolyPos
].setX( nLastX
- 1 );
386 aArr
[ nPolyPos
++ ].setY( nLastY
);
388 aArr
[ nPolyPos
].setX( nLastX
- 1 );
389 aArr
[ nPolyPos
++ ].setY( nLastY
+ 1 );
391 aArr
[ nPolyPos
].setX( nLastX
);
392 aArr
[ nPolyPos
++ ].setY( nLastY
+ 1 );
394 else if( cMove
== 0 && cNextMove
== 1 )
396 aArr
[ nPolyPos
].setX( nLastX
);
397 aArr
[ nPolyPos
++ ].setY( nLastY
+ 1 );
399 aArr
[ nPolyPos
].setX( nLastX
+ 1 );
400 aArr
[ nPolyPos
++ ].setY( nLastY
+ 1 );
402 aArr
[ nPolyPos
].setX( nLastX
+ 1 );
403 aArr
[ nPolyPos
++ ].setY( nLastY
);
405 else if( cMove
== 1 && cNextMove
== 2 )
407 aArr
[ nPolyPos
].setX( nLastX
+ 1 );
408 aArr
[ nPolyPos
++ ].setY( nLastY
+ 1 );
410 aArr
[ nPolyPos
].setX( nLastX
+ 1 );
411 aArr
[ nPolyPos
++ ].setY( nLastY
- 1 );
413 aArr
[ nPolyPos
].setX( nLastX
);
414 aArr
[ nPolyPos
++ ].setY( nLastY
- 1 );
419 else if( cMove
== 7 && cNextMove
== 0 )
421 aArr
[ nPolyPos
].setX( nLastX
- 1 );
422 aArr
[ nPolyPos
++ ].setY( nLastY
);
424 aArr
[ nPolyPos
].setX( nLastX
);
425 aArr
[ nPolyPos
++ ].setY( nLastY
+ 1 );
427 else if( cMove
== 4 && cNextMove
== 1 )
429 aArr
[ nPolyPos
].setX( nLastX
);
430 aArr
[ nPolyPos
++ ].setY( nLastY
+ 1 );
432 aArr
[ nPolyPos
].setX( nLastX
+ 1 );
433 aArr
[ nPolyPos
++ ].setY( nLastY
);
440 aArr
[ nPolyPos
].setX( nLastX
+ rMoveInner
.nDX
);
441 aArr
[ nPolyPos
++ ].setY( nLastY
+ rMoveInner
.nDY
);
445 aArr
[ nPolyPos
].setX( nFirstX
+ 1 );
446 aArr
[ nPolyPos
++ ].setY( nFirstY
+ 1 );
447 aArr
.ImplSetRealSize( nPolyPos
);
449 else if( nFlag
& VECT_POLY_INLINE_OUTER
)
451 tools::Long nFirstX
, nFirstY
;
452 tools::Long nLastX
, nLastY
;
454 nFirstX
= nLastX
= maStartPt
.X();
455 nFirstY
= nLastY
= maStartPt
.Y();
456 aArr
.ImplSetSize( mnCount
<< 1 );
460 for( i
= 0, nPolyPos
= 0; i
< ( mnCount
- 1 ); i
++ )
462 const sal_uInt8 cMove
= mpCodes
[ i
];
463 const sal_uInt8 cNextMove
= mpCodes
[ i
+ 1 ];
464 const ChainMove
& rMove
= aImplMove
[ cMove
];
465 const ChainMove
& rMoveOuter
= aImplMoveOuter
[ cMove
];
466 // Point& rPt = aArr[ nPolyPos ];
474 if( ( cMove
== 0 && cNextMove
== 1 ) ||
475 ( cMove
== 1 && cNextMove
== 2 ) ||
476 ( cMove
== 2 && cNextMove
== 3 ) ||
477 ( cMove
== 3 && cNextMove
== 0 ) )
480 else if( cMove
== 0 && cNextMove
== 3 )
482 aArr
[ nPolyPos
].setX( nLastX
);
483 aArr
[ nPolyPos
++ ].setY( nLastY
- 1 );
485 aArr
[ nPolyPos
].setX( nLastX
+ 1 );
486 aArr
[ nPolyPos
++ ].setY( nLastY
- 1 );
488 aArr
[ nPolyPos
].setX( nLastX
+ 1 );
489 aArr
[ nPolyPos
++ ].setY( nLastY
);
491 else if( cMove
== 3 && cNextMove
== 2 )
493 aArr
[ nPolyPos
].setX( nLastX
+ 1 );
494 aArr
[ nPolyPos
++ ].setY( nLastY
);
496 aArr
[ nPolyPos
].setX( nLastX
+ 1 );
497 aArr
[ nPolyPos
++ ].setY( nLastY
+ 1 );
499 aArr
[ nPolyPos
].setX( nLastX
);
500 aArr
[ nPolyPos
++ ].setY( nLastY
+ 1 );
502 else if( cMove
== 2 && cNextMove
== 1 )
504 aArr
[ nPolyPos
].setX( nLastX
);
505 aArr
[ nPolyPos
++ ].setY( nLastY
+ 1 );
507 aArr
[ nPolyPos
].setX( nLastX
- 1 );
508 aArr
[ nPolyPos
++ ].setY( nLastY
+ 1 );
510 aArr
[ nPolyPos
].setX( nLastX
- 1 );
511 aArr
[ nPolyPos
++ ].setY( nLastY
);
513 else if( cMove
== 1 && cNextMove
== 0 )
515 aArr
[ nPolyPos
].setX( nLastX
- 1 );
516 aArr
[ nPolyPos
++ ].setY( nLastY
);
518 aArr
[ nPolyPos
].setX( nLastX
- 1 );
519 aArr
[ nPolyPos
++ ].setY( nLastY
- 1 );
521 aArr
[ nPolyPos
].setX( nLastX
);
522 aArr
[ nPolyPos
++ ].setY( nLastY
- 1 );
527 else if( cMove
== 7 && cNextMove
== 3 )
529 aArr
[ nPolyPos
].setX( nLastX
);
530 aArr
[ nPolyPos
++ ].setY( nLastY
- 1 );
532 aArr
[ nPolyPos
].setX( nLastX
+ 1 );
533 aArr
[ nPolyPos
++ ].setY( nLastY
);
535 else if( cMove
== 6 && cNextMove
== 2 )
537 aArr
[ nPolyPos
].setX( nLastX
+ 1 );
538 aArr
[ nPolyPos
++ ].setY( nLastY
);
540 aArr
[ nPolyPos
].setX( nLastX
);
541 aArr
[ nPolyPos
++ ].setY( nLastY
+ 1 );
548 aArr
[ nPolyPos
].setX( nLastX
+ rMoveOuter
.nDX
);
549 aArr
[ nPolyPos
++ ].setY( nLastY
+ rMoveOuter
.nDY
);
553 aArr
[ nPolyPos
].setX( nFirstX
- 1 );
554 aArr
[ nPolyPos
++ ].setY( nFirstY
- 1 );
555 aArr
.ImplSetRealSize( nPolyPos
);
559 tools::Long nLastX
= maStartPt
.X(), nLastY
= maStartPt
.Y();
561 aArr
.ImplSetSize( mnCount
+ 1 );
562 aArr
[ 0 ] = Point( nLastX
, nLastY
);
564 for( sal_uLong i
= 0; i
< mnCount
; )
566 const ChainMove
& rMove
= aImplMove
[ mpCodes
[ i
] ];
569 aArr
[ ++i
] = Point( nLastX
, nLastY
);
572 aArr
.ImplSetRealSize( mnCount
+ 1 );
575 ImplPostProcess( aArr
);
581 void ImplChain::ImplPostProcess( const ImplPointArray
& rArr
)
583 ImplPointArray aNewArr1
;
584 ImplPointArray aNewArr2
;
588 sal_uLong nCount
= rArr
.ImplGetRealSize();
592 aNewArr1
.ImplSetSize( nCount
);
593 pLast
= &( aNewArr1
[ 0 ] );
594 pLast
->setX( BACK_MAP( rArr
[ 0 ].X() ) );
595 pLast
->setY( BACK_MAP( rArr
[ 0 ].Y() ) );
597 for( n
= nNewPos
= 1; n
< nCount
; )
599 const Point
& rPt
= rArr
[ n
++ ];
600 const tools::Long nX
= BACK_MAP( rPt
.X() );
601 const tools::Long nY
= BACK_MAP( rPt
.Y() );
603 if( nX
!= pLast
->X() || nY
!= pLast
->Y() )
605 pLast
= pLeast
= &( aNewArr1
[ nNewPos
++ ] );
612 aNewArr1
.ImplSetRealSize( nCount
);
615 aNewArr2
.ImplSetSize( nCount
);
616 pLast
= &( aNewArr2
[ 0 ] );
617 *pLast
= aNewArr1
[ 0 ];
619 for( n
= nNewPos
= 1; n
< nCount
; )
621 pLeast
= &( aNewArr1
[ n
++ ] );
623 if( pLeast
->X() == pLast
->X() )
625 while( n
< nCount
&& aNewArr1
[ n
].X() == pLast
->X() )
626 pLeast
= &( aNewArr1
[ n
++ ] );
628 else if( pLeast
->Y() == pLast
->Y() )
630 while( n
< nCount
&& aNewArr1
[ n
].Y() == pLast
->Y() )
631 pLeast
= &( aNewArr1
[ n
++ ] );
635 aNewArr2
[ nNewPos
++ ] = *pLast
;
638 aNewArr2
.ImplSetRealSize( nNewPos
);
639 aNewArr2
.ImplCreatePoly( maPoly
);
642 namespace ImplVectorizer
{
644 bool ImplVectorize( const Bitmap
& rColorBmp
, GDIMetaFile
& rMtf
,
645 sal_uInt8 cReduce
, const Link
<tools::Long
,void>* pProgress
)
649 VECT_PROGRESS( pProgress
, 0 );
651 std::unique_ptr
<Bitmap
> xBmp(new Bitmap( rColorBmp
));
652 Bitmap::ScopedReadAccess
pRAcc(*xBmp
);
656 tools::PolyPolygon aPolyPoly
;
657 double fPercent
= 0.0;
658 double fPercentStep_2
= 0.0;
659 const tools::Long nWidth
= pRAcc
->Width();
660 const tools::Long nHeight
= pRAcc
->Height();
661 const sal_uInt16 nColorCount
= pRAcc
->GetPaletteEntryCount();
663 std::array
<ImplColorSet
, 256> aColorSet
;
667 // get used palette colors and sort them from light to dark colors
668 for( n
= 0; n
< nColorCount
; n
++ )
670 aColorSet
[ n
].mnIndex
= n
;
671 aColorSet
[ n
].maColor
= pRAcc
->GetPaletteColor( n
);
674 for( tools::Long nY
= 0; nY
< nHeight
; nY
++ )
676 Scanline pScanlineRead
= pRAcc
->GetScanline( nY
);
677 for( tools::Long nX
= 0; nX
< nWidth
; nX
++ )
678 aColorSet
[ pRAcc
->GetIndexFromData( pScanlineRead
, nX
) ].mbSet
= true;
681 std::sort( aColorSet
.begin(), aColorSet
.end(), ImplColorSetCmpFnc
);
683 for( n
= 0; n
< 256; n
++ )
684 if( !aColorSet
[ n
].mbSet
)
688 fPercentStep_2
= 45.0 / n
;
691 VECT_PROGRESS( pProgress
, FRound( fPercent
) );
693 for( sal_uInt16 i
= 0; i
< n
; i
++ )
695 const BitmapColor
aBmpCol( pRAcc
->GetPaletteColor( aColorSet
[ i
].mnIndex
) );
696 const Color
aFindColor( aBmpCol
.GetRed(), aBmpCol
.GetGreen(), aBmpCol
.GetBlue() );
697 std::unique_ptr
<ImplVectMap
> xMap(ImplExpand( pRAcc
.get(), aFindColor
));
699 fPercent
+= fPercentStep_2
;
700 VECT_PROGRESS( pProgress
, FRound( fPercent
) );
705 ImplCalculate( xMap
.get(), aPolyPoly
, cReduce
);
708 if( aPolyPoly
.Count() )
710 ImplLimitPolyPoly( aPolyPoly
);
712 aPolyPoly
.Optimize( PolyOptimizeFlags::EDGES
);
714 if( aPolyPoly
.Count() )
716 rMtf
.AddAction( new MetaLineColorAction( aFindColor
, true ) );
717 rMtf
.AddAction( new MetaFillColorAction( aFindColor
, true ) );
718 rMtf
.AddAction( new MetaPolyPolygonAction( aPolyPoly
) );
723 fPercent
+= fPercentStep_2
;
724 VECT_PROGRESS( pProgress
, FRound( fPercent
) );
727 if( rMtf
.GetActionSize() )
729 MapMode
aMap( MapUnit::Map100thMM
);
730 ScopedVclPtrInstance
< VirtualDevice
> aVDev
;
731 const Size
aLogSize1( aVDev
->PixelToLogic( Size( 1, 1 ), aMap
) );
733 rMtf
.SetPrefMapMode( aMap
);
734 rMtf
.SetPrefSize( Size( nWidth
+ 2, nHeight
+ 2 ) );
736 rMtf
.Scale( aLogSize1
.Width(), aLogSize1
.Height() );
743 VECT_PROGRESS( pProgress
, 100 );
748 void ImplLimitPolyPoly( tools::PolyPolygon
& rPolyPoly
)
750 if( rPolyPoly
.Count() <= VECT_POLY_MAX
)
753 tools::PolyPolygon aNewPolyPoly
;
754 tools::Long nReduce
= 0;
755 sal_uInt16 nNewCount
;
759 aNewPolyPoly
.Clear();
762 for( sal_uInt16 i
= 0, nCount
= rPolyPoly
.Count(); i
< nCount
; i
++ )
764 const tools::Rectangle
aBound( rPolyPoly
[ i
].GetBoundRect() );
766 if( aBound
.GetWidth() > nReduce
&& aBound
.GetHeight() > nReduce
)
768 if( rPolyPoly
[ i
].GetSize() )
769 aNewPolyPoly
.Insert( rPolyPoly
[ i
] );
773 nNewCount
= aNewPolyPoly
.Count();
775 while( nNewCount
> VECT_POLY_MAX
);
777 rPolyPoly
= aNewPolyPoly
;
780 ImplVectMap
* ImplExpand( BitmapReadAccess
* pRAcc
, const Color
& rColor
)
782 ImplVectMap
* pMap
= nullptr;
784 if( pRAcc
&& pRAcc
->Width() && pRAcc
->Height() )
786 const tools::Long nOldWidth
= pRAcc
->Width();
787 const tools::Long nOldHeight
= pRAcc
->Height();
788 const tools::Long nNewWidth
= ( nOldWidth
<< 2 ) + 4;
789 const tools::Long nNewHeight
= ( nOldHeight
<< 2 ) + 4;
790 const BitmapColor
aTest( pRAcc
->GetBestMatchingColor( rColor
) );
791 std::unique_ptr
<tools::Long
[]> pMapIn(new tools::Long
[ std::max( nOldWidth
, nOldHeight
) ]);
792 std::unique_ptr
<tools::Long
[]> pMapOut(new tools::Long
[ std::max( nOldWidth
, nOldHeight
) ]);
793 tools::Long nX
, nY
, nTmpX
, nTmpY
;
795 pMap
= new ImplVectMap( nNewWidth
, nNewHeight
);
797 for( nX
= 0; nX
< nOldWidth
; nX
++ )
798 VECT_MAP( pMapIn
, pMapOut
, nX
);
800 for( nY
= 0, nTmpY
= 5; nY
< nOldHeight
; nY
++, nTmpY
+= 4 )
802 Scanline pScanlineRead
= pRAcc
->GetScanline( nY
);
803 for( nX
= 0; nX
< nOldWidth
; )
805 if( pRAcc
->GetPixelFromData( pScanlineRead
, nX
) == aTest
)
807 nTmpX
= pMapIn
[ nX
++ ];
810 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
811 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
812 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
813 pMap
->Set( nTmpY
, nTmpX
, VECT_CONT_INDEX
);
815 while( nX
< nOldWidth
&& pRAcc
->GetPixelFromData( pScanlineRead
, nX
) == aTest
)
818 nTmpX
= pMapOut
[ nX
- 1 ];
821 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
822 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
823 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
824 pMap
->Set( nTmpY
, nTmpX
, VECT_CONT_INDEX
);
831 for( nY
= 0; nY
< nOldHeight
; nY
++ )
832 VECT_MAP( pMapIn
, pMapOut
, nY
);
834 for( nX
= 0, nTmpX
= 5; nX
< nOldWidth
; nX
++, nTmpX
+= 4 )
836 for( nY
= 0; nY
< nOldHeight
; )
838 if( pRAcc
->GetPixel( nY
, nX
) == aTest
)
841 nTmpY
= pMapIn
[ nY
++ ];
843 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
844 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
845 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
846 pMap
->Set( nTmpY
, nTmpX
, VECT_CONT_INDEX
);
848 while( nY
< nOldHeight
&& pRAcc
->GetPixel( nY
, nX
) == aTest
)
852 nTmpY
= pMapOut
[ nY
- 1 ];
854 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
855 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
856 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
857 pMap
->Set( nTmpY
, nTmpX
, VECT_CONT_INDEX
);
868 void ImplCalculate( ImplVectMap
* pMap
, tools::PolyPolygon
& rPolyPoly
, sal_uInt8 cReduce
)
870 const tools::Long nWidth
= pMap
->Width(), nHeight
= pMap
->Height();
872 for( tools::Long nY
= 0; nY
< nHeight
; nY
++ )
880 while( ( nX
< nWidth
) && pMap
->IsFree( nY
, nX
) )
886 if( pMap
->IsCont( nY
, nX
) )
890 const Point
aStartPt( nX
++, nY
);
893 aChain
.ImplBeginAdd( aStartPt
);
894 ImplGetChain( pMap
, aStartPt
, aChain
);
896 aChain
.ImplEndAdd( bInner
? VECT_POLY_OUTLINE_INNER
: VECT_POLY_OUTLINE_OUTER
);
898 const tools::Polygon
& rPoly
= aChain
.ImplGetPoly();
900 if( rPoly
.GetSize() > 2 )
904 const tools::Rectangle
aBound( rPoly
.GetBoundRect() );
906 if( aBound
.GetWidth() > cReduce
&& aBound
.GetHeight() > cReduce
)
907 rPolyPoly
.Insert( rPoly
);
910 rPolyPoly
.Insert( rPoly
);
913 // skip rest of detected contour
914 while( pMap
->IsCont( nY
, nX
) )
919 // process done segment
920 const tools::Long nStartSegX
= nX
++;
922 while( pMap
->IsDone( nY
, nX
) )
925 if( ( ( nX
- nStartSegX
) == 1 ) || ( ImplIsUp( pMap
, nY
, nStartSegX
) != ImplIsUp( pMap
, nY
, nX
- 1 ) ) )
932 bool ImplGetChain( ImplVectMap
* pMap
, const Point
& rStartPt
, ImplChain
& rChain
)
934 tools::Long nActX
= rStartPt
.X();
935 tools::Long nActY
= rStartPt
.Y();
937 sal_uLong nLastDir
= 0;
944 // first try last direction
945 tools::Long nTryX
= nActX
+ aImplMove
[ nLastDir
].nDX
;
946 tools::Long nTryY
= nActY
+ aImplMove
[ nLastDir
].nDY
;
948 if( pMap
->IsCont( nTryY
, nTryX
) )
950 rChain
.ImplAdd( static_cast<sal_uInt8
>(nLastDir
) );
953 pMap
->Set( nActY
, nActX
, VECT_DONE_INDEX
);
958 // try other directions
959 for( nDir
= 0; nDir
< 8; nDir
++ )
961 // we already tried nLastDir
962 if( nDir
!= nLastDir
)
964 nTryX
= nActX
+ aImplMove
[ nDir
].nDX
;
965 nTryY
= nActY
+ aImplMove
[ nDir
].nDY
;
967 if( pMap
->IsCont( nTryY
, nTryX
) )
969 rChain
.ImplAdd( static_cast<sal_uInt8
>(nDir
) );
972 pMap
->Set( nActY
, nActX
, VECT_DONE_INDEX
);
986 bool ImplIsUp( ImplVectMap
const * pMap
, tools::Long nY
, tools::Long nX
)
988 if( pMap
->IsDone( nY
- 1, nX
) )
990 else if( pMap
->IsDone( nY
+ 1, nX
) )
992 else if( pMap
->IsDone( nY
- 1, nX
- 1 ) || pMap
->IsDone( nY
- 1, nX
+ 1 ) )
1000 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */