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/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>
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)));
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 ] = {
74 static const ChainMove aImplMoveInner
[ 8 ] = {
85 static const ChainMove aImplMoveOuter
[ 8 ] = {
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
);
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
)
117 else if( pSet2
->mbSet
)
129 sal_uLong mnRealSize
;
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() :
155 ImplPointArray::~ImplPointArray()
158 rtl_freeMemory( mpArray
);
161 void ImplPointArray::ImplSetSize( sal_uLong nSize
)
163 const sal_uLong nTotal
= nSize
* sizeof( Point
);
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
);
203 ImplVectMap( long nWidth
, long nHeight
);
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
) :
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
) );
271 sal_uLong mnArraySize
;
278 void ImplPostProcess( const ImplPointArray
& rArr
);
282 ImplChain( sal_uLong nInitCount
= 1024UL, long nResize
= -1L );
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
),
297 DBG_ASSERT( nInitCount
&& nResize
, "ImplChain::ImplChain(): invalid parameters!" );
298 mpCodes
= new sal_uInt8
[ mnArraySize
];
301 ImplChain::~ImplChain()
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
);
318 void ImplChain::ImplBeginAdd( const Point
& rStartPt
)
321 maStartPt
= rStartPt
;
325 inline void ImplChain::ImplAdd( sal_uInt8 nCode
)
327 if( mnCount
== mnArraySize
)
330 mpCodes
[ mnCount
++ ] = nCode
;
333 void ImplChain::ImplEndAdd( sal_uLong nFlag
)
339 if( nFlag
& VECT_POLY_INLINE_INNER
)
341 long nFirstX
, nFirstY
;
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 ];
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;
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
;
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
;
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 ];
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;
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;
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
);
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
);
575 void ImplChain::ImplPostProcess( const ImplPointArray
& rArr
)
577 ImplPointArray aNewArr1
;
578 ImplPointArray aNewArr2
;
582 sal_uLong nCount
= rArr
.ImplGetRealSize();
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
++ ] );
605 aNewArr1
.ImplSetRealSize( nCount
= nNewPos
);
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
)
641 VECT_PROGRESS( pProgress
, 0 );
643 std::unique_ptr
<Bitmap
> xBmp(new Bitmap( rColorBmp
));
644 BitmapReadAccess
* pRAcc
= xBmp
->AcquireReadAccess();
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();
655 ImplColorSet
* pColorSet
= reinterpret_cast<ImplColorSet
*>(new sal_uInt8
[ 256 * sizeof( ImplColorSet
) ]);
657 memset( pColorSet
, 0, 256 * sizeof( ImplColorSet
) );
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
)
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
) );
693 ImplCalculate( xMap
.get(), aPolyPoly
, cReduce
, nFlags
);
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 ) );
726 rMtf
.Scale( aLogSize1
.Width(), aLogSize1
.Height() );
731 Bitmap::ReleaseAccess( pRAcc
);
733 VECT_PROGRESS( pProgress
, 100 );
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
;
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
);
758 VECT_PROGRESS( pProgress
, 60 );
763 ImplCalculate( xMap
.get(), rPolyPoly
, 0, nFlags
);
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 ] ) )
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
-- ) );
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
818 const Polygon
aFirst( rPolyPoly
.GetObject( static_cast< sal_uInt16
>( nFirstPoly
) ) );
820 rPolyPoly
.Remove( static_cast< sal_uInt16
>( nFirstPoly
) );
821 rPolyPoly
.Insert( aFirst
, 0 );
827 VECT_PROGRESS( pProgress
, 100 );
832 void ImplLimitPolyPoly( tools::PolyPolygon
& rPolyPoly
)
834 if( rPolyPoly
.Count() > VECT_POLY_MAX
)
836 tools::PolyPolygon aNewPolyPoly
;
838 sal_uInt16 nNewCount
;
842 aNewPolyPoly
.Clear();
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
++ ];
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
)
901 nTmpX
= pMapOut
[ nX
- 1L ];
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
);
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
)
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
)
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
);
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
++ )
963 while( ( nX
< nWidth
) && pMap
->IsFree( nY
, nX
) )
969 if( pMap
->IsCont( nY
, nX
) )
973 const Point
aStartPt( nX
++, nY
);
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
);
982 aChain
.ImplEndAdd( bInner
? VECT_POLY_OUTLINE_INNER
: VECT_POLY_OUTLINE_OUTER
);
984 const Polygon
& rPoly
= aChain
.ImplGetPoly();
986 if( rPoly
.GetSize() > 2 )
990 const Rectangle
aBound( rPoly
.GetBoundRect() );
992 if( aBound
.GetWidth() > cReduce
&& aBound
.GetHeight() > cReduce
)
993 rPolyPoly
.Insert( rPoly
);
996 rPolyPoly
.Insert( rPoly
);
999 // skip rest of detected contour
1000 while( pMap
->IsCont( nY
, nX
) )
1005 // process done segment
1006 const long nStartSegX
= nX
++;
1008 while( pMap
->IsDone( nY
, nX
) )
1011 if( ( ( nX
- nStartSegX
) == 1L ) || ( ImplIsUp( pMap
, nY
, nStartSegX
) != ImplIsUp( pMap
, nY
, nX
- 1L ) ) )
1018 bool ImplGetChain( ImplVectMap
* pMap
, const Point
& rStartPt
, ImplChain
& rChain
)
1020 long nActX
= rStartPt
.X();
1021 long nActY
= rStartPt
.Y();
1023 sal_uLong nLastDir
= 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
);
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
);
1068 bool ImplIsUp( ImplVectMap
* pMap
, long nY
, long nX
)
1070 if( pMap
->IsDone( nY
- 1L, nX
) )
1072 else if( pMap
->IsDone( nY
+ 1L, nX
) )
1074 else if( pMap
->IsDone( nY
- 1L, nX
- 1L ) || pMap
->IsDone( nY
- 1L, nX
+ 1L ) )
1082 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */