| /************************************************************** |
| * |
| * 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_canvas.hxx" |
| |
| #include <ctype.h> // don't ask. msdev breaks otherwise... |
| #include <canvas/debug.hxx> |
| #include <canvas/canvastools.hxx> |
| #include <tools/diagnose_ex.h> |
| |
| #include <vcl/bitmapex.hxx> |
| |
| #include <boost/preprocessor/repetition.hpp> |
| #include <boost/preprocessor/iteration/local.hpp> |
| #include <boost/scoped_array.hpp> |
| |
| #include "dx_canvasbitmap.hxx" |
| #include "dx_impltools.hxx" |
| |
| |
| using namespace ::com::sun::star; |
| |
| namespace dxcanvas |
| { |
| CanvasBitmap::CanvasBitmap( const IBitmapSharedPtr& rBitmap, |
| const DeviceRef& rDevice ) : |
| mpDevice( rDevice ), |
| mpBitmap( rBitmap ) |
| { |
| ENSURE_OR_THROW( mpDevice.is() && mpBitmap, |
| "CanvasBitmap::CanvasBitmap(): Invalid surface or device" ); |
| |
| maCanvasHelper.setDevice( *mpDevice.get() ); |
| maCanvasHelper.setTarget( mpBitmap ); |
| } |
| |
| void SAL_CALL CanvasBitmap::disposing() |
| { |
| mpBitmap.reset(); |
| mpDevice.clear(); |
| |
| // forward to parent |
| CanvasBitmap_Base::disposing(); |
| } |
| |
| struct AlphaDIB |
| { |
| BITMAPINFOHEADER bmiHeader; |
| RGBQUAD bmiColors[256]; |
| }; |
| |
| uno::Any SAL_CALL CanvasBitmap::getFastPropertyValue( sal_Int32 nHandle ) throw (uno::RuntimeException) |
| { |
| uno::Any aRes; |
| // 0 ... get BitmapEx |
| // 1 ... get Pixbuf with bitmap RGB content |
| // 2 ... get Pixbuf with bitmap alpha mask |
| switch( nHandle ) |
| { |
| // sorry, no BitmapEx here... |
| case 0: |
| aRes = ::com::sun::star::uno::Any( reinterpret_cast<sal_Int64>( (BitmapEx*) NULL ) ); |
| break; |
| |
| case 1: |
| { |
| if(!mpBitmap->hasAlpha()) |
| { |
| HBITMAP aHBmp; |
| mpBitmap->getBitmap()->GetHBITMAP(Gdiplus::Color(), &aHBmp ); |
| |
| uno::Sequence< uno::Any > args(1); |
| args[0] = uno::Any( sal_Int64(aHBmp) ); |
| |
| aRes <<= args; |
| } |
| else |
| { |
| // need to copy&convert the bitmap, since dx |
| // canvas uses inline alpha channel |
| HDC hScreenDC=GetDC(NULL); |
| const basegfx::B2IVector aSize(mpBitmap->getSize()); |
| HBITMAP hBmpBitmap = CreateCompatibleBitmap( hScreenDC, |
| aSize.getX(), |
| aSize.getY() ); |
| if( !hBmpBitmap ) |
| return aRes; |
| |
| BITMAPINFOHEADER aBIH; |
| |
| aBIH.biSize = sizeof( BITMAPINFOHEADER ); |
| aBIH.biWidth = aSize.getX(); |
| aBIH.biHeight = -aSize.getY(); |
| aBIH.biPlanes = 1; |
| aBIH.biBitCount = 32; |
| aBIH.biCompression = BI_RGB; // expects pixel in |
| // bbggrrxx format |
| // (little endian) |
| aBIH.biSizeImage = 0; |
| aBIH.biXPelsPerMeter = 0; |
| aBIH.biYPelsPerMeter = 0; |
| aBIH.biClrUsed = 0; |
| aBIH.biClrImportant = 0; |
| |
| Gdiplus::BitmapData aBmpData; |
| aBmpData.Width = aSize.getX(); |
| aBmpData.Height = aSize.getY(); |
| aBmpData.Stride = 4*aBmpData.Width; |
| aBmpData.PixelFormat = PixelFormat32bppARGB; |
| aBmpData.Scan0 = NULL; |
| const Gdiplus::Rect aRect( 0,0,aSize.getX(),aSize.getY() ); |
| BitmapSharedPtr pGDIPlusBitmap=mpBitmap->getBitmap(); |
| if( Gdiplus::Ok != pGDIPlusBitmap->LockBits( &aRect, |
| Gdiplus::ImageLockModeRead, |
| PixelFormat32bppARGB, // outputs ARGB (big endian) |
| &aBmpData ) ) |
| { |
| // failed to lock, bail out |
| return aRes; |
| } |
| |
| // now aBmpData.Scan0 contains our bits - push |
| // them into HBITMAP, ignoring alpha |
| SetDIBits( hScreenDC, hBmpBitmap, 0, aSize.getY(), aBmpData.Scan0, (PBITMAPINFO)&aBIH, DIB_RGB_COLORS ); |
| |
| pGDIPlusBitmap->UnlockBits( &aBmpData ); |
| |
| uno::Sequence< uno::Any > args(1); |
| args[0] = uno::Any( sal_Int64(hBmpBitmap) ); |
| |
| aRes <<= args; |
| } |
| } |
| break; |
| |
| case 2: |
| { |
| if(!mpBitmap->hasAlpha()) |
| { |
| return aRes; |
| } |
| else |
| { |
| static AlphaDIB aDIB= |
| { |
| {0,0,0,1,8,BI_RGB,0,0,0,0,0}, |
| { |
| // this here fills palette with grey |
| // level colors, starting from 0,0,0 |
| // up to 255,255,255 |
| #define BOOST_PP_LOCAL_MACRO(n_) \ |
| BOOST_PP_COMMA_IF(n_) \ |
| {n_,n_,n_,n_} |
| #define BOOST_PP_LOCAL_LIMITS (0, 255) |
| #include BOOST_PP_LOCAL_ITERATE() |
| } |
| }; |
| |
| // need to copy&convert the bitmap, since dx |
| // canvas uses inline alpha channel |
| HDC hScreenDC=GetDC(NULL); |
| const basegfx::B2IVector aSize(mpBitmap->getSize()); |
| HBITMAP hBmpBitmap = CreateCompatibleBitmap( hScreenDC, aSize.getX(), aSize.getY() ); |
| if( !hBmpBitmap ) |
| return aRes; |
| |
| aDIB.bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); |
| aDIB.bmiHeader.biWidth = aSize.getX(); |
| aDIB.bmiHeader.biHeight = -aSize.getY(); |
| aDIB.bmiHeader.biPlanes = 1; |
| aDIB.bmiHeader.biBitCount = 8; |
| aDIB.bmiHeader.biCompression = BI_RGB; |
| aDIB.bmiHeader.biSizeImage = 0; |
| aDIB.bmiHeader.biXPelsPerMeter = 0; |
| aDIB.bmiHeader.biYPelsPerMeter = 0; |
| aDIB.bmiHeader.biClrUsed = 0; |
| aDIB.bmiHeader.biClrImportant = 0; |
| |
| Gdiplus::BitmapData aBmpData; |
| aBmpData.Width = aSize.getX(); |
| aBmpData.Height = aSize.getY(); |
| aBmpData.Stride = 4*aBmpData.Width; |
| aBmpData.PixelFormat = PixelFormat32bppARGB; |
| aBmpData.Scan0 = NULL; |
| const Gdiplus::Rect aRect( 0,0,aSize.getX(),aSize.getY() ); |
| BitmapSharedPtr pGDIPlusBitmap=mpBitmap->getBitmap(); |
| if( Gdiplus::Ok != pGDIPlusBitmap->LockBits( &aRect, |
| Gdiplus::ImageLockModeRead, |
| PixelFormat32bppARGB, // outputs ARGB (big endian) |
| &aBmpData ) ) |
| { |
| // failed to lock, bail out |
| return aRes; |
| } |
| |
| // copy only alpha channel to pAlphaBits |
| const sal_Int32 nScanWidth((aSize.getX() + 3) & ~3); |
| boost::scoped_array<sal_uInt8> pAlphaBits( new sal_uInt8[nScanWidth*aSize.getY()] ); |
| const sal_uInt8* pInBits=(sal_uInt8*)aBmpData.Scan0; |
| pInBits+=3; |
| sal_uInt8* pOutBits; |
| for( sal_Int32 y=0; y<aSize.getY(); ++y ) |
| { |
| pOutBits=pAlphaBits.get()+y*nScanWidth; |
| for( sal_Int32 x=0; x<aSize.getX(); ++x ) |
| { |
| *pOutBits++ = 255-*pInBits; |
| pInBits += 4; |
| } |
| } |
| |
| pGDIPlusBitmap->UnlockBits( &aBmpData ); |
| |
| // set bits to newly create HBITMAP |
| SetDIBits( hScreenDC, hBmpBitmap, 0, |
| aSize.getY(), pAlphaBits.get(), |
| (PBITMAPINFO)&aDIB, DIB_RGB_COLORS ); |
| |
| uno::Sequence< uno::Any > args(1); |
| args[0] = uno::Any( sal_Int64(hBmpBitmap) ); |
| |
| aRes <<= args; |
| } |
| } |
| break; |
| } |
| |
| return aRes; |
| } |
| |
| #define IMPLEMENTATION_NAME "DXCanvas.CanvasBitmap" |
| #define SERVICE_NAME "com.sun.star.rendering.CanvasBitmap" |
| |
| ::rtl::OUString SAL_CALL CanvasBitmap::getImplementationName( ) throw (uno::RuntimeException) |
| { |
| return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) ); |
| } |
| |
| sal_Bool SAL_CALL CanvasBitmap::supportsService( const ::rtl::OUString& ServiceName ) throw (uno::RuntimeException) |
| { |
| return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); |
| } |
| |
| uno::Sequence< ::rtl::OUString > SAL_CALL CanvasBitmap::getSupportedServiceNames( ) throw (uno::RuntimeException) |
| { |
| uno::Sequence< ::rtl::OUString > aRet(1); |
| aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) ); |
| |
| return aRet; |
| } |
| |
| } |