LibreOffice Module canvas (master)  1
dx_vcltools.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 
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>
30 
31 #include "dx_impltools.hxx"
32 #include "dx_vcltools.hxx"
33 
34 using namespace ::com::sun::star;
35 
36 namespace dxcanvas::tools
37 {
38  namespace
39  {
41  sal_Int32 calcDIBColorCount( const BITMAPINFOHEADER& rBIH )
42  {
43  if( rBIH.biSize != sizeof( BITMAPCOREHEADER ) )
44  {
45  if( rBIH.biBitCount <= 8 )
46  {
47  if( rBIH.biClrUsed )
48  return rBIH.biClrUsed;
49  else
50  return 1 << rBIH.biBitCount;
51  }
52  }
53  else
54  {
55  BITMAPCOREHEADER const * pCoreHeader = reinterpret_cast<BITMAPCOREHEADER const *>(&rBIH);
56 
57  if( pCoreHeader->bcBitCount <= 8 )
58  return 1 << pCoreHeader->bcBitCount;
59  }
60 
61  return 0; // nothing known
62  }
63 
65  bool drawDIBits( const std::shared_ptr< Gdiplus::Graphics >& rGraphics,
66  const void* hDIB )
67  {
68  bool bRet( false );
69 
70  const BITMAPINFO* pBI = static_cast<BITMAPINFO*>(GlobalLock( const_cast<void *>(hDIB) ));
71 
72  if( pBI )
73  {
74  const BYTE* pBits = reinterpret_cast<BYTE const *>(pBI) + pBI->bmiHeader.biSize +
75  calcDIBColorCount( pBI->bmiHeader ) * sizeof( RGBQUAD );
76 
77  // forward to outsourced GDI+ rendering method
78  // (header clashes)
79  bRet = tools::drawDIBits( rGraphics, *pBI, pBits );
80 
81  GlobalUnlock( const_cast<void *>(hDIB) );
82  }
83 
84  return bRet;
85  }
86 
93  bool drawVCLBitmap( const std::shared_ptr< Gdiplus::Graphics >& rGraphics,
94  ::Bitmap& rBmp )
95  {
96  BitmapSystemData aBmpSysData;
97 
98  if( !rBmp.GetSystemData( aBmpSysData ) ||
99  !aBmpSysData.pDIB )
100  {
101  // first of all, ensure that Bitmap contains a DIB, by
102  // acquiring a read access
103  BitmapReadAccess* pReadAcc = rBmp.AcquireReadAccess();
104 
105  // TODO(P2): Acquiring a read access can actually
106  // force a read from VRAM, thus, avoiding this
107  // step somehow will increase performance
108  // here.
109  if( pReadAcc )
110  {
111  // try again: now, WinSalBitmap must have
112  // generated a DIB
113  if( rBmp.GetSystemData( aBmpSysData ) &&
114  aBmpSysData.pDIB )
115  {
116  return drawDIBits( rGraphics,
117  aBmpSysData.pDIB );
118  }
119 
120  Bitmap::ReleaseAccess( pReadAcc );
121  }
122  }
123  else
124  {
125  return drawDIBits( rGraphics,
126  aBmpSysData.pDIB );
127  }
128 
129  // failed to generate DIBits from vcl bitmap
130  return false;
131  }
132 
135  RawRGBABitmap bitmapFromVCLBitmapEx( const ::BitmapEx& rBmpEx )
136  {
137  // TODO(P2): Avoid temporary bitmap generation, maybe
138  // even ensure that created DIBs are copied back to
139  // BmpEx (currently, every AcquireReadAccess() will
140  // make the local bitmap copy unique, effectively
141  // duplicating the memory used)
142 
143  ENSURE_OR_THROW( rBmpEx.IsAlpha(),
144  "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
145  "BmpEx has no alpha" );
146 
147  // convert transparent bitmap to 32bit RGBA
148  // ========================================
149 
150  const ::Size aBmpSize( rBmpEx.GetSizePixel() );
151 
152  RawRGBABitmap aBmpData;
153  aBmpData.mnWidth = aBmpSize.Width();
154  aBmpData.mnHeight = aBmpSize.Height();
155  aBmpData.maBitmapData.resize(4*aBmpData.mnWidth*aBmpData.mnHeight);
156 
157  Bitmap aBitmap( rBmpEx.GetBitmap() );
158 
159  Bitmap::ScopedReadAccess pReadAccess( aBitmap );
160 
161  const sal_Int32 nWidth( aBmpSize.Width() );
162  const sal_Int32 nHeight( aBmpSize.Height() );
163 
164  ENSURE_OR_THROW( pReadAccess.get() != nullptr,
165  "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
166  "Unable to acquire read access to bitmap" );
167 
168  Bitmap aAlpha( rBmpEx.GetAlpha().GetBitmap() );
169 
170  Bitmap::ScopedReadAccess pAlphaReadAccess( aAlpha );
171 
172  // By convention, the access buffer always has
173  // one of the following formats:
174 
175  // ScanlineFormat::N1BitMsbPal
176  // ScanlineFormat::N8BitPal
177  // ScanlineFormat::N24BitTcBgr
178  // ScanlineFormat::N32BitTcMask
179 
180  // and is always ScanlineFormat::BottomUp
181 
182  // This is the way
183  // WinSalBitmap::AcquireBuffer() sets up the
184  // buffer
185 
186  ENSURE_OR_THROW( pAlphaReadAccess.get() != nullptr,
187  "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
188  "Unable to acquire read access to alpha" );
189 
190  ENSURE_OR_THROW( pAlphaReadAccess->GetScanlineFormat() == ScanlineFormat::N8BitPal,
191  "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
192  "Unsupported alpha scanline format" );
193 
194  BitmapColor aCol;
195  sal_uInt8* pCurrOutput(aBmpData.maBitmapData.data());
196  int x, y;
197 
198  for( y=0; y<nHeight; ++y )
199  {
200  switch( pReadAccess->GetScanlineFormat() )
201  {
202  case ScanlineFormat::N8BitPal:
203  {
204  Scanline pScan = pReadAccess->GetScanline( y );
205  Scanline pAScan = pAlphaReadAccess->GetScanline( y );
206 
207  for( x=0; x<nWidth; ++x )
208  {
209  aCol = pReadAccess->GetPaletteColor( *pScan++ );
210 
211  *pCurrOutput++ = aCol.GetBlue();
212  *pCurrOutput++ = aCol.GetGreen();
213  *pCurrOutput++ = aCol.GetRed();
214 
215  // our notion of alpha is
216  // different from the rest
217  // of the world's
218  *pCurrOutput++ = 255 - static_cast<BYTE>(*pAScan++);
219  }
220  }
221  break;
222 
223  case ScanlineFormat::N24BitTcBgr:
224  {
225  Scanline pScan = pReadAccess->GetScanline( y );
226  Scanline pAScan = pAlphaReadAccess->GetScanline( y );
227 
228  for( x=0; x<nWidth; ++x )
229  {
230  // store as RGBA
231  *pCurrOutput++ = *pScan++;
232  *pCurrOutput++ = *pScan++;
233  *pCurrOutput++ = *pScan++;
234 
235  // our notion of alpha is
236  // different from the rest
237  // of the world's
238  *pCurrOutput++ = 255 - static_cast<BYTE>(*pAScan++);
239  }
240  }
241  break;
242 
243  // TODO(P2): Might be advantageous
244  // to hand-formulate the following
245  // formats, too.
246  case ScanlineFormat::N1BitMsbPal:
247  case ScanlineFormat::N32BitTcMask:
248  {
249  Scanline pAScan = pAlphaReadAccess->GetScanline( y );
250 
251  // using fallback for those
252  // seldom formats
253  for( x=0; x<nWidth; ++x )
254  {
255  // yes. x and y are swapped on Get/SetPixel
256  aCol = pReadAccess->GetColor(y,x);
257 
258  *pCurrOutput++ = aCol.GetBlue();
259  *pCurrOutput++ = aCol.GetGreen();
260  *pCurrOutput++ = aCol.GetRed();
261 
262  // our notion of alpha is
263  // different from the rest
264  // of the world's
265  *pCurrOutput++ = 255 - static_cast<BYTE>(*pAScan++);
266  }
267  }
268  break;
269 
270  case ScanlineFormat::N1BitLsbPal:
271  case ScanlineFormat::N24BitTcRgb:
272  case ScanlineFormat::N32BitTcAbgr:
273  case ScanlineFormat::N32BitTcArgb:
274  case ScanlineFormat::N32BitTcBgra:
275  case ScanlineFormat::N32BitTcRgba:
276  default:
277  ENSURE_OR_THROW( false,
278  "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
279  "Unexpected scanline format - has "
280  "WinSalBitmap::AcquireBuffer() changed?" );
281  }
282  }
283 
284  return aBmpData;
285  }
286 
287  bool drawVCLBitmapEx( const std::shared_ptr< Gdiplus::Graphics >& rGraphics,
288  const ::BitmapEx& rBmpEx )
289  {
290  if( !rBmpEx.IsAlpha() )
291  {
292  Bitmap aBmp( rBmpEx.GetBitmap() );
293  return drawVCLBitmap( rGraphics, aBmp );
294  }
295  else
296  {
297  return drawRGBABits( rGraphics,
298  bitmapFromVCLBitmapEx( rBmpEx ) );
299  }
300  }
301  }
302 
303  bool drawVCLBitmapFromXBitmap( const std::shared_ptr< Gdiplus::Graphics >& rGraphics,
304  const uno::Reference< rendering::XBitmap >& xBitmap )
305  {
306  // TODO(F2): add support for floating point bitmap formats
307  uno::Reference< rendering::XIntegerReadOnlyBitmap > xIntBmp(
308  xBitmap, uno::UNO_QUERY );
309 
310  if( !xIntBmp.is() )
311  return false;
312 
314  if( aBmpEx.IsEmpty() )
315  return false;
316 
317  return drawVCLBitmapEx( rGraphics, aBmpEx );
318  }
319 }
320 
321 
322 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
unsigned char BYTE
BitmapReadAccess * AcquireReadAccess()
bool drawDIBits(const std::shared_ptr< Gdiplus::Graphics > &rGraphics, const BITMAPINFO &rBI, const void *pBits)
::BitmapEx bitmapExFromXBitmap(const uno::Reference< rendering::XIntegerReadOnlyBitmap > &xInputBitmap)
float x
Definition: dx_9rm.cxx:190
float y
Definition: dx_9rm.cxx:190
bool drawRGBABits(const std::shared_ptr< Gdiplus::Graphics > &rGraphics, const RawRGBABitmap &rRawRGBAData)
bool IsEmpty() const
sal_uInt8 * Scanline
bool GetSystemData(BitmapSystemData &rData) const
static void ReleaseAccess(BitmapInfoAccess *pAccess)
Gdiplus::BitmapData aBmpData
#define ENSURE_OR_THROW(c, m)
unsigned char sal_uInt8
bool drawVCLBitmapFromXBitmap(const std::shared_ptr< Gdiplus::Graphics > &rGraphics, const uno::Reference< rendering::XBitmap > &xBitmap)