1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dx_vcltools.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_canvas.hxx"
34 #include <vcl/canvastools.hxx>
36 #include <vcl/bitmap.hxx>
37 #include <vcl/bitmapex.hxx>
38 #include <vcl/bmpacc.hxx>
39 #include <tools/diagnose_ex.h>
41 #include "dx_impltools.hxx"
42 #include <basegfx/numeric/ftools.hxx>
44 #include <canvas/debug.hxx>
45 #include <canvas/verbosetrace.hxx>
47 #include <com/sun/star/lang/XServiceInfo.hpp>
48 #include <com/sun/star/rendering/XIntegerBitmap.hpp>
50 #include <boost/scoped_array.hpp>
52 #include "dx_vcltools.hxx"
54 using namespace ::com::sun::star
;
62 /// Calc number of colors in given BitmapInfoHeader
63 sal_Int32
calcDIBColorCount( const BITMAPINFOHEADER
& rBIH
)
65 if( rBIH
.biSize
!= sizeof( BITMAPCOREHEADER
) )
67 if( rBIH
.biBitCount
<= 8 )
70 return rBIH
.biClrUsed
;
72 return 1L << rBIH
.biBitCount
;
77 BITMAPCOREHEADER
* pCoreHeader
= (BITMAPCOREHEADER
*)&rBIH
;
79 if( pCoreHeader
->bcBitCount
<= 8 )
80 return 1L << pCoreHeader
->bcBitCount
;
83 return 0; // nothing known
86 /// Draw DI bits to given Graphics
87 bool drawDIBits( const ::boost::shared_ptr
< Gdiplus::Graphics
>& rGraphics
,
91 BitmapSharedPtr pBitmap
;
93 const BITMAPINFO
* pBI
= (BITMAPINFO
*)GlobalLock( (HGLOBAL
)hDIB
);
97 const BITMAPINFOHEADER
* pBIH
= (BITMAPINFOHEADER
*)pBI
;
98 const BYTE
* pBits
= (BYTE
*) pBI
+ *(DWORD
*)pBI
+
99 calcDIBColorCount( *pBIH
) * sizeof( RGBQUAD
);
101 // forward to outsourced GDI+ rendering method
103 bRet
= tools::drawDIBits( rGraphics
, *pBI
, (void*)pBits
);
105 GlobalUnlock( (HGLOBAL
)hDIB
);
111 /** Draw VCL bitmap to given Graphics
114 Reference to bitmap. Might get modified, in such a way
115 that it will hold a DIB after a successful function call.
117 bool drawVCLBitmap( const ::boost::shared_ptr
< Gdiplus::Graphics
>& rGraphics
,
120 BitmapSystemData aBmpSysData
;
122 if( !rBmp
.GetSystemData( aBmpSysData
) ||
125 // first of all, ensure that Bitmap contains a DIB, by
126 // aquiring a read access
127 BitmapReadAccess
* pReadAcc
= rBmp
.AcquireReadAccess();
129 // TODO(P2): Acquiring a read access can actually
130 // force a read from VRAM, thus, avoiding this
131 // step somehow will increase performance
135 // try again: now, WinSalBitmap must have
137 if( rBmp
.GetSystemData( aBmpSysData
) &&
140 return drawDIBits( rGraphics
,
144 rBmp
.ReleaseAccess( pReadAcc
);
149 return drawDIBits( rGraphics
,
153 // failed to generate DIBits from vcl bitmap
157 /** Create a chunk of raw RGBA data GDI+ Bitmap from VCL BbitmapEX
159 RawRGBABitmap
bitmapFromVCLBitmapEx( const ::BitmapEx
& rBmpEx
)
161 // TODO(P2): Avoid temporary bitmap generation, maybe
162 // even ensure that created DIBs are copied back to
163 // BmpEx (currently, every AcquireReadAccess() will
164 // make the local bitmap copy unique, effectively
165 // duplicating the memory used)
167 ENSURE_OR_THROW( rBmpEx
.IsTransparent(),
168 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
169 "BmpEx not transparent" );
171 // convert transparent bitmap to 32bit RGBA
172 // ========================================
174 const ::Size
aBmpSize( rBmpEx
.GetSizePixel() );
176 RawRGBABitmap aBmpData
;
177 aBmpData
.mnWidth
= aBmpSize
.Width();
178 aBmpData
.mnHeight
= aBmpSize
.Height();
179 aBmpData
.mpBitmapData
.reset( new sal_uInt8
[ 4*aBmpData
.mnWidth
*aBmpData
.mnHeight
] );
181 Bitmap
aBitmap( rBmpEx
.GetBitmap() );
183 ScopedBitmapReadAccess
pReadAccess( aBitmap
.AcquireReadAccess(),
186 const sal_Int32
nWidth( aBmpSize
.Width() );
187 const sal_Int32
nHeight( aBmpSize
.Height() );
189 ENSURE_OR_THROW( pReadAccess
.get() != NULL
,
190 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
191 "Unable to acquire read acces to bitmap" );
193 if( rBmpEx
.IsAlpha() )
195 Bitmap
aAlpha( rBmpEx
.GetAlpha().GetBitmap() );
197 ScopedBitmapReadAccess
pAlphaReadAccess( aAlpha
.AcquireReadAccess(),
200 // By convention, the access buffer always has
201 // one of the following formats:
203 // BMP_FORMAT_1BIT_MSB_PAL
204 // BMP_FORMAT_4BIT_MSN_PAL
205 // BMP_FORMAT_8BIT_PAL
206 // BMP_FORMAT_16BIT_TC_LSB_MASK
207 // BMP_FORMAT_24BIT_TC_BGR
208 // BMP_FORMAT_32BIT_TC_MASK
210 // and is always BMP_FORMAT_BOTTOM_UP
213 // WinSalBitmap::AcquireBuffer() sets up the
216 ENSURE_OR_THROW( pAlphaReadAccess
.get() != NULL
,
217 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
218 "Unable to acquire read acces to alpha" );
220 ENSURE_OR_THROW( pAlphaReadAccess
->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL
||
221 pAlphaReadAccess
->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK
,
222 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
223 "Unsupported alpha scanline format" );
226 const sal_Int32
nWidth( aBmpSize
.Width() );
227 const sal_Int32
nHeight( aBmpSize
.Height() );
228 sal_uInt8
* pCurrOutput( aBmpData
.mpBitmapData
.get() );
231 for( y
=0; y
<nHeight
; ++y
)
233 switch( pReadAccess
->GetScanlineFormat() )
235 case BMP_FORMAT_8BIT_PAL
:
237 Scanline pScan
= pReadAccess
->GetScanline( y
);
238 Scanline pAScan
= pAlphaReadAccess
->GetScanline( y
);
240 for( x
=0; x
<nWidth
; ++x
)
242 aCol
= pReadAccess
->GetPaletteColor( *pScan
++ );
244 *pCurrOutput
++ = aCol
.GetBlue();
245 *pCurrOutput
++ = aCol
.GetGreen();
246 *pCurrOutput
++ = aCol
.GetRed();
248 // out notion of alpha is
249 // different from the rest
251 *pCurrOutput
++ = 255 - (BYTE
)*pAScan
++;
256 case BMP_FORMAT_24BIT_TC_BGR
:
258 Scanline pScan
= pReadAccess
->GetScanline( y
);
259 Scanline pAScan
= pAlphaReadAccess
->GetScanline( y
);
261 for( x
=0; x
<nWidth
; ++x
)
264 *pCurrOutput
++ = *pScan
++;
265 *pCurrOutput
++ = *pScan
++;
266 *pCurrOutput
++ = *pScan
++;
268 // out notion of alpha is
269 // different from the rest
271 *pCurrOutput
++ = 255 - (BYTE
)*pAScan
++;
276 // TODO(P2): Might be advantageous
277 // to hand-formulate the following
279 case BMP_FORMAT_1BIT_MSB_PAL
:
280 // FALLTHROUGH intended
281 case BMP_FORMAT_4BIT_MSN_PAL
:
282 // FALLTHROUGH intended
283 case BMP_FORMAT_16BIT_TC_LSB_MASK
:
284 // FALLTHROUGH intended
285 case BMP_FORMAT_32BIT_TC_MASK
:
287 Scanline pAScan
= pAlphaReadAccess
->GetScanline( y
);
289 // using fallback for those
291 for( x
=0; x
<nWidth
; ++x
)
293 // yes. x and y are swapped on Get/SetPixel
294 aCol
= pReadAccess
->GetColor(y
,x
);
296 *pCurrOutput
++ = aCol
.GetBlue();
297 *pCurrOutput
++ = aCol
.GetGreen();
298 *pCurrOutput
++ = aCol
.GetRed();
300 // out notion of alpha is
301 // different from the rest
303 *pCurrOutput
++ = 255 - (BYTE
)*pAScan
++;
308 case BMP_FORMAT_1BIT_LSB_PAL
:
309 // FALLTHROUGH intended
310 case BMP_FORMAT_4BIT_LSN_PAL
:
311 // FALLTHROUGH intended
312 case BMP_FORMAT_8BIT_TC_MASK
:
313 // FALLTHROUGH intended
314 case BMP_FORMAT_24BIT_TC_RGB
:
315 // FALLTHROUGH intended
316 case BMP_FORMAT_24BIT_TC_MASK
:
317 // FALLTHROUGH intended
318 case BMP_FORMAT_16BIT_TC_MSB_MASK
:
319 // FALLTHROUGH intended
320 case BMP_FORMAT_32BIT_TC_ABGR
:
321 // FALLTHROUGH intended
322 case BMP_FORMAT_32BIT_TC_ARGB
:
323 // FALLTHROUGH intended
324 case BMP_FORMAT_32BIT_TC_BGRA
:
325 // FALLTHROUGH intended
326 case BMP_FORMAT_32BIT_TC_RGBA
:
327 // FALLTHROUGH intended
329 ENSURE_OR_THROW( false,
330 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
331 "Unexpected scanline format - has "
332 "WinSalBitmap::AcquireBuffer() changed?" );
338 Bitmap
aMask( rBmpEx
.GetMask() );
340 ScopedBitmapReadAccess
pMaskReadAccess( aMask
.AcquireReadAccess(),
343 // By convention, the access buffer always has
344 // one of the following formats:
346 // BMP_FORMAT_1BIT_MSB_PAL
347 // BMP_FORMAT_4BIT_MSN_PAL
348 // BMP_FORMAT_8BIT_PAL
349 // BMP_FORMAT_16BIT_TC_LSB_MASK
350 // BMP_FORMAT_24BIT_TC_BGR
351 // BMP_FORMAT_32BIT_TC_MASK
353 // and is always BMP_FORMAT_BOTTOM_UP
356 // WinSalBitmap::AcquireBuffer() sets up the
359 ENSURE_OR_THROW( pMaskReadAccess
.get() != NULL
,
360 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
361 "Unable to acquire read acces to mask" );
363 ENSURE_OR_THROW( pMaskReadAccess
->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL
,
364 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
365 "Unsupported mask scanline format" );
369 const int nMask( 1L );
370 const int nInitialBit(7);
371 sal_uInt8
* pCurrOutput( aBmpData
.mpBitmapData
.get() );
374 // mapping table, to get from mask index color to
375 // alpha value (which depends on the mask's palette)
376 sal_uInt8 aColorMap
[2];
378 const BitmapColor
& rCol0( pMaskReadAccess
->GetPaletteColor( 0 ) );
379 const BitmapColor
& rCol1( pMaskReadAccess
->GetPaletteColor( 1 ) );
381 // shortcut for true luminance calculation
382 // (assumes that palette is grey-level). Note the
383 // swapped the indices here, to account for the
384 // fact that VCL's notion of alpha is inverted to
385 // the rest of the world's.
386 aColorMap
[0] = rCol1
.GetRed();
387 aColorMap
[1] = rCol0
.GetRed();
389 for( y
=0; y
<nHeight
; ++y
)
391 switch( pReadAccess
->GetScanlineFormat() )
393 case BMP_FORMAT_8BIT_PAL
:
395 Scanline pScan
= pReadAccess
->GetScanline( y
);
396 Scanline pMScan
= pMaskReadAccess
->GetScanline( y
);
398 for( x
=0, nCurrBit
=nInitialBit
; x
<nWidth
; ++x
)
400 aCol
= pReadAccess
->GetPaletteColor( *pScan
++ );
402 *pCurrOutput
++ = aCol
.GetBlue();
403 *pCurrOutput
++ = aCol
.GetGreen();
404 *pCurrOutput
++ = aCol
.GetRed();
406 *pCurrOutput
++ = aColorMap
[ (pMScan
[ (x
& ~7L) >> 3L ] >> nCurrBit
) & nMask
];
407 nCurrBit
= ((nCurrBit
- 1) % 8L) & 7L;
412 case BMP_FORMAT_24BIT_TC_BGR
:
414 Scanline pScan
= pReadAccess
->GetScanline( y
);
415 Scanline pMScan
= pMaskReadAccess
->GetScanline( y
);
417 for( x
=0, nCurrBit
=nInitialBit
; x
<nWidth
; ++x
)
420 *pCurrOutput
++ = *pScan
++;
421 *pCurrOutput
++ = *pScan
++;
422 *pCurrOutput
++ = *pScan
++;
424 *pCurrOutput
++ = aColorMap
[ (pMScan
[ (x
& ~7L) >> 3L ] >> nCurrBit
) & nMask
];
425 nCurrBit
= ((nCurrBit
- 1) % 8L) & 7L;
430 // TODO(P2): Might be advantageous
431 // to hand-formulate the following
433 case BMP_FORMAT_1BIT_MSB_PAL
:
434 // FALLTHROUGH intended
435 case BMP_FORMAT_4BIT_MSN_PAL
:
436 // FALLTHROUGH intended
437 case BMP_FORMAT_16BIT_TC_LSB_MASK
:
438 // FALLTHROUGH intended
439 case BMP_FORMAT_32BIT_TC_MASK
:
441 Scanline pMScan
= pMaskReadAccess
->GetScanline( y
);
443 // using fallback for those
445 for( x
=0, nCurrBit
=nInitialBit
; x
<nWidth
; ++x
)
447 // yes. x and y are swapped on Get/SetPixel
448 aCol
= pReadAccess
->GetColor(y
,x
);
451 *pCurrOutput
++ = aCol
.GetBlue();
452 *pCurrOutput
++ = aCol
.GetGreen();
453 *pCurrOutput
++ = aCol
.GetRed();
455 *pCurrOutput
++ = aColorMap
[ (pMScan
[ (x
& ~7L) >> 3L ] >> nCurrBit
) & nMask
];
456 nCurrBit
= ((nCurrBit
- 1) % 8L) & 7L;
461 case BMP_FORMAT_1BIT_LSB_PAL
:
462 // FALLTHROUGH intended
463 case BMP_FORMAT_4BIT_LSN_PAL
:
464 // FALLTHROUGH intended
465 case BMP_FORMAT_8BIT_TC_MASK
:
466 // FALLTHROUGH intended
467 case BMP_FORMAT_24BIT_TC_RGB
:
468 // FALLTHROUGH intended
469 case BMP_FORMAT_24BIT_TC_MASK
:
470 // FALLTHROUGH intended
471 case BMP_FORMAT_16BIT_TC_MSB_MASK
:
472 // FALLTHROUGH intended
473 case BMP_FORMAT_32BIT_TC_ABGR
:
474 // FALLTHROUGH intended
475 case BMP_FORMAT_32BIT_TC_ARGB
:
476 // FALLTHROUGH intended
477 case BMP_FORMAT_32BIT_TC_BGRA
:
478 // FALLTHROUGH intended
479 case BMP_FORMAT_32BIT_TC_RGBA
:
480 // FALLTHROUGH intended
482 ENSURE_OR_THROW( false,
483 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
484 "Unexpected scanline format - has "
485 "WinSalBitmap::AcquireBuffer() changed?" );
493 bool drawVCLBitmapEx( const ::boost::shared_ptr
< Gdiplus::Graphics
>& rGraphics
,
494 const ::BitmapEx
& rBmpEx
)
496 if( !rBmpEx
.IsTransparent() )
498 Bitmap
aBmp( rBmpEx
.GetBitmap() );
499 return drawVCLBitmap( rGraphics
, aBmp
);
503 return drawRGBABits( rGraphics
,
504 bitmapFromVCLBitmapEx( rBmpEx
) );
509 bool drawVCLBitmapFromXBitmap( const ::boost::shared_ptr
< Gdiplus::Graphics
>& rGraphics
,
510 const uno::Reference
< rendering::XBitmap
>& xBitmap
)
512 // TODO(F2): add support for floating point bitmap formats
513 uno::Reference
< rendering::XIntegerReadOnlyBitmap
> xIntBmp(
514 xBitmap
, uno::UNO_QUERY
);
519 ::BitmapEx aBmpEx
= ::vcl::unotools::bitmapExFromXBitmap( xIntBmp
);
523 return drawVCLBitmapEx( rGraphics
, aBmpEx
);