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