Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/vcl/source/bitmap/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 30 kB image not shown  

Quelle  Vectorizer.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   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 .
 */


#include <sal/log.hxx>
#include <vcl/BitmapReadAccess.hxx>
#include <tools/link.hxx>
#include <tools/poly.hxx>
#include <tools/helpers.hxx>
#include <vcl/gdimtf.hxx>
#include <vcl/metaact.hxx>
#include <vcl/virdev.hxx>
#include <vcl/bitmap/Vectorizer.hxx>
#include <array>
#include <memory>

#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

static void VECT_MAP( const std::unique_ptr<sal_Int32 []> & pMapIn, const std::unique_ptr<sal_Int32 []>& pMapOut, tools::Long nVal )
{
    pMapIn[nVal] = (nVal * 4) + 1;
    pMapOut[nVal] = pMapIn[nVal] + 5;
}
static constexpr tools::Long BACK_MAP( tools::Long _def_nVal )
{
    return ((_def_nVal + 2) >> 2) - 1;
}

namespace {

class ImplVectMap;
class ImplChain;

}

namespace vcl
{
    static void ImplExpand( std::optional<ImplVectMap>& rMap, const BitmapReadAccess* pRAcc, const Color& rColor );
    static void ImplCalculate( ImplVectMap& rMap, tools::PolyPolygon& rPolyPoly, sal_uInt8 cReduce );
    static bool ImplGetChain( ImplVectMap& rMap, const Point& rStartPt, ImplChain&&nbsp;rChain );
    static bool ImplIsUp( ImplVectMap const & rMap, tools::Long nY, tools::Long nX );
    static void ImplLimitPolyPoly( tools::PolyPolygon& rPolyPoly );
}

namespace {

struct ChainMove { tools::Long nDX; tools::Long nDY; };

}

const ChainMove aImplMove[ 8 ] =   {
                                        { 1, 0 },
                                        { 0, -1 },
                                        { -1, 0 },
                                        { 0, 1 },
                                        { 1, -1 },
                                        { -1, -1 },
                                        { -1, 1 },
                                        { 1, 1 }
                                    };

const ChainMove aImplMoveInner[ 8 ] =  {
                                            { 0, 1 },
                                            { 1, 0 },
                                            { 0, -1 },
                                            { -1, 0 },
                                            { 0, 1 },
                                            { 1, 0 },
                                            { 0, -1 },
                                            { -1, 0 }
                                        };

const ChainMove aImplMoveOuter[ 8 ] =  {
                                            { 0, -1 },
                                            { -1, 0 },
                                            { 0, 1 },
                                            { 1, 0 },
                                            { -1, 0 },
                                            { 0, 1 },
                                            { 1, 0 },
                                            { 0, -1 }
                                        };

namespace {

struct ImplColorSet
{
    BitmapColor maColor;
    sal_uInt16      mnIndex = 0;
    bool        mbSet = false;
};

}

static bool ImplColorSetCmpFnc( const ImplColorSet& lhs, const ImplColorSet& rhs)
{
    if( lhs.mbSet && rhs.mbSet )
    {
        const sal_uInt8 cLum1 = lhs.maColor.GetLuminance();
        const sal_uInt8 cLum2 = rhs.maColor.GetLuminance();
        return cLum1 < cLum2;
    }
    return lhs.mbSet > rhs.mbSet;
}

namespace {

class ImplPointArray
{
    std::unique_ptr<Point[]> mpArray;
    sal_uLong mnSize;
    sal_uLong mnRealSize;

public:

    ImplPointArray();

    void ImplSetSize( sal_uLong nSize );
    sal_uLong ImplGetRealSize() const { return mnRealSize; }
    void ImplSetRealSize( sal_uLong nRealSize ) { mnRealSize = nRealSize; }
    void ImplCreatePoly( tools::Polygon& rPoly ) const;

    inline Point& operator[]( sal_uLong nPos );
    inline const Point& operator[]( sal_uLong nPos ) const;

};

}

ImplPointArray::ImplPointArray() :
    mnSize      ( 0 ),
    mnRealSize  ( 0 )

{
}

void ImplPointArray::ImplSetSize( sal_uLong nSize )
{
    const sal_uLong nTotal = nSize * sizeof( Point );

    mnSize = nSize;
    mnRealSize = 0;

    mpArray = std::make_unique<Point[]>( nTotal );
}

inline Point& ImplPointArray::operator[]( sal_uLong nPos )
{
    SAL_WARN_IF( nPos >= mnSize, "vcl""ImplPointArray::operator[]: nPos out of range!" );
    return mpArray[ nPos ];
}

inline const Point& ImplPointArray::operator[]( sal_uLong nPos ) const
{
    SAL_WARN_IF( nPos >= mnSize, "vcl""ImplPointArray::operator[]: nPos out of range!" );
    return mpArray[ nPos ];
}

void ImplPointArray::ImplCreatePoly( tools::Polygon& rPoly ) const
{
    rPoly = tools::Polygon( sal::static_int_cast<sal_uInt16>(mnRealSize), mpArray.get() );
}

namespace {

class ImplVectMap
{
private:

    Scanline        mpBuf;
    Scanline*       mpScan;
    tools::Long            mnWidth;
    tools::Long            mnHeight;

public:

                    ImplVectMap( tools::Long nWidth, tools::Long nHeight );
                    ~ImplVectMap();

    tools::Long     Width() const { return mnWidth; }
    tools::Long     Height() const { return mnHeight; }

    inline void     Set( tools::Long nY, tools::Long nX, sal_uInt8 cVal );
    inline sal_uInt8        Get( tools::Long nY, tools::Long nX ) const;

    inline bool     IsFree( tools::Long nY, tools::Long nX ) const;
    inline bool     IsCont( tools::Long nY, tools::Long nX ) const;
    inline bool     IsDone( tools::Long nY, tools::Long nX ) const;

};

}

ImplVectMap::ImplVectMap( tools::Long nWidth, tools::Long nHeight ) :
    mpBuf ( static_cast<Scanline>(rtl_allocateZeroMemory(nWidth * nHeight)) ),
    mpScan ( static_cast<Scanline*>(std::malloc(nHeight * sizeof(Scanline))) ),
    mnWidth ( nWidth ),
    mnHeight( nHeight )
{
    assert(mpScan && "Don't handle OOM conditions");

    const tools::Long  nWidthAl = ( nWidth >> 2 ) + 1;
    Scanline    pTmp = mpBuf;

    for( tools::Long nY = 0; nY < nHeight; pTmp += nWidthAl )
        mpScan[ nY++ ] = pTmp;
}

ImplVectMap::~ImplVectMap()
{
    std::free( mpBuf );
    std::free( mpScan );
}

inline void ImplVectMap::Set( tools::Long nY, tools::Long nX, sal_uInt8 cVal )
{
    const sal_uInt8 cShift = sal::static_int_cast<sal_uInt8>(6 - ( ( nX & 3 ) << 1 ));
    auto & rPixel = mpScan[ nY ][ nX >> 2 ];
    rPixel = (rPixel & ~( 3 << cShift ) ) | ( cVal << cShift );
}

inline sal_uInt8    ImplVectMap::Get( tools::Long nY, tools::Long nX ) const
{
    return sal::static_int_cast<sal_uInt8>( ( ( mpScan[ nY ][ nX >> 2 ] ) >> ( 6 - ( ( nX & 3 ) << 1 ) ) ) & 3 );
}

inline bool ImplVectMap::IsFree( tools::Long nY, tools::Long nX ) const
{
    return( VECT_FREE_INDEX == Get( nY, nX ) );
}

inline bool ImplVectMap::IsCont( tools::Long nY, tools::Long nX ) const
{
    return( VECT_CONT_INDEX == Get( nY, nX ) );
}

inline bool ImplVectMap::IsDone( tools::Long nY, tools::Long nX ) const
{
    return( VECT_DONE_INDEX == Get( nY, nX ) );
}

namespace {

class ImplChain
{
private:

    tools::Polygon  maPoly;
    Point           maStartPt;
    sal_uLong       mnArraySize;
    sal_uLong       mnCount;
    std::unique_ptr<sal_uInt8[]>
                    mpCodes;

    void            ImplGetSpace();

    void            ImplPostProcess( const ImplPointArray& rArr );

    ImplChain(const ImplChain&) = delete;
    ImplChain& operator=(const ImplChain&) = delete;

public:

                    ImplChain();

    void            ImplBeginAdd( const Point& rStartPt );
    inline void     ImplAdd( sal_uInt8 nCode );
    void            ImplEndAdd( sal_uLong nTypeFlag );

    const tools::Polygon& ImplGetPoly() const { return maPoly; }
};

}

ImplChain::ImplChain() :
    mnArraySize ( 1024 ),
    mnCount     ( 0 ),
    mpCodes     ( new sal_uInt8[mnArraySize] )
{
}

void ImplChain::ImplGetSpace()
{
    const sal_uLong nOldArraySize = mnArraySize;
    sal_uInt8*      pNewCodes;

    mnArraySize = mnArraySize << 1;
    pNewCodes = new sal_uInt8[ mnArraySize ];
    memcpy( pNewCodes, mpCodes.get(), nOldArraySize );
    mpCodes.reset( pNewCodes );
}

void ImplChain::ImplBeginAdd( const Point& rStartPt )
{
    maPoly = tools::Polygon();
    maStartPt = rStartPt;
    mnCount = 0;
}

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 )
        {
            tools::Long nFirstX, nFirstY;
            tools::Long nLastX, nLastY;

            nFirstX = nLastX = maStartPt.X();
            nFirstY = nLastY = maStartPt.Y();
            aArr.ImplSetSize( mnCount << 1 );

            sal_uInt16 nPolyPos;
            sal_uLong i;
            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 ];
                bool                    bDone = 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 ].setX( nLastX );
                        aArr[ nPolyPos++ ].setY( nLastY - 1 );

                        aArr[ nPolyPos ].setX( nLastX - 1 );
                        aArr[ nPolyPos++ ].setY( nLastY - 1 );

                        aArr[ nPolyPos ].setX( nLastX - 1 );
                        aArr[ nPolyPos++ ].setY( nLastY );
                    }
                    else if( cMove == 3 && cNextMove == 0 )
                    {
                        aArr[ nPolyPos ].setX( nLastX - 1 );
                        aArr[ nPolyPos++ ].setY( nLastY );

                        aArr[ nPolyPos ].setX( nLastX - 1 );
                        aArr[ nPolyPos++ ].setY( nLastY + 1 );

                        aArr[ nPolyPos ].setX( nLastX );
                        aArr[ nPolyPos++ ].setY( nLastY + 1 );
                    }
                    else if( cMove == 0 && cNextMove == 1 )
                    {
                        aArr[ nPolyPos ].setX( nLastX );
                        aArr[ nPolyPos++ ].setY( nLastY + 1 );

                        aArr[ nPolyPos ].setX( nLastX + 1 );
                        aArr[ nPolyPos++ ].setY( nLastY + 1 );

                        aArr[ nPolyPos ].setX( nLastX + 1 );
                        aArr[ nPolyPos++ ].setY( nLastY );
                    }
                    else if( cMove == 1 && cNextMove == 2 )
                    {
                        aArr[ nPolyPos ].setX( nLastX + 1 );
                        aArr[ nPolyPos++ ].setY( nLastY + 1 );

                        aArr[ nPolyPos ].setX( nLastX + 1 );
                        aArr[ nPolyPos++ ].setY( nLastY - 1 );

                        aArr[ nPolyPos ].setX( nLastX );
                        aArr[ nPolyPos++ ].setY( nLastY - 1 );
                    }
                    else
                        bDone = false;
                }
                else if( cMove == 7 && cNextMove == 0 )
                {
                    aArr[ nPolyPos ].setX( nLastX - 1 );
                    aArr[ nPolyPos++ ].setY( nLastY );

                    aArr[ nPolyPos ].setX( nLastX );
                    aArr[ nPolyPos++ ].setY( nLastY + 1 );
                }
                else if( cMove == 4 && cNextMove == 1 )
                {
                    aArr[ nPolyPos ].setX( nLastX );
                    aArr[ nPolyPos++ ].setY( nLastY + 1 );

                    aArr[ nPolyPos ].setX( nLastX + 1 );
                    aArr[ nPolyPos++ ].setY( nLastY );
                }
                else
                    bDone = false;

                if( !bDone )
                {
                    aArr[ nPolyPos ].setX( nLastX + rMoveInner.nDX );
                    aArr[ nPolyPos++ ].setY( nLastY + rMoveInner.nDY );
                }
            }

            aArr[ nPolyPos ].setX( nFirstX + 1 );
            aArr[ nPolyPos++ ].setY( nFirstY + 1 );
            aArr.ImplSetRealSize( nPolyPos );
        }
        else if( nFlag & VECT_POLY_INLINE_OUTER )
        {
            tools::Long nFirstX, nFirstY;
            tools::Long nLastX, nLastY;

            nFirstX = nLastX = maStartPt.X();
            nFirstY = nLastY = maStartPt.Y();
            aArr.ImplSetSize( mnCount << 1 );

            sal_uInt16 nPolyPos;
            sal_uLong i;
            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 ];
                bool                    bDone = 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 ].setX( nLastX );
                        aArr[ nPolyPos++ ].setY( nLastY - 1 );

                        aArr[ nPolyPos ].setX( nLastX + 1 );
                        aArr[ nPolyPos++ ].setY( nLastY - 1 );

                        aArr[ nPolyPos ].setX( nLastX + 1 );
                        aArr[ nPolyPos++ ].setY( nLastY );
                    }
                    else if( cMove == 3 && cNextMove == 2 )
                    {
                        aArr[ nPolyPos ].setX( nLastX + 1 );
                        aArr[ nPolyPos++ ].setY( nLastY );

                        aArr[ nPolyPos ].setX( nLastX + 1 );
                        aArr[ nPolyPos++ ].setY( nLastY + 1 );

                        aArr[ nPolyPos ].setX( nLastX );
                        aArr[ nPolyPos++ ].setY( nLastY + 1 );
                    }
                    else if( cMove == 2 && cNextMove == 1 )
                    {
                        aArr[ nPolyPos ].setX( nLastX );
                        aArr[ nPolyPos++ ].setY( nLastY + 1 );

                        aArr[ nPolyPos ].setX( nLastX - 1 );
                        aArr[ nPolyPos++ ].setY( nLastY + 1 );

                        aArr[ nPolyPos ].setX( nLastX - 1 );
                        aArr[ nPolyPos++ ].setY( nLastY );
                    }
                    else if( cMove == 1 && cNextMove == 0 )
                    {
                        aArr[ nPolyPos ].setX( nLastX - 1 );
                        aArr[ nPolyPos++ ].setY( nLastY );

                        aArr[ nPolyPos ].setX( nLastX - 1 );
                        aArr[ nPolyPos++ ].setY( nLastY - 1 );

                        aArr[ nPolyPos ].setX( nLastX );
                        aArr[ nPolyPos++ ].setY( nLastY - 1 );
                    }
                    else
                        bDone = false;
                }
                else if( cMove == 7 && cNextMove == 3 )
                {
                    aArr[ nPolyPos ].setX( nLastX );
                    aArr[ nPolyPos++ ].setY( nLastY - 1 );

                    aArr[ nPolyPos ].setX( nLastX + 1 );
                    aArr[ nPolyPos++ ].setY( nLastY );
                }
                else if( cMove == 6 && cNextMove == 2 )
                {
                    aArr[ nPolyPos ].setX( nLastX + 1 );
                    aArr[ nPolyPos++ ].setY( nLastY );

                    aArr[ nPolyPos ].setX( nLastX );
                    aArr[ nPolyPos++ ].setY( nLastY + 1 );
                }
                else
                    bDone = false;

                if( !bDone )
                {
                    aArr[ nPolyPos ].setX( nLastX + rMoveOuter.nDX );
                    aArr[ nPolyPos++ ].setY( nLastY + rMoveOuter.nDY );
                }
            }

            aArr[ nPolyPos ].setX( nFirstX - 1 );
            aArr[ nPolyPos++ ].setY( nFirstY - 1 );
            aArr.ImplSetRealSize( nPolyPos );
        }
        else
        {
            tools::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 ] ];
                nLastX += rMove.nDX;
                nLastY += rMove.nDY;
                aArr[ ++i ] = Point( nLastX, nLastY );
            }

            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->setX( BACK_MAP( rArr[ 0 ].X() ) );
    pLast->setY( BACK_MAP( rArr[ 0 ].Y() ) );

    for( n = nNewPos = 1; n < nCount; )
    {
        const Point& rPt = rArr[ n++ ];
        const tools::Long   nX = BACK_MAP( rPt.X() );
        const tools::Long   nY = BACK_MAP( rPt.Y() );

        if( nX != pLast->X() || nY != pLast->Y() )
        {
            pLast = pLeast = &( aNewArr1[ nNewPos++ ] );
            pLeast->setX( nX );
            pLeast->setY( nY );
        }
    }

    nCount = nNewPos;
    aNewArr1.ImplSetRealSize( nCount );

    // 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++ ] );
        }

        pLast = pLeast;
        aNewArr2[ nNewPos++ ] = *pLast;
    }

    aNewArr2.ImplSetRealSize( nNewPos );
    aNewArr2.ImplCreatePoly( maPoly );
}

namespace vcl
{
void Vectorizer::updateProgress(tools::Long nProgress)
{
    if (mpProgress)
       mpProgress->Call(nProgress);
}

bool Vectorizer::vectorize(BitmapEx const& rBitmap, GDIMetaFile& rMetafile)
{
    bool bRet = false;

    updateProgress(0);

    std::optional<Bitmap> xBmp(std::in_place, rBitmap.GetBitmap());
    BitmapScopedReadAccess pRAcc(*xBmp);

    if( pRAcc )
    {
        double              fPercent = 0.0;
        double              fPercentStep_2 = 0.0;
        const tools::Long          nWidth = pRAcc->Width();
        const tools::Long          nHeight = pRAcc->Height();
        const sal_uInt16        nColorCount = pRAcc->GetPaletteEntryCount();
        sal_uInt16              n;
        std::array<ImplColorSet, 256> aColorSet;

        rMetafile.Clear();

        // get used palette colors and sort them from light to dark colors
        for( n = 0; n < nColorCount; n++ )
        {
            aColorSet[ n ].mnIndex = n;
            aColorSet[ n ].maColor = pRAcc->GetPaletteColor( n );
        }

        for( tools::Long nY = 0; nY < nHeight; nY++ )
        {
            Scanline pScanlineRead = pRAcc->GetScanline( nY );
            for( tools::Long nX = 0; nX < nWidth; nX++ )
                aColorSet[ pRAcc->GetIndexFromData( pScanlineRead, nX ) ].mbSet = true;
        }

        std::sort( aColorSet.begin(), aColorSet.end(), ImplColorSetCmpFnc );

        for( n = 0; n < 256; n++ )
            if( !aColorSet[ n ].mbSet )
                break;

        if( n )
            fPercentStep_2 = 45.0 / n;

        fPercent += 10.0;
        updateProgress(basegfx::fround<tools::Long>(fPercent));

        for( sal_uInt16 i = 0; i < n; i++ )
        {
            const BitmapColor   aBmpCol( pRAcc->GetPaletteColor( aColorSet[ i ].mnIndex ) );
            const Color         aFindColor( aBmpCol.GetRed(), aBmpCol.GetGreen(), aBmpCol.GetBlue() );
            std::optional<ImplVectMap> oMap;
            ImplExpand( oMap, pRAcc.get(), aFindColor );

            fPercent += fPercentStep_2;
            updateProgress(basegfx::fround<tools::Long>(fPercent));

            if( oMap )
            {
                tools::PolyPolygon         aPolyPoly;
                ImplCalculate(*oMap, aPolyPoly, mnReduce);
                oMap.reset();

                if( aPolyPoly.Count() )
                {
                    ImplLimitPolyPoly( aPolyPoly );

                    aPolyPoly.Optimize( PolyOptimizeFlags::EDGES );

                    if( aPolyPoly.Count() )
                    {
                        rMetafile.AddAction( new MetaLineColorAction( aFindColor, true ) );
                        rMetafile.AddAction( new MetaFillColorAction( aFindColor, true ) );
                        rMetafile.AddAction( new MetaPolyPolygonAction( std::move(aPolyPoly) ) );
                    }
                }
            }

            fPercent += fPercentStep_2;
            updateProgress(basegfx::fround<tools::Long>(fPercent));
        }

        if (rMetafile.GetActionSize())
        {
            MapMode         aMap( MapUnit::Map100thMM );
            ScopedVclPtrInstance< VirtualDevice > aVDev;
            const Size      aLogSize1( aVDev->PixelToLogic( Size( 1, 1 ), aMap ) );

            rMetafile.SetPrefMapMode( aMap );
            rMetafile.SetPrefSize( Size( nWidth + 2, nHeight + 2 ) );
            rMetafile.Move( 1, 1 );
            rMetafile.Scale( aLogSize1.Width(), aLogSize1.Height() );
            bRet = true;
        }
    }

    pRAcc.reset();
    xBmp.reset();
    updateProgress(100);

    return bRet;
}

void ImplLimitPolyPoly( tools::PolyPolygon& rPolyPoly )
{
    if( rPolyPoly.Count() <= VECT_POLY_MAX )
        return;

    tools::PolyPolygon aNewPolyPoly;
    tools::Long        nReduce = 0;
    sal_uInt16      nNewCount;

    do
    {
        aNewPolyPoly.Clear();
        nReduce++;

        for( sal_uInt16 i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ )
        {
            const tools::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 = std::move(aNewPolyPoly);
}

void ImplExpand( std::optional<ImplVectMap>& oMap, const BitmapReadAccess* pRAcc, const Color& rColor )
{
    if( !pRAcc || !pRAcc->Width() || !pRAcc->Height() )
        return;

    const tools::Long          nOldWidth = pRAcc->Width();
    const tools::Long          nOldHeight = pRAcc->Height();
    const tools::Long          nNewWidth = ( nOldWidth << 2 ) + 4;
    const tools::Long          nNewHeight = ( nOldHeight << 2 ) + 4;
    const BitmapColor   aTest( pRAcc->GetBestMatchingColor( rColor ) );
    std::unique_ptr<sal_Int32[]> pMapIn(new sal_Int32[ std::max( nOldWidth, nOldHeight ) ]);
    std::unique_ptr<sal_Int32[]> pMapOut(new sal_Int32[ std::max( nOldWidth, nOldHeight ) ]);
    tools::Long                nX, nY, nTmpX, nTmpY;

    oMap.emplace( nNewWidth, nNewHeight );

    for( nX = 0; nX < nOldWidth; nX++ )
        VECT_MAP( pMapIn, pMapOut, nX );

    for( nY = 0, nTmpY = 5; nY < nOldHeight; nY++, nTmpY += 4 )
    {
        Scanline pScanlineRead = pRAcc->GetScanline( nY );
        for( nX = 0; nX < nOldWidth; )
        {
            if( pRAcc->GetPixelFromData( pScanlineRead, nX ) == aTest )
            {
                nTmpX = pMapIn[ nX++ ];
                nTmpY -= 3;

                oMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
                oMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
                oMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
                oMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );

                while( nX < nOldWidth && pRAcc->GetPixelFromData( pScanlineRead, nX ) == aTest )
                     nX++;

                nTmpX = pMapOut[ nX - 1 ];
                nTmpY -= 3;

                oMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
                oMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
                oMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
                oMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
            }
            else
                nX++;
        }
    }

    for( nY = 0; nY < nOldHeight; nY++ )
        VECT_MAP( pMapIn, pMapOut, nY );

    for( nX = 0, nTmpX = 5; nX < nOldWidth; nX++, nTmpX += 4 )
    {
        for( nY = 0; nY < nOldHeight; )
        {
            if( pRAcc->GetPixel( nY, nX ) == aTest )
            {
                nTmpX -= 3;
                nTmpY = pMapIn[ nY++ ];

                oMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
                oMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
                oMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
                oMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );

                while( nY < nOldHeight && pRAcc->GetPixel( nY, nX ) == aTest )
                    nY++;

                nTmpX -= 3;
                nTmpY = pMapOut[ nY - 1 ];

                oMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
                oMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
                oMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
                oMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
            }
            else
                nY++;
        }
    }
}

void ImplCalculate( ImplVectMap& rMap, tools::PolyPolygon& rPolyPoly, sal_uInt8 cReduce )
{
    const tools::Long nWidth = rMap.Width(), nHeight = rMap.Height();

    for( tools::Long nY = 0; nY < nHeight; nY++ )
    {
        tools::Long    nX = 0;
        bool    bInner = true;

        while( nX < nWidth )
        {
            // skip free
            while( ( nX < nWidth ) && rMap.IsFree( nY, nX ) )
                nX++;

            if( nX == nWidth )
                break;

            if( rMap.IsCont( nY, nX ) )
            {
                // new contour
                ImplChain   aChain;
                const Point aStartPt( nX++, nY );

                // get chain code
                aChain.ImplBeginAdd( aStartPt );
                ImplGetChain( rMap, aStartPt, aChain );

                aChain.ImplEndAdd( bInner ? VECT_POLY_OUTLINE_INNER : VECT_POLY_OUTLINE_OUTER );

                const tools::Polygon& rPoly = aChain.ImplGetPoly();

                if( rPoly.GetSize() > 2 )
                {
                    if( cReduce )
                    {
                        const tools::Rectangle aBound( rPoly.GetBoundRect() );

                        if( aBound.GetWidth() > cReduce && aBound.GetHeight() > cReduce )
                            rPolyPoly.Insert( rPoly );
                    }
                    else
                        rPolyPoly.Insert( rPoly  );
                }

                // skip rest of detected contour
                while( rMap.IsCont( nY, nX ) )
                    nX++;
            }
            else
            {
                // process done segment
                const tools::Long nStartSegX = nX++;

                while( rMap.IsDone( nY, nX ) )
                    nX++;

                if( ( ( nX - nStartSegX ) == 1 ) || ( ImplIsUp( rMap, nY, nStartSegX ) != ImplIsUp( rMap, nY, nX - 1 ) ) )
                    bInner = !bInner;
            }
        }
    }
}

bool ImplGetChain(  ImplVectMap& rMap, const Point& rStartPt, ImplChain& rChain )
{
    tools::Long                nActX = rStartPt.X();
    tools::Long                nActY = rStartPt.Y();
    sal_uLong               nFound;
    sal_uLong               nLastDir = 0;
    sal_uLong               nDir;

    do
    {
        nFound = 0;

        // first try last direction
        tools::Long nTryX = nActX + aImplMove[ nLastDir ].nDX;
        tools::Long nTryY = nActY + aImplMove[ nLastDir ].nDY;

        if( rMap.IsCont( nTryY, nTryX ) )
        {
            rChain.ImplAdd( static_cast<sal_uInt8>(nLastDir) );
            nActY = nTryY;
            nActX = nTryX;
            rMap.Set( nActY, nActX, VECT_DONE_INDEX );
            nFound = 1;
        }
        else
        {
            // try other directions
            for( nDir = 0; nDir < 8; nDir++ )
            {
                // we already tried nLastDir
                if( nDir != nLastDir )
                {
                    nTryX = nActX + aImplMove[ nDir ].nDX;
                    nTryY = nActY + aImplMove[ nDir ].nDY;

                    if( rMap.IsCont( nTryY, nTryX ) )
                    {
                        rChain.ImplAdd( static_cast<sal_uInt8>(nDir) );
                        nActY = nTryY;
                        nActX = nTryX;
                        rMap.Set( nActY, nActX, VECT_DONE_INDEX );
                        nFound = 1;
                        nLastDir = nDir;
                        break;
                    }
                }
            }
        }
    }
    while( nFound );

    return true;
}

bool ImplIsUp( ImplVectMap const & rMap, tools::Long nY, tools::Long nX )
{
    if( rMap.IsDone( nY - 1, nX ) )
        return true;
    else if( rMap.IsDone( nY + 1, nX ) )
        return false;
    else if( rMap.IsDone( nY - 1, nX - 1 ) || rMap.IsDone( nY - 1, nX + 1 ) )
        return true;
    else
        return false;
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=96 H=91 G=93

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.