Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/canvas/source/directx/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 22 kB image not shown  

Quelle  dx_surfacebitmap.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/config.h>

#include <memory>
#include <string.h>

#include <com/sun/star/rendering/ColorComponentTag.hpp>

#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/range/b2irange.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <rendering/icolorbuffer.hxx>

#include "dx_graphicsprovider.hxx"
#include "dx_impltools.hxx"
#include "dx_surfacebitmap.hxx"
#include "dx_surfacegraphics.hxx"

using namespace ::com::sun::star;

namespace dxcanvas
{
    namespace
    {

        // DXColorBuffer


        struct DXColorBuffer : public canvas::IColorBuffer
        {
        public:
            DXColorBuffer( const sal::systools::COMReference<surface_type>& rSurface,
                           const ::basegfx::B2ISize& rSize )
                : maSize(rSize)
                , maLockedRect{}
                , mpSurface(rSurface)
            {
            }

        // implementation of the 'IColorBuffer' interface
        public:

            virtual sal_uInt8* lock() const override;
            virtual void       unlock() const override;
            virtual sal_uInt32 getWidth() const override;
            virtual sal_uInt32 getHeight() const override;
            virtual sal_uInt32 getStride() const override;
            virtual Format     getFormat() const override;

        private:

            ::basegfx::B2ISize maSize;
            mutable D3DLOCKED_RECT maLockedRect;
            sal::systools::COMReference<surface_type> mpSurface;
        };

        sal_uInt8* DXColorBuffer::lock() const
        {
            if(SUCCEEDED(mpSurface->LockRect(&maLockedRect,nullptr,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
                return static_cast<sal_uInt8 *>(maLockedRect.pBits);
            return nullptr;
        }

        void DXColorBuffer::unlock() const
        {
            mpSurface->UnlockRect();
        }

        sal_uInt32 DXColorBuffer::getWidth() const
        {
            return maSize.getWidth();
        }

        sal_uInt32 DXColorBuffer::getHeight() const
        {
            return maSize.getHeight();
        }

        sal_uInt32 DXColorBuffer::getStride() const
        {
            return maLockedRect.Pitch;
        }

        canvas::IColorBuffer::Format DXColorBuffer::getFormat() const
        {
            return canvas::IColorBuffer::Format::X8R8G8B8;
        }


        // GDIColorBuffer


        struct GDIColorBuffer : public canvas::IColorBuffer
        {
        public:

            GDIColorBuffer( const BitmapSharedPtr&      rSurface,
                            const ::basegfx::B2ISize& rSize )
                : maSize(rSize)
                , aBmpData{}
                , mpGDIPlusBitmap(rSurface)
            {
            }

        // implementation of the 'IColorBuffer' interface
        public:

            virtual sal_uInt8* lock() const override;
            virtual void       unlock() const override;
            virtual sal_uInt32 getWidth() const override;
            virtual sal_uInt32 getHeight() const override;
            virtual sal_uInt32 getStride() const override;
            virtual Format     getFormat() const override;

        private:

            ::basegfx::B2ISize maSize;
            mutable Gdiplus::BitmapData aBmpData;
            BitmapSharedPtr mpGDIPlusBitmap;
        };

        sal_uInt8* GDIColorBuffer::lock() const
        {
            aBmpData.Width = maSize.getWidth();
            aBmpData.Height = maSize.getHeight();
            aBmpData.Stride = 4*aBmpData.Width;
            aBmpData.PixelFormat = PixelFormat32bppARGB;
            aBmpData.Scan0 = nullptr;
            const Gdiplus::Rect aRect( 0,0,aBmpData.Width,aBmpData.Height );
            if( Gdiplus::Ok != mpGDIPlusBitmap->LockBits( &aRect,
                                                          Gdiplus::ImageLockModeRead,
                                                          PixelFormat32bppARGB,
                                                          &aBmpData ) )
            {
                return nullptr;
            }

            return static_cast<sal_uInt8*>(aBmpData.Scan0);
        }

        void GDIColorBuffer::unlock() const
        {
            mpGDIPlusBitmap->UnlockBits( &aBmpData );
        }

        sal_uInt32 GDIColorBuffer::getWidth() const
        {
            return maSize.getWidth();
        }

        sal_uInt32 GDIColorBuffer::getHeight() const
        {
            return maSize.getHeight();
        }

        sal_uInt32 GDIColorBuffer::getStride() const
        {
            return aBmpData.Stride;
        }

        canvas::IColorBuffer::Format GDIColorBuffer::getFormat() const
        {
            return canvas::IColorBuffer::Format::A8R8G8B8;
        }
    }


    // DXSurfaceBitmap::DXSurfaceBitmap


    DXSurfaceBitmap::DXSurfaceBitmap( const ::basegfx::B2ISize& rSize,
                                      const std::shared_ptr<canvas::ISurfaceProxyManager>&  rMgr,
                                      const IDXRenderModuleSharedPtr& rRenderModule,
                                      bool bWithAlpha ) :
        mpGdiPlusUser( GDIPlusUser::createInstance() ),
        maSize(rSize),
        mpRenderModule(rRenderModule),
        mpSurfaceManager(rMgr),
        mpSurfaceProxy(),
        mpSurface(),
        mpGDIPlusBitmap(),
        mpGraphics(),
        mpColorBuffer(),
        mbIsSurfaceDirty(true),
        mbAlpha(bWithAlpha)
    {
        init();
    }


    // DXSurfaceBitmap::getSize


    ::basegfx::B2ISize DXSurfaceBitmap::getSize() const
    {
        return maSize;
    }


    // DXSurfaceBitmap::init


    void DXSurfaceBitmap::init()
    {
        // create container for pixel data
        if(mbAlpha)
        {
            mpGDIPlusBitmap = std::make_shared<Gdiplus::Bitmap>(
                    maSize.getWidth(),
                    maSize.getHeight(),
                    PixelFormat32bppARGB
                    );
            mpGraphics = tools::createGraphicsFromBitmap(mpGDIPlusBitmap);

            // create the colorbuffer object, which is basically a simple
            // wrapper around the directx surface. the colorbuffer is the
            // interface which is used by the surfaceproxy to support any
            // kind of underlying structure for the pixel data container.
            mpColorBuffer = std::make_shared<GDIColorBuffer>(mpGDIPlusBitmap, maSize);
        }
        else
        {
            mpSurface = mpRenderModule->createSystemMemorySurface(maSize);

            // create the colorbuffer object, which is basically a simple
            // wrapper around the directx surface. the colorbuffer is the
            // interface which is used by the surfaceproxy to support any
            // kind of underlying structure for the pixel data container.
            mpColorBuffer = std::make_shared<DXColorBuffer>(mpSurface, maSize);
        }

        // create a (possibly hardware accelerated) mirror surface.
        mpSurfaceProxy = mpSurfaceManager->createSurfaceProxy(mpColorBuffer);
    }


    // DXSurfaceBitmap::resize


    bool DXSurfaceBitmap::resize(const ::basegfx::B2ISize& rSize)
    {
        if(maSize != rSize)
        {
            maSize = rSize;
            init();
        }

        return true;
    }


    // DXSurfaceBitmap::clear


    void DXSurfaceBitmap::clear()
    {
        GraphicsSharedPtr pGraphics(getGraphics());
        Gdiplus::Color transColor(255,0,0,0);
        pGraphics->SetCompositingMode( Gdiplus::CompositingModeSourceCopy );
        pGraphics->Clear( transColor );
    }


    // DXSurfaceBitmap::hasAlpha


    bool DXSurfaceBitmap::hasAlpha() const
    {
        return mbAlpha;
    }


    // DXSurfaceBitmap::getGraphics


    GraphicsSharedPtr DXSurfaceBitmap::getGraphics()
    {
        // since clients will most probably draw directly
        // to the GDI+ bitmap, we need to mark it as dirty
        // to ensure that the corresponding dxsurface will
        // be updated.
        mbIsSurfaceDirty = true;

        if(hasAlpha())
            return mpGraphics;
        else
            return createSurfaceGraphics(mpSurface);
    }


    // DXSurfaceBitmap::getBitmap


    BitmapSharedPtr DXSurfaceBitmap::getBitmap() const
    {
        if(hasAlpha())
            return mpGDIPlusBitmap;

        BitmapSharedPtr pResult;

        D3DLOCKED_RECT aLockedRect;
        if(SUCCEEDED(mpSurface->LockRect(&aLockedRect,nullptr,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
        {
            // decide about the format we pass the gdi+, the directx surface is always
            // 32bit, either with or without alpha component.
            Gdiplus::PixelFormat nFormat = hasAlpha() ? PixelFormat32bppARGB : PixelFormat32bppRGB;

            // construct a gdi+ bitmap from the raw pixel data.
            pResult = std::make_shared<Gdiplus::Bitmap>(maSize.getWidth(), maSize.getHeight(),
                                                aLockedRect.Pitch,
                                                nFormat,
                                                static_cast<BYTE *>(aLockedRect.pBits) );

            mpSurface->UnlockRect();
        }

        return pResult;
    }


    // DXSurfaceBitmap::draw


    bool DXSurfaceBitmap::draw( double                           fAlpha,
                                const ::basegfx::B2DPoint&       rPos,
                                const ::basegfx::B2DPolyPolygon& rClipPoly,
                                const ::basegfx::B2DHomMatrix&   rTransform )
    {
        if( mbIsSurfaceDirty )
        {
            mpSurfaceProxy->setColorBufferDirty();
            mbIsSurfaceDirty = false;
        }

        return mpSurfaceProxy->draw( fAlpha, rPos, rClipPoly, rTransform );
    }


    // DXSurfaceBitmap::draw


    bool DXSurfaceBitmap::draw( double                         fAlpha,
                                const ::basegfx::B2DPoint&     rPos,
                                const ::basegfx::B2DRange&     rArea,
                                const ::basegfx::B2DHomMatrix& rTransform )
    {
        if( mbIsSurfaceDirty )
        {
            mpSurfaceProxy->setColorBufferDirty();
            mbIsSurfaceDirty = false;
        }

        return mpSurfaceProxy->draw( fAlpha, rPos, rArea, rTransform );
    }


    // DXSurfaceBitmap::draw


    bool DXSurfaceBitmap::draw( double                         fAlpha,
                                const ::basegfx::B2DPoint&     rPos,
                                const ::basegfx::B2DHomMatrix& rTransform )
    {
        if( mbIsSurfaceDirty )
        {
            mpSurfaceProxy->setColorBufferDirty();
            mbIsSurfaceDirty = false;
        }

        return mpSurfaceProxy->draw( fAlpha, rPos, rTransform );
    }


    // DXSurfaceBitmap::draw


    bool DXSurfaceBitmap::draw( const ::basegfx::B2IRange& rArea )
    {
        if( mbIsSurfaceDirty )
        {
            mpSurfaceProxy->setColorBufferDirty();
            mbIsSurfaceDirty = false;
        }

        const double                  fAlpha(1.0);
        const ::basegfx::B2DHomMatrix aTransform;
        const ::basegfx::B2DRange     aIEEEArea( rArea );
        return mpSurfaceProxy->draw(fAlpha,
                                    ::basegfx::B2DPoint(),
                                    aIEEEArea,
                                    aTransform);
    }


    // DXSurfaceBitmap::getData


    uno::Sequence< sal_Int8 > DXSurfaceBitmap::getData( rendering::IntegerBitmapLayout& ;rBitmapLayout,
                                                        const geometry::IntegerRectangle2D& rect )
    {
        if(hasAlpha())
        {
            uno::Sequence< sal_Int8 > aRes( (rect.X2-rect.X1)*(rect.Y2-rect.Y1)*4 ); // TODO(F1): Be format-agnostic here

            const Gdiplus::Rect aRect( tools::gdiPlusRectFromIntegerRectangle2D( rect ) );

            Gdiplus::BitmapData aBmpData;
            aBmpData.Width       = rect.X2-rect.X1;
            aBmpData.Height      = rect.Y2-rect.Y1;
            aBmpData.Stride      = 4*aBmpData.Width;
            aBmpData.PixelFormat = PixelFormat32bppARGB;
            aBmpData.Scan0       = aRes.getArray();

            // TODO(F1): Support more pixel formats natively

            // read data from bitmap
            if( Gdiplus::Ok != mpGDIPlusBitmap->LockBits( &aRect,
                                                Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeUserInputBuf,
                                                PixelFormat32bppARGB, // TODO(F1): Adapt to
                                                                           // Graphics native
                                                                        // format/change
                                                                        // getMemoryLayout
                                                &aBmpData ) )
            {
                // failed to lock, bail out
                return uno::Sequence< sal_Int8 >();
            }

            mpGDIPlusBitmap->UnlockBits( &aBmpData );

            return aRes;
        }
        else
        {
            sal_uInt32 nWidth = rect.X2-rect.X1;
            sal_uInt32 nHeight = rect.Y2-rect.Y1;

            uno::Sequence< sal_Int8 > aRes(nWidth*nHeight*4);

            D3DLOCKED_RECT aLockedRect;
            if(FAILED(mpSurface->LockRect(&aLockedRect,nullptr,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
                return uno::Sequence< sal_Int8 >();
            D3DSURFACE_DESC aDesc;
            if(FAILED(mpSurface->GetDesc(&aDesc)))
                return uno::Sequence< sal_Int8 >();

            assert(aDesc.Format == D3DFMT_A8R8G8B8 || aDesc.Format == D3DFMT_X8R8G8B8);

            sal_uInt8 *pSrc = (static_cast<BYTE *>(aLockedRect.pBits)+(rect.Y1*aLockedRect.Pitch))+rect.X1;
            sal_uInt8 *pDst = reinterpret_cast<sal_uInt8 *>(aRes.getArray());
            sal_uInt32 nSegmentSizeInBytes = nWidth*4;
            for(sal_uInt32 y=0; y<nHeight; ++y)
            {
                memcpy(pDst,pSrc,nSegmentSizeInBytes);
                pDst += nSegmentSizeInBytes;
                pSrc += aLockedRect.Pitch;
            }

            if(rBitmapLayout.ColorSpace->getComponentTags().getArray()[0] == rendering::ColorComponentTag::RGB_RED &&
               rBitmapLayout.ColorSpace->getComponentTags().getArray()[2] == rendering::ColorComponentTag::RGB_BLUE)
            {
                pDst = reinterpret_cast<sal_uInt8 *>(aRes.getArray());
                for(sal_uInt32 y=0; y<nHeight; ++y)
                {
                    sal_uInt8* pPixel = pDst;
                    for(sal_uInt32 n = 0; n<nWidth; n++)
                    {
                        sal_uInt8 nB = pPixel[0];
                        pPixel[0] = pPixel[2];
                        pPixel[2] = nB;
                        pPixel += 4;
                    }
                    pDst += nSegmentSizeInBytes;
                }
            }

            mpSurface->UnlockRect();
            return aRes;
        }
    }


    // DXSurfaceBitmap::setData


    void DXSurfaceBitmap::setData( const uno::Sequence< sal_Int8 >&      data,
                                   const rendering::IntegerBitmapLayout& /*bitmapLayout*/,
                                   const geometry::IntegerRectangle2D&   rect )
    {
        if(hasAlpha())
        {
            const Gdiplus::Rect aRect( tools::gdiPlusRectFromIntegerRectangle2D( rect ) );

            Gdiplus::BitmapData aBmpData;
            aBmpData.Width       = rect.X2-rect.X1;
            aBmpData.Height      = rect.Y2-rect.Y1;
            aBmpData.Stride      = 4*aBmpData.Width;
            aBmpData.PixelFormat = PixelFormat32bppARGB;
            aBmpData.Scan0       = const_cast<sal_Int8 *>(data.getConstArray());

            // TODO(F1): Support more pixel formats natively

            if( Gdiplus::Ok != mpGDIPlusBitmap->LockBits( &aRect,
                                                Gdiplus::ImageLockModeWrite | Gdiplus::ImageLockModeUserInputBuf,
                                                PixelFormat32bppARGB, // TODO: Adapt to
                                                                           // Graphics native
                                                                          // format/change
                                                                          // getMemoryLayout
                                                &aBmpData ) )
            {
                throw uno::RuntimeException("GDIPlus method call was unsuccessful, problem with locking bitmap aRect object");
            }

            // commit data to bitmap
            mpGDIPlusBitmap->UnlockBits( &aBmpData );
        }
        else
        {
            sal_uInt32 nWidth = rect.X2-rect.X1;
            sal_uInt32 nHeight = rect.Y2-rect.Y1;

            // lock the directx surface to receive the pointer to the surface memory.
            D3DLOCKED_RECT aLockedRect;
            if(FAILED(mpSurface->LockRect(&aLockedRect,nullptr,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
                throw uno::RuntimeException("failed to lock directx surface to surface memory");

            auto* pSrc = data.getConstArray();
            sal_uInt8 *pDst = (static_cast<BYTE *>(aLockedRect.pBits)+(rect.Y1*aLockedRect.Pitch))+rect.X1;
            sal_uInt32 nSegmentSizeInBytes = nWidth<<4;
            for(sal_uInt32 y=0; y<nHeight; ++y)
            {
                memcpy(pDst,pSrc,nSegmentSizeInBytes);
                pSrc += nSegmentSizeInBytes;
                pDst += aLockedRect.Pitch;
            }

            mpSurface->UnlockRect();
        }

        mbIsSurfaceDirty = true;
    }


    // DXSurfaceBitmap::setPixel


    void DXSurfaceBitmap::setPixel( const uno::Sequence< sal_Int8 >&      color,
                                    const rendering::IntegerBitmapLayout& /*bitmapLayout*/,
                                    const geometry::IntegerPoint2D&       pos )
    {
        if(hasAlpha())
        {
            const geometry::IntegerSize2D aSize( maSize.getWidth(), maSize.getHeight() );

            ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aSize.Width,
                            "CanvasHelper::setPixel: X coordinate out of bounds" );
            ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aSize.Height,
                            "CanvasHelper::setPixel: Y coordinate out of bounds" );
            ENSURE_ARG_OR_THROW( color.getLength() > 3,
                            "CanvasHelper::setPixel: not enough color components" );

            if( Gdiplus::Ok != mpGDIPlusBitmap->SetPixel( pos.X, pos.Y,
                                                Gdiplus::Color( tools::sequenceToArgb( color ))))
            {
                throw uno::RuntimeException("Problem with setting the color of bitmap object");
            }
        }
        else
        {
            ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < maSize.getWidth(),
                            "CanvasHelper::setPixel: X coordinate out of bounds" );
            ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < maSize.getHeight(),
                            "CanvasHelper::setPixel: Y coordinate out of bounds" );
            ENSURE_ARG_OR_THROW( color.getLength() > 3,
                            "CanvasHelper::setPixel: not enough color components" );

            Gdiplus::Color aColor(tools::sequenceToArgb(color));

            // lock the directx surface to receive the pointer to the surface memory.
            D3DLOCKED_RECT aLockedRect;
            if(FAILED(mpSurface->LockRect(&aLockedRect,nullptr,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
                throw uno::RuntimeException("cannot lock the directx surface to surface memory");

            sal_uInt32 *pDst = reinterpret_cast<sal_uInt32 *>((static_cast<BYTE *>(aLockedRect.pBits)+(pos.Y*aLockedRect.Pitch))+pos.X);
            *pDst = aColor.GetValue();
            mpSurface->UnlockRect();
        }

        mbIsSurfaceDirty = true;
    }


    // DXSurfaceBitmap::getPixel


    uno::Sequence< sal_Int8 > DXSurfaceBitmap::getPixel( rendering::IntegerBitmapLayout&&nbsp;  /*bitmapLayout*/,
                                                         const geometry::IntegerPoint2D&   pos )
    {
        if(hasAlpha())
        {
            const geometry::IntegerSize2D aSize(maSize.getWidth(), maSize.getHeight());

            ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aSize.Width,
                            "CanvasHelper::getPixel: X coordinate out of bounds" );
            ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aSize.Height,
                            "CanvasHelper::getPixel: Y coordinate out of bounds" );

            Gdiplus::Color aColor;

            if( Gdiplus::Ok != mpGDIPlusBitmap->GetPixel( pos.X, pos.Y, &aColor ) )
                return uno::Sequence< sal_Int8 >();

            return tools::argbToIntSequence(aColor.GetValue());
        }
        else
        {
            ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < maSize.getWidth(),
                            "CanvasHelper::getPixel: X coordinate out of bounds" );
            ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < maSize.getHeight(),
                            "CanvasHelper::getPixel: Y coordinate out of bounds" );

            // lock the directx surface to receive the pointer to the surface memory.
            D3DLOCKED_RECT aLockedRect;
            if(FAILED(mpSurface->LockRect(&aLockedRect,nullptr,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
                throw uno::RuntimeException("failed to lock directX surface to surface memory");

            sal_uInt32 *pDst = reinterpret_cast<sal_uInt32 *>((static_cast<BYTE *>(aLockedRect.pBits)+(pos.Y*aLockedRect.Pitch))+pos.X);
            Gdiplus::Color aColor(*pDst);
            mpSurface->UnlockRect();

            return tools::argbToIntSequence(aColor.GetValue());
        }
    }
}

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

Messung V0.5
C=95 H=94 G=94

¤ Dauer der Verarbeitung: 0.8 Sekunden  ¤

*© 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.