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 .
21 #include <vcl/bitmapaccess.hxx>
22 #include <tools/poly.hxx>
23 #include <vcl/gdimtf.hxx>
24 #include <vcl/metaact.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/wrkwin.hxx>
27 #include <vcl/virdev.hxx>
28 #include <impvect.hxx>
31 #define VECT_POLY_MAX 8192
33 #define VECT_FREE_INDEX 0
34 #define VECT_CONT_INDEX 1
35 #define VECT_DONE_INDEX 2
37 #define VECT_POLY_INLINE_INNER 1UL
38 #define VECT_POLY_INLINE_OUTER 2UL
39 #define VECT_POLY_OUTLINE_INNER 4UL
40 #define VECT_POLY_OUTLINE_OUTER 8UL
42 #define VECT_MAP( _def_pIn, _def_pOut, _def_nVal ) _def_pOut[_def_nVal]=(_def_pIn[_def_nVal]=((_def_nVal)*4)+1)+5;
43 #define BACK_MAP( _def_nVal ) ((((_def_nVal)+2)>>2)-1)
44 #define VECT_PROGRESS( _def_pProgress, _def_nVal ) \
46 (_def_pProgress->Call(_def_nVal));
51 namespace ImplVectorizer
53 ImplVectMap
* ImplExpand( BitmapReadAccess
* pRAcc
, const Color
& rColor
);
54 void ImplCalculate( ImplVectMap
* pMap
, tools::PolyPolygon
& rPolyPoly
, sal_uInt8 cReduce
);
55 bool ImplGetChain( ImplVectMap
* pMap
, const Point
& rStartPt
, ImplChain
& rChain
);
56 bool ImplIsUp( ImplVectMap
* pMap
, long nY
, long nX
);
57 void ImplLimitPolyPoly( tools::PolyPolygon
& rPolyPoly
);
60 struct ChainMove
{ long nDX
; long nDY
; };
62 static const ChainMove aImplMove
[ 8 ] = {
73 static const ChainMove aImplMoveInner
[ 8 ] = {
84 static const ChainMove aImplMoveOuter
[ 8 ] = {
102 extern "C" int SAL_CALL
ImplColorSetCmpFnc( const void* p1
, const void* p2
)
104 ImplColorSet
const * pSet1
= static_cast<ImplColorSet
const *>(p1
);
105 ImplColorSet
const * pSet2
= static_cast<ImplColorSet
const *>(p2
);
108 if( pSet1
->mbSet
&& pSet2
->mbSet
)
110 const sal_uInt8 cLum1
= pSet1
->maColor
.GetLuminance();
111 const sal_uInt8 cLum2
= pSet2
->maColor
.GetLuminance();
112 nRet
= ( ( cLum1
> cLum2
) ? -1 : ( ( cLum1
== cLum2
) ? 0 : 1 ) );
114 else if( pSet1
->mbSet
)
116 else if( pSet2
->mbSet
)
128 sal_uLong mnRealSize
;
135 void ImplSetSize( sal_uLong nSize
);
136 sal_uLong
ImplGetRealSize() const { return mnRealSize
; }
137 void ImplSetRealSize( sal_uLong nRealSize
) { mnRealSize
= nRealSize
; }
138 void ImplCreatePoly( tools::Polygon
& rPoly
) const;
140 inline Point
& operator[]( sal_uLong nPos
);
141 inline const Point
& operator[]( sal_uLong nPos
) const;
145 ImplPointArray::ImplPointArray() :
153 ImplPointArray::~ImplPointArray()
156 rtl_freeMemory( mpArray
);
159 void ImplPointArray::ImplSetSize( sal_uLong nSize
)
161 const sal_uLong nTotal
= nSize
* sizeof( Point
);
167 rtl_freeMemory( mpArray
);
169 mpArray
= static_cast<Point
*>(rtl_allocateMemory( nTotal
));
170 memset( mpArray
, 0, nTotal
);
173 inline Point
& ImplPointArray::operator[]( sal_uLong nPos
)
175 SAL_WARN_IF( nPos
>= mnSize
, "vcl", "ImplPointArray::operator[]: nPos out of range!" );
176 return mpArray
[ nPos
];
179 inline const Point
& ImplPointArray::operator[]( sal_uLong nPos
) const
181 SAL_WARN_IF( nPos
>= mnSize
, "vcl", "ImplPointArray::operator[]: nPos out of range!" );
182 return mpArray
[ nPos
];
185 void ImplPointArray::ImplCreatePoly( tools::Polygon
& rPoly
) const
187 rPoly
= tools::Polygon( sal::static_int_cast
<sal_uInt16
>(mnRealSize
), mpArray
);
201 ImplVectMap( long nWidth
, long nHeight
);
204 long Width() const { return mnWidth
; }
205 long Height() const { return mnHeight
; }
207 inline void Set( long nY
, long nX
, sal_uInt8 cVal
);
208 inline sal_uInt8
Get( long nY
, long nX
) const;
210 inline bool IsFree( long nY
, long nX
) const;
211 inline bool IsCont( long nY
, long nX
) const;
212 inline bool IsDone( long nY
, long nX
) const;
216 ImplVectMap::ImplVectMap( long nWidth
, long nHeight
) :
220 const long nWidthAl
= ( nWidth
>> 2 ) + 1;
221 const long nSize
= nWidthAl
* nHeight
;
222 Scanline pTmp
= mpBuf
= static_cast<Scanline
>(rtl_allocateMemory( nSize
));
224 memset( mpBuf
, 0, nSize
);
225 mpScan
= static_cast<Scanline
*>(rtl_allocateMemory( nHeight
* sizeof( Scanline
) ));
227 for( long nY
= 0; nY
< nHeight
; pTmp
+= nWidthAl
)
228 mpScan
[ nY
++ ] = pTmp
;
231 ImplVectMap::~ImplVectMap()
233 rtl_freeMemory( mpBuf
);
234 rtl_freeMemory( mpScan
);
237 inline void ImplVectMap::Set( long nY
, long nX
, sal_uInt8 cVal
)
239 const sal_uInt8 cShift
= sal::static_int_cast
<sal_uInt8
>(6 - ( ( nX
& 3 ) << 1 ));
240 ( ( mpScan
[ nY
][ nX
>> 2 ] ) &= ~( 3 << cShift
) ) |= ( cVal
<< cShift
);
243 inline sal_uInt8
ImplVectMap::Get( long nY
, long nX
) const
245 return sal::static_int_cast
<sal_uInt8
>( ( ( mpScan
[ nY
][ nX
>> 2 ] ) >> ( 6 - ( ( nX
& 3 ) << 1 ) ) ) & 3 );
248 inline bool ImplVectMap::IsFree( long nY
, long nX
) const
250 return( VECT_FREE_INDEX
== Get( nY
, nX
) );
253 inline bool ImplVectMap::IsCont( long nY
, long nX
) const
255 return( VECT_CONT_INDEX
== Get( nY
, nX
) );
258 inline bool ImplVectMap::IsDone( long nY
, long nX
) const
260 return( VECT_DONE_INDEX
== Get( nY
, nX
) );
267 tools::Polygon maPoly
;
269 sal_uLong mnArraySize
;
271 std::unique_ptr
<sal_uInt8
[]>
276 void ImplPostProcess( const ImplPointArray
& rArr
);
278 ImplChain(const ImplChain
&) = delete;
279 ImplChain
& operator=(const ImplChain
&) = delete;
285 void ImplBeginAdd( const Point
& rStartPt
);
286 inline void ImplAdd( sal_uInt8 nCode
);
287 void ImplEndAdd( sal_uLong nTypeFlag
);
289 const tools::Polygon
& ImplGetPoly() const { return maPoly
; }
292 ImplChain::ImplChain() :
293 mnArraySize ( 1024UL ),
296 mpCodes
.reset( new sal_uInt8
[ mnArraySize
] );
299 void ImplChain::ImplGetSpace()
301 const sal_uLong nOldArraySize
= mnArraySize
;
302 sal_uInt8
* pNewCodes
;
304 mnArraySize
= mnArraySize
<< 1UL;
305 pNewCodes
= new sal_uInt8
[ mnArraySize
];
306 memcpy( pNewCodes
, mpCodes
.get(), nOldArraySize
);
307 mpCodes
.reset( pNewCodes
);
310 void ImplChain::ImplBeginAdd( const Point
& rStartPt
)
312 maPoly
= tools::Polygon();
313 maStartPt
= rStartPt
;
317 inline void ImplChain::ImplAdd( sal_uInt8 nCode
)
319 if( mnCount
== mnArraySize
)
322 mpCodes
[ mnCount
++ ] = nCode
;
325 void ImplChain::ImplEndAdd( sal_uLong nFlag
)
331 if( nFlag
& VECT_POLY_INLINE_INNER
)
333 long nFirstX
, nFirstY
;
336 nFirstX
= nLastX
= maStartPt
.X();
337 nFirstY
= nLastY
= maStartPt
.Y();
338 aArr
.ImplSetSize( mnCount
<< 1 );
340 sal_uInt16 i
, nPolyPos
;
341 for( i
= 0, nPolyPos
= 0; i
< ( mnCount
- 1 ); i
++ )
343 const sal_uInt8 cMove
= mpCodes
[ i
];
344 const sal_uInt8 cNextMove
= mpCodes
[ i
+ 1 ];
345 const ChainMove
& rMove
= aImplMove
[ cMove
];
346 const ChainMove
& rMoveInner
= aImplMoveInner
[ cMove
];
347 // Point& rPt = aArr[ nPolyPos ];
355 if( ( cMove
== 0 && cNextMove
== 3 ) ||
356 ( cMove
== 3 && cNextMove
== 2 ) ||
357 ( cMove
== 2 && cNextMove
== 1 ) ||
358 ( cMove
== 1 && cNextMove
== 0 ) )
361 else if( cMove
== 2 && cNextMove
== 3 )
363 aArr
[ nPolyPos
].X() = nLastX
;
364 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
366 aArr
[ nPolyPos
].X() = nLastX
- 1;
367 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
369 aArr
[ nPolyPos
].X() = nLastX
- 1;
370 aArr
[ nPolyPos
++ ].Y() = nLastY
;
372 else if( cMove
== 3 && cNextMove
== 0 )
374 aArr
[ nPolyPos
].X() = nLastX
- 1;
375 aArr
[ nPolyPos
++ ].Y() = nLastY
;
377 aArr
[ nPolyPos
].X() = nLastX
- 1;
378 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
380 aArr
[ nPolyPos
].X() = nLastX
;
381 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
383 else if( cMove
== 0 && cNextMove
== 1 )
385 aArr
[ nPolyPos
].X() = nLastX
;
386 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
388 aArr
[ nPolyPos
].X() = nLastX
+ 1;
389 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
391 aArr
[ nPolyPos
].X() = nLastX
+ 1;
392 aArr
[ nPolyPos
++ ].Y() = nLastY
;
394 else if( cMove
== 1 && cNextMove
== 2 )
396 aArr
[ nPolyPos
].X() = nLastX
+ 1;
397 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
399 aArr
[ nPolyPos
].X() = nLastX
+ 1;
400 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
402 aArr
[ nPolyPos
].X() = nLastX
;
403 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
408 else if( cMove
== 7 && cNextMove
== 0 )
410 aArr
[ nPolyPos
].X() = nLastX
- 1;
411 aArr
[ nPolyPos
++ ].Y() = nLastY
;
413 aArr
[ nPolyPos
].X() = nLastX
;
414 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
416 else if( cMove
== 4 && cNextMove
== 1 )
418 aArr
[ nPolyPos
].X() = nLastX
;
419 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
421 aArr
[ nPolyPos
].X() = nLastX
+ 1;
422 aArr
[ nPolyPos
++ ].Y() = nLastY
;
429 aArr
[ nPolyPos
].X() = nLastX
+ rMoveInner
.nDX
;
430 aArr
[ nPolyPos
++ ].Y() = nLastY
+ rMoveInner
.nDY
;
434 aArr
[ nPolyPos
].X() = nFirstX
+ 1;
435 aArr
[ nPolyPos
++ ].Y() = nFirstY
+ 1;
436 aArr
.ImplSetRealSize( nPolyPos
);
438 else if( nFlag
& VECT_POLY_INLINE_OUTER
)
440 long nFirstX
, nFirstY
;
443 nFirstX
= nLastX
= maStartPt
.X();
444 nFirstY
= nLastY
= maStartPt
.Y();
445 aArr
.ImplSetSize( mnCount
<< 1 );
447 sal_uInt16 i
, nPolyPos
;
448 for( i
= 0, nPolyPos
= 0; i
< ( mnCount
- 1 ); i
++ )
450 const sal_uInt8 cMove
= mpCodes
[ i
];
451 const sal_uInt8 cNextMove
= mpCodes
[ i
+ 1 ];
452 const ChainMove
& rMove
= aImplMove
[ cMove
];
453 const ChainMove
& rMoveOuter
= aImplMoveOuter
[ cMove
];
454 // Point& rPt = aArr[ nPolyPos ];
462 if( ( cMove
== 0 && cNextMove
== 1 ) ||
463 ( cMove
== 1 && cNextMove
== 2 ) ||
464 ( cMove
== 2 && cNextMove
== 3 ) ||
465 ( cMove
== 3 && cNextMove
== 0 ) )
468 else if( cMove
== 0 && cNextMove
== 3 )
470 aArr
[ nPolyPos
].X() = nLastX
;
471 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
473 aArr
[ nPolyPos
].X() = nLastX
+ 1;
474 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
476 aArr
[ nPolyPos
].X() = nLastX
+ 1;
477 aArr
[ nPolyPos
++ ].Y() = nLastY
;
479 else if( cMove
== 3 && cNextMove
== 2 )
481 aArr
[ nPolyPos
].X() = nLastX
+ 1;
482 aArr
[ nPolyPos
++ ].Y() = nLastY
;
484 aArr
[ nPolyPos
].X() = nLastX
+ 1;
485 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
487 aArr
[ nPolyPos
].X() = nLastX
;
488 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
490 else if( cMove
== 2 && cNextMove
== 1 )
492 aArr
[ nPolyPos
].X() = nLastX
;
493 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
495 aArr
[ nPolyPos
].X() = nLastX
- 1;
496 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
498 aArr
[ nPolyPos
].X() = nLastX
- 1;
499 aArr
[ nPolyPos
++ ].Y() = nLastY
;
501 else if( cMove
== 1 && cNextMove
== 0 )
503 aArr
[ nPolyPos
].X() = nLastX
- 1;
504 aArr
[ nPolyPos
++ ].Y() = nLastY
;
506 aArr
[ nPolyPos
].X() = nLastX
- 1;
507 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
509 aArr
[ nPolyPos
].X() = nLastX
;
510 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
515 else if( cMove
== 7 && cNextMove
== 3 )
517 aArr
[ nPolyPos
].X() = nLastX
;
518 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
520 aArr
[ nPolyPos
].X() = nLastX
+ 1;
521 aArr
[ nPolyPos
++ ].Y() = nLastY
;
523 else if( cMove
== 6 && cNextMove
== 2 )
525 aArr
[ nPolyPos
].X() = nLastX
+ 1;
526 aArr
[ nPolyPos
++ ].Y() = nLastY
;
528 aArr
[ nPolyPos
].X() = nLastX
;
529 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
536 aArr
[ nPolyPos
].X() = nLastX
+ rMoveOuter
.nDX
;
537 aArr
[ nPolyPos
++ ].Y() = nLastY
+ rMoveOuter
.nDY
;
541 aArr
[ nPolyPos
].X() = nFirstX
- 1;
542 aArr
[ nPolyPos
++ ].Y() = nFirstY
- 1;
543 aArr
.ImplSetRealSize( nPolyPos
);
547 long nLastX
= maStartPt
.X(), nLastY
= maStartPt
.Y();
549 aArr
.ImplSetSize( mnCount
+ 1 );
550 aArr
[ 0 ] = Point( nLastX
, nLastY
);
552 for( sal_uLong i
= 0; i
< mnCount
; )
554 const ChainMove
& rMove
= aImplMove
[ mpCodes
[ i
] ];
555 aArr
[ ++i
] = Point( nLastX
+= rMove
.nDX
, nLastY
+= rMove
.nDY
);
558 aArr
.ImplSetRealSize( mnCount
+ 1 );
561 ImplPostProcess( aArr
);
567 void ImplChain::ImplPostProcess( const ImplPointArray
& rArr
)
569 ImplPointArray aNewArr1
;
570 ImplPointArray aNewArr2
;
574 sal_uLong nCount
= rArr
.ImplGetRealSize();
578 aNewArr1
.ImplSetSize( nCount
);
579 pLast
= &( aNewArr1
[ 0 ] );
580 pLast
->X() = BACK_MAP( rArr
[ 0 ].X() );
581 pLast
->Y() = BACK_MAP( rArr
[ 0 ].Y() );
583 for( n
= nNewPos
= 1; n
< nCount
; )
585 const Point
& rPt
= rArr
[ n
++ ];
586 const long nX
= BACK_MAP( rPt
.X() );
587 const long nY
= BACK_MAP( rPt
.Y() );
589 if( nX
!= pLast
->X() || nY
!= pLast
->Y() )
591 pLast
= pLeast
= &( aNewArr1
[ nNewPos
++ ] );
597 aNewArr1
.ImplSetRealSize( nCount
= nNewPos
);
600 aNewArr2
.ImplSetSize( nCount
);
601 pLast
= &( aNewArr2
[ 0 ] );
602 *pLast
= aNewArr1
[ 0 ];
604 for( n
= nNewPos
= 1; n
< nCount
; )
606 pLeast
= &( aNewArr1
[ n
++ ] );
608 if( pLeast
->X() == pLast
->X() )
610 while( n
< nCount
&& aNewArr1
[ n
].X() == pLast
->X() )
611 pLeast
= &( aNewArr1
[ n
++ ] );
613 else if( pLeast
->Y() == pLast
->Y() )
615 while( n
< nCount
&& aNewArr1
[ n
].Y() == pLast
->Y() )
616 pLeast
= &( aNewArr1
[ n
++ ] );
619 aNewArr2
[ nNewPos
++ ] = *( pLast
= pLeast
);
622 aNewArr2
.ImplSetRealSize( nNewPos
);
623 aNewArr2
.ImplCreatePoly( maPoly
);
626 namespace ImplVectorizer
{
628 bool ImplVectorize( const Bitmap
& rColorBmp
, GDIMetaFile
& rMtf
,
629 sal_uInt8 cReduce
, const Link
<long,void>* pProgress
)
633 VECT_PROGRESS( pProgress
, 0 );
635 std::unique_ptr
<Bitmap
> xBmp(new Bitmap( rColorBmp
));
636 Bitmap::ScopedReadAccess
pRAcc(*xBmp
);
640 tools::PolyPolygon aPolyPoly
;
641 double fPercent
= 0.0;
642 double fPercentStep_2
= 0.0;
643 const long nWidth
= pRAcc
->Width();
644 const long nHeight
= pRAcc
->Height();
645 const sal_uInt16 nColorCount
= pRAcc
->GetPaletteEntryCount();
647 ImplColorSet
* pColorSet
= reinterpret_cast<ImplColorSet
*>(new sal_uInt8
[ 256 * sizeof( ImplColorSet
) ]);
649 memset( pColorSet
, 0, 256 * sizeof( ImplColorSet
) );
652 // get used palette colors and sort them from light to dark colors
653 for( n
= 0; n
< nColorCount
; n
++ )
655 pColorSet
[ n
].mnIndex
= n
;
656 pColorSet
[ n
].maColor
= pRAcc
->GetPaletteColor( n
);
659 for( long nY
= 0; nY
< nHeight
; nY
++ )
660 for( long nX
= 0; nX
< nWidth
; nX
++ )
661 pColorSet
[ pRAcc
->GetPixel( nY
, nX
).GetIndex() ].mbSet
= true;
663 qsort( pColorSet
, 256, sizeof( ImplColorSet
), ImplColorSetCmpFnc
);
665 for( n
= 0; n
< 256; n
++ )
666 if( !pColorSet
[ n
].mbSet
)
670 fPercentStep_2
= 45.0 / n
;
672 VECT_PROGRESS( pProgress
, FRound( fPercent
+= 10.0 ) );
674 for( sal_uInt16 i
= 0; i
< n
; i
++ )
676 const BitmapColor
aBmpCol( pRAcc
->GetPaletteColor( pColorSet
[ i
].mnIndex
) );
677 const Color
aFindColor( aBmpCol
.GetRed(), aBmpCol
.GetGreen(), aBmpCol
.GetBlue() );
678 std::unique_ptr
<ImplVectMap
> xMap(ImplExpand( pRAcc
.get(), aFindColor
));
680 VECT_PROGRESS( pProgress
, FRound( fPercent
+= fPercentStep_2
) );
685 ImplCalculate( xMap
.get(), aPolyPoly
, cReduce
);
688 if( aPolyPoly
.Count() )
690 ImplLimitPolyPoly( aPolyPoly
);
692 aPolyPoly
.Optimize( PolyOptimizeFlags::EDGES
);
694 if( aPolyPoly
.Count() )
696 rMtf
.AddAction( new MetaLineColorAction( aFindColor
, true ) );
697 rMtf
.AddAction( new MetaFillColorAction( aFindColor
, true ) );
698 rMtf
.AddAction( new MetaPolyPolygonAction( aPolyPoly
) );
703 VECT_PROGRESS( pProgress
, FRound( fPercent
+= fPercentStep_2
) );
706 delete[] reinterpret_cast<sal_uInt8
*>(pColorSet
);
708 if( rMtf
.GetActionSize() )
710 MapMode
aMap( MapUnit::Map100thMM
);
711 ScopedVclPtrInstance
< VirtualDevice
> aVDev
;
712 const Size
aLogSize1( aVDev
->PixelToLogic( Size( 1, 1 ), aMap
) );
714 rMtf
.SetPrefMapMode( aMap
);
715 rMtf
.SetPrefSize( Size( nWidth
+ 2, nHeight
+ 2 ) );
717 rMtf
.Scale( aLogSize1
.Width(), aLogSize1
.Height() );
724 VECT_PROGRESS( pProgress
, 100 );
729 void ImplLimitPolyPoly( tools::PolyPolygon
& rPolyPoly
)
731 if( rPolyPoly
.Count() > VECT_POLY_MAX
)
733 tools::PolyPolygon aNewPolyPoly
;
735 sal_uInt16 nNewCount
;
739 aNewPolyPoly
.Clear();
742 for( sal_uInt16 i
= 0, nCount
= rPolyPoly
.Count(); i
< nCount
; i
++ )
744 const tools::Rectangle
aBound( rPolyPoly
[ i
].GetBoundRect() );
746 if( aBound
.GetWidth() > nReduce
&& aBound
.GetHeight() > nReduce
)
748 if( rPolyPoly
[ i
].GetSize() )
749 aNewPolyPoly
.Insert( rPolyPoly
[ i
] );
753 nNewCount
= aNewPolyPoly
.Count();
755 while( nNewCount
> VECT_POLY_MAX
);
757 rPolyPoly
= aNewPolyPoly
;
761 ImplVectMap
* ImplExpand( BitmapReadAccess
* pRAcc
, const Color
& rColor
)
763 ImplVectMap
* pMap
= nullptr;
765 if( pRAcc
&& pRAcc
->Width() && pRAcc
->Height() )
767 const long nOldWidth
= pRAcc
->Width();
768 const long nOldHeight
= pRAcc
->Height();
769 const long nNewWidth
= ( nOldWidth
<< 2 ) + 4;
770 const long nNewHeight
= ( nOldHeight
<< 2 ) + 4;
771 const BitmapColor
aTest( pRAcc
->GetBestMatchingColor( rColor
) );
772 std::unique_ptr
<long[]> pMapIn(new long[ std::max( nOldWidth
, nOldHeight
) ]);
773 std::unique_ptr
<long[]> pMapOut(new long[ std::max( nOldWidth
, nOldHeight
) ]);
774 long nX
, nY
, nTmpX
, nTmpY
;
776 pMap
= new ImplVectMap( nNewWidth
, nNewHeight
);
778 for( nX
= 0; nX
< nOldWidth
; nX
++ )
779 VECT_MAP( pMapIn
, pMapOut
, nX
);
781 for( nY
= 0, nTmpY
= 5; nY
< nOldHeight
; nY
++, nTmpY
+= 4 )
783 for( nX
= 0; nX
< nOldWidth
; )
785 if( pRAcc
->GetPixel( nY
, nX
) == aTest
)
787 nTmpX
= pMapIn
[ nX
++ ];
790 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
791 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
792 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
793 pMap
->Set( nTmpY
, nTmpX
, VECT_CONT_INDEX
);
795 while( nX
< nOldWidth
&& pRAcc
->GetPixel( nY
, nX
) == aTest
)
798 nTmpX
= pMapOut
[ nX
- 1 ];
801 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
802 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
803 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
804 pMap
->Set( nTmpY
, nTmpX
, VECT_CONT_INDEX
);
811 for( nY
= 0; nY
< nOldHeight
; nY
++ )
812 VECT_MAP( pMapIn
, pMapOut
, nY
);
814 for( nX
= 0, nTmpX
= 5; nX
< nOldWidth
; nX
++, nTmpX
+= 4 )
816 for( nY
= 0; nY
< nOldHeight
; )
818 if( pRAcc
->GetPixel( nY
, nX
) == aTest
)
821 nTmpY
= pMapIn
[ nY
++ ];
823 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
824 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
825 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
826 pMap
->Set( nTmpY
, nTmpX
, VECT_CONT_INDEX
);
828 while( nY
< nOldHeight
&& pRAcc
->GetPixel( nY
, nX
) == aTest
)
832 nTmpY
= pMapOut
[ nY
- 1 ];
834 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
835 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
836 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
837 pMap
->Set( nTmpY
, nTmpX
, VECT_CONT_INDEX
);
848 void ImplCalculate( ImplVectMap
* pMap
, tools::PolyPolygon
& rPolyPoly
, sal_uInt8 cReduce
)
850 const long nWidth
= pMap
->Width(), nHeight
= pMap
->Height();
852 for( long nY
= 0; nY
< nHeight
; nY
++ )
860 while( ( nX
< nWidth
) && pMap
->IsFree( nY
, nX
) )
866 if( pMap
->IsCont( nY
, nX
) )
870 const Point
aStartPt( nX
++, nY
);
873 aChain
.ImplBeginAdd( aStartPt
);
874 ImplGetChain( pMap
, aStartPt
, aChain
);
876 aChain
.ImplEndAdd( bInner
? VECT_POLY_OUTLINE_INNER
: VECT_POLY_OUTLINE_OUTER
);
878 const tools::Polygon
& rPoly
= aChain
.ImplGetPoly();
880 if( rPoly
.GetSize() > 2 )
884 const tools::Rectangle
aBound( rPoly
.GetBoundRect() );
886 if( aBound
.GetWidth() > cReduce
&& aBound
.GetHeight() > cReduce
)
887 rPolyPoly
.Insert( rPoly
);
890 rPolyPoly
.Insert( rPoly
);
893 // skip rest of detected contour
894 while( pMap
->IsCont( nY
, nX
) )
899 // process done segment
900 const long nStartSegX
= nX
++;
902 while( pMap
->IsDone( nY
, nX
) )
905 if( ( ( nX
- nStartSegX
) == 1 ) || ( ImplIsUp( pMap
, nY
, nStartSegX
) != ImplIsUp( pMap
, nY
, nX
- 1 ) ) )
912 bool ImplGetChain( ImplVectMap
* pMap
, const Point
& rStartPt
, ImplChain
& rChain
)
914 long nActX
= rStartPt
.X();
915 long nActY
= rStartPt
.Y();
917 sal_uLong nLastDir
= 0UL;
924 // first try last direction
925 long nTryX
= nActX
+ aImplMove
[ nLastDir
].nDX
;
926 long nTryY
= nActY
+ aImplMove
[ nLastDir
].nDY
;
928 if( pMap
->IsCont( nTryY
, nTryX
) )
930 rChain
.ImplAdd( (sal_uInt8
) nLastDir
);
931 pMap
->Set( nActY
= nTryY
, nActX
= nTryX
, VECT_DONE_INDEX
);
936 // try other directions
937 for( nDir
= 0UL; nDir
< 8UL; nDir
++ )
939 // we already tried nLastDir
940 if( nDir
!= nLastDir
)
942 nTryX
= nActX
+ aImplMove
[ nDir
].nDX
;
943 nTryY
= nActY
+ aImplMove
[ nDir
].nDY
;
945 if( pMap
->IsCont( nTryY
, nTryX
) )
947 rChain
.ImplAdd( (sal_uInt8
) nDir
);
948 pMap
->Set( nActY
= nTryY
, nActX
= nTryX
, VECT_DONE_INDEX
);
962 bool ImplIsUp( ImplVectMap
* pMap
, long nY
, long nX
)
964 if( pMap
->IsDone( nY
- 1, nX
) )
966 else if( pMap
->IsDone( nY
+ 1, nX
) )
968 else if( pMap
->IsDone( nY
- 1, nX
- 1 ) || pMap
->IsDone( nY
- 1, nX
+ 1 ) )
976 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */