1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: impvect.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
35 #include <vcl/bmpacc.hxx>
36 #include <tools/poly.hxx>
37 #include <vcl/gdimtf.hxx>
38 #include <vcl/metaact.hxx>
39 #include <vcl/svapp.hxx>
40 #include <vcl/wrkwin.hxx>
41 #include <vcl/virdev.hxx>
42 #ifndef _SV_VECTORIZ_HXX
43 #include <impvect.hxx>
50 #define VECT_POLY_MAX 8192
52 // -----------------------------------------------------------------------------
54 #define VECT_FREE_INDEX 0
55 #define VECT_CONT_INDEX 1
56 #define VECT_DONE_INDEX 2
58 // -----------------------------------------------------------------------------
60 #define VECT_POLY_INLINE_INNER 1UL
61 #define VECT_POLY_INLINE_OUTER 2UL
62 #define VECT_POLY_OUTLINE_INNER 4UL
63 #define VECT_POLY_OUTLINE_OUTER 8UL
65 // -----------------------------------------------------------------------------
67 #define VECT_MAP( _def_pIn, _def_pOut, _def_nVal ) _def_pOut[_def_nVal]=(_def_pIn[_def_nVal]=((_def_nVal)*4L)+1L)+5L;
68 #define BACK_MAP( _def_nVal ) ((((_def_nVal)+2)>>2)-1)
69 #define VECT_PROGRESS( _def_pProgress, _def_nVal ) if(_def_pProgress&&_def_pProgress->IsSet())(_def_pProgress->Call((void*)_def_nVal));
75 struct ChainMove
{ long nDX
; long nDY
; };
77 static ChainMove aImplMove
[ 8 ] = {
88 static ChainMove aImplMoveInner
[ 8 ] = {
99 static ChainMove aImplMoveOuter
[ 8 ] = {
120 BOOL
operator<( const ImplColorSet
& rSet
) const;
121 BOOL
operator>( const ImplColorSet
& rSet
) const;
124 // ----------------------------------------------------------------------------
126 inline BOOL
ImplColorSet::operator<( const ImplColorSet
& rSet
) const
128 return( mbSet
&& ( !rSet
.mbSet
|| ( maColor
.GetLuminance() > rSet
.maColor
.GetLuminance() ) ) );
131 // ----------------------------------------------------------------------------
133 inline BOOL
ImplColorSet::operator>( const ImplColorSet
& rSet
) const
135 return( !mbSet
|| ( rSet
.mbSet
&& maColor
.GetLuminance() < rSet
.maColor
.GetLuminance() ) );
138 // ----------------------------------------------------------------------------
140 extern "C" int __LOADONCALLAPI
ImplColorSetCmpFnc( const void* p1
, const void* p2
)
142 ImplColorSet
* pSet1
= (ImplColorSet
*) p1
;
143 ImplColorSet
* pSet2
= (ImplColorSet
*) p2
;
146 if( pSet1
->mbSet
&& pSet2
->mbSet
)
148 const BYTE cLum1
= pSet1
->maColor
.GetLuminance();
149 const BYTE cLum2
= pSet2
->maColor
.GetLuminance();
150 nRet
= ( ( cLum1
> cLum2
) ? -1 : ( ( cLum1
== cLum2
) ? 0 : 1 ) );
152 else if( pSet1
->mbSet
)
154 else if( pSet2
->mbSet
)
162 // ------------------
163 // - ImplPointArray -
164 // ------------------
177 void ImplSetSize( ULONG nSize
);
179 ULONG
ImplGetRealSize() const { return mnRealSize
; }
180 void ImplSetRealSize( ULONG nRealSize
) { mnRealSize
= nRealSize
; }
182 inline Point
& operator[]( ULONG nPos
);
183 inline const Point
& operator[]( ULONG nPos
) const;
185 void ImplCreatePoly( Polygon
& rPoly
) const;
188 // -----------------------------------------------------------------------------
190 ImplPointArray::ImplPointArray() :
198 // -----------------------------------------------------------------------------
200 ImplPointArray::~ImplPointArray()
203 rtl_freeMemory( mpArray
);
206 // -----------------------------------------------------------------------------
208 void ImplPointArray::ImplSetSize( ULONG nSize
)
210 const ULONG nTotal
= nSize
* sizeof( Point
);
216 rtl_freeMemory( mpArray
);
218 mpArray
= (Point
*) rtl_allocateMemory( nTotal
);
219 memset( (HPBYTE
) mpArray
, 0, nTotal
);
222 // -----------------------------------------------------------------------------
224 inline Point
& ImplPointArray::operator[]( ULONG nPos
)
226 DBG_ASSERT( nPos
< mnSize
, "ImplPointArray::operator[]: nPos out of range!" );
227 return mpArray
[ nPos
];
230 // -----------------------------------------------------------------------------
232 inline const Point
& ImplPointArray::operator[]( ULONG nPos
) const
234 DBG_ASSERT( nPos
< mnSize
, "ImplPointArray::operator[]: nPos out of range!" );
235 return mpArray
[ nPos
];
238 // -----------------------------------------------------------------------------
240 void ImplPointArray::ImplCreatePoly( Polygon
& rPoly
) const
242 rPoly
= Polygon( sal::static_int_cast
<USHORT
>(mnRealSize
), mpArray
);
262 ImplVectMap( long nWidth
, long nHeight
);
265 inline long Width() const { return mnWidth
; }
266 inline long Height() const { return mnHeight
; }
268 inline void Set( long nY
, long nX
, BYTE cVal
);
269 inline BYTE
Get( long nY
, long nX
) const;
271 inline BOOL
IsFree( long nY
, long nX
) const;
272 inline BOOL
IsCont( long nY
, long nX
) const;
273 inline BOOL
IsDone( long nY
, long nX
) const;
277 // -----------------------------------------------------------------------------
279 ImplVectMap::ImplVectMap( long nWidth
, long nHeight
) :
283 const long nWidthAl
= ( nWidth
>> 2L ) + 1L;
284 const long nSize
= nWidthAl
* nHeight
;
285 Scanline pTmp
= mpBuf
= (Scanline
) rtl_allocateMemory( nSize
);
287 memset( mpBuf
, 0, nSize
);
288 mpScan
= (Scanline
*) rtl_allocateMemory( nHeight
* sizeof( Scanline
) );
290 for( long nY
= 0L; nY
< nHeight
; pTmp
+= nWidthAl
)
291 mpScan
[ nY
++ ] = pTmp
;
294 // -----------------------------------------------------------------------------
297 ImplVectMap::~ImplVectMap()
299 rtl_freeMemory( mpBuf
);
300 rtl_freeMemory( mpScan
);
303 // -----------------------------------------------------------------------------
305 inline void ImplVectMap::Set( long nY
, long nX
, BYTE cVal
)
307 const BYTE cShift
= sal::static_int_cast
<BYTE
>(6 - ( ( nX
& 3 ) << 1 ));
308 ( ( mpScan
[ nY
][ nX
>> 2 ] ) &= ~( 3 << cShift
) ) |= ( cVal
<< cShift
);
311 // -----------------------------------------------------------------------------
313 inline BYTE
ImplVectMap::Get( long nY
, long nX
) const
315 return sal::static_int_cast
<BYTE
>( ( ( mpScan
[ nY
][ nX
>> 2 ] ) >> ( 6 - ( ( nX
& 3 ) << 1 ) ) ) & 3 );
318 // -----------------------------------------------------------------------------
320 inline BOOL
ImplVectMap::IsFree( long nY
, long nX
) const
322 return( VECT_FREE_INDEX
== Get( nY
, nX
) );
325 // -----------------------------------------------------------------------------
327 inline BOOL
ImplVectMap::IsCont( long nY
, long nX
) const
329 return( VECT_CONT_INDEX
== Get( nY
, nX
) );
332 // -----------------------------------------------------------------------------
334 inline BOOL
ImplVectMap::IsDone( long nY
, long nX
) const
336 return( VECT_DONE_INDEX
== Get( nY
, nX
) );
357 void ImplCreateInner();
358 void ImplCreateOuter();
359 void ImplPostProcess( const ImplPointArray
& rArr
);
363 ImplChain( ULONG nInitCount
= 1024UL, long nResize
= -1L );
366 void ImplBeginAdd( const Point
& rStartPt
);
367 inline void ImplAdd( BYTE nCode
);
368 void ImplEndAdd( ULONG nTypeFlag
);
370 const Polygon
& ImplGetPoly() { return maPoly
; }
373 // -----------------------------------------------------------------------------
375 ImplChain::ImplChain( ULONG nInitCount
, long nResize
) :
376 mnArraySize ( nInitCount
),
380 DBG_ASSERT( nInitCount
&& nResize
, "ImplChain::ImplChain(): invalid parameters!" );
381 mpCodes
= new BYTE
[ mnArraySize
];
384 // -----------------------------------------------------------------------------
386 ImplChain::~ImplChain()
391 // -----------------------------------------------------------------------------
393 void ImplChain::ImplGetSpace()
395 const ULONG nOldArraySize
= mnArraySize
;
398 mnArraySize
= ( mnResize
< 0L ) ? ( mnArraySize
<< 1UL ) : ( mnArraySize
+ (ULONG
) mnResize
);
399 pNewCodes
= new BYTE
[ mnArraySize
];
400 memcpy( pNewCodes
, mpCodes
, nOldArraySize
);
405 // -----------------------------------------------------------------------------
407 void ImplChain::ImplBeginAdd( const Point
& rStartPt
)
410 maStartPt
= rStartPt
;
414 // -----------------------------------------------------------------------------
416 inline void ImplChain::ImplAdd( BYTE nCode
)
418 if( mnCount
== mnArraySize
)
421 mpCodes
[ mnCount
++ ] = nCode
;
424 // -----------------------------------------------------------------------------
426 void ImplChain::ImplEndAdd( ULONG nFlag
)
432 if( nFlag
& VECT_POLY_INLINE_INNER
)
434 long nFirstX
, nFirstY
;
437 nFirstX
= nLastX
= maStartPt
.X();
438 nFirstY
= nLastY
= maStartPt
.Y();
439 aArr
.ImplSetSize( mnCount
<< 1 );
442 for( i
= 0, nPolyPos
= 0; i
< ( mnCount
- 1 ); i
++ )
444 const BYTE cMove
= mpCodes
[ i
];
445 const BYTE cNextMove
= mpCodes
[ i
+ 1 ];
446 const ChainMove
& rMove
= aImplMove
[ cMove
];
447 const ChainMove
& rMoveInner
= aImplMoveInner
[ cMove
];
448 // Point& rPt = aArr[ nPolyPos ];
456 if( ( cMove
== 0 && cNextMove
== 3 ) ||
457 ( cMove
== 3 && cNextMove
== 2 ) ||
458 ( cMove
== 2 && cNextMove
== 1 ) ||
459 ( cMove
== 1 && cNextMove
== 0 ) )
462 else if( cMove
== 2 && cNextMove
== 3 )
464 aArr
[ nPolyPos
].X() = nLastX
;
465 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
467 aArr
[ nPolyPos
].X() = nLastX
- 1;
468 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
470 aArr
[ nPolyPos
].X() = nLastX
- 1;
471 aArr
[ nPolyPos
++ ].Y() = nLastY
;
473 else if( cMove
== 3 && cNextMove
== 0 )
475 aArr
[ nPolyPos
].X() = nLastX
- 1;
476 aArr
[ nPolyPos
++ ].Y() = nLastY
;
478 aArr
[ nPolyPos
].X() = nLastX
- 1;
479 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
481 aArr
[ nPolyPos
].X() = nLastX
;
482 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
484 else if( cMove
== 0 && cNextMove
== 1 )
486 aArr
[ nPolyPos
].X() = nLastX
;
487 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
489 aArr
[ nPolyPos
].X() = nLastX
+ 1;
490 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
492 aArr
[ nPolyPos
].X() = nLastX
+ 1;
493 aArr
[ nPolyPos
++ ].Y() = nLastY
;
495 else if( cMove
== 1 && cNextMove
== 2 )
497 aArr
[ nPolyPos
].X() = nLastX
+ 1;
498 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
500 aArr
[ nPolyPos
].X() = nLastX
+ 1;
501 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
503 aArr
[ nPolyPos
].X() = nLastX
;
504 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
509 else if( cMove
== 7 && cNextMove
== 0 )
511 aArr
[ nPolyPos
].X() = nLastX
- 1;
512 aArr
[ nPolyPos
++ ].Y() = nLastY
;
514 aArr
[ nPolyPos
].X() = nLastX
;
515 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
517 else if( cMove
== 4 && cNextMove
== 1 )
519 aArr
[ nPolyPos
].X() = nLastX
;
520 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
522 aArr
[ nPolyPos
].X() = nLastX
+ 1;
523 aArr
[ nPolyPos
++ ].Y() = nLastY
;
530 aArr
[ nPolyPos
].X() = nLastX
+ rMoveInner
.nDX
;
531 aArr
[ nPolyPos
++ ].Y() = nLastY
+ rMoveInner
.nDY
;
535 aArr
[ nPolyPos
].X() = nFirstX
+ 1L;
536 aArr
[ nPolyPos
++ ].Y() = nFirstY
+ 1L;
537 aArr
.ImplSetRealSize( nPolyPos
);
539 else if( nFlag
& VECT_POLY_INLINE_OUTER
)
541 long nFirstX
, nFirstY
;
544 nFirstX
= nLastX
= maStartPt
.X();
545 nFirstY
= nLastY
= maStartPt
.Y();
546 aArr
.ImplSetSize( mnCount
<< 1 );
549 for( i
= 0, nPolyPos
= 0; i
< ( mnCount
- 1 ); i
++ )
551 const BYTE cMove
= mpCodes
[ i
];
552 const BYTE cNextMove
= mpCodes
[ i
+ 1 ];
553 const ChainMove
& rMove
= aImplMove
[ cMove
];
554 const ChainMove
& rMoveOuter
= aImplMoveOuter
[ cMove
];
555 // Point& rPt = aArr[ nPolyPos ];
563 if( ( cMove
== 0 && cNextMove
== 1 ) ||
564 ( cMove
== 1 && cNextMove
== 2 ) ||
565 ( cMove
== 2 && cNextMove
== 3 ) ||
566 ( cMove
== 3 && cNextMove
== 0 ) )
569 else if( cMove
== 0 && cNextMove
== 3 )
571 aArr
[ nPolyPos
].X() = nLastX
;
572 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
574 aArr
[ nPolyPos
].X() = nLastX
+ 1;
575 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
577 aArr
[ nPolyPos
].X() = nLastX
+ 1;
578 aArr
[ nPolyPos
++ ].Y() = nLastY
;
580 else if( cMove
== 3 && cNextMove
== 2 )
582 aArr
[ nPolyPos
].X() = nLastX
+ 1;
583 aArr
[ nPolyPos
++ ].Y() = nLastY
;
585 aArr
[ nPolyPos
].X() = nLastX
+ 1;
586 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
588 aArr
[ nPolyPos
].X() = nLastX
;
589 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
591 else if( cMove
== 2 && cNextMove
== 1 )
593 aArr
[ nPolyPos
].X() = nLastX
;
594 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
596 aArr
[ nPolyPos
].X() = nLastX
- 1;
597 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
599 aArr
[ nPolyPos
].X() = nLastX
- 1;
600 aArr
[ nPolyPos
++ ].Y() = nLastY
;
602 else if( cMove
== 1 && cNextMove
== 0 )
604 aArr
[ nPolyPos
].X() = nLastX
- 1;
605 aArr
[ nPolyPos
++ ].Y() = nLastY
;
607 aArr
[ nPolyPos
].X() = nLastX
- 1;
608 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
610 aArr
[ nPolyPos
].X() = nLastX
;
611 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
616 else if( cMove
== 7 && cNextMove
== 3 )
618 aArr
[ nPolyPos
].X() = nLastX
;
619 aArr
[ nPolyPos
++ ].Y() = nLastY
- 1;
621 aArr
[ nPolyPos
].X() = nLastX
+ 1;
622 aArr
[ nPolyPos
++ ].Y() = nLastY
;
624 else if( cMove
== 6 && cNextMove
== 2 )
626 aArr
[ nPolyPos
].X() = nLastX
+ 1;
627 aArr
[ nPolyPos
++ ].Y() = nLastY
;
629 aArr
[ nPolyPos
].X() = nLastX
;
630 aArr
[ nPolyPos
++ ].Y() = nLastY
+ 1;
637 aArr
[ nPolyPos
].X() = nLastX
+ rMoveOuter
.nDX
;
638 aArr
[ nPolyPos
++ ].Y() = nLastY
+ rMoveOuter
.nDY
;
642 aArr
[ nPolyPos
].X() = nFirstX
- 1L;
643 aArr
[ nPolyPos
++ ].Y() = nFirstY
- 1L;
644 aArr
.ImplSetRealSize( nPolyPos
);
648 long nLastX
= maStartPt
.X(), nLastY
= maStartPt
.Y();
650 aArr
.ImplSetSize( mnCount
+ 1 );
651 aArr
[ 0 ] = Point( nLastX
, nLastY
);
653 for( ULONG i
= 0; i
< mnCount
; )
655 const ChainMove
& rMove
= aImplMove
[ mpCodes
[ i
] ];
656 aArr
[ ++i
] = Point( nLastX
+= rMove
.nDX
, nLastY
+= rMove
.nDY
);
659 aArr
.ImplSetRealSize( mnCount
+ 1 );
662 ImplPostProcess( aArr
);
668 // -----------------------------------------------------------------------------
670 void ImplChain::ImplPostProcess( const ImplPointArray
& rArr
)
672 ImplPointArray aNewArr1
;
673 ImplPointArray aNewArr2
;
677 ULONG nCount
= rArr
.ImplGetRealSize();
681 aNewArr1
.ImplSetSize( nCount
);
682 pLast
= &( aNewArr1
[ 0 ] );
683 pLast
->X() = BACK_MAP( rArr
[ 0 ].X() );
684 pLast
->Y() = BACK_MAP( rArr
[ 0 ].Y() );
686 for( n
= nNewPos
= 1; n
< nCount
; )
688 const Point
& rPt
= rArr
[ n
++ ];
689 const long nX
= BACK_MAP( rPt
.X() );
690 const long nY
= BACK_MAP( rPt
.Y() );
692 if( nX
!= pLast
->X() || nY
!= pLast
->Y() )
694 pLast
= pLeast
= &( aNewArr1
[ nNewPos
++ ] );
700 aNewArr1
.ImplSetRealSize( nCount
= nNewPos
);
703 aNewArr2
.ImplSetSize( nCount
);
704 pLast
= &( aNewArr2
[ 0 ] );
705 *pLast
= aNewArr1
[ 0 ];
707 for( n
= nNewPos
= 1; n
< nCount
; )
709 pLeast
= &( aNewArr1
[ n
++ ] );
711 if( pLeast
->X() == pLast
->X() )
713 while( n
< nCount
&& aNewArr1
[ n
].X() == pLast
->X() )
714 pLeast
= &( aNewArr1
[ n
++ ] );
716 else if( pLeast
->Y() == pLast
->Y() )
718 while( n
< nCount
&& aNewArr1
[ n
].Y() == pLast
->Y() )
719 pLeast
= &( aNewArr1
[ n
++ ] );
722 aNewArr2
[ nNewPos
++ ] = *( pLast
= pLeast
);
725 aNewArr2
.ImplSetRealSize( nNewPos
);
726 aNewArr2
.ImplCreatePoly( maPoly
);
729 // ------------------
730 // - ImplVectorizer -
731 // ------------------
733 ImplVectorizer::ImplVectorizer()
737 // -----------------------------------------------------------------------------
739 ImplVectorizer::~ImplVectorizer()
743 // -----------------------------------------------------------------------------
745 BOOL
ImplVectorizer::ImplVectorize( const Bitmap
& rColorBmp
, GDIMetaFile
& rMtf
,
746 BYTE cReduce
, ULONG nFlags
, const Link
* pProgress
)
750 VECT_PROGRESS( pProgress
, 0 );
752 Bitmap
* pBmp
= new Bitmap( rColorBmp
);
753 BitmapReadAccess
* pRAcc
= pBmp
->AcquireReadAccess();
757 PolyPolygon aPolyPoly
;
758 double fPercent
= 0.0;
759 double fPercentStep_2
= 0.0;
760 const long nWidth
= pRAcc
->Width();
761 const long nHeight
= pRAcc
->Height();
762 const USHORT nColorCount
= pRAcc
->GetPaletteEntryCount();
764 ImplColorSet
* pColorSet
= (ImplColorSet
*) new BYTE
[ 256 * sizeof( ImplColorSet
) ];
766 memset( pColorSet
, 0, 256 * sizeof( ImplColorSet
) );
769 // get used palette colors and sort them from light to dark colors
770 for( n
= 0; n
< nColorCount
; n
++ )
772 pColorSet
[ n
].mnIndex
= n
;
773 pColorSet
[ n
].maColor
= pRAcc
->GetPaletteColor( n
);
776 for( long nY
= 0L; nY
< nHeight
; nY
++ )
777 for( long nX
= 0L; nX
< nWidth
; nX
++ )
778 pColorSet
[ pRAcc
->GetPixel( nY
, nX
).GetIndex() ].mbSet
= 1;
780 qsort( pColorSet
, 256, sizeof( ImplColorSet
), ImplColorSetCmpFnc
);
782 for( n
= 0; n
< 256; n
++ )
783 if( !pColorSet
[ n
].mbSet
)
787 fPercentStep_2
= 45.0 / n
;
789 VECT_PROGRESS( pProgress
, FRound( fPercent
+= 10.0 ) );
791 for( USHORT i
= 0; i
< n
; i
++ )
793 const BitmapColor
aBmpCol( pRAcc
->GetPaletteColor( pColorSet
[ i
].mnIndex
) );
794 const Color
aFindColor( aBmpCol
.GetRed(), aBmpCol
.GetGreen(), aBmpCol
.GetBlue() );
795 // const BYTE cLum = aFindColor.GetLuminance();
796 ImplVectMap
* pMap
= ImplExpand( pRAcc
, aFindColor
);
798 VECT_PROGRESS( pProgress
, FRound( fPercent
+= fPercentStep_2
) );
803 ImplCalculate( pMap
, aPolyPoly
, cReduce
, nFlags
);
806 if( aPolyPoly
.Count() )
808 ImplLimitPolyPoly( aPolyPoly
);
810 if( nFlags
& BMP_VECTORIZE_REDUCE_EDGES
)
811 aPolyPoly
.Optimize( POLY_OPTIMIZE_EDGES
);
813 if( aPolyPoly
.Count() )
815 rMtf
.AddAction( new MetaLineColorAction( aFindColor
, TRUE
) );
816 rMtf
.AddAction( new MetaFillColorAction( aFindColor
, TRUE
) );
817 rMtf
.AddAction( new MetaPolyPolygonAction( aPolyPoly
) );
822 VECT_PROGRESS( pProgress
, FRound( fPercent
+= fPercentStep_2
) );
825 delete[] (BYTE
*) pColorSet
;
827 if( rMtf
.GetActionCount() )
829 MapMode
aMap( MAP_100TH_MM
);
831 const Size
aLogSize1( aVDev
.PixelToLogic( Size( 1, 1 ), aMap
) );
833 rMtf
.SetPrefMapMode( aMap
);
834 rMtf
.SetPrefSize( Size( nWidth
+ 2, nHeight
+ 2 ) );
836 rMtf
.Scale( aLogSize1
.Width(), aLogSize1
.Height() );
841 pBmp
->ReleaseAccess( pRAcc
);
843 VECT_PROGRESS( pProgress
, 100 );
848 // -----------------------------------------------------------------------------
850 BOOL
ImplVectorizer::ImplVectorize( const Bitmap
& rMonoBmp
,
851 PolyPolygon
& rPolyPoly
,
852 ULONG nFlags
, const Link
* pProgress
)
854 Bitmap
* pBmp
= new Bitmap( rMonoBmp
);
855 BitmapReadAccess
* pRAcc
;
859 VECT_PROGRESS( pProgress
, 10 );
861 if( pBmp
->GetBitCount() > 1 )
862 pBmp
->Convert( BMP_CONVERSION_1BIT_THRESHOLD
);
864 VECT_PROGRESS( pProgress
, 30 );
866 pRAcc
= pBmp
->AcquireReadAccess();
867 pMap
= ImplExpand( pRAcc
, COL_BLACK
);
868 pBmp
->ReleaseAccess( pRAcc
);
871 VECT_PROGRESS( pProgress
, 60 );
876 ImplCalculate( pMap
, rPolyPoly
, 0, nFlags
);
878 ImplLimitPolyPoly( rPolyPoly
);
880 if( nFlags
& BMP_VECTORIZE_REDUCE_EDGES
)
881 rPolyPoly
.Optimize( POLY_OPTIMIZE_EDGES
);
883 // #i14895#:setting the correct direction for polygons
884 // that represent holes and non-holes; non-hole polygons
885 // need to have a right orientation, holes need to have a
886 // left orientation in order to be treated correctly by
887 // several external tools like Flash viewers
888 sal_Int32 nFirstPoly
= -1;
889 sal_uInt16
nCurPoly( 0 ), nCount( rPolyPoly
.Count() );
891 for( ; nCurPoly
< nCount
; ++nCurPoly
)
893 const Polygon
& rPoly
= rPolyPoly
.GetObject( nCurPoly
);
894 const sal_uInt16
nSize( rPoly
.GetSize() );
895 sal_uInt16
nDepth( 0 ), i( 0 );
896 const bool bRight( rPoly
.IsRightOrientated() );
898 for( ; i
< nCount
; ++i
)
899 if( ( i
!= nCurPoly
) && rPolyPoly
.GetObject( i
).IsInside( rPoly
[ 0 ] ) )
902 const bool bHole( ( nDepth
& 0x0001 ) == 1 );
904 if( nSize
&& ( ( !bRight
&& !bHole
) || ( bRight
&& bHole
) ) )
906 Polygon
aNewPoly( nSize
);
907 sal_uInt16
nPrim( 0 ), nSec( nSize
- 1 );
909 if( rPoly
.HasFlags() )
911 while( nPrim
< nSize
)
913 aNewPoly
.SetPoint( rPoly
.GetPoint( nSec
), nPrim
);
914 aNewPoly
.SetFlags( nPrim
++, rPoly
.GetFlags( nSec
-- ) );
918 while( nPrim
< nSize
)
919 aNewPoly
.SetPoint( rPoly
.GetPoint( nSec
-- ), nPrim
++ );
921 rPolyPoly
.Replace( aNewPoly
, nCurPoly
);
924 if( ( 0 == nDepth
) && ( -1 == nFirstPoly
) )
925 nFirstPoly
= nCurPoly
;
928 // put outmost polygon to the front
931 const Polygon
aFirst( rPolyPoly
.GetObject( static_cast< USHORT
>( nFirstPoly
) ) );
933 rPolyPoly
.Remove( static_cast< USHORT
>( nFirstPoly
) );
934 rPolyPoly
.Insert( aFirst
, 0 );
940 VECT_PROGRESS( pProgress
, 100 );
945 // -----------------------------------------------------------------------------
947 void ImplVectorizer::ImplLimitPolyPoly( PolyPolygon
& rPolyPoly
)
949 if( rPolyPoly
.Count() > VECT_POLY_MAX
)
951 PolyPolygon aNewPolyPoly
;
957 aNewPolyPoly
.Clear();
960 for( USHORT i
= 0, nCount
= rPolyPoly
.Count(); i
< nCount
; i
++ )
962 const Rectangle
aBound( rPolyPoly
[ i
].GetBoundRect() );
964 if( aBound
.GetWidth() > nReduce
&& aBound
.GetHeight() > nReduce
)
966 if( rPolyPoly
[ i
].GetSize() )
967 aNewPolyPoly
.Insert( rPolyPoly
[ i
] );
971 nNewCount
= aNewPolyPoly
.Count();
973 while( nNewCount
> VECT_POLY_MAX
);
975 rPolyPoly
= aNewPolyPoly
;
979 // -----------------------------------------------------------------------------
981 ImplVectMap
* ImplVectorizer::ImplExpand( BitmapReadAccess
* pRAcc
, const Color
& rColor
)
983 ImplVectMap
* pMap
= NULL
;
985 if( pRAcc
&& pRAcc
->Width() && pRAcc
->Height() )
987 const long nOldWidth
= pRAcc
->Width();
988 const long nOldHeight
= pRAcc
->Height();
989 const long nNewWidth
= ( nOldWidth
<< 2L ) + 4L;
990 const long nNewHeight
= ( nOldHeight
<< 2L ) + 4L;
991 const BitmapColor
aTest( pRAcc
->GetBestMatchingColor( rColor
) );
992 long* pMapIn
= new long[ Max( nOldWidth
, nOldHeight
) ];
993 long* pMapOut
= new long[ Max( nOldWidth
, nOldHeight
) ];
994 long nX
, nY
, nTmpX
, nTmpY
;
996 pMap
= new ImplVectMap( nNewWidth
, nNewHeight
);
998 for( nX
= 0L; nX
< nOldWidth
; nX
++ )
999 VECT_MAP( pMapIn
, pMapOut
, nX
);
1001 for( nY
= 0L, nTmpY
= 5L; nY
< nOldHeight
; nY
++, nTmpY
+= 4L )
1003 for( nX
= 0L; nX
< nOldWidth
; )
1005 if( pRAcc
->GetPixel( nY
, nX
) == aTest
)
1007 nTmpX
= pMapIn
[ nX
++ ];
1010 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
1011 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
1012 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
1013 pMap
->Set( nTmpY
, nTmpX
, VECT_CONT_INDEX
);
1015 while( nX
< nOldWidth
&& pRAcc
->GetPixel( nY
, nX
) == aTest
)
1018 nTmpX
= pMapOut
[ nX
- 1L ];
1021 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
1022 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
1023 pMap
->Set( nTmpY
++, nTmpX
, VECT_CONT_INDEX
);
1024 pMap
->Set( nTmpY
, nTmpX
, VECT_CONT_INDEX
);
1031 for( nY
= 0L; nY
< nOldHeight
; nY
++ )
1032 VECT_MAP( pMapIn
, pMapOut
, nY
);
1034 for( nX
= 0L, nTmpX
= 5L; nX
< nOldWidth
; nX
++, nTmpX
+= 4L )
1036 for( nY
= 0L; nY
< nOldHeight
; )
1038 if( pRAcc
->GetPixel( nY
, nX
) == aTest
)
1041 nTmpY
= pMapIn
[ nY
++ ];
1043 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
1044 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
1045 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
1046 pMap
->Set( nTmpY
, nTmpX
, VECT_CONT_INDEX
);
1048 while( nY
< nOldHeight
&& pRAcc
->GetPixel( nY
, nX
) == aTest
)
1052 nTmpY
= pMapOut
[ nY
- 1L ];
1054 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
1055 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
1056 pMap
->Set( nTmpY
, nTmpX
++, VECT_CONT_INDEX
);
1057 pMap
->Set( nTmpY
, nTmpX
, VECT_CONT_INDEX
);
1072 // -----------------------------------------------------------------------------
1074 void ImplVectorizer::ImplCalculate( ImplVectMap
* pMap
, PolyPolygon
& rPolyPoly
, BYTE cReduce
, ULONG nFlags
)
1076 const long nWidth
= pMap
->Width(), nHeight
= pMap
->Height();
1078 for( long nY
= 0L; nY
< nHeight
; nY
++ )
1083 while( nX
< nWidth
)
1086 while( ( nX
< nWidth
) && pMap
->IsFree( nY
, nX
) )
1092 if( pMap
->IsCont( nY
, nX
) )
1096 const Point
aStartPt( nX
++, nY
);
1099 aChain
.ImplBeginAdd( aStartPt
);
1100 ImplGetChain( pMap
, aStartPt
, aChain
);
1102 if( nFlags
& BMP_VECTORIZE_INNER
)
1103 aChain
.ImplEndAdd( bInner
? VECT_POLY_INLINE_INNER
: VECT_POLY_INLINE_OUTER
);
1105 aChain
.ImplEndAdd( bInner
? VECT_POLY_OUTLINE_INNER
: VECT_POLY_OUTLINE_OUTER
);
1107 const Polygon
& rPoly
= aChain
.ImplGetPoly();
1109 if( rPoly
.GetSize() > 2 )
1113 const Rectangle
aBound( rPoly
.GetBoundRect() );
1115 if( aBound
.GetWidth() > cReduce
&& aBound
.GetHeight() > cReduce
)
1116 rPolyPoly
.Insert( rPoly
);
1119 rPolyPoly
.Insert( rPoly
);
1122 // skip rest of detected contour
1123 while( pMap
->IsCont( nY
, nX
) )
1128 // process done segment
1129 const long nStartSegX
= nX
++;
1131 while( pMap
->IsDone( nY
, nX
) )
1134 if( ( ( nX
- nStartSegX
) == 1L ) || ( ImplIsUp( pMap
, nY
, nStartSegX
) != ImplIsUp( pMap
, nY
, nX
- 1L ) ) )
1141 // -----------------------------------------------------------------------------
1143 BOOL
ImplVectorizer::ImplGetChain( ImplVectMap
* pMap
, const Point
& rStartPt
, ImplChain
& rChain
)
1145 long nActX
= rStartPt
.X();
1146 long nActY
= rStartPt
.Y();
1150 ULONG nLastDir
= 0UL;
1157 // first try last direction
1158 nTryX
= nActX
+ aImplMove
[ nLastDir
].nDX
;
1159 nTryY
= nActY
+ aImplMove
[ nLastDir
].nDY
;
1161 if( pMap
->IsCont( nTryY
, nTryX
) )
1163 rChain
.ImplAdd( (BYTE
) nLastDir
);
1164 pMap
->Set( nActY
= nTryY
, nActX
= nTryX
, VECT_DONE_INDEX
);
1169 // try other directions
1170 for( nDir
= 0UL; nDir
< 8UL; nDir
++ )
1172 // we already tried nLastDir
1173 if( nDir
!= nLastDir
)
1175 nTryX
= nActX
+ aImplMove
[ nDir
].nDX
;
1176 nTryY
= nActY
+ aImplMove
[ nDir
].nDY
;
1178 if( pMap
->IsCont( nTryY
, nTryX
) )
1180 rChain
.ImplAdd( (BYTE
) nDir
);
1181 pMap
->Set( nActY
= nTryY
, nActX
= nTryX
, VECT_DONE_INDEX
);
1195 // -----------------------------------------------------------------------------
1197 BOOL
ImplVectorizer::ImplIsUp( ImplVectMap
* pMap
, long nY
, long nX
) const
1199 if( pMap
->IsDone( nY
- 1L, nX
) )
1201 else if( pMap
->IsDone( nY
+ 1L, nX
) )
1203 else if( pMap
->IsDone( nY
- 1L, nX
- 1L ) || pMap
->IsDone( nY
- 1L, nX
+ 1L ) )