1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <basegfx/numeric/ftools.hxx>
23 #include <com/sun/star/lang/XServiceInfo.hpp>
24 #include <com/sun/star/rendering/XIntegerBitmap.hpp>
25 #include <tools/diagnose_ex.h>
26 #include <vcl/bitmap.hxx>
27 #include <vcl/bitmapex.hxx>
28 #include <vcl/BitmapReadAccess.hxx>
29 #include <vcl/canvastools.hxx>
31 #include "dx_impltools.hxx"
32 #include "dx_vcltools.hxx"
34 using namespace ::com::sun::star
;
36 namespace dxcanvas::tools
40 /// Calc number of colors in given BitmapInfoHeader
41 sal_Int32
calcDIBColorCount( const BITMAPINFOHEADER
& rBIH
)
43 if( rBIH
.biSize
!= sizeof( BITMAPCOREHEADER
) )
45 if( rBIH
.biBitCount
<= 8 )
48 return rBIH
.biClrUsed
;
50 return 1 << rBIH
.biBitCount
;
55 BITMAPCOREHEADER
const * pCoreHeader
= reinterpret_cast<BITMAPCOREHEADER
const *>(&rBIH
);
57 if( pCoreHeader
->bcBitCount
<= 8 )
58 return 1 << pCoreHeader
->bcBitCount
;
61 return 0; // nothing known
64 /// Draw DI bits to given Graphics
65 bool drawDIBits( const std::shared_ptr
< Gdiplus::Graphics
>& rGraphics
,
69 BitmapSharedPtr pBitmap
;
71 const BITMAPINFO
* pBI
= static_cast<BITMAPINFO
*>(GlobalLock( const_cast<void *>(hDIB
) ));
75 const BYTE
* pBits
= reinterpret_cast<BYTE
const *>(pBI
) + pBI
->bmiHeader
.biSize
+
76 calcDIBColorCount( pBI
->bmiHeader
) * sizeof( RGBQUAD
);
78 // forward to outsourced GDI+ rendering method
80 bRet
= tools::drawDIBits( rGraphics
, *pBI
, pBits
);
82 GlobalUnlock( const_cast<void *>(hDIB
) );
88 /** Draw VCL bitmap to given Graphics
91 Reference to bitmap. Might get modified, in such a way
92 that it will hold a DIB after a successful function call.
94 bool drawVCLBitmap( const std::shared_ptr
< Gdiplus::Graphics
>& rGraphics
,
97 BitmapSystemData aBmpSysData
;
99 if( !rBmp
.GetSystemData( aBmpSysData
) ||
102 // first of all, ensure that Bitmap contains a DIB, by
103 // acquiring a read access
104 BitmapReadAccess
* pReadAcc
= rBmp
.AcquireReadAccess();
106 // TODO(P2): Acquiring a read access can actually
107 // force a read from VRAM, thus, avoiding this
108 // step somehow will increase performance
112 // try again: now, WinSalBitmap must have
114 if( rBmp
.GetSystemData( aBmpSysData
) &&
117 return drawDIBits( rGraphics
,
121 Bitmap::ReleaseAccess( pReadAcc
);
126 return drawDIBits( rGraphics
,
130 // failed to generate DIBits from vcl bitmap
134 /** Create a chunk of raw RGBA data GDI+ Bitmap from VCL BitmapEx
136 RawRGBABitmap
bitmapFromVCLBitmapEx( const ::BitmapEx
& rBmpEx
)
138 // TODO(P2): Avoid temporary bitmap generation, maybe
139 // even ensure that created DIBs are copied back to
140 // BmpEx (currently, every AcquireReadAccess() will
141 // make the local bitmap copy unique, effectively
142 // duplicating the memory used)
144 ENSURE_OR_THROW( rBmpEx
.IsAlpha(),
145 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
146 "BmpEx has no alpha" );
148 // convert transparent bitmap to 32bit RGBA
149 // ========================================
151 const ::Size
aBmpSize( rBmpEx
.GetSizePixel() );
153 RawRGBABitmap aBmpData
;
154 aBmpData
.mnWidth
= aBmpSize
.Width();
155 aBmpData
.mnHeight
= aBmpSize
.Height();
156 aBmpData
.maBitmapData
.resize(4*aBmpData
.mnWidth
*aBmpData
.mnHeight
);
158 Bitmap
aBitmap( rBmpEx
.GetBitmap() );
160 Bitmap::ScopedReadAccess
pReadAccess( aBitmap
);
162 const sal_Int32
nWidth( aBmpSize
.Width() );
163 const sal_Int32
nHeight( aBmpSize
.Height() );
165 ENSURE_OR_THROW( pReadAccess
.get() != nullptr,
166 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
167 "Unable to acquire read access to bitmap" );
169 Bitmap
aAlpha( rBmpEx
.GetAlpha().GetBitmap() );
171 Bitmap::ScopedReadAccess
pAlphaReadAccess( aAlpha
);
173 // By convention, the access buffer always has
174 // one of the following formats:
176 // ScanlineFormat::N1BitMsbPal
177 // ScanlineFormat::N8BitPal
178 // ScanlineFormat::N24BitTcBgr
179 // ScanlineFormat::N32BitTcMask
181 // and is always ScanlineFormat::BottomUp
184 // WinSalBitmap::AcquireBuffer() sets up the
187 ENSURE_OR_THROW( pAlphaReadAccess
.get() != nullptr,
188 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
189 "Unable to acquire read access to alpha" );
191 ENSURE_OR_THROW( pAlphaReadAccess
->GetScanlineFormat() == ScanlineFormat::N8BitPal
,
192 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
193 "Unsupported alpha scanline format" );
196 sal_uInt8
* pCurrOutput(aBmpData
.maBitmapData
.data());
199 for( y
=0; y
<nHeight
; ++y
)
201 switch( pReadAccess
->GetScanlineFormat() )
203 case ScanlineFormat::N8BitPal
:
205 Scanline pScan
= pReadAccess
->GetScanline( y
);
206 Scanline pAScan
= pAlphaReadAccess
->GetScanline( y
);
208 for( x
=0; x
<nWidth
; ++x
)
210 aCol
= pReadAccess
->GetPaletteColor( *pScan
++ );
212 *pCurrOutput
++ = aCol
.GetBlue();
213 *pCurrOutput
++ = aCol
.GetGreen();
214 *pCurrOutput
++ = aCol
.GetRed();
216 // our notion of alpha is
217 // different from the rest
219 *pCurrOutput
++ = 255 - static_cast<BYTE
>(*pAScan
++);
224 case ScanlineFormat::N24BitTcBgr
:
226 Scanline pScan
= pReadAccess
->GetScanline( y
);
227 Scanline pAScan
= pAlphaReadAccess
->GetScanline( y
);
229 for( x
=0; x
<nWidth
; ++x
)
232 *pCurrOutput
++ = *pScan
++;
233 *pCurrOutput
++ = *pScan
++;
234 *pCurrOutput
++ = *pScan
++;
236 // our notion of alpha is
237 // different from the rest
239 *pCurrOutput
++ = 255 - static_cast<BYTE
>(*pAScan
++);
244 // TODO(P2): Might be advantageous
245 // to hand-formulate the following
247 case ScanlineFormat::N1BitMsbPal
:
248 case ScanlineFormat::N32BitTcMask
:
250 Scanline pAScan
= pAlphaReadAccess
->GetScanline( y
);
252 // using fallback for those
254 for( x
=0; x
<nWidth
; ++x
)
256 // yes. x and y are swapped on Get/SetPixel
257 aCol
= pReadAccess
->GetColor(y
,x
);
259 *pCurrOutput
++ = aCol
.GetBlue();
260 *pCurrOutput
++ = aCol
.GetGreen();
261 *pCurrOutput
++ = aCol
.GetRed();
263 // our notion of alpha is
264 // different from the rest
266 *pCurrOutput
++ = 255 - static_cast<BYTE
>(*pAScan
++);
271 case ScanlineFormat::N1BitLsbPal
:
272 case ScanlineFormat::N24BitTcRgb
:
273 case ScanlineFormat::N32BitTcAbgr
:
274 case ScanlineFormat::N32BitTcArgb
:
275 case ScanlineFormat::N32BitTcBgra
:
276 case ScanlineFormat::N32BitTcRgba
:
278 ENSURE_OR_THROW( false,
279 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
280 "Unexpected scanline format - has "
281 "WinSalBitmap::AcquireBuffer() changed?" );
288 bool drawVCLBitmapEx( const std::shared_ptr
< Gdiplus::Graphics
>& rGraphics
,
289 const ::BitmapEx
& rBmpEx
)
291 if( !rBmpEx
.IsAlpha() )
293 Bitmap
aBmp( rBmpEx
.GetBitmap() );
294 return drawVCLBitmap( rGraphics
, aBmp
);
298 return drawRGBABits( rGraphics
,
299 bitmapFromVCLBitmapEx( rBmpEx
) );
304 bool drawVCLBitmapFromXBitmap( const std::shared_ptr
< Gdiplus::Graphics
>& rGraphics
,
305 const uno::Reference
< rendering::XBitmap
>& xBitmap
)
307 // TODO(F2): add support for floating point bitmap formats
308 uno::Reference
< rendering::XIntegerReadOnlyBitmap
> xIntBmp(
309 xBitmap
, uno::UNO_QUERY
);
314 ::BitmapEx aBmpEx
= vcl::unotools::bitmapExFromXBitmap( xIntBmp
);
315 if( aBmpEx
.IsEmpty() )
318 return drawVCLBitmapEx( rGraphics
, aBmpEx
);
323 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */