update dev300-m58
[ooovba.git] / vcl / source / gdi / impvect.cxx
blob8e7399636a04ccbe4e6063c09ad4a52bada5e2ba
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: impvect.cxx,v $
10 * $Revision: 1.10 $
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"
34 #include <stdlib.h>
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>
44 #endif
46 // -----------
47 // - Defines -
48 // -----------
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));
71 // -----------
72 // - statics -
73 // -----------
75 struct ChainMove { long nDX; long nDY; };
77 static ChainMove aImplMove[ 8 ] = {
78 { 1L, 0L },
79 { 0L, -1L },
80 { -1L, 0L },
81 { 0L, 1L },
82 { 1L, -1L },
83 { -1, -1L },
84 { -1L, 1L },
85 { 1L, 1L }
88 static ChainMove aImplMoveInner[ 8 ] = {
89 { 0L, 1L },
90 { 1L, 0L },
91 { 0L, -1L },
92 { -1L, 0L },
93 { 0L, 1L },
94 { 1L, 0L },
95 { 0L, -1L },
96 { -1L, 0L }
99 static ChainMove aImplMoveOuter[ 8 ] = {
100 { 0L, -1L },
101 { -1L, 0L },
102 { 0L, 1L },
103 { 1L, 0L },
104 { -1L, 0L },
105 { 0L, 1L },
106 { 1L, 0L },
107 { 0L, -1L }
110 // ----------------
111 // - ImplColorSet -
112 // ----------------
114 struct ImplColorSet
116 BitmapColor maColor;
117 USHORT mnIndex;
118 BOOL mbSet;
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;
144 int nRet;
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 )
153 nRet = -1;
154 else if( pSet2->mbSet )
155 nRet = 1;
156 else
157 nRet = 0;
159 return nRet;
162 // ------------------
163 // - ImplPointArray -
164 // ------------------
166 class ImplPointArray
168 Point* mpArray;
169 ULONG mnSize;
170 ULONG mnRealSize;
172 public:
174 ImplPointArray();
175 ~ImplPointArray();
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() :
191 mpArray ( NULL ),
192 mnSize ( 0UL ),
193 mnRealSize ( 0UL )
198 // -----------------------------------------------------------------------------
200 ImplPointArray::~ImplPointArray()
202 if( mpArray )
203 rtl_freeMemory( mpArray );
206 // -----------------------------------------------------------------------------
208 void ImplPointArray::ImplSetSize( ULONG nSize )
210 const ULONG nTotal = nSize * sizeof( Point );
212 mnSize = nSize;
213 mnRealSize = 0UL;
215 if( mpArray )
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 );
245 // ---------------
246 // - ImplVectMap -
247 // ---------------
249 class ImplVectMap
251 private:
253 Scanline mpBuf;
254 Scanline* mpScan;
255 long mnWidth;
256 long mnHeight;
258 ImplVectMap() {};
260 public:
262 ImplVectMap( long nWidth, long nHeight );
263 ~ImplVectMap();
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 ) :
280 mnWidth ( nWidth ),
281 mnHeight( 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 ) );
339 // -------------
340 // - ImplChain -
341 // -------------
343 class ImplChain
345 private:
347 Polygon maPoly;
348 Point maStartPt;
349 ULONG mnArraySize;
350 ULONG mnCount;
351 long mnResize;
352 BYTE* mpCodes;
354 void ImplGetSpace();
356 void ImplCreate();
357 void ImplCreateInner();
358 void ImplCreateOuter();
359 void ImplPostProcess( const ImplPointArray& rArr );
361 public:
363 ImplChain( ULONG nInitCount = 1024UL, long nResize = -1L );
364 ~ImplChain();
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 ),
377 mnCount ( 0UL ),
378 mnResize ( nResize )
380 DBG_ASSERT( nInitCount && nResize, "ImplChain::ImplChain(): invalid parameters!" );
381 mpCodes = new BYTE[ mnArraySize ];
384 // -----------------------------------------------------------------------------
386 ImplChain::~ImplChain()
388 delete[] mpCodes;
391 // -----------------------------------------------------------------------------
393 void ImplChain::ImplGetSpace()
395 const ULONG nOldArraySize = mnArraySize;
396 BYTE* pNewCodes;
398 mnArraySize = ( mnResize < 0L ) ? ( mnArraySize << 1UL ) : ( mnArraySize + (ULONG) mnResize );
399 pNewCodes = new BYTE[ mnArraySize ];
400 memcpy( pNewCodes, mpCodes, nOldArraySize );
401 delete[] mpCodes;
402 mpCodes = pNewCodes;
405 // -----------------------------------------------------------------------------
407 void ImplChain::ImplBeginAdd( const Point& rStartPt )
409 maPoly = Polygon();
410 maStartPt = rStartPt;
411 mnCount = 0UL;
414 // -----------------------------------------------------------------------------
416 inline void ImplChain::ImplAdd( BYTE nCode )
418 if( mnCount == mnArraySize )
419 ImplGetSpace();
421 mpCodes[ mnCount++ ] = nCode;
424 // -----------------------------------------------------------------------------
426 void ImplChain::ImplEndAdd( ULONG nFlag )
428 if( mnCount )
430 ImplPointArray aArr;
432 if( nFlag & VECT_POLY_INLINE_INNER )
434 long nFirstX, nFirstY;
435 long nLastX, nLastY;
437 nFirstX = nLastX = maStartPt.X();
438 nFirstY = nLastY = maStartPt.Y();
439 aArr.ImplSetSize( mnCount << 1 );
441 USHORT i, nPolyPos;
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 ];
449 BOOL bDone = TRUE;
451 nLastX += rMove.nDX;
452 nLastY += rMove.nDY;
454 if( cMove < 4 )
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;
506 else
507 bDone = FALSE;
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;
525 else
526 bDone = FALSE;
528 if( !bDone )
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;
542 long nLastX, nLastY;
544 nFirstX = nLastX = maStartPt.X();
545 nFirstY = nLastY = maStartPt.Y();
546 aArr.ImplSetSize( mnCount << 1 );
548 USHORT i, nPolyPos;
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 ];
556 BOOL bDone = TRUE;
558 nLastX += rMove.nDX;
559 nLastY += rMove.nDY;
561 if( cMove < 4 )
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;
613 else
614 bDone = FALSE;
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;
632 else
633 bDone = FALSE;
635 if( !bDone )
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 );
646 else
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 );
664 else
665 maPoly.SetSize( 0 );
668 // -----------------------------------------------------------------------------
670 void ImplChain::ImplPostProcess( const ImplPointArray& rArr )
672 ImplPointArray aNewArr1;
673 ImplPointArray aNewArr2;
674 Point* pLast;
675 Point* pLeast;
676 ULONG nNewPos;
677 ULONG nCount = rArr.ImplGetRealSize();
678 ULONG n;
680 // pass 1
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++ ] );
695 pLeast->X() = nX;
696 pLeast->Y() = nY;
700 aNewArr1.ImplSetRealSize( nCount = nNewPos );
702 // pass 2
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 )
748 BOOL bRet = FALSE;
750 VECT_PROGRESS( pProgress, 0 );
752 Bitmap* pBmp = new Bitmap( rColorBmp );
753 BitmapReadAccess* pRAcc = pBmp->AcquireReadAccess();
755 if( pRAcc )
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();
763 USHORT n;
764 ImplColorSet* pColorSet = (ImplColorSet*) new BYTE[ 256 * sizeof( ImplColorSet ) ];
766 memset( pColorSet, 0, 256 * sizeof( ImplColorSet ) );
767 rMtf.Clear();
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 )
784 break;
786 if( n )
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 ) );
800 if( pMap )
802 aPolyPoly.Clear();
803 ImplCalculate( pMap, aPolyPoly, cReduce, nFlags );
804 delete pMap;
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 );
830 VirtualDevice aVDev;
831 const Size aLogSize1( aVDev.PixelToLogic( Size( 1, 1 ), aMap ) );
833 rMtf.SetPrefMapMode( aMap );
834 rMtf.SetPrefSize( Size( nWidth + 2, nHeight + 2 ) );
835 rMtf.Move( 1, 1 );
836 rMtf.Scale( aLogSize1.Width(), aLogSize1.Height() );
837 bRet = TRUE;
841 pBmp->ReleaseAccess( pRAcc );
842 delete pBmp;
843 VECT_PROGRESS( pProgress, 100 );
845 return bRet;
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;
856 ImplVectMap* pMap;
857 BOOL bRet = FALSE;
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 );
869 delete pBmp;
871 VECT_PROGRESS( pProgress, 60 );
873 if( pMap )
875 rPolyPoly.Clear();
876 ImplCalculate( pMap, rPolyPoly, 0, nFlags );
877 delete pMap;
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 ] ) )
900 ++nDepth;
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-- ) );
917 else
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
929 if( nFirstPoly > 0 )
931 const Polygon aFirst( rPolyPoly.GetObject( static_cast< USHORT >( nFirstPoly ) ) );
933 rPolyPoly.Remove( static_cast< USHORT >( nFirstPoly ) );
934 rPolyPoly.Insert( aFirst, 0 );
937 bRet = TRUE;
940 VECT_PROGRESS( pProgress, 100 );
942 return bRet;
945 // -----------------------------------------------------------------------------
947 void ImplVectorizer::ImplLimitPolyPoly( PolyPolygon& rPolyPoly )
949 if( rPolyPoly.Count() > VECT_POLY_MAX )
951 PolyPolygon aNewPolyPoly;
952 long nReduce = 0;
953 USHORT nNewCount;
957 aNewPolyPoly.Clear();
958 nReduce++;
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++ ];
1008 nTmpY -= 3L;
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 )
1016 nX++;
1018 nTmpX = pMapOut[ nX - 1L ];
1019 nTmpY -= 3L;
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 );
1026 else
1027 nX++;
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 )
1040 nTmpX -= 3L;
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 )
1049 nY++;
1051 nTmpX -= 3L;
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 );
1059 else
1060 nY++;
1064 // cleanup
1065 delete[] pMapIn;
1066 delete[] pMapOut;
1069 return pMap;
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++ )
1080 long nX = 0L;
1081 BOOL bInner = TRUE;
1083 while( nX < nWidth )
1085 // skip free
1086 while( ( nX < nWidth ) && pMap->IsFree( nY, nX ) )
1087 nX++;
1089 if( nX == nWidth )
1090 break;
1092 if( pMap->IsCont( nY, nX ) )
1094 // new contour
1095 ImplChain aChain;
1096 const Point aStartPt( nX++, nY );
1098 // get chain code
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 );
1104 else
1105 aChain.ImplEndAdd( bInner ? VECT_POLY_OUTLINE_INNER : VECT_POLY_OUTLINE_OUTER );
1107 const Polygon& rPoly = aChain.ImplGetPoly();
1109 if( rPoly.GetSize() > 2 )
1111 if( cReduce )
1113 const Rectangle aBound( rPoly.GetBoundRect() );
1115 if( aBound.GetWidth() > cReduce && aBound.GetHeight() > cReduce )
1116 rPolyPoly.Insert( rPoly );
1118 else
1119 rPolyPoly.Insert( rPoly );
1122 // skip rest of detected contour
1123 while( pMap->IsCont( nY, nX ) )
1124 nX++;
1126 else
1128 // process done segment
1129 const long nStartSegX = nX++;
1131 while( pMap->IsDone( nY, nX ) )
1132 nX++;
1134 if( ( ( nX - nStartSegX ) == 1L ) || ( ImplIsUp( pMap, nY, nStartSegX ) != ImplIsUp( pMap, nY, nX - 1L ) ) )
1135 bInner = !bInner;
1141 // -----------------------------------------------------------------------------
1143 BOOL ImplVectorizer::ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain )
1145 long nActX = rStartPt.X();
1146 long nActY = rStartPt.Y();
1147 long nTryX;
1148 long nTryY;
1149 ULONG nFound;
1150 ULONG nLastDir = 0UL;
1151 ULONG nDir;
1155 nFound = 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 );
1165 nFound = 1UL;
1167 else
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 );
1182 nFound = 1UL;
1183 nLastDir = nDir;
1184 break;
1190 while( nFound );
1192 return TRUE;
1195 // -----------------------------------------------------------------------------
1197 BOOL ImplVectorizer::ImplIsUp( ImplVectMap* pMap, long nY, long nX ) const
1199 if( pMap->IsDone( nY - 1L, nX ) )
1200 return TRUE;
1201 else if( pMap->IsDone( nY + 1L, nX ) )
1202 return FALSE;
1203 else if( pMap->IsDone( nY - 1L, nX - 1L ) || pMap->IsDone( nY - 1L, nX + 1L ) )
1204 return TRUE;
1205 else
1206 return FALSE;