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/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"
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
)
55 pProgress
->Call(_def_nVal
);
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 ] = {
83 static const ChainMove aImplMoveInner
[ 8 ] = {
94 static const ChainMove aImplMoveOuter
[ 8 ] = {
108 sal_uInt16 mnIndex
= 0;
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
;
125 std::unique_ptr
<Point
[]> mpArray
;
127 sal_uLong mnRealSize
;
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() :
150 void ImplPointArray::ImplSetSize( sal_uLong nSize
)
152 const sal_uLong nTotal
= nSize
* sizeof( Point
);
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() );
181 Scanline
const mpBuf
;
188 ImplVectMap( long nWidth
, long nHeight
);
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
))) ),
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()
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
) );
253 tools::Polygon maPoly
;
255 sal_uLong mnArraySize
;
257 std::unique_ptr
<sal_uInt8
[]>
262 void ImplPostProcess( const ImplPointArray
& rArr
);
264 ImplChain(const ImplChain
&) = delete;
265 ImplChain
& operator=(const ImplChain
&) = delete;
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 ),
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
;
303 inline void ImplChain::ImplAdd( sal_uInt8 nCode
)
305 if( mnCount
== mnArraySize
)
308 mpCodes
[ mnCount
++ ] = nCode
;
311 void ImplChain::ImplEndAdd( sal_uLong nFlag
)
317 if( nFlag
& VECT_POLY_INLINE_INNER
)
319 long nFirstX
, nFirstY
;
322 nFirstX
= nLastX
= maStartPt
.X();
323 nFirstY
= nLastY
= maStartPt
.Y();
324 aArr
.ImplSetSize( mnCount
<< 1 );
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 ];
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 );
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
);
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
;
430 nFirstX
= nLastX
= maStartPt
.X();
431 nFirstY
= nLastY
= maStartPt
.Y();
432 aArr
.ImplSetSize( mnCount
<< 1 );
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 ];
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 );
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 );
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
);
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
);
555 void ImplChain::ImplPostProcess( const ImplPointArray
& rArr
)
557 ImplPointArray aNewArr1
;
558 ImplPointArray aNewArr2
;
562 sal_uLong nCount
= rArr
.ImplGetRealSize();
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
++ ] );
586 aNewArr1
.ImplSetRealSize( nCount
);
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
++ ] );
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
)
623 VECT_PROGRESS( pProgress
, 0 );
625 std::unique_ptr
<Bitmap
> xBmp(new Bitmap( rColorBmp
));
626 Bitmap::ScopedReadAccess
pRAcc(*xBmp
);
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();
637 std::array
<ImplColorSet
, 256> aColorSet
;
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
)
662 fPercentStep_2
= 45.0 / n
;
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
) );
679 ImplCalculate( xMap
.get(), aPolyPoly
, cReduce
);
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 ) );
710 rMtf
.Scale( aLogSize1
.Width(), aLogSize1
.Height() );
717 VECT_PROGRESS( pProgress
, 100 );
722 void ImplLimitPolyPoly( tools::PolyPolygon
& rPolyPoly
)
724 if( rPolyPoly
.Count() > VECT_POLY_MAX
)
726 tools::PolyPolygon aNewPolyPoly
;
728 sal_uInt16 nNewCount
;
732 aNewPolyPoly
.Clear();
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
++ ];
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
)
792 nTmpX
= pMapOut
[ nX
- 1 ];
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
);
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
)
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
)
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
);
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
++ )
854 while( ( nX
< nWidth
) && pMap
->IsFree( nY
, nX
) )
860 if( pMap
->IsCont( nY
, nX
) )
864 const Point
aStartPt( nX
++, nY
);
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 )
878 const tools::Rectangle
aBound( rPoly
.GetBoundRect() );
880 if( aBound
.GetWidth() > cReduce
&& aBound
.GetHeight() > cReduce
)
881 rPolyPoly
.Insert( rPoly
);
884 rPolyPoly
.Insert( rPoly
);
887 // skip rest of detected contour
888 while( pMap
->IsCont( nY
, nX
) )
893 // process done segment
894 const long nStartSegX
= nX
++;
896 while( pMap
->IsDone( nY
, nX
) )
899 if( ( ( nX
- nStartSegX
) == 1 ) || ( ImplIsUp( pMap
, nY
, nStartSegX
) != ImplIsUp( pMap
, nY
, nX
- 1 ) ) )
906 bool ImplGetChain( ImplVectMap
* pMap
, const Point
& rStartPt
, ImplChain
& rChain
)
908 long nActX
= rStartPt
.X();
909 long nActY
= rStartPt
.Y();
911 sal_uLong nLastDir
= 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
) );
927 pMap
->Set( nActY
, nActX
, VECT_DONE_INDEX
);
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
) );
946 pMap
->Set( nActY
, nActX
, VECT_DONE_INDEX
);
960 bool ImplIsUp( ImplVectMap
const * pMap
, long nY
, long nX
)
962 if( pMap
->IsDone( nY
- 1, nX
) )
964 else if( pMap
->IsDone( nY
+ 1, nX
) )
966 else if( pMap
->IsDone( nY
- 1, nX
- 1 ) || pMap
->IsDone( nY
- 1, nX
+ 1 ) )
974 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */