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