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 <vcl/canvastools.hxx> 32 33 #include <vcl/bitmap.hxx> 34 #include <vcl/bitmapex.hxx> 35 #include <vcl/bmpacc.hxx> 36 #include <tools/diagnose_ex.h> 37 38 #include "dx_impltools.hxx" 39 #include <basegfx/numeric/ftools.hxx> 40 41 #include <canvas/debug.hxx> 42 #include <canvas/verbosetrace.hxx> 43 44 #include <com/sun/star/lang/XServiceInfo.hpp> 45 #include <com/sun/star/rendering/XIntegerBitmap.hpp> 46 47 #include <boost/scoped_array.hpp> 48 49 #include "dx_vcltools.hxx" 50 51 using namespace ::com::sun::star; 52 53 namespace dxcanvas 54 { 55 namespace tools 56 { 57 namespace 58 { 59 /// Calc number of colors in given BitmapInfoHeader 60 sal_Int32 calcDIBColorCount( const BITMAPINFOHEADER& rBIH ) 61 { 62 if( rBIH.biSize != sizeof( BITMAPCOREHEADER ) ) 63 { 64 if( rBIH.biBitCount <= 8 ) 65 { 66 if( rBIH.biClrUsed ) 67 return rBIH.biClrUsed; 68 else 69 return 1L << rBIH.biBitCount; 70 } 71 } 72 else 73 { 74 BITMAPCOREHEADER* pCoreHeader = (BITMAPCOREHEADER*)&rBIH; 75 76 if( pCoreHeader->bcBitCount <= 8 ) 77 return 1L << pCoreHeader->bcBitCount; 78 } 79 80 return 0; // nothing known 81 } 82 83 /// Draw DI bits to given Graphics 84 bool drawDIBits( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, 85 const void* hDIB ) 86 { 87 bool bRet( false ); 88 BitmapSharedPtr pBitmap; 89 90 const BITMAPINFO* pBI = (BITMAPINFO*)GlobalLock( (HGLOBAL)hDIB ); 91 92 if( pBI ) 93 { 94 const BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*)pBI; 95 const BYTE* pBits = (BYTE*) pBI + *(DWORD*)pBI + 96 calcDIBColorCount( *pBIH ) * sizeof( RGBQUAD ); 97 98 // forward to outsourced GDI+ rendering method 99 // (header clashes) 100 bRet = tools::drawDIBits( rGraphics, *pBI, (void*)pBits ); 101 102 GlobalUnlock( (HGLOBAL)hDIB ); 103 } 104 105 return bRet; 106 } 107 108 /** Draw VCL bitmap to given Graphics 109 110 @param rBmp 111 Reference to bitmap. Might get modified, in such a way 112 that it will hold a DIB after a successful function call. 113 */ 114 bool drawVCLBitmap( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, 115 ::Bitmap& rBmp ) 116 { 117 BitmapSystemData aBmpSysData; 118 119 if( !rBmp.GetSystemData( aBmpSysData ) || 120 !aBmpSysData.pDIB ) 121 { 122 // first of all, ensure that Bitmap contains a DIB, by 123 // aquiring a read access 124 BitmapReadAccess* pReadAcc = rBmp.AcquireReadAccess(); 125 126 // TODO(P2): Acquiring a read access can actually 127 // force a read from VRAM, thus, avoiding this 128 // step somehow will increase performance 129 // here. 130 if( pReadAcc ) 131 { 132 // try again: now, WinSalBitmap must have 133 // generated a DIB 134 if( rBmp.GetSystemData( aBmpSysData ) && 135 aBmpSysData.pDIB ) 136 { 137 return drawDIBits( rGraphics, 138 aBmpSysData.pDIB ); 139 } 140 141 rBmp.ReleaseAccess( pReadAcc ); 142 } 143 } 144 else 145 { 146 return drawDIBits( rGraphics, 147 aBmpSysData.pDIB ); 148 } 149 150 // failed to generate DIBits from vcl bitmap 151 return false; 152 } 153 154 /** Create a chunk of raw RGBA data GDI+ Bitmap from VCL BbitmapEX 155 */ 156 RawRGBABitmap bitmapFromVCLBitmapEx( const ::BitmapEx& rBmpEx ) 157 { 158 // TODO(P2): Avoid temporary bitmap generation, maybe 159 // even ensure that created DIBs are copied back to 160 // BmpEx (currently, every AcquireReadAccess() will 161 // make the local bitmap copy unique, effectively 162 // duplicating the memory used) 163 164 ENSURE_OR_THROW( rBmpEx.IsTransparent(), 165 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " 166 "BmpEx not transparent" ); 167 168 // convert transparent bitmap to 32bit RGBA 169 // ======================================== 170 171 const ::Size aBmpSize( rBmpEx.GetSizePixel() ); 172 173 RawRGBABitmap aBmpData; 174 aBmpData.mnWidth = aBmpSize.Width(); 175 aBmpData.mnHeight = aBmpSize.Height(); 176 aBmpData.mpBitmapData.reset( new sal_uInt8[ 4*aBmpData.mnWidth*aBmpData.mnHeight ] ); 177 178 Bitmap aBitmap( rBmpEx.GetBitmap() ); 179 180 ScopedBitmapReadAccess pReadAccess( aBitmap.AcquireReadAccess(), 181 aBitmap ); 182 183 const sal_Int32 nWidth( aBmpSize.Width() ); 184 const sal_Int32 nHeight( aBmpSize.Height() ); 185 186 ENSURE_OR_THROW( pReadAccess.get() != NULL, 187 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " 188 "Unable to acquire read acces to bitmap" ); 189 190 if( rBmpEx.IsAlpha() ) 191 { 192 Bitmap aAlpha( rBmpEx.GetAlpha().GetBitmap() ); 193 194 ScopedBitmapReadAccess pAlphaReadAccess( aAlpha.AcquireReadAccess(), 195 aAlpha ); 196 197 // By convention, the access buffer always has 198 // one of the following formats: 199 // 200 // BMP_FORMAT_1BIT_MSB_PAL 201 // BMP_FORMAT_4BIT_MSN_PAL 202 // BMP_FORMAT_8BIT_PAL 203 // BMP_FORMAT_16BIT_TC_LSB_MASK 204 // BMP_FORMAT_24BIT_TC_BGR 205 // BMP_FORMAT_32BIT_TC_MASK 206 // 207 // and is always BMP_FORMAT_BOTTOM_UP 208 // 209 // This is the way 210 // WinSalBitmap::AcquireBuffer() sets up the 211 // buffer 212 213 ENSURE_OR_THROW( pAlphaReadAccess.get() != NULL, 214 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " 215 "Unable to acquire read acces to alpha" ); 216 217 ENSURE_OR_THROW( pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL || 218 pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK, 219 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " 220 "Unsupported alpha scanline format" ); 221 222 BitmapColor aCol; 223 const sal_Int32 nWidth( aBmpSize.Width() ); 224 const sal_Int32 nHeight( aBmpSize.Height() ); 225 sal_uInt8* pCurrOutput( aBmpData.mpBitmapData.get() ); 226 int x, y; 227 228 for( y=0; y<nHeight; ++y ) 229 { 230 switch( pReadAccess->GetScanlineFormat() ) 231 { 232 case BMP_FORMAT_8BIT_PAL: 233 { 234 Scanline pScan = pReadAccess->GetScanline( y ); 235 Scanline pAScan = pAlphaReadAccess->GetScanline( y ); 236 237 for( x=0; x<nWidth; ++x ) 238 { 239 aCol = pReadAccess->GetPaletteColor( *pScan++ ); 240 241 *pCurrOutput++ = aCol.GetBlue(); 242 *pCurrOutput++ = aCol.GetGreen(); 243 *pCurrOutput++ = aCol.GetRed(); 244 245 // out notion of alpha is 246 // different from the rest 247 // of the world's 248 *pCurrOutput++ = 255 - (BYTE)*pAScan++; 249 } 250 } 251 break; 252 253 case BMP_FORMAT_24BIT_TC_BGR: 254 { 255 Scanline pScan = pReadAccess->GetScanline( y ); 256 Scanline pAScan = pAlphaReadAccess->GetScanline( y ); 257 258 for( x=0; x<nWidth; ++x ) 259 { 260 // store as RGBA 261 *pCurrOutput++ = *pScan++; 262 *pCurrOutput++ = *pScan++; 263 *pCurrOutput++ = *pScan++; 264 265 // out notion of alpha is 266 // different from the rest 267 // of the world's 268 *pCurrOutput++ = 255 - (BYTE)*pAScan++; 269 } 270 } 271 break; 272 273 // TODO(P2): Might be advantageous 274 // to hand-formulate the following 275 // formats, too. 276 case BMP_FORMAT_1BIT_MSB_PAL: 277 // FALLTHROUGH intended 278 case BMP_FORMAT_4BIT_MSN_PAL: 279 // FALLTHROUGH intended 280 case BMP_FORMAT_16BIT_TC_LSB_MASK: 281 // FALLTHROUGH intended 282 case BMP_FORMAT_32BIT_TC_MASK: 283 { 284 Scanline pAScan = pAlphaReadAccess->GetScanline( y ); 285 286 // using fallback for those 287 // seldom formats 288 for( x=0; x<nWidth; ++x ) 289 { 290 // yes. x and y are swapped on Get/SetPixel 291 aCol = pReadAccess->GetColor(y,x); 292 293 *pCurrOutput++ = aCol.GetBlue(); 294 *pCurrOutput++ = aCol.GetGreen(); 295 *pCurrOutput++ = aCol.GetRed(); 296 297 // out notion of alpha is 298 // different from the rest 299 // of the world's 300 *pCurrOutput++ = 255 - (BYTE)*pAScan++; 301 } 302 } 303 break; 304 305 case BMP_FORMAT_1BIT_LSB_PAL: 306 // FALLTHROUGH intended 307 case BMP_FORMAT_4BIT_LSN_PAL: 308 // FALLTHROUGH intended 309 case BMP_FORMAT_8BIT_TC_MASK: 310 // FALLTHROUGH intended 311 case BMP_FORMAT_24BIT_TC_RGB: 312 // FALLTHROUGH intended 313 case BMP_FORMAT_24BIT_TC_MASK: 314 // FALLTHROUGH intended 315 case BMP_FORMAT_16BIT_TC_MSB_MASK: 316 // FALLTHROUGH intended 317 case BMP_FORMAT_32BIT_TC_ABGR: 318 // FALLTHROUGH intended 319 case BMP_FORMAT_32BIT_TC_ARGB: 320 // FALLTHROUGH intended 321 case BMP_FORMAT_32BIT_TC_BGRA: 322 // FALLTHROUGH intended 323 case BMP_FORMAT_32BIT_TC_RGBA: 324 // FALLTHROUGH intended 325 default: 326 ENSURE_OR_THROW( false, 327 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " 328 "Unexpected scanline format - has " 329 "WinSalBitmap::AcquireBuffer() changed?" ); 330 } 331 } 332 } 333 else 334 { 335 Bitmap aMask( rBmpEx.GetMask() ); 336 337 ScopedBitmapReadAccess pMaskReadAccess( aMask.AcquireReadAccess(), 338 aMask ); 339 340 // By convention, the access buffer always has 341 // one of the following formats: 342 // 343 // BMP_FORMAT_1BIT_MSB_PAL 344 // BMP_FORMAT_4BIT_MSN_PAL 345 // BMP_FORMAT_8BIT_PAL 346 // BMP_FORMAT_16BIT_TC_LSB_MASK 347 // BMP_FORMAT_24BIT_TC_BGR 348 // BMP_FORMAT_32BIT_TC_MASK 349 // 350 // and is always BMP_FORMAT_BOTTOM_UP 351 // 352 // This is the way 353 // WinSalBitmap::AcquireBuffer() sets up the 354 // buffer 355 356 ENSURE_OR_THROW( pMaskReadAccess.get() != NULL, 357 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " 358 "Unable to acquire read acces to mask" ); 359 360 ENSURE_OR_THROW( pMaskReadAccess->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL, 361 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " 362 "Unsupported mask scanline format" ); 363 364 BitmapColor aCol; 365 int nCurrBit; 366 const int nMask( 1L ); 367 const int nInitialBit(7); 368 sal_uInt8* pCurrOutput( aBmpData.mpBitmapData.get() ); 369 int x, y; 370 371 // mapping table, to get from mask index color to 372 // alpha value (which depends on the mask's palette) 373 sal_uInt8 aColorMap[2]; 374 375 const BitmapColor& rCol0( pMaskReadAccess->GetPaletteColor( 0 ) ); 376 const BitmapColor& rCol1( pMaskReadAccess->GetPaletteColor( 1 ) ); 377 378 // shortcut for true luminance calculation 379 // (assumes that palette is grey-level). Note the 380 // swapped the indices here, to account for the 381 // fact that VCL's notion of alpha is inverted to 382 // the rest of the world's. 383 aColorMap[0] = rCol1.GetRed(); 384 aColorMap[1] = rCol0.GetRed(); 385 386 for( y=0; y<nHeight; ++y ) 387 { 388 switch( pReadAccess->GetScanlineFormat() ) 389 { 390 case BMP_FORMAT_8BIT_PAL: 391 { 392 Scanline pScan = pReadAccess->GetScanline( y ); 393 Scanline pMScan = pMaskReadAccess->GetScanline( y ); 394 395 for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x ) 396 { 397 aCol = pReadAccess->GetPaletteColor( *pScan++ ); 398 399 *pCurrOutput++ = aCol.GetBlue(); 400 *pCurrOutput++ = aCol.GetGreen(); 401 *pCurrOutput++ = aCol.GetRed(); 402 403 *pCurrOutput++ = aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ]; 404 nCurrBit = ((nCurrBit - 1) % 8L) & 7L; 405 } 406 } 407 break; 408 409 case BMP_FORMAT_24BIT_TC_BGR: 410 { 411 Scanline pScan = pReadAccess->GetScanline( y ); 412 Scanline pMScan = pMaskReadAccess->GetScanline( y ); 413 414 for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x ) 415 { 416 // store as RGBA 417 *pCurrOutput++ = *pScan++; 418 *pCurrOutput++ = *pScan++; 419 *pCurrOutput++ = *pScan++; 420 421 *pCurrOutput++ = aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ]; 422 nCurrBit = ((nCurrBit - 1) % 8L) & 7L; 423 } 424 } 425 break; 426 427 // TODO(P2): Might be advantageous 428 // to hand-formulate the following 429 // formats, too. 430 case BMP_FORMAT_1BIT_MSB_PAL: 431 // FALLTHROUGH intended 432 case BMP_FORMAT_4BIT_MSN_PAL: 433 // FALLTHROUGH intended 434 case BMP_FORMAT_16BIT_TC_LSB_MASK: 435 // FALLTHROUGH intended 436 case BMP_FORMAT_32BIT_TC_MASK: 437 { 438 Scanline pMScan = pMaskReadAccess->GetScanline( y ); 439 440 // using fallback for those 441 // seldom formats 442 for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x ) 443 { 444 // yes. x and y are swapped on Get/SetPixel 445 aCol = pReadAccess->GetColor(y,x); 446 447 // store as RGBA 448 *pCurrOutput++ = aCol.GetBlue(); 449 *pCurrOutput++ = aCol.GetGreen(); 450 *pCurrOutput++ = aCol.GetRed(); 451 452 *pCurrOutput++ = aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ]; 453 nCurrBit = ((nCurrBit - 1) % 8L) & 7L; 454 } 455 } 456 break; 457 458 case BMP_FORMAT_1BIT_LSB_PAL: 459 // FALLTHROUGH intended 460 case BMP_FORMAT_4BIT_LSN_PAL: 461 // FALLTHROUGH intended 462 case BMP_FORMAT_8BIT_TC_MASK: 463 // FALLTHROUGH intended 464 case BMP_FORMAT_24BIT_TC_RGB: 465 // FALLTHROUGH intended 466 case BMP_FORMAT_24BIT_TC_MASK: 467 // FALLTHROUGH intended 468 case BMP_FORMAT_16BIT_TC_MSB_MASK: 469 // FALLTHROUGH intended 470 case BMP_FORMAT_32BIT_TC_ABGR: 471 // FALLTHROUGH intended 472 case BMP_FORMAT_32BIT_TC_ARGB: 473 // FALLTHROUGH intended 474 case BMP_FORMAT_32BIT_TC_BGRA: 475 // FALLTHROUGH intended 476 case BMP_FORMAT_32BIT_TC_RGBA: 477 // FALLTHROUGH intended 478 default: 479 ENSURE_OR_THROW( false, 480 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " 481 "Unexpected scanline format - has " 482 "WinSalBitmap::AcquireBuffer() changed?" ); 483 } 484 } 485 } 486 487 return aBmpData; 488 } 489 490 bool drawVCLBitmapEx( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, 491 const ::BitmapEx& rBmpEx ) 492 { 493 if( !rBmpEx.IsTransparent() ) 494 { 495 Bitmap aBmp( rBmpEx.GetBitmap() ); 496 return drawVCLBitmap( rGraphics, aBmp ); 497 } 498 else 499 { 500 return drawRGBABits( rGraphics, 501 bitmapFromVCLBitmapEx( rBmpEx ) ); 502 } 503 } 504 } 505 506 bool drawVCLBitmapFromXBitmap( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, 507 const uno::Reference< rendering::XBitmap >& xBitmap ) 508 { 509 // TODO(F2): add support for floating point bitmap formats 510 uno::Reference< rendering::XIntegerReadOnlyBitmap > xIntBmp( 511 xBitmap, uno::UNO_QUERY ); 512 513 if( !xIntBmp.is() ) 514 return false; 515 516 ::BitmapEx aBmpEx = ::vcl::unotools::bitmapExFromXBitmap( xIntBmp ); 517 if( !aBmpEx ) 518 return false; 519 520 return drawVCLBitmapEx( rGraphics, aBmpEx ); 521 } 522 } 523 } 524