1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_canvas.hxx" 30 31 #include <ctype.h> // don't ask. msdev breaks otherwise... 32 #include <canvas/debug.hxx> 33 #include <canvas/canvastools.hxx> 34 #include <tools/diagnose_ex.h> 35 36 #include <vcl/bitmapex.hxx> 37 38 #include <boost/preprocessor/repetition.hpp> 39 #include <boost/preprocessor/iteration/local.hpp> 40 #include <boost/scoped_array.hpp> 41 42 #include "dx_canvasbitmap.hxx" 43 #include "dx_impltools.hxx" 44 45 46 using namespace ::com::sun::star; 47 48 namespace dxcanvas 49 { 50 CanvasBitmap::CanvasBitmap( const IBitmapSharedPtr& rBitmap, 51 const DeviceRef& rDevice ) : 52 mpDevice( rDevice ), 53 mpBitmap( rBitmap ) 54 { 55 ENSURE_OR_THROW( mpDevice.is() && mpBitmap, 56 "CanvasBitmap::CanvasBitmap(): Invalid surface or device" ); 57 58 maCanvasHelper.setDevice( *mpDevice.get() ); 59 maCanvasHelper.setTarget( mpBitmap ); 60 } 61 62 void SAL_CALL CanvasBitmap::disposing() 63 { 64 mpBitmap.reset(); 65 mpDevice.clear(); 66 67 // forward to parent 68 CanvasBitmap_Base::disposing(); 69 } 70 71 struct AlphaDIB 72 { 73 BITMAPINFOHEADER bmiHeader; 74 RGBQUAD bmiColors[256]; 75 }; 76 77 uno::Any SAL_CALL CanvasBitmap::getFastPropertyValue( sal_Int32 nHandle ) throw (uno::RuntimeException) 78 { 79 uno::Any aRes; 80 // 0 ... get BitmapEx 81 // 1 ... get Pixbuf with bitmap RGB content 82 // 2 ... get Pixbuf with bitmap alpha mask 83 switch( nHandle ) 84 { 85 // sorry, no BitmapEx here... 86 case 0: 87 aRes = ::com::sun::star::uno::Any( reinterpret_cast<sal_Int64>( (BitmapEx*) NULL ) ); 88 break; 89 90 case 1: 91 { 92 if(!mpBitmap->hasAlpha()) 93 { 94 HBITMAP aHBmp; 95 mpBitmap->getBitmap()->GetHBITMAP(Gdiplus::Color(), &aHBmp ); 96 97 uno::Sequence< uno::Any > args(1); 98 args[0] = uno::Any( sal_Int64(aHBmp) ); 99 100 aRes <<= args; 101 } 102 else 103 { 104 // need to copy&convert the bitmap, since dx 105 // canvas uses inline alpha channel 106 HDC hScreenDC=GetDC(NULL); 107 const basegfx::B2IVector aSize(mpBitmap->getSize()); 108 HBITMAP hBmpBitmap = CreateCompatibleBitmap( hScreenDC, 109 aSize.getX(), 110 aSize.getY() ); 111 if( !hBmpBitmap ) 112 return aRes; 113 114 BITMAPINFOHEADER aBIH; 115 116 aBIH.biSize = sizeof( BITMAPINFOHEADER ); 117 aBIH.biWidth = aSize.getX(); 118 aBIH.biHeight = -aSize.getY(); 119 aBIH.biPlanes = 1; 120 aBIH.biBitCount = 32; 121 aBIH.biCompression = BI_RGB; // expects pixel in 122 // bbggrrxx format 123 // (little endian) 124 aBIH.biSizeImage = 0; 125 aBIH.biXPelsPerMeter = 0; 126 aBIH.biYPelsPerMeter = 0; 127 aBIH.biClrUsed = 0; 128 aBIH.biClrImportant = 0; 129 130 Gdiplus::BitmapData aBmpData; 131 aBmpData.Width = aSize.getX(); 132 aBmpData.Height = aSize.getY(); 133 aBmpData.Stride = 4*aBmpData.Width; 134 aBmpData.PixelFormat = PixelFormat32bppARGB; 135 aBmpData.Scan0 = NULL; 136 const Gdiplus::Rect aRect( 0,0,aSize.getX(),aSize.getY() ); 137 BitmapSharedPtr pGDIPlusBitmap=mpBitmap->getBitmap(); 138 if( Gdiplus::Ok != pGDIPlusBitmap->LockBits( &aRect, 139 Gdiplus::ImageLockModeRead, 140 PixelFormat32bppARGB, // outputs ARGB (big endian) 141 &aBmpData ) ) 142 { 143 // failed to lock, bail out 144 return aRes; 145 } 146 147 // now aBmpData.Scan0 contains our bits - push 148 // them into HBITMAP, ignoring alpha 149 SetDIBits( hScreenDC, hBmpBitmap, 0, aSize.getY(), aBmpData.Scan0, (PBITMAPINFO)&aBIH, DIB_RGB_COLORS ); 150 151 pGDIPlusBitmap->UnlockBits( &aBmpData ); 152 153 uno::Sequence< uno::Any > args(1); 154 args[0] = uno::Any( sal_Int64(hBmpBitmap) ); 155 156 aRes <<= args; 157 } 158 } 159 break; 160 161 case 2: 162 { 163 if(!mpBitmap->hasAlpha()) 164 { 165 return aRes; 166 } 167 else 168 { 169 static AlphaDIB aDIB= 170 { 171 {0,0,0,1,8,BI_RGB,0,0,0,0,0}, 172 { 173 // this here fills palette with grey 174 // level colors, starting from 0,0,0 175 // up to 255,255,255 176 #define BOOST_PP_LOCAL_MACRO(n_) \ 177 BOOST_PP_COMMA_IF(n_) \ 178 {n_,n_,n_,n_} 179 #define BOOST_PP_LOCAL_LIMITS (0, 255) 180 #include BOOST_PP_LOCAL_ITERATE() 181 } 182 }; 183 184 // need to copy&convert the bitmap, since dx 185 // canvas uses inline alpha channel 186 HDC hScreenDC=GetDC(NULL); 187 const basegfx::B2IVector aSize(mpBitmap->getSize()); 188 HBITMAP hBmpBitmap = CreateCompatibleBitmap( hScreenDC, aSize.getX(), aSize.getY() ); 189 if( !hBmpBitmap ) 190 return aRes; 191 192 aDIB.bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); 193 aDIB.bmiHeader.biWidth = aSize.getX(); 194 aDIB.bmiHeader.biHeight = -aSize.getY(); 195 aDIB.bmiHeader.biPlanes = 1; 196 aDIB.bmiHeader.biBitCount = 8; 197 aDIB.bmiHeader.biCompression = BI_RGB; 198 aDIB.bmiHeader.biSizeImage = 0; 199 aDIB.bmiHeader.biXPelsPerMeter = 0; 200 aDIB.bmiHeader.biYPelsPerMeter = 0; 201 aDIB.bmiHeader.biClrUsed = 0; 202 aDIB.bmiHeader.biClrImportant = 0; 203 204 Gdiplus::BitmapData aBmpData; 205 aBmpData.Width = aSize.getX(); 206 aBmpData.Height = aSize.getY(); 207 aBmpData.Stride = 4*aBmpData.Width; 208 aBmpData.PixelFormat = PixelFormat32bppARGB; 209 aBmpData.Scan0 = NULL; 210 const Gdiplus::Rect aRect( 0,0,aSize.getX(),aSize.getY() ); 211 BitmapSharedPtr pGDIPlusBitmap=mpBitmap->getBitmap(); 212 if( Gdiplus::Ok != pGDIPlusBitmap->LockBits( &aRect, 213 Gdiplus::ImageLockModeRead, 214 PixelFormat32bppARGB, // outputs ARGB (big endian) 215 &aBmpData ) ) 216 { 217 // failed to lock, bail out 218 return aRes; 219 } 220 221 // copy only alpha channel to pAlphaBits 222 const sal_Int32 nScanWidth((aSize.getX() + 3) & ~3); 223 boost::scoped_array<sal_uInt8> pAlphaBits( new sal_uInt8[nScanWidth*aSize.getY()] ); 224 const sal_uInt8* pInBits=(sal_uInt8*)aBmpData.Scan0; 225 pInBits+=3; 226 sal_uInt8* pOutBits; 227 for( sal_Int32 y=0; y<aSize.getY(); ++y ) 228 { 229 pOutBits=pAlphaBits.get()+y*nScanWidth; 230 for( sal_Int32 x=0; x<aSize.getX(); ++x ) 231 { 232 *pOutBits++ = 255-*pInBits; 233 pInBits += 4; 234 } 235 } 236 237 pGDIPlusBitmap->UnlockBits( &aBmpData ); 238 239 // set bits to newly create HBITMAP 240 SetDIBits( hScreenDC, hBmpBitmap, 0, 241 aSize.getY(), pAlphaBits.get(), 242 (PBITMAPINFO)&aDIB, DIB_RGB_COLORS ); 243 244 uno::Sequence< uno::Any > args(1); 245 args[0] = uno::Any( sal_Int64(hBmpBitmap) ); 246 247 aRes <<= args; 248 } 249 } 250 break; 251 } 252 253 return aRes; 254 } 255 256 #define IMPLEMENTATION_NAME "DXCanvas.CanvasBitmap" 257 #define SERVICE_NAME "com.sun.star.rendering.CanvasBitmap" 258 259 ::rtl::OUString SAL_CALL CanvasBitmap::getImplementationName( ) throw (uno::RuntimeException) 260 { 261 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) ); 262 } 263 264 sal_Bool SAL_CALL CanvasBitmap::supportsService( const ::rtl::OUString& ServiceName ) throw (uno::RuntimeException) 265 { 266 return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); 267 } 268 269 uno::Sequence< ::rtl::OUString > SAL_CALL CanvasBitmap::getSupportedServiceNames( ) throw (uno::RuntimeException) 270 { 271 uno::Sequence< ::rtl::OUString > aRet(1); 272 aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) ); 273 274 return aRet; 275 } 276 277 } 278