| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_vcl.hxx" |
| |
| #include <stdlib.h> |
| #include <vcl/bmpacc.hxx> |
| #include <tools/poly.hxx> |
| #include <vcl/gdimtf.hxx> |
| #include <vcl/metaact.hxx> |
| #include <vcl/svapp.hxx> |
| #include <vcl/wrkwin.hxx> |
| #include <vcl/virdev.hxx> |
| #ifndef _SV_VECTORIZ_HXX |
| #include <impvect.hxx> |
| #endif |
| |
| // ----------- |
| // - Defines - |
| // ----------- |
| |
| #define VECT_POLY_MAX 8192 |
| |
| // ----------------------------------------------------------------------------- |
| |
| #define VECT_FREE_INDEX 0 |
| #define VECT_CONT_INDEX 1 |
| #define VECT_DONE_INDEX 2 |
| |
| // ----------------------------------------------------------------------------- |
| |
| #define VECT_POLY_INLINE_INNER 1UL |
| #define VECT_POLY_INLINE_OUTER 2UL |
| #define VECT_POLY_OUTLINE_INNER 4UL |
| #define VECT_POLY_OUTLINE_OUTER 8UL |
| |
| // ----------------------------------------------------------------------------- |
| |
| #define VECT_MAP( _def_pIn, _def_pOut, _def_nVal ) _def_pOut[_def_nVal]=(_def_pIn[_def_nVal]=((_def_nVal)*4L)+1L)+5L; |
| #define BACK_MAP( _def_nVal ) ((((_def_nVal)+2)>>2)-1) |
| #define VECT_PROGRESS( _def_pProgress, _def_nVal ) if(_def_pProgress&&_def_pProgress->IsSet())(_def_pProgress->Call((void*)_def_nVal)); |
| |
| // ----------- |
| // - statics - |
| // ----------- |
| |
| struct ChainMove { long nDX; long nDY; }; |
| |
| static ChainMove aImplMove[ 8 ] = { |
| { 1L, 0L }, |
| { 0L, -1L }, |
| { -1L, 0L }, |
| { 0L, 1L }, |
| { 1L, -1L }, |
| { -1, -1L }, |
| { -1L, 1L }, |
| { 1L, 1L } |
| }; |
| |
| static ChainMove aImplMoveInner[ 8 ] = { |
| { 0L, 1L }, |
| { 1L, 0L }, |
| { 0L, -1L }, |
| { -1L, 0L }, |
| { 0L, 1L }, |
| { 1L, 0L }, |
| { 0L, -1L }, |
| { -1L, 0L } |
| }; |
| |
| static ChainMove aImplMoveOuter[ 8 ] = { |
| { 0L, -1L }, |
| { -1L, 0L }, |
| { 0L, 1L }, |
| { 1L, 0L }, |
| { -1L, 0L }, |
| { 0L, 1L }, |
| { 1L, 0L }, |
| { 0L, -1L } |
| }; |
| |
| // ---------------- |
| // - ImplColorSet - |
| // ---------------- |
| |
| struct ImplColorSet |
| { |
| BitmapColor maColor; |
| sal_uInt16 mnIndex; |
| sal_Bool mbSet; |
| |
| sal_Bool operator<( const ImplColorSet& rSet ) const; |
| sal_Bool operator>( const ImplColorSet& rSet ) const; |
| }; |
| |
| // ---------------------------------------------------------------------------- |
| |
| inline sal_Bool ImplColorSet::operator<( const ImplColorSet& rSet ) const |
| { |
| return( mbSet && ( !rSet.mbSet || ( maColor.GetLuminance() > rSet.maColor.GetLuminance() ) ) ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| inline sal_Bool ImplColorSet::operator>( const ImplColorSet& rSet ) const |
| { |
| return( !mbSet || ( rSet.mbSet && maColor.GetLuminance() < rSet.maColor.GetLuminance() ) ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| extern "C" int __LOADONCALLAPI ImplColorSetCmpFnc( const void* p1, const void* p2 ) |
| { |
| ImplColorSet* pSet1 = (ImplColorSet*) p1; |
| ImplColorSet* pSet2 = (ImplColorSet*) p2; |
| int nRet; |
| |
| if( pSet1->mbSet && pSet2->mbSet ) |
| { |
| const sal_uInt8 cLum1 = pSet1->maColor.GetLuminance(); |
| const sal_uInt8 cLum2 = pSet2->maColor.GetLuminance(); |
| nRet = ( ( cLum1 > cLum2 ) ? -1 : ( ( cLum1 == cLum2 ) ? 0 : 1 ) ); |
| } |
| else if( pSet1->mbSet ) |
| nRet = -1; |
| else if( pSet2->mbSet ) |
| nRet = 1; |
| else |
| nRet = 0; |
| |
| return nRet; |
| } |
| |
| // ------------------ |
| // - ImplPointArray - |
| // ------------------ |
| |
| class ImplPointArray |
| { |
| Point* mpArray; |
| sal_uLong mnSize; |
| sal_uLong mnRealSize; |
| |
| public: |
| |
| ImplPointArray(); |
| ~ImplPointArray(); |
| |
| void ImplSetSize( sal_uLong nSize ); |
| |
| sal_uLong ImplGetRealSize() const { return mnRealSize; } |
| void ImplSetRealSize( sal_uLong nRealSize ) { mnRealSize = nRealSize; } |
| |
| inline Point& operator[]( sal_uLong nPos ); |
| inline const Point& operator[]( sal_uLong nPos ) const; |
| |
| void ImplCreatePoly( Polygon& rPoly ) const; |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| |
| ImplPointArray::ImplPointArray() : |
| mpArray ( NULL ), |
| mnSize ( 0UL ), |
| mnRealSize ( 0UL ) |
| |
| { |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| ImplPointArray::~ImplPointArray() |
| { |
| if( mpArray ) |
| rtl_freeMemory( mpArray ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void ImplPointArray::ImplSetSize( sal_uLong nSize ) |
| { |
| const sal_uLong nTotal = nSize * sizeof( Point ); |
| |
| mnSize = nSize; |
| mnRealSize = 0UL; |
| |
| if( mpArray ) |
| rtl_freeMemory( mpArray ); |
| |
| mpArray = (Point*) rtl_allocateMemory( nTotal ); |
| memset( (HPBYTE) mpArray, 0, nTotal ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| inline Point& ImplPointArray::operator[]( sal_uLong nPos ) |
| { |
| DBG_ASSERT( nPos < mnSize, "ImplPointArray::operator[]: nPos out of range!" ); |
| return mpArray[ nPos ]; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| inline const Point& ImplPointArray::operator[]( sal_uLong nPos ) const |
| { |
| DBG_ASSERT( nPos < mnSize, "ImplPointArray::operator[]: nPos out of range!" ); |
| return mpArray[ nPos ]; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void ImplPointArray::ImplCreatePoly( Polygon& rPoly ) const |
| { |
| rPoly = Polygon( sal::static_int_cast<sal_uInt16>(mnRealSize), mpArray ); |
| } |
| |
| // --------------- |
| // - ImplVectMap - |
| // --------------- |
| |
| class ImplVectMap |
| { |
| private: |
| |
| Scanline mpBuf; |
| Scanline* mpScan; |
| long mnWidth; |
| long mnHeight; |
| |
| ImplVectMap() {}; |
| |
| public: |
| |
| ImplVectMap( long nWidth, long nHeight ); |
| ~ImplVectMap(); |
| |
| inline long Width() const { return mnWidth; } |
| inline long Height() const { return mnHeight; } |
| |
| inline void Set( long nY, long nX, sal_uInt8 cVal ); |
| inline sal_uInt8 Get( long nY, long nX ) const; |
| |
| inline sal_Bool IsFree( long nY, long nX ) const; |
| inline sal_Bool IsCont( long nY, long nX ) const; |
| inline sal_Bool IsDone( long nY, long nX ) const; |
| |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| |
| ImplVectMap::ImplVectMap( long nWidth, long nHeight ) : |
| mnWidth ( nWidth ), |
| mnHeight( nHeight ) |
| { |
| const long nWidthAl = ( nWidth >> 2L ) + 1L; |
| const long nSize = nWidthAl * nHeight; |
| Scanline pTmp = mpBuf = (Scanline) rtl_allocateMemory( nSize ); |
| |
| memset( mpBuf, 0, nSize ); |
| mpScan = (Scanline*) rtl_allocateMemory( nHeight * sizeof( Scanline ) ); |
| |
| for( long nY = 0L; nY < nHeight; pTmp += nWidthAl ) |
| mpScan[ nY++ ] = pTmp; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| |
| ImplVectMap::~ImplVectMap() |
| { |
| rtl_freeMemory( mpBuf ); |
| rtl_freeMemory( mpScan ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| inline void ImplVectMap::Set( long nY, long nX, sal_uInt8 cVal ) |
| { |
| const sal_uInt8 cShift = sal::static_int_cast<sal_uInt8>(6 - ( ( nX & 3 ) << 1 )); |
| ( ( mpScan[ nY ][ nX >> 2 ] ) &= ~( 3 << cShift ) ) |= ( cVal << cShift ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| inline sal_uInt8 ImplVectMap::Get( long nY, long nX ) const |
| { |
| return sal::static_int_cast<sal_uInt8>( ( ( mpScan[ nY ][ nX >> 2 ] ) >> ( 6 - ( ( nX & 3 ) << 1 ) ) ) & 3 ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| inline sal_Bool ImplVectMap::IsFree( long nY, long nX ) const |
| { |
| return( VECT_FREE_INDEX == Get( nY, nX ) ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| inline sal_Bool ImplVectMap::IsCont( long nY, long nX ) const |
| { |
| return( VECT_CONT_INDEX == Get( nY, nX ) ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| inline sal_Bool ImplVectMap::IsDone( long nY, long nX ) const |
| { |
| return( VECT_DONE_INDEX == Get( nY, nX ) ); |
| } |
| |
| // ------------- |
| // - ImplChain - |
| // ------------- |
| |
| class ImplChain |
| { |
| private: |
| |
| Polygon maPoly; |
| Point maStartPt; |
| sal_uLong mnArraySize; |
| sal_uLong mnCount; |
| long mnResize; |
| sal_uInt8* mpCodes; |
| |
| void ImplGetSpace(); |
| |
| void ImplCreate(); |
| void ImplCreateInner(); |
| void ImplCreateOuter(); |
| void ImplPostProcess( const ImplPointArray& rArr ); |
| |
| public: |
| |
| ImplChain( sal_uLong nInitCount = 1024UL, long nResize = -1L ); |
| ~ImplChain(); |
| |
| void ImplBeginAdd( const Point& rStartPt ); |
| inline void ImplAdd( sal_uInt8 nCode ); |
| void ImplEndAdd( sal_uLong nTypeFlag ); |
| |
| const Polygon& ImplGetPoly() { return maPoly; } |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| |
| ImplChain::ImplChain( sal_uLong nInitCount, long nResize ) : |
| mnArraySize ( nInitCount ), |
| mnCount ( 0UL ), |
| mnResize ( nResize ) |
| { |
| DBG_ASSERT( nInitCount && nResize, "ImplChain::ImplChain(): invalid parameters!" ); |
| mpCodes = new sal_uInt8[ mnArraySize ]; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| ImplChain::~ImplChain() |
| { |
| delete[] mpCodes; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void ImplChain::ImplGetSpace() |
| { |
| const sal_uLong nOldArraySize = mnArraySize; |
| sal_uInt8* pNewCodes; |
| |
| mnArraySize = ( mnResize < 0L ) ? ( mnArraySize << 1UL ) : ( mnArraySize + (sal_uLong) mnResize ); |
| pNewCodes = new sal_uInt8[ mnArraySize ]; |
| memcpy( pNewCodes, mpCodes, nOldArraySize ); |
| delete[] mpCodes; |
| mpCodes = pNewCodes; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void ImplChain::ImplBeginAdd( const Point& rStartPt ) |
| { |
| maPoly = Polygon(); |
| maStartPt = rStartPt; |
| mnCount = 0UL; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| inline void ImplChain::ImplAdd( sal_uInt8 nCode ) |
| { |
| if( mnCount == mnArraySize ) |
| ImplGetSpace(); |
| |
| mpCodes[ mnCount++ ] = nCode; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void ImplChain::ImplEndAdd( sal_uLong nFlag ) |
| { |
| if( mnCount ) |
| { |
| ImplPointArray aArr; |
| |
| if( nFlag & VECT_POLY_INLINE_INNER ) |
| { |
| long nFirstX, nFirstY; |
| long nLastX, nLastY; |
| |
| nFirstX = nLastX = maStartPt.X(); |
| nFirstY = nLastY = maStartPt.Y(); |
| aArr.ImplSetSize( mnCount << 1 ); |
| |
| sal_uInt16 i, nPolyPos; |
| for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ ) |
| { |
| const sal_uInt8 cMove = mpCodes[ i ]; |
| const sal_uInt8 cNextMove = mpCodes[ i + 1 ]; |
| const ChainMove& rMove = aImplMove[ cMove ]; |
| const ChainMove& rMoveInner = aImplMoveInner[ cMove ]; |
| // Point& rPt = aArr[ nPolyPos ]; |
| sal_Bool bDone = sal_True; |
| |
| nLastX += rMove.nDX; |
| nLastY += rMove.nDY; |
| |
| if( cMove < 4 ) |
| { |
| if( ( cMove == 0 && cNextMove == 3 ) || |
| ( cMove == 3 && cNextMove == 2 ) || |
| ( cMove == 2 && cNextMove == 1 ) || |
| ( cMove == 1 && cNextMove == 0 ) ) |
| { |
| } |
| else if( cMove == 2 && cNextMove == 3 ) |
| { |
| aArr[ nPolyPos ].X() = nLastX; |
| aArr[ nPolyPos++ ].Y() = nLastY - 1; |
| |
| aArr[ nPolyPos ].X() = nLastX - 1; |
| aArr[ nPolyPos++ ].Y() = nLastY - 1; |
| |
| aArr[ nPolyPos ].X() = nLastX - 1; |
| aArr[ nPolyPos++ ].Y() = nLastY; |
| } |
| else if( cMove == 3 && cNextMove == 0 ) |
| { |
| aArr[ nPolyPos ].X() = nLastX - 1; |
| aArr[ nPolyPos++ ].Y() = nLastY; |
| |
| aArr[ nPolyPos ].X() = nLastX - 1; |
| aArr[ nPolyPos++ ].Y() = nLastY + 1; |
| |
| aArr[ nPolyPos ].X() = nLastX; |
| aArr[ nPolyPos++ ].Y() = nLastY + 1; |
| } |
| else if( cMove == 0 && cNextMove == 1 ) |
| { |
| aArr[ nPolyPos ].X() = nLastX; |
| aArr[ nPolyPos++ ].Y() = nLastY + 1; |
| |
| aArr[ nPolyPos ].X() = nLastX + 1; |
| aArr[ nPolyPos++ ].Y() = nLastY + 1; |
| |
| aArr[ nPolyPos ].X() = nLastX + 1; |
| aArr[ nPolyPos++ ].Y() = nLastY; |
| } |
| else if( cMove == 1 && cNextMove == 2 ) |
| { |
| aArr[ nPolyPos ].X() = nLastX + 1; |
| aArr[ nPolyPos++ ].Y() = nLastY + 1; |
| |
| aArr[ nPolyPos ].X() = nLastX + 1; |
| aArr[ nPolyPos++ ].Y() = nLastY - 1; |
| |
| aArr[ nPolyPos ].X() = nLastX; |
| aArr[ nPolyPos++ ].Y() = nLastY - 1; |
| } |
| else |
| bDone = sal_False; |
| } |
| else if( cMove == 7 && cNextMove == 0 ) |
| { |
| aArr[ nPolyPos ].X() = nLastX - 1; |
| aArr[ nPolyPos++ ].Y() = nLastY; |
| |
| aArr[ nPolyPos ].X() = nLastX; |
| aArr[ nPolyPos++ ].Y() = nLastY + 1; |
| } |
| else if( cMove == 4 && cNextMove == 1 ) |
| { |
| aArr[ nPolyPos ].X() = nLastX; |
| aArr[ nPolyPos++ ].Y() = nLastY + 1; |
| |
| aArr[ nPolyPos ].X() = nLastX + 1; |
| aArr[ nPolyPos++ ].Y() = nLastY; |
| } |
| else |
| bDone = sal_False; |
| |
| if( !bDone ) |
| { |
| aArr[ nPolyPos ].X() = nLastX + rMoveInner.nDX; |
| aArr[ nPolyPos++ ].Y() = nLastY + rMoveInner.nDY; |
| } |
| } |
| |
| aArr[ nPolyPos ].X() = nFirstX + 1L; |
| aArr[ nPolyPos++ ].Y() = nFirstY + 1L; |
| aArr.ImplSetRealSize( nPolyPos ); |
| } |
| else if( nFlag & VECT_POLY_INLINE_OUTER ) |
| { |
| long nFirstX, nFirstY; |
| long nLastX, nLastY; |
| |
| nFirstX = nLastX = maStartPt.X(); |
| nFirstY = nLastY = maStartPt.Y(); |
| aArr.ImplSetSize( mnCount << 1 ); |
| |
| sal_uInt16 i, nPolyPos; |
| for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ ) |
| { |
| const sal_uInt8 cMove = mpCodes[ i ]; |
| const sal_uInt8 cNextMove = mpCodes[ i + 1 ]; |
| const ChainMove& rMove = aImplMove[ cMove ]; |
| const ChainMove& rMoveOuter = aImplMoveOuter[ cMove ]; |
| // Point& rPt = aArr[ nPolyPos ]; |
| sal_Bool bDone = sal_True; |
| |
| nLastX += rMove.nDX; |
| nLastY += rMove.nDY; |
| |
| if( cMove < 4 ) |
| { |
| if( ( cMove == 0 && cNextMove == 1 ) || |
| ( cMove == 1 && cNextMove == 2 ) || |
| ( cMove == 2 && cNextMove == 3 ) || |
| ( cMove == 3 && cNextMove == 0 ) ) |
| { |
| } |
| else if( cMove == 0 && cNextMove == 3 ) |
| { |
| aArr[ nPolyPos ].X() = nLastX; |
| aArr[ nPolyPos++ ].Y() = nLastY - 1; |
| |
| aArr[ nPolyPos ].X() = nLastX + 1; |
| aArr[ nPolyPos++ ].Y() = nLastY - 1; |
| |
| aArr[ nPolyPos ].X() = nLastX + 1; |
| aArr[ nPolyPos++ ].Y() = nLastY; |
| } |
| else if( cMove == 3 && cNextMove == 2 ) |
| { |
| aArr[ nPolyPos ].X() = nLastX + 1; |
| aArr[ nPolyPos++ ].Y() = nLastY; |
| |
| aArr[ nPolyPos ].X() = nLastX + 1; |
| aArr[ nPolyPos++ ].Y() = nLastY + 1; |
| |
| aArr[ nPolyPos ].X() = nLastX; |
| aArr[ nPolyPos++ ].Y() = nLastY + 1; |
| } |
| else if( cMove == 2 && cNextMove == 1 ) |
| { |
| aArr[ nPolyPos ].X() = nLastX; |
| aArr[ nPolyPos++ ].Y() = nLastY + 1; |
| |
| aArr[ nPolyPos ].X() = nLastX - 1; |
| aArr[ nPolyPos++ ].Y() = nLastY + 1; |
| |
| aArr[ nPolyPos ].X() = nLastX - 1; |
| aArr[ nPolyPos++ ].Y() = nLastY; |
| } |
| else if( cMove == 1 && cNextMove == 0 ) |
| { |
| aArr[ nPolyPos ].X() = nLastX - 1; |
| aArr[ nPolyPos++ ].Y() = nLastY; |
| |
| aArr[ nPolyPos ].X() = nLastX - 1; |
| aArr[ nPolyPos++ ].Y() = nLastY - 1; |
| |
| aArr[ nPolyPos ].X() = nLastX; |
| aArr[ nPolyPos++ ].Y() = nLastY - 1; |
| } |
| else |
| bDone = sal_False; |
| } |
| else if( cMove == 7 && cNextMove == 3 ) |
| { |
| aArr[ nPolyPos ].X() = nLastX; |
| aArr[ nPolyPos++ ].Y() = nLastY - 1; |
| |
| aArr[ nPolyPos ].X() = nLastX + 1; |
| aArr[ nPolyPos++ ].Y() = nLastY; |
| } |
| else if( cMove == 6 && cNextMove == 2 ) |
| { |
| aArr[ nPolyPos ].X() = nLastX + 1; |
| aArr[ nPolyPos++ ].Y() = nLastY; |
| |
| aArr[ nPolyPos ].X() = nLastX; |
| aArr[ nPolyPos++ ].Y() = nLastY + 1; |
| } |
| else |
| bDone = sal_False; |
| |
| if( !bDone ) |
| { |
| aArr[ nPolyPos ].X() = nLastX + rMoveOuter.nDX; |
| aArr[ nPolyPos++ ].Y() = nLastY + rMoveOuter.nDY; |
| } |
| } |
| |
| aArr[ nPolyPos ].X() = nFirstX - 1L; |
| aArr[ nPolyPos++ ].Y() = nFirstY - 1L; |
| aArr.ImplSetRealSize( nPolyPos ); |
| } |
| else |
| { |
| long nLastX = maStartPt.X(), nLastY = maStartPt.Y(); |
| |
| aArr.ImplSetSize( mnCount + 1 ); |
| aArr[ 0 ] = Point( nLastX, nLastY ); |
| |
| for( sal_uLong i = 0; i < mnCount; ) |
| { |
| const ChainMove& rMove = aImplMove[ mpCodes[ i ] ]; |
| aArr[ ++i ] = Point( nLastX += rMove.nDX, nLastY += rMove.nDY ); |
| } |
| |
| aArr.ImplSetRealSize( mnCount + 1 ); |
| } |
| |
| ImplPostProcess( aArr ); |
| } |
| else |
| maPoly.SetSize( 0 ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void ImplChain::ImplPostProcess( const ImplPointArray& rArr ) |
| { |
| ImplPointArray aNewArr1; |
| ImplPointArray aNewArr2; |
| Point* pLast; |
| Point* pLeast; |
| sal_uLong nNewPos; |
| sal_uLong nCount = rArr.ImplGetRealSize(); |
| sal_uLong n; |
| |
| // pass 1 |
| aNewArr1.ImplSetSize( nCount ); |
| pLast = &( aNewArr1[ 0 ] ); |
| pLast->X() = BACK_MAP( rArr[ 0 ].X() ); |
| pLast->Y() = BACK_MAP( rArr[ 0 ].Y() ); |
| |
| for( n = nNewPos = 1; n < nCount; ) |
| { |
| const Point& rPt = rArr[ n++ ]; |
| const long nX = BACK_MAP( rPt.X() ); |
| const long nY = BACK_MAP( rPt.Y() ); |
| |
| if( nX != pLast->X() || nY != pLast->Y() ) |
| { |
| pLast = pLeast = &( aNewArr1[ nNewPos++ ] ); |
| pLeast->X() = nX; |
| pLeast->Y() = nY; |
| } |
| } |
| |
| aNewArr1.ImplSetRealSize( nCount = nNewPos ); |
| |
| // pass 2 |
| aNewArr2.ImplSetSize( nCount ); |
| pLast = &( aNewArr2[ 0 ] ); |
| *pLast = aNewArr1[ 0 ]; |
| |
| for( n = nNewPos = 1; n < nCount; ) |
| { |
| pLeast = &( aNewArr1[ n++ ] ); |
| |
| if( pLeast->X() == pLast->X() ) |
| { |
| while( n < nCount && aNewArr1[ n ].X() == pLast->X() ) |
| pLeast = &( aNewArr1[ n++ ] ); |
| } |
| else if( pLeast->Y() == pLast->Y() ) |
| { |
| while( n < nCount && aNewArr1[ n ].Y() == pLast->Y() ) |
| pLeast = &( aNewArr1[ n++ ] ); |
| } |
| |
| aNewArr2[ nNewPos++ ] = *( pLast = pLeast ); |
| } |
| |
| aNewArr2.ImplSetRealSize( nNewPos ); |
| aNewArr2.ImplCreatePoly( maPoly ); |
| } |
| |
| // ------------------ |
| // - ImplVectorizer - |
| // ------------------ |
| |
| ImplVectorizer::ImplVectorizer() |
| { |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| ImplVectorizer::~ImplVectorizer() |
| { |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool ImplVectorizer::ImplVectorize( const Bitmap& rColorBmp, GDIMetaFile& rMtf, |
| sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress ) |
| { |
| sal_Bool bRet = sal_False; |
| |
| VECT_PROGRESS( pProgress, 0 ); |
| |
| Bitmap* pBmp = new Bitmap( rColorBmp ); |
| BitmapReadAccess* pRAcc = pBmp->AcquireReadAccess(); |
| |
| if( pRAcc ) |
| { |
| PolyPolygon aPolyPoly; |
| double fPercent = 0.0; |
| double fPercentStep_2 = 0.0; |
| const long nWidth = pRAcc->Width(); |
| const long nHeight = pRAcc->Height(); |
| const sal_uInt16 nColorCount = pRAcc->GetPaletteEntryCount(); |
| sal_uInt16 n; |
| ImplColorSet* pColorSet = (ImplColorSet*) new sal_uInt8[ 256 * sizeof( ImplColorSet ) ]; |
| |
| memset( pColorSet, 0, 256 * sizeof( ImplColorSet ) ); |
| rMtf.Clear(); |
| |
| // get used palette colors and sort them from light to dark colors |
| for( n = 0; n < nColorCount; n++ ) |
| { |
| pColorSet[ n ].mnIndex = n; |
| pColorSet[ n ].maColor = pRAcc->GetPaletteColor( n ); |
| } |
| |
| for( long nY = 0L; nY < nHeight; nY++ ) |
| for( long nX = 0L; nX < nWidth; nX++ ) |
| pColorSet[ pRAcc->GetPixel( nY, nX ).GetIndex() ].mbSet = 1; |
| |
| qsort( pColorSet, 256, sizeof( ImplColorSet ), ImplColorSetCmpFnc ); |
| |
| for( n = 0; n < 256; n++ ) |
| if( !pColorSet[ n ].mbSet ) |
| break; |
| |
| if( n ) |
| fPercentStep_2 = 45.0 / n; |
| |
| VECT_PROGRESS( pProgress, FRound( fPercent += 10.0 ) ); |
| |
| for( sal_uInt16 i = 0; i < n; i++ ) |
| { |
| const BitmapColor aBmpCol( pRAcc->GetPaletteColor( pColorSet[ i ].mnIndex ) ); |
| const Color aFindColor( aBmpCol.GetRed(), aBmpCol.GetGreen(), aBmpCol.GetBlue() ); |
| // const sal_uInt8 cLum = aFindColor.GetLuminance(); |
| ImplVectMap* pMap = ImplExpand( pRAcc, aFindColor ); |
| |
| VECT_PROGRESS( pProgress, FRound( fPercent += fPercentStep_2 ) ); |
| |
| if( pMap ) |
| { |
| aPolyPoly.Clear(); |
| ImplCalculate( pMap, aPolyPoly, cReduce, nFlags ); |
| delete pMap; |
| |
| if( aPolyPoly.Count() ) |
| { |
| ImplLimitPolyPoly( aPolyPoly ); |
| |
| if( nFlags & BMP_VECTORIZE_REDUCE_EDGES ) |
| aPolyPoly.Optimize( POLY_OPTIMIZE_EDGES ); |
| |
| if( aPolyPoly.Count() ) |
| { |
| rMtf.AddAction( new MetaLineColorAction( aFindColor, sal_True ) ); |
| rMtf.AddAction( new MetaFillColorAction( aFindColor, sal_True ) ); |
| rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) ); |
| } |
| } |
| } |
| |
| VECT_PROGRESS( pProgress, FRound( fPercent += fPercentStep_2 ) ); |
| } |
| |
| delete[] (sal_uInt8*) pColorSet; |
| |
| if( rMtf.GetActionCount() ) |
| { |
| MapMode aMap( MAP_100TH_MM ); |
| VirtualDevice aVDev; |
| const Size aLogSize1( aVDev.PixelToLogic( Size( 1, 1 ), aMap ) ); |
| |
| rMtf.SetPrefMapMode( aMap ); |
| rMtf.SetPrefSize( Size( nWidth + 2, nHeight + 2 ) ); |
| rMtf.Move( 1, 1 ); |
| rMtf.Scale( aLogSize1.Width(), aLogSize1.Height() ); |
| bRet = sal_True; |
| } |
| } |
| |
| pBmp->ReleaseAccess( pRAcc ); |
| delete pBmp; |
| VECT_PROGRESS( pProgress, 100 ); |
| |
| return bRet; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool ImplVectorizer::ImplVectorize( const Bitmap& rMonoBmp, |
| PolyPolygon& rPolyPoly, |
| sal_uLong nFlags, const Link* pProgress ) |
| { |
| Bitmap* pBmp = new Bitmap( rMonoBmp ); |
| BitmapReadAccess* pRAcc; |
| ImplVectMap* pMap; |
| sal_Bool bRet = sal_False; |
| |
| VECT_PROGRESS( pProgress, 10 ); |
| |
| if( pBmp->GetBitCount() > 1 ) |
| pBmp->Convert( BMP_CONVERSION_1BIT_THRESHOLD ); |
| |
| VECT_PROGRESS( pProgress, 30 ); |
| |
| pRAcc = pBmp->AcquireReadAccess(); |
| pMap = ImplExpand( pRAcc, COL_BLACK ); |
| pBmp->ReleaseAccess( pRAcc ); |
| delete pBmp; |
| |
| VECT_PROGRESS( pProgress, 60 ); |
| |
| if( pMap ) |
| { |
| rPolyPoly.Clear(); |
| ImplCalculate( pMap, rPolyPoly, 0, nFlags ); |
| delete pMap; |
| ImplLimitPolyPoly( rPolyPoly ); |
| |
| if( nFlags & BMP_VECTORIZE_REDUCE_EDGES ) |
| rPolyPoly.Optimize( POLY_OPTIMIZE_EDGES ); |
| |
| // #i14895#:setting the correct direction for polygons |
| // that represent holes and non-holes; non-hole polygons |
| // need to have a right orientation, holes need to have a |
| // left orientation in order to be treated correctly by |
| // several external tools like Flash viewers |
| sal_Int32 nFirstPoly = -1; |
| sal_uInt16 nCurPoly( 0 ), nCount( rPolyPoly.Count() ); |
| |
| for( ; nCurPoly < nCount; ++nCurPoly ) |
| { |
| const Polygon& rPoly = rPolyPoly.GetObject( nCurPoly ); |
| const sal_uInt16 nSize( rPoly.GetSize() ); |
| sal_uInt16 nDepth( 0 ), i( 0 ); |
| const bool bRight( rPoly.IsRightOrientated() ); |
| |
| for( ; i < nCount; ++i ) |
| if( ( i != nCurPoly ) && rPolyPoly.GetObject( i ).IsInside( rPoly[ 0 ] ) ) |
| ++nDepth; |
| |
| const bool bHole( ( nDepth & 0x0001 ) == 1 ); |
| |
| if( nSize && ( ( !bRight && !bHole ) || ( bRight && bHole ) ) ) |
| { |
| Polygon aNewPoly( nSize ); |
| sal_uInt16 nPrim( 0 ), nSec( nSize - 1 ); |
| |
| if( rPoly.HasFlags() ) |
| { |
| while( nPrim < nSize ) |
| { |
| aNewPoly.SetPoint( rPoly.GetPoint( nSec ), nPrim ); |
| aNewPoly.SetFlags( nPrim++, rPoly.GetFlags( nSec-- ) ); |
| } |
| } |
| else |
| while( nPrim < nSize ) |
| aNewPoly.SetPoint( rPoly.GetPoint( nSec-- ), nPrim++ ); |
| |
| rPolyPoly.Replace( aNewPoly, nCurPoly ); |
| } |
| |
| if( ( 0 == nDepth ) && ( -1 == nFirstPoly ) ) |
| nFirstPoly = nCurPoly; |
| } |
| |
| // put outmost polygon to the front |
| if( nFirstPoly > 0 ) |
| { |
| const Polygon aFirst( rPolyPoly.GetObject( static_cast< sal_uInt16 >( nFirstPoly ) ) ); |
| |
| rPolyPoly.Remove( static_cast< sal_uInt16 >( nFirstPoly ) ); |
| rPolyPoly.Insert( aFirst, 0 ); |
| } |
| |
| bRet = sal_True; |
| } |
| |
| VECT_PROGRESS( pProgress, 100 ); |
| |
| return bRet; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void ImplVectorizer::ImplLimitPolyPoly( PolyPolygon& rPolyPoly ) |
| { |
| if( rPolyPoly.Count() > VECT_POLY_MAX ) |
| { |
| PolyPolygon aNewPolyPoly; |
| long nReduce = 0; |
| sal_uInt16 nNewCount; |
| |
| do |
| { |
| aNewPolyPoly.Clear(); |
| nReduce++; |
| |
| for( sal_uInt16 i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ ) |
| { |
| const Rectangle aBound( rPolyPoly[ i ].GetBoundRect() ); |
| |
| if( aBound.GetWidth() > nReduce && aBound.GetHeight() > nReduce ) |
| { |
| if( rPolyPoly[ i ].GetSize() ) |
| aNewPolyPoly.Insert( rPolyPoly[ i ] ); |
| } |
| } |
| |
| nNewCount = aNewPolyPoly.Count(); |
| } |
| while( nNewCount > VECT_POLY_MAX ); |
| |
| rPolyPoly = aNewPolyPoly; |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| ImplVectMap* ImplVectorizer::ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor ) |
| { |
| ImplVectMap* pMap = NULL; |
| |
| if( pRAcc && pRAcc->Width() && pRAcc->Height() ) |
| { |
| const long nOldWidth = pRAcc->Width(); |
| const long nOldHeight = pRAcc->Height(); |
| const long nNewWidth = ( nOldWidth << 2L ) + 4L; |
| const long nNewHeight = ( nOldHeight << 2L ) + 4L; |
| const BitmapColor aTest( pRAcc->GetBestMatchingColor( rColor ) ); |
| long* pMapIn = new long[ Max( nOldWidth, nOldHeight ) ]; |
| long* pMapOut = new long[ Max( nOldWidth, nOldHeight ) ]; |
| long nX, nY, nTmpX, nTmpY; |
| |
| pMap = new ImplVectMap( nNewWidth, nNewHeight ); |
| |
| for( nX = 0L; nX < nOldWidth; nX++ ) |
| VECT_MAP( pMapIn, pMapOut, nX ); |
| |
| for( nY = 0L, nTmpY = 5L; nY < nOldHeight; nY++, nTmpY += 4L ) |
| { |
| for( nX = 0L; nX < nOldWidth; ) |
| { |
| if( pRAcc->GetPixel( nY, nX ) == aTest ) |
| { |
| nTmpX = pMapIn[ nX++ ]; |
| nTmpY -= 3L; |
| |
| pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); |
| pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); |
| pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); |
| pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX ); |
| |
| while( nX < nOldWidth && pRAcc->GetPixel( nY, nX ) == aTest ) |
| nX++; |
| |
| nTmpX = pMapOut[ nX - 1L ]; |
| nTmpY -= 3L; |
| |
| pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); |
| pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); |
| pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); |
| pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX ); |
| } |
| else |
| nX++; |
| } |
| } |
| |
| for( nY = 0L; nY < nOldHeight; nY++ ) |
| VECT_MAP( pMapIn, pMapOut, nY ); |
| |
| for( nX = 0L, nTmpX = 5L; nX < nOldWidth; nX++, nTmpX += 4L ) |
| { |
| for( nY = 0L; nY < nOldHeight; ) |
| { |
| if( pRAcc->GetPixel( nY, nX ) == aTest ) |
| { |
| nTmpX -= 3L; |
| nTmpY = pMapIn[ nY++ ]; |
| |
| pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); |
| pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); |
| pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); |
| pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX ); |
| |
| while( nY < nOldHeight && pRAcc->GetPixel( nY, nX ) == aTest ) |
| nY++; |
| |
| nTmpX -= 3L; |
| nTmpY = pMapOut[ nY - 1L ]; |
| |
| pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); |
| pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); |
| pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); |
| pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX ); |
| } |
| else |
| nY++; |
| } |
| } |
| |
| // cleanup |
| delete[] pMapIn; |
| delete[] pMapOut; |
| } |
| |
| return pMap; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void ImplVectorizer::ImplCalculate( ImplVectMap* pMap, PolyPolygon& rPolyPoly, sal_uInt8 cReduce, sal_uLong nFlags ) |
| { |
| const long nWidth = pMap->Width(), nHeight= pMap->Height(); |
| |
| for( long nY = 0L; nY < nHeight; nY++ ) |
| { |
| long nX = 0L; |
| sal_Bool bInner = sal_True; |
| |
| while( nX < nWidth ) |
| { |
| // skip free |
| while( ( nX < nWidth ) && pMap->IsFree( nY, nX ) ) |
| nX++; |
| |
| if( nX == nWidth ) |
| break; |
| |
| if( pMap->IsCont( nY, nX ) ) |
| { |
| // new contour |
| ImplChain aChain; |
| const Point aStartPt( nX++, nY ); |
| |
| // get chain code |
| aChain.ImplBeginAdd( aStartPt ); |
| ImplGetChain( pMap, aStartPt, aChain ); |
| |
| if( nFlags & BMP_VECTORIZE_INNER ) |
| aChain.ImplEndAdd( bInner ? VECT_POLY_INLINE_INNER : VECT_POLY_INLINE_OUTER ); |
| else |
| aChain.ImplEndAdd( bInner ? VECT_POLY_OUTLINE_INNER : VECT_POLY_OUTLINE_OUTER ); |
| |
| const Polygon& rPoly = aChain.ImplGetPoly(); |
| |
| if( rPoly.GetSize() > 2 ) |
| { |
| if( cReduce ) |
| { |
| const Rectangle aBound( rPoly.GetBoundRect() ); |
| |
| if( aBound.GetWidth() > cReduce && aBound.GetHeight() > cReduce ) |
| rPolyPoly.Insert( rPoly ); |
| } |
| else |
| rPolyPoly.Insert( rPoly ); |
| } |
| |
| // skip rest of detected contour |
| while( pMap->IsCont( nY, nX ) ) |
| nX++; |
| } |
| else |
| { |
| // process done segment |
| const long nStartSegX = nX++; |
| |
| while( pMap->IsDone( nY, nX ) ) |
| nX++; |
| |
| if( ( ( nX - nStartSegX ) == 1L ) || ( ImplIsUp( pMap, nY, nStartSegX ) != ImplIsUp( pMap, nY, nX - 1L ) ) ) |
| bInner = !bInner; |
| } |
| } |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool ImplVectorizer::ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain ) |
| { |
| long nActX = rStartPt.X(); |
| long nActY = rStartPt.Y(); |
| long nTryX; |
| long nTryY; |
| sal_uLong nFound; |
| sal_uLong nLastDir = 0UL; |
| sal_uLong nDir; |
| |
| do |
| { |
| nFound = 0UL; |
| |
| // first try last direction |
| nTryX = nActX + aImplMove[ nLastDir ].nDX; |
| nTryY = nActY + aImplMove[ nLastDir ].nDY; |
| |
| if( pMap->IsCont( nTryY, nTryX ) ) |
| { |
| rChain.ImplAdd( (sal_uInt8) nLastDir ); |
| pMap->Set( nActY = nTryY, nActX = nTryX, VECT_DONE_INDEX ); |
| nFound = 1UL; |
| } |
| else |
| { |
| // try other directions |
| for( nDir = 0UL; nDir < 8UL; nDir++ ) |
| { |
| // we already tried nLastDir |
| if( nDir != nLastDir ) |
| { |
| nTryX = nActX + aImplMove[ nDir ].nDX; |
| nTryY = nActY + aImplMove[ nDir ].nDY; |
| |
| if( pMap->IsCont( nTryY, nTryX ) ) |
| { |
| rChain.ImplAdd( (sal_uInt8) nDir ); |
| pMap->Set( nActY = nTryY, nActX = nTryX, VECT_DONE_INDEX ); |
| nFound = 1UL; |
| nLastDir = nDir; |
| break; |
| } |
| } |
| } |
| } |
| } |
| while( nFound ); |
| |
| return sal_True; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool ImplVectorizer::ImplIsUp( ImplVectMap* pMap, long nY, long nX ) const |
| { |
| if( pMap->IsDone( nY - 1L, nX ) ) |
| return sal_True; |
| else if( pMap->IsDone( nY + 1L, nX ) ) |
| return sal_False; |
| else if( pMap->IsDone( nY - 1L, nX - 1L ) || pMap->IsDone( nY - 1L, nX + 1L ) ) |
| return sal_True; |
| else |
| return sal_False; |
| } |