1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_canvas.hxx"
31 #include <vcl/canvastools.hxx>
33 #include <vcl/bitmap.hxx>
34 #include <vcl/bitmapex.hxx>
35 #include <vcl/bmpacc.hxx>
36 #include <tools/diagnose_ex.h>
38 #include "dx_impltools.hxx"
39 #include <basegfx/numeric/ftools.hxx>
41 #include <canvas/debug.hxx>
42 #include <canvas/verbosetrace.hxx>
44 #include <com/sun/star/lang/XServiceInfo.hpp>
45 #include <com/sun/star/rendering/XIntegerBitmap.hpp>
47 #include <boost/scoped_array.hpp>
49 #include "dx_vcltools.hxx"
51 using namespace ::com::sun::star
;
59 /// Calc number of colors in given BitmapInfoHeader
60 sal_Int32
calcDIBColorCount( const BITMAPINFOHEADER
& rBIH
)
62 if( rBIH
.biSize
!= sizeof( BITMAPCOREHEADER
) )
64 if( rBIH
.biBitCount
<= 8 )
67 return rBIH
.biClrUsed
;
69 return 1L << rBIH
.biBitCount
;
74 BITMAPCOREHEADER
* pCoreHeader
= (BITMAPCOREHEADER
*)&rBIH
;
76 if( pCoreHeader
->bcBitCount
<= 8 )
77 return 1L << pCoreHeader
->bcBitCount
;
80 return 0; // nothing known
83 /// Draw DI bits to given Graphics
84 bool drawDIBits( const ::boost::shared_ptr
< Gdiplus::Graphics
>& rGraphics
,
88 BitmapSharedPtr pBitmap
;
90 const BITMAPINFO
* pBI
= (BITMAPINFO
*)GlobalLock( (HGLOBAL
)hDIB
);
94 const BITMAPINFOHEADER
* pBIH
= (BITMAPINFOHEADER
*)pBI
;
95 const BYTE
* pBits
= (BYTE
*) pBI
+ *(DWORD
*)pBI
+
96 calcDIBColorCount( *pBIH
) * sizeof( RGBQUAD
);
98 // forward to outsourced GDI+ rendering method
100 bRet
= tools::drawDIBits( rGraphics
, *pBI
, (void*)pBits
);
102 GlobalUnlock( (HGLOBAL
)hDIB
);
108 /** Draw VCL bitmap to given Graphics
111 Reference to bitmap. Might get modified, in such a way
112 that it will hold a DIB after a successful function call.
114 bool drawVCLBitmap( const ::boost::shared_ptr
< Gdiplus::Graphics
>& rGraphics
,
117 BitmapSystemData aBmpSysData
;
119 if( !rBmp
.GetSystemData( aBmpSysData
) ||
122 // first of all, ensure that Bitmap contains a DIB, by
123 // aquiring a read access
124 BitmapReadAccess
* pReadAcc
= rBmp
.AcquireReadAccess();
126 // TODO(P2): Acquiring a read access can actually
127 // force a read from VRAM, thus, avoiding this
128 // step somehow will increase performance
132 // try again: now, WinSalBitmap must have
134 if( rBmp
.GetSystemData( aBmpSysData
) &&
137 return drawDIBits( rGraphics
,
141 rBmp
.ReleaseAccess( pReadAcc
);
146 return drawDIBits( rGraphics
,
150 // failed to generate DIBits from vcl bitmap
154 /** Create a chunk of raw RGBA data GDI+ Bitmap from VCL BbitmapEX
156 RawRGBABitmap
bitmapFromVCLBitmapEx( const ::BitmapEx
& rBmpEx
)
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)
164 ENSURE_OR_THROW( rBmpEx
.IsTransparent(),
165 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
166 "BmpEx not transparent" );
168 // convert transparent bitmap to 32bit RGBA
169 // ========================================
171 const ::Size
aBmpSize( rBmpEx
.GetSizePixel() );
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
] );
178 Bitmap
aBitmap( rBmpEx
.GetBitmap() );
180 ScopedBitmapReadAccess
pReadAccess( aBitmap
.AcquireReadAccess(),
183 const sal_Int32
nWidth( aBmpSize
.Width() );
184 const sal_Int32
nHeight( aBmpSize
.Height() );
186 ENSURE_OR_THROW( pReadAccess
.get() != NULL
,
187 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
188 "Unable to acquire read acces to bitmap" );
190 if( rBmpEx
.IsAlpha() )
192 Bitmap
aAlpha( rBmpEx
.GetAlpha().GetBitmap() );
194 ScopedBitmapReadAccess
pAlphaReadAccess( aAlpha
.AcquireReadAccess(),
197 // By convention, the access buffer always has
198 // one of the following formats:
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
207 // and is always BMP_FORMAT_BOTTOM_UP
210 // WinSalBitmap::AcquireBuffer() sets up the
213 ENSURE_OR_THROW( pAlphaReadAccess
.get() != NULL
,
214 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
215 "Unable to acquire read acces to alpha" );
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" );
223 const sal_Int32
nWidth( aBmpSize
.Width() );
224 const sal_Int32
nHeight( aBmpSize
.Height() );
225 sal_uInt8
* pCurrOutput( aBmpData
.mpBitmapData
.get() );
228 for( y
=0; y
<nHeight
; ++y
)
230 switch( pReadAccess
->GetScanlineFormat() )
232 case BMP_FORMAT_8BIT_PAL
:
234 Scanline pScan
= pReadAccess
->GetScanline( y
);
235 Scanline pAScan
= pAlphaReadAccess
->GetScanline( y
);
237 for( x
=0; x
<nWidth
; ++x
)
239 aCol
= pReadAccess
->GetPaletteColor( *pScan
++ );
241 *pCurrOutput
++ = aCol
.GetBlue();
242 *pCurrOutput
++ = aCol
.GetGreen();
243 *pCurrOutput
++ = aCol
.GetRed();
245 // out notion of alpha is
246 // different from the rest
248 *pCurrOutput
++ = 255 - (BYTE
)*pAScan
++;
253 case BMP_FORMAT_24BIT_TC_BGR
:
255 Scanline pScan
= pReadAccess
->GetScanline( y
);
256 Scanline pAScan
= pAlphaReadAccess
->GetScanline( y
);
258 for( x
=0; x
<nWidth
; ++x
)
261 *pCurrOutput
++ = *pScan
++;
262 *pCurrOutput
++ = *pScan
++;
263 *pCurrOutput
++ = *pScan
++;
265 // out notion of alpha is
266 // different from the rest
268 *pCurrOutput
++ = 255 - (BYTE
)*pAScan
++;
273 // TODO(P2): Might be advantageous
274 // to hand-formulate the following
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
:
284 Scanline pAScan
= pAlphaReadAccess
->GetScanline( y
);
286 // using fallback for those
288 for( x
=0; x
<nWidth
; ++x
)
290 // yes. x and y are swapped on Get/SetPixel
291 aCol
= pReadAccess
->GetColor(y
,x
);
293 *pCurrOutput
++ = aCol
.GetBlue();
294 *pCurrOutput
++ = aCol
.GetGreen();
295 *pCurrOutput
++ = aCol
.GetRed();
297 // out notion of alpha is
298 // different from the rest
300 *pCurrOutput
++ = 255 - (BYTE
)*pAScan
++;
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
326 ENSURE_OR_THROW( false,
327 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
328 "Unexpected scanline format - has "
329 "WinSalBitmap::AcquireBuffer() changed?" );
335 Bitmap
aMask( rBmpEx
.GetMask() );
337 ScopedBitmapReadAccess
pMaskReadAccess( aMask
.AcquireReadAccess(),
340 // By convention, the access buffer always has
341 // one of the following formats:
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
350 // and is always BMP_FORMAT_BOTTOM_UP
353 // WinSalBitmap::AcquireBuffer() sets up the
356 ENSURE_OR_THROW( pMaskReadAccess
.get() != NULL
,
357 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
358 "Unable to acquire read acces to mask" );
360 ENSURE_OR_THROW( pMaskReadAccess
->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL
,
361 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
362 "Unsupported mask scanline format" );
366 const int nMask( 1L );
367 const int nInitialBit(7);
368 sal_uInt8
* pCurrOutput( aBmpData
.mpBitmapData
.get() );
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];
375 const BitmapColor
& rCol0( pMaskReadAccess
->GetPaletteColor( 0 ) );
376 const BitmapColor
& rCol1( pMaskReadAccess
->GetPaletteColor( 1 ) );
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();
386 for( y
=0; y
<nHeight
; ++y
)
388 switch( pReadAccess
->GetScanlineFormat() )
390 case BMP_FORMAT_8BIT_PAL
:
392 Scanline pScan
= pReadAccess
->GetScanline( y
);
393 Scanline pMScan
= pMaskReadAccess
->GetScanline( y
);
395 for( x
=0, nCurrBit
=nInitialBit
; x
<nWidth
; ++x
)
397 aCol
= pReadAccess
->GetPaletteColor( *pScan
++ );
399 *pCurrOutput
++ = aCol
.GetBlue();
400 *pCurrOutput
++ = aCol
.GetGreen();
401 *pCurrOutput
++ = aCol
.GetRed();
403 *pCurrOutput
++ = aColorMap
[ (pMScan
[ (x
& ~7L) >> 3L ] >> nCurrBit
) & nMask
];
404 nCurrBit
= ((nCurrBit
- 1) % 8L) & 7L;
409 case BMP_FORMAT_24BIT_TC_BGR
:
411 Scanline pScan
= pReadAccess
->GetScanline( y
);
412 Scanline pMScan
= pMaskReadAccess
->GetScanline( y
);
414 for( x
=0, nCurrBit
=nInitialBit
; x
<nWidth
; ++x
)
417 *pCurrOutput
++ = *pScan
++;
418 *pCurrOutput
++ = *pScan
++;
419 *pCurrOutput
++ = *pScan
++;
421 *pCurrOutput
++ = aColorMap
[ (pMScan
[ (x
& ~7L) >> 3L ] >> nCurrBit
) & nMask
];
422 nCurrBit
= ((nCurrBit
- 1) % 8L) & 7L;
427 // TODO(P2): Might be advantageous
428 // to hand-formulate the following
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
:
438 Scanline pMScan
= pMaskReadAccess
->GetScanline( y
);
440 // using fallback for those
442 for( x
=0, nCurrBit
=nInitialBit
; x
<nWidth
; ++x
)
444 // yes. x and y are swapped on Get/SetPixel
445 aCol
= pReadAccess
->GetColor(y
,x
);
448 *pCurrOutput
++ = aCol
.GetBlue();
449 *pCurrOutput
++ = aCol
.GetGreen();
450 *pCurrOutput
++ = aCol
.GetRed();
452 *pCurrOutput
++ = aColorMap
[ (pMScan
[ (x
& ~7L) >> 3L ] >> nCurrBit
) & nMask
];
453 nCurrBit
= ((nCurrBit
- 1) % 8L) & 7L;
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
479 ENSURE_OR_THROW( false,
480 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
481 "Unexpected scanline format - has "
482 "WinSalBitmap::AcquireBuffer() changed?" );
490 bool drawVCLBitmapEx( const ::boost::shared_ptr
< Gdiplus::Graphics
>& rGraphics
,
491 const ::BitmapEx
& rBmpEx
)
493 if( !rBmpEx
.IsTransparent() )
495 Bitmap
aBmp( rBmpEx
.GetBitmap() );
496 return drawVCLBitmap( rGraphics
, aBmp
);
500 return drawRGBABits( rGraphics
,
501 bitmapFromVCLBitmapEx( rBmpEx
) );
506 bool drawVCLBitmapFromXBitmap( const ::boost::shared_ptr
< Gdiplus::Graphics
>& rGraphics
,
507 const uno::Reference
< rendering::XBitmap
>& xBitmap
)
509 // TODO(F2): add support for floating point bitmap formats
510 uno::Reference
< rendering::XIntegerReadOnlyBitmap
> xIntBmp(
511 xBitmap
, uno::UNO_QUERY
);
516 ::BitmapEx aBmpEx
= ::vcl::unotools::bitmapExFromXBitmap( xIntBmp
);
520 return drawVCLBitmapEx( rGraphics
, aBmpEx
);