LibreOffice Module vcl (master)  1
BitmapTools.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  */
10 
11 #include <sal/config.h>
12 
13 #include <array>
14 #include <utility>
15 
16 #include <tools/helpers.hxx>
17 #include <vcl/BitmapTools.hxx>
18 
19 #include <sal/log.hxx>
21 #include <comphelper/seqstream.hxx>
22 #include <vcl/canvastools.hxx>
24 
25 #include <com/sun/star/graphic/SvgTools.hpp>
26 #include <com/sun/star/graphic/Primitive2DTools.hpp>
27 
29 
30 #include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp>
31 
32 #include <vcl/dibtools.hxx>
33 #include <vcl/settings.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/virdev.hxx>
36 #if ENABLE_CAIRO_CANVAS
37 #include <cairo.h>
38 #endif
39 #include <tools/diagnose_ex.h>
40 #include <tools/fract.hxx>
41 #include <tools/stream.hxx>
43 
44 using namespace css;
45 
48 
49 namespace vcl::bitmap
50 {
51 
52 BitmapEx loadFromName(const OUString& rFileName, const ImageLoadFlags eFlags)
53 {
54  bool bSuccess = true;
55  OUString aIconTheme;
56  BitmapEx aBitmapEx;
57  try
58  {
60  ImageTree::get().loadImage(rFileName, aIconTheme, aBitmapEx, true, eFlags);
61  }
62  catch (...)
63  {
64  bSuccess = false;
65  }
66 
67  SAL_WARN_IF(!bSuccess, "vcl", "vcl::bitmap::loadFromName : could not load image " << rFileName << " via icon theme " << aIconTheme);
68 
69  return aBitmapEx;
70 }
71 
72 void loadFromSvg(SvStream& rStream, const OUString& sPath, BitmapEx& rBitmapEx, double fScalingFactor)
73 {
74  uno::Reference<uno::XComponentContext> xContext(comphelper::getProcessComponentContext());
75  const uno::Reference<graphic::XSvgParser> xSvgParser = graphic::SvgTools::create(xContext);
76 
77  std::size_t nSize = rStream.remainingSize();
78  std::vector<sal_Int8> aBuffer(nSize + 1);
79  rStream.ReadBytes(aBuffer.data(), nSize);
80  aBuffer[nSize] = 0;
81 
82  uno::Sequence<sal_Int8> aData(aBuffer.data(), nSize + 1);
83  uno::Reference<io::XInputStream> aInputStream(new comphelper::SequenceInputStream(aData));
84 
85  const Primitive2DSequence aPrimitiveSequence = xSvgParser->getDecomposition(aInputStream, sPath);
86 
87  if (!aPrimitiveSequence.hasElements())
88  return;
89 
90  uno::Sequence<beans::PropertyValue> aViewParameters;
91 
92  geometry::RealRectangle2D aRealRect;
93  basegfx::B2DRange aRange;
94  for (Primitive2DReference const & xReference : aPrimitiveSequence)
95  {
96  if (xReference.is())
97  {
98  aRealRect = xReference->getRange(aViewParameters);
99  aRange.expand(basegfx::B2DRange(aRealRect.X1, aRealRect.Y1, aRealRect.X2, aRealRect.Y2));
100  }
101  }
102 
103  aRealRect.X1 = aRange.getMinX();
104  aRealRect.Y1 = aRange.getMinY();
105  aRealRect.X2 = aRange.getMaxX();
106  aRealRect.Y2 = aRange.getMaxY();
107 
108  double nDPI = 96 * fScalingFactor;
109 
110  const css::uno::Reference<css::graphic::XPrimitive2DRenderer> xPrimitive2DRenderer = css::graphic::Primitive2DTools::create(xContext);
111  const css::uno::Reference<css::rendering::XBitmap> xBitmap(
112  xPrimitive2DRenderer->rasterize(aPrimitiveSequence, aViewParameters, nDPI, nDPI, aRealRect, 256*256));
113 
114  if (xBitmap.is())
115  {
116  const css::uno::Reference<css::rendering::XIntegerReadOnlyBitmap> xIntBmp(xBitmap, uno::UNO_QUERY_THROW);
117  rBitmapEx = vcl::unotools::bitmapExFromXBitmap(xIntBmp);
118  }
119 
120 }
121 
132 BitmapEx CreateFromData(sal_uInt8 const *pData, sal_Int32 nWidth, sal_Int32 nHeight,
133  sal_Int32 nStride, vcl::PixelFormat ePixelFormat,
134  bool bReversColors, bool bReverseAlpha)
135 {
136  auto nBitCount = sal_uInt16(ePixelFormat);
137 
138  assert(nStride >= (nWidth * nBitCount / 8));
139  assert(nBitCount == 1 || nBitCount == 24 || nBitCount == 32);
140 
141  Bitmap aBmp(Size(nWidth, nHeight), ePixelFormat);
142 
143  BitmapScopedWriteAccess pWrite(aBmp);
144  assert(pWrite.get());
145  if( !pWrite )
146  return BitmapEx();
147  std::unique_ptr<AlphaMask> pAlphaMask;
148  AlphaScopedWriteAccess xMaskAcc;
149  if (nBitCount == 32)
150  {
151  pAlphaMask.reset( new AlphaMask( Size(nWidth, nHeight) ) );
152  xMaskAcc = AlphaScopedWriteAccess(*pAlphaMask);
153  }
154  if (nBitCount == 1)
155  {
156  for( tools::Long y = 0; y < nHeight; ++y )
157  {
158  sal_uInt8 const *p = pData + y * nStride / 8;
159  Scanline pScanline = pWrite->GetScanline(y);
160  for (tools::Long x = 0; x < nWidth; ++x)
161  {
162  int bitIndex = (y * nStride + x) % 8;
163 
164  pWrite->SetPixelOnData(pScanline, x, BitmapColor((*p >> bitIndex) & 1));
165  }
166  }
167  }
168  else
169  {
170  for( tools::Long y = 0; y < nHeight; ++y )
171  {
172  sal_uInt8 const *p = pData + (y * nStride);
173  Scanline pScanline = pWrite->GetScanline(y);
174  for (tools::Long x = 0; x < nWidth; ++x)
175  {
176  BitmapColor col;
177  if ( bReversColors )
178  col = BitmapColor( p[2], p[1], p[0] );
179  else
180  col = BitmapColor( p[0], p[1], p[2] );
181  pWrite->SetPixelOnData(pScanline, x, col);
182  p += nBitCount/8;
183  }
184  if (nBitCount == 32)
185  {
186  p = pData + (y * nStride) + 3;
187  Scanline pMaskScanLine = xMaskAcc->GetScanline(y);
188  for (tools::Long x = 0; x < nWidth; ++x)
189  {
190  const sal_uInt8 nValue = bReverseAlpha ? 0xff - *p : *p;
191  xMaskAcc->SetPixelOnData(pMaskScanLine, x, BitmapColor(nValue));
192  p += 4;
193  }
194  }
195  }
196  }
197  if (nBitCount == 32)
198  return BitmapEx(aBmp, *pAlphaMask);
199  else
200  return BitmapEx(aBmp);
201 }
202 
207 {
208  auto nBitCount = rawBitmap.GetBitCount();
209  assert( nBitCount == 24 || nBitCount == 32);
210 
211  auto ePixelFormat = vcl::PixelFormat::INVALID;
212 
213  if (nBitCount == 24)
214  ePixelFormat = vcl::PixelFormat::N24_BPP;
215  else if (nBitCount == 32)
216  ePixelFormat = vcl::PixelFormat::N32_BPP;
217 
218  assert(ePixelFormat != vcl::PixelFormat::INVALID);
219 
220  Bitmap aBmp(rawBitmap.maSize, ePixelFormat);
221 
222  BitmapScopedWriteAccess pWrite(aBmp);
223  assert(pWrite.get());
224  if( !pWrite )
225  return BitmapEx();
226  std::unique_ptr<AlphaMask> pAlphaMask;
227  AlphaScopedWriteAccess xMaskAcc;
228  if (nBitCount == 32)
229  {
230  pAlphaMask.reset( new AlphaMask( rawBitmap.maSize ) );
231  xMaskAcc = AlphaScopedWriteAccess(*pAlphaMask);
232  }
233 
234  auto nHeight = rawBitmap.maSize.getHeight();
235  auto nWidth = rawBitmap.maSize.getWidth();
236  auto nStride = nWidth * nBitCount / 8;
237  for( tools::Long y = 0; y < nHeight; ++y )
238  {
239  sal_uInt8 const *p = rawBitmap.mpData.get() + (y * nStride);
240  Scanline pScanline = pWrite->GetScanline(y);
241  for (tools::Long x = 0; x < nWidth; ++x)
242  {
243  BitmapColor col(p[0], p[1], p[2]);
244  pWrite->SetPixelOnData(pScanline, x, col);
245  p += nBitCount/8;
246  }
247  if (nBitCount == 32)
248  {
249  p = rawBitmap.mpData.get() + (y * nStride) + 3;
250  Scanline pMaskScanLine = xMaskAcc->GetScanline(y);
251  for (tools::Long x = 0; x < nWidth; ++x)
252  {
253  xMaskAcc->SetPixelOnData(pMaskScanLine, x, BitmapColor(255 - *p));
254  p += 4;
255  }
256  }
257  }
258  if (nBitCount == 32)
259  return BitmapEx(aBmp, *pAlphaMask);
260  else
261  return BitmapEx(aBmp);
262 }
263 
264 #if ENABLE_CAIRO_CANVAS
265 BitmapEx* CreateFromCairoSurface(Size aSize, cairo_surface_t * pSurface)
266 {
267  // FIXME: if we could teach VCL/ about cairo handles, life could
268  // be significantly better here perhaps.
269 
270 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
271  cairo_surface_t *pPixels = cairo_surface_create_similar_image(pSurface,
272 #else
273  cairo_surface_t *pPixels = cairo_image_surface_create(
274 #endif
275  CAIRO_FORMAT_ARGB32, aSize.Width(), aSize.Height());
276  cairo_t *pCairo = cairo_create( pPixels );
277  if( !pPixels || !pCairo || cairo_status(pCairo) != CAIRO_STATUS_SUCCESS )
278  return nullptr;
279 
280  // suck ourselves from the X server to this buffer so then we can fiddle with
281  // Alpha to turn it into the ultra-lame vcl required format and then push it
282  // all back again later at vast expense [ urgh ]
283  cairo_set_source_surface( pCairo, pSurface, 0, 0 );
284  cairo_set_operator( pCairo, CAIRO_OPERATOR_SOURCE );
285  cairo_paint( pCairo );
286 
287  Bitmap aRGB(aSize, vcl::PixelFormat::N24_BPP);
288  ::AlphaMask aMask( aSize );
289 
290  BitmapScopedWriteAccess pRGBWrite(aRGB);
291  assert(pRGBWrite);
292  if (!pRGBWrite)
293  return nullptr;
294 
295  AlphaScopedWriteAccess pMaskWrite(aMask);
296  assert(pMaskWrite);
297  if (!pMaskWrite)
298  return nullptr;
299 
300  cairo_surface_flush(pPixels);
301  unsigned char *pSrc = cairo_image_surface_get_data( pPixels );
302  unsigned int nStride = cairo_image_surface_get_stride( pPixels );
303  vcl::bitmap::lookup_table const & unpremultiply_table = vcl::bitmap::get_unpremultiply_table();
304  for( tools::Long y = 0; y < aSize.Height(); y++ )
305  {
306  sal_uInt32 *pPix = reinterpret_cast<sal_uInt32 *>(pSrc + nStride * y);
307  for( tools::Long x = 0; x < aSize.Width(); x++ )
308  {
309 #if defined OSL_BIGENDIAN
310  sal_uInt8 nB = (*pPix >> 24);
311  sal_uInt8 nG = (*pPix >> 16) & 0xff;
312  sal_uInt8 nR = (*pPix >> 8) & 0xff;
313  sal_uInt8 nAlpha = *pPix & 0xff;
314 #else
315  sal_uInt8 nAlpha = (*pPix >> 24);
316  sal_uInt8 nR = (*pPix >> 16) & 0xff;
317  sal_uInt8 nG = (*pPix >> 8) & 0xff;
318  sal_uInt8 nB = *pPix & 0xff;
319 #endif
320  if( nAlpha != 0 && nAlpha != 255 )
321  {
322  // Cairo uses pre-multiplied alpha - we do not => re-multiply
323  nR = unpremultiply_table[nAlpha][nR];
324  nG = unpremultiply_table[nAlpha][nG];
325  nB = unpremultiply_table[nAlpha][nB];
326  }
327  pRGBWrite->SetPixel( y, x, BitmapColor( nR, nG, nB ) );
328  pMaskWrite->SetPixelIndex( y, x, 255 - nAlpha );
329  pPix++;
330  }
331  }
332 
333  // ignore potential errors above. will get caller a
334  // uniformly white bitmap, but not that there would
335  // be error handling in calling code ...
336  ::BitmapEx *pBitmapEx = new ::BitmapEx( aRGB, aMask );
337 
338  cairo_destroy( pCairo );
339  cairo_surface_destroy( pPixels );
340  return pBitmapEx;
341 }
342 #endif
343 
345  const ::basegfx::B2DHomMatrix& rTransform,
346  ::basegfx::B2DRectangle const & rDestRect,
347  ::basegfx::B2DHomMatrix const & rLocalTransform )
348 {
349  const Size aBmpSize( rBitmap.GetSizePixel() );
350  Bitmap aSrcBitmap( rBitmap.GetBitmap() );
351  Bitmap aSrcAlpha;
352 
353  // differentiate mask and alpha channel (on-off
354  // vs. multi-level transparency)
355  if( rBitmap.IsAlpha() )
356  {
357  aSrcAlpha = rBitmap.GetAlpha().GetBitmap();
358  }
359 
360  Bitmap::ScopedReadAccess pReadAccess( aSrcBitmap );
361  Bitmap::ScopedReadAccess pAlphaReadAccess( rBitmap.IsAlpha() ?
362  aSrcAlpha.AcquireReadAccess() :
363  nullptr,
364  aSrcAlpha );
365 
366  if( pReadAccess.get() == nullptr ||
367  (pAlphaReadAccess.get() == nullptr && rBitmap.IsAlpha()) )
368  {
369  // TODO(E2): Error handling!
370  ENSURE_OR_THROW( false,
371  "transformBitmap(): could not access source bitmap" );
372  }
373 
374  // mapping table, to translate pAlphaReadAccess' pixel
375  // values into destination alpha values (needed e.g. for
376  // paletted 1-bit masks).
377  sal_uInt8 aAlphaMap[256];
378 
379  if( rBitmap.IsAlpha() )
380  {
381  // source already has alpha channel - 1:1 mapping,
382  // i.e. aAlphaMap[0]=0,...,aAlphaMap[255]=255.
383  sal_uInt8 val=0;
384  sal_uInt8* pCur=aAlphaMap;
385  sal_uInt8* const pEnd=&aAlphaMap[256];
386  while(pCur != pEnd)
387  *pCur++ = val++;
388  }
389  // else: mapping table is not used
390 
391  const Size aDestBmpSize( ::basegfx::fround( rDestRect.getWidth() ),
392  ::basegfx::fround( rDestRect.getHeight() ) );
393 
394  if( aDestBmpSize.IsEmpty() )
395  return BitmapEx();
396 
397  Bitmap aDstBitmap(aDestBmpSize, aSrcBitmap.getPixelFormat(), &pReadAccess->GetPalette());
398  Bitmap aDstAlpha( AlphaMask( aDestBmpSize ).GetBitmap() );
399 
400  {
401  // just to be on the safe side: let the
402  // ScopedAccessors get destructed before
403  // copy-constructing the resulting bitmap. This will
404  // rule out the possibility that cached accessor data
405  // is not yet written back.
406  BitmapScopedWriteAccess pWriteAccess( aDstBitmap );
407  BitmapScopedWriteAccess pAlphaWriteAccess( aDstAlpha );
408 
409 
410  if( pWriteAccess.get() != nullptr &&
411  pAlphaWriteAccess.get() != nullptr &&
412  rTransform.isInvertible() )
413  {
414  // we're doing inverse mapping here, i.e. mapping
415  // points from the destination bitmap back to the
416  // source
417  ::basegfx::B2DHomMatrix aTransform( rLocalTransform );
418  aTransform.invert();
419 
420  // for the time being, always read as ARGB
421  for( tools::Long y=0; y<aDestBmpSize.Height(); ++y )
422  {
423  // differentiate mask and alpha channel (on-off
424  // vs. multi-level transparency)
425  if( rBitmap.IsAlpha() )
426  {
427  Scanline pScan = pWriteAccess->GetScanline( y );
428  Scanline pScanAlpha = pAlphaWriteAccess->GetScanline( y );
429  // Handling alpha and mask just the same...
430  for( tools::Long x=0; x<aDestBmpSize.Width(); ++x )
431  {
432  ::basegfx::B2DPoint aPoint(x,y);
433  aPoint *= aTransform;
434 
435  const int nSrcX( ::basegfx::fround( aPoint.getX() ) );
436  const int nSrcY( ::basegfx::fround( aPoint.getY() ) );
437  if( nSrcX < 0 || nSrcX >= aBmpSize.Width() ||
438  nSrcY < 0 || nSrcY >= aBmpSize.Height() )
439  {
440  pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x, BitmapColor(255) );
441  }
442  else
443  {
444  const sal_uInt8 cAlphaIdx = pAlphaReadAccess->GetPixelIndex( nSrcY, nSrcX );
445  pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x, BitmapColor(aAlphaMap[ cAlphaIdx ]) );
446  pWriteAccess->SetPixelOnData( pScan, x, pReadAccess->GetPixel( nSrcY, nSrcX ) );
447  }
448  }
449  }
450  else
451  {
452  Scanline pScan = pWriteAccess->GetScanline( y );
453  Scanline pScanAlpha = pAlphaWriteAccess->GetScanline( y );
454  for( tools::Long x=0; x<aDestBmpSize.Width(); ++x )
455  {
456  ::basegfx::B2DPoint aPoint(x,y);
457  aPoint *= aTransform;
458 
459  const int nSrcX( ::basegfx::fround( aPoint.getX() ) );
460  const int nSrcY( ::basegfx::fround( aPoint.getY() ) );
461  if( nSrcX < 0 || nSrcX >= aBmpSize.Width() ||
462  nSrcY < 0 || nSrcY >= aBmpSize.Height() )
463  {
464  pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x, BitmapColor(255) );
465  }
466  else
467  {
468  pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x, BitmapColor(0) );
469  pWriteAccess->SetPixelOnData( pScan, x, pReadAccess->GetPixel( nSrcY,
470  nSrcX ) );
471  }
472  }
473  }
474  }
475  }
476  else
477  {
478  // TODO(E2): Error handling!
479  ENSURE_OR_THROW( false,
480  "transformBitmap(): could not access bitmap" );
481  }
482  }
483 
484  return BitmapEx(aDstBitmap, AlphaMask(aDstAlpha));
485 }
486 
487 
488 void DrawAlphaBitmapAndAlphaGradient(BitmapEx & rBitmapEx, bool bFixedTransparence, float fTransparence, AlphaMask & rNewMask)
489 {
490  // mix existing and new alpha mask
491  AlphaMask aOldMask;
492 
493  if(rBitmapEx.IsAlpha())
494  {
495  aOldMask = rBitmapEx.GetAlpha();
496  }
497 
498  {
499  AlphaScopedWriteAccess pOld(aOldMask);
500 
501  assert(pOld && "Got no access to old alpha mask (!)");
502 
503  const double fFactor(1.0 / 255.0);
504 
505  if(bFixedTransparence)
506  {
507  const double fOpNew(1.0 - fTransparence);
508 
509  for(tools::Long y(0); y < pOld->Height(); y++)
510  {
511  Scanline pScanline = pOld->GetScanline( y );
512  for(tools::Long x(0); x < pOld->Width(); x++)
513  {
514  const double fOpOld(1.0 - (pOld->GetIndexFromData(pScanline, x) * fFactor));
515  const sal_uInt8 aCol(basegfx::fround((1.0 - (fOpOld * fOpNew)) * 255.0));
516 
517  pOld->SetPixelOnData(pScanline, x, BitmapColor(aCol));
518  }
519  }
520  }
521  else
522  {
523  AlphaMask::ScopedReadAccess pNew(rNewMask);
524 
525  assert(pNew && "Got no access to new alpha mask (!)");
526 
527  assert(pOld->Width() == pNew->Width() && pOld->Height() == pNew->Height() &&
528  "Alpha masks have different sizes (!)");
529 
530  for(tools::Long y(0); y < pOld->Height(); y++)
531  {
532  Scanline pScanline = pOld->GetScanline( y );
533  for(tools::Long x(0); x < pOld->Width(); x++)
534  {
535  const double fOpOld(1.0 - (pOld->GetIndexFromData(pScanline, x) * fFactor));
536  const double fOpNew(1.0 - (pNew->GetIndexFromData(pScanline, x) * fFactor));
537  const sal_uInt8 aCol(basegfx::fround((1.0 - (fOpOld * fOpNew)) * 255.0));
538 
539  pOld->SetPixelOnData(pScanline, x, BitmapColor(aCol));
540  }
541  }
542  }
543 
544  }
545 
546  // apply combined bitmap as mask
547  rBitmapEx = BitmapEx(rBitmapEx.GetBitmap(), aOldMask);
548 }
549 
550 
551 void DrawAndClipBitmap(const Point& rPos, const Size& rSize, const BitmapEx& rBitmap, BitmapEx & aBmpEx, basegfx::B2DPolyPolygon const & rClipPath)
552 {
554  MapMode aMapMode( MapUnit::Map100thMM );
555  aMapMode.SetOrigin( Point( -rPos.X(), -rPos.Y() ) );
556  const Size aOutputSizePixel( pVDev->LogicToPixel( rSize, aMapMode ) );
557  const Size aSizePixel( rBitmap.GetSizePixel() );
558  if ( aOutputSizePixel.Width() && aOutputSizePixel.Height() )
559  {
560  aMapMode.SetScaleX( Fraction( aSizePixel.Width(), aOutputSizePixel.Width() ) );
561  aMapMode.SetScaleY( Fraction( aSizePixel.Height(), aOutputSizePixel.Height() ) );
562  }
563  pVDev->SetMapMode( aMapMode );
564  pVDev->SetOutputSizePixel( aSizePixel );
565  pVDev->SetFillColor( COL_BLACK );
566  const tools::PolyPolygon aClip( rClipPath );
567  pVDev->DrawPolyPolygon( aClip );
568 
569  // #i50672# Extract whole VDev content (to match size of rBitmap)
570  pVDev->EnableMapMode( false );
571  const Bitmap aVDevMask(pVDev->GetBitmap(Point(), aSizePixel));
572 
573  if(aBmpEx.IsAlpha())
574  {
575  // bitmap already uses a Mask or Alpha, we need to blend that with
576  // the new masking in pVDev.
577  // need to blend in AlphaMask quality (8Bit)
578  AlphaMask fromVDev(aVDevMask);
579  AlphaMask fromBmpEx(aBmpEx.GetAlpha());
580  AlphaMask::ScopedReadAccess pR(fromVDev);
581  AlphaScopedWriteAccess pW(fromBmpEx);
582 
583  if(pR && pW)
584  {
585  const tools::Long nWidth(std::min(pR->Width(), pW->Width()));
586  const tools::Long nHeight(std::min(pR->Height(), pW->Height()));
587 
588  for(tools::Long nY(0); nY < nHeight; nY++)
589  {
590  Scanline pScanlineR = pR->GetScanline( nY );
591  Scanline pScanlineW = pW->GetScanline( nY );
592  for(tools::Long nX(0); nX < nWidth; nX++)
593  {
594  const sal_uInt8 nIndR(pR->GetIndexFromData(pScanlineR, nX));
595  const sal_uInt8 nIndW(pW->GetIndexFromData(pScanlineW, nX));
596 
597  // these values represent transparency (0 == no, 255 == fully transparent),
598  // so to blend these we have to multiply the inverse (opacity)
599  // and re-invert the result to transparence
600  const sal_uInt8 nCombined(0x00ff - (((0x00ff - nIndR) * (0x00ff - nIndW)) >> 8));
601 
602  pW->SetPixelOnData(pScanlineW, nX, BitmapColor(nCombined));
603  }
604  }
605  }
606 
607  pR.reset();
608  pW.reset();
609  aBmpEx = BitmapEx(aBmpEx.GetBitmap(), fromBmpEx);
610  }
611  else
612  {
613  // no mask yet, create and add new mask. For better quality, use Alpha,
614  // this allows the drawn mask being processed with AntiAliasing (AAed)
615  aBmpEx = BitmapEx(rBitmap.GetBitmap(), aVDevMask);
616  }
617 }
618 
619 
620 css::uno::Sequence< sal_Int8 > GetMaskDIB(BitmapEx const & aBmpEx)
621 {
622  if ( aBmpEx.IsAlpha() )
623  {
624  SvMemoryStream aMem;
625  WriteDIB(aBmpEx.GetAlpha().GetBitmap(), aMem, false, true);
626  return css::uno::Sequence< sal_Int8 >( static_cast<sal_Int8 const *>(aMem.GetData()), aMem.Tell() );
627  }
628 
629  return css::uno::Sequence< sal_Int8 >();
630 }
631 
632 static bool readAlpha( BitmapReadAccess const * pAlphaReadAcc, tools::Long nY, const tools::Long nWidth, unsigned char* data, tools::Long nOff )
633 {
634  bool bIsAlpha = false;
635  tools::Long nX;
636  int nAlpha;
637  Scanline pReadScan;
638 
639  nOff += 3;
640 
641  switch( pAlphaReadAcc->GetScanlineFormat() )
642  {
644  pReadScan = pAlphaReadAcc->GetScanline( nY );
645  for( nX = 0; nX < nWidth; nX++ )
646  {
647  BitmapColor const& rColor(
648  pAlphaReadAcc->GetPaletteColor(*pReadScan));
649  pReadScan++;
650  nAlpha = data[ nOff ] = 255 - rColor.GetIndex();
651  if( nAlpha != 255 )
652  bIsAlpha = true;
653  nOff += 4;
654  }
655  break;
656  default:
657  SAL_INFO( "canvas.cairo", "fallback to GetColor for alpha - slow, format: " << static_cast<int>(pAlphaReadAcc->GetScanlineFormat()) );
658  for( nX = 0; nX < nWidth; nX++ )
659  {
660  nAlpha = data[ nOff ] = 255 - pAlphaReadAcc->GetColor( nY, nX ).GetIndex();
661  if( nAlpha != 255 )
662  bIsAlpha = true;
663  nOff += 4;
664  }
665  }
666 
667  return bIsAlpha;
668 }
669 
670 
671 
676 void CanvasCairoExtractBitmapData( BitmapEx const & aBmpEx, Bitmap & aBitmap, unsigned char*& data, bool& bHasAlpha, tools::Long& rnWidth, tools::Long& rnHeight )
677 {
678  AlphaMask aAlpha = aBmpEx.GetAlpha();
679 
680  ::BitmapReadAccess* pBitmapReadAcc = aBitmap.AcquireReadAccess();
681  ::BitmapReadAccess* pAlphaReadAcc = nullptr;
682  const tools::Long nWidth = rnWidth = pBitmapReadAcc->Width();
683  const tools::Long nHeight = rnHeight = pBitmapReadAcc->Height();
684  tools::Long nX, nY;
685  bool bIsAlpha = false;
686 
687  if( aBmpEx.IsAlpha() )
688  pAlphaReadAcc = aAlpha.AcquireReadAccess();
689 
690  data = static_cast<unsigned char*>(malloc( nWidth*nHeight*4 ));
691 
692  tools::Long nOff = 0;
693  ::Color aColor;
694  unsigned int nAlpha = 255;
695 
697  for( nY = 0; nY < nHeight; nY++ )
698  {
699  ::Scanline pReadScan;
700 
701  switch( pBitmapReadAcc->GetScanlineFormat() )
702  {
704  pReadScan = pBitmapReadAcc->GetScanline( nY );
705  if( pAlphaReadAcc )
706  if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
707  bIsAlpha = true;
708 
709  for( nX = 0; nX < nWidth; nX++ )
710  {
711 #ifdef OSL_BIGENDIAN
712  if( pAlphaReadAcc )
713  nAlpha = data[ nOff++ ];
714  else
715  nAlpha = data[ nOff++ ] = 255;
716 #else
717  if( pAlphaReadAcc )
718  nAlpha = data[ nOff + 3 ];
719  else
720  nAlpha = data[ nOff + 3 ] = 255;
721 #endif
722  aColor = pBitmapReadAcc->GetPaletteColor(*pReadScan++);
723 
724 #ifdef OSL_BIGENDIAN
725  data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetRed()];
726  data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetGreen()];
727  data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetBlue()];
728 #else
729  data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetBlue()];
730  data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetGreen()];
731  data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetRed()];
732  nOff++;
733 #endif
734  }
735  break;
737  pReadScan = pBitmapReadAcc->GetScanline( nY );
738  if( pAlphaReadAcc )
739  if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
740  bIsAlpha = true;
741 
742  for( nX = 0; nX < nWidth; nX++ )
743  {
744 #ifdef OSL_BIGENDIAN
745  if( pAlphaReadAcc )
746  nAlpha = data[ nOff ];
747  else
748  nAlpha = data[ nOff ] = 255;
749  data[ nOff + 3 ] = premultiply_table[nAlpha][*pReadScan++];
750  data[ nOff + 2 ] = premultiply_table[nAlpha][*pReadScan++];
751  data[ nOff + 1 ] = premultiply_table[nAlpha][*pReadScan++];
752  nOff += 4;
753 #else
754  if( pAlphaReadAcc )
755  nAlpha = data[ nOff + 3 ];
756  else
757  nAlpha = data[ nOff + 3 ] = 255;
758  data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
759  data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
760  data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
761  nOff++;
762 #endif
763  }
764  break;
766  pReadScan = pBitmapReadAcc->GetScanline( nY );
767  if( pAlphaReadAcc )
768  if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
769  bIsAlpha = true;
770 
771  for( nX = 0; nX < nWidth; nX++ )
772  {
773 #ifdef OSL_BIGENDIAN
774  if( pAlphaReadAcc )
775  nAlpha = data[ nOff++ ];
776  else
777  nAlpha = data[ nOff++ ] = 255;
778  data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
779  data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
780  data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
781 #else
782  if( pAlphaReadAcc )
783  nAlpha = data[ nOff + 3 ];
784  else
785  nAlpha = data[ nOff + 3 ] = 255;
786  data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 2 ]];
787  data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 1 ]];
788  data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 0 ]];
789  pReadScan += 3;
790  nOff++;
791 #endif
792  }
793  break;
795  pReadScan = pBitmapReadAcc->GetScanline( nY );
796  if( pAlphaReadAcc )
797  if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
798  bIsAlpha = true;
799 
800  for( nX = 0; nX < nWidth; nX++ )
801  {
802 #ifdef OSL_BIGENDIAN
803  if( pAlphaReadAcc )
804  nAlpha = data[ nOff++ ];
805  else
806  nAlpha = data[ nOff++ ] = 255;
807  data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 2 ]];
808  data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 1 ]];
809  data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 0 ]];
810  pReadScan += 4;
811 #else
812  if( pAlphaReadAcc )
813  nAlpha = data[ nOff + 3 ];
814  else
815  nAlpha = data[ nOff + 3 ] = 255;
816  data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
817  data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
818  data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
819  pReadScan++;
820  nOff++;
821 #endif
822  }
823  break;
825  pReadScan = pBitmapReadAcc->GetScanline( nY );
826  if( pAlphaReadAcc )
827  if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
828  bIsAlpha = true;
829 
830  for( nX = 0; nX < nWidth; nX++ )
831  {
832 #ifdef OSL_BIGENDIAN
833  if( pAlphaReadAcc )
834  nAlpha = data[ nOff ++ ];
835  else
836  nAlpha = data[ nOff ++ ] = 255;
837  data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
838  data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
839  data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
840  pReadScan++;
841 #else
842  if( pAlphaReadAcc )
843  nAlpha = data[ nOff + 3 ];
844  else
845  nAlpha = data[ nOff + 3 ] = 255;
846  data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 2 ]];
847  data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 1 ]];
848  data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 0 ]];
849  pReadScan += 4;
850  nOff++;
851 #endif
852  }
853  break;
854  default:
855  SAL_INFO( "canvas.cairo", "fallback to GetColor - slow, format: " << static_cast<int>(pBitmapReadAcc->GetScanlineFormat()) );
856 
857  if( pAlphaReadAcc )
858  if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
859  bIsAlpha = true;
860 
861  for( nX = 0; nX < nWidth; nX++ )
862  {
863  aColor = pBitmapReadAcc->GetColor( nY, nX );
864 
865  // cairo need premultiplied color values
866  // TODO(rodo) handle endianness
867 #ifdef OSL_BIGENDIAN
868  if( pAlphaReadAcc )
869  nAlpha = data[ nOff++ ];
870  else
871  nAlpha = data[ nOff++ ] = 255;
872  data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetRed()];
873  data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetGreen()];
874  data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetBlue()];
875 #else
876  if( pAlphaReadAcc )
877  nAlpha = data[ nOff + 3 ];
878  else
879  nAlpha = data[ nOff + 3 ] = 255;
880  data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetBlue()];
881  data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetGreen()];
882  data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetRed()];
883  nOff ++;
884 #endif
885  }
886  }
887  }
888 
889  ::Bitmap::ReleaseAccess( pBitmapReadAcc );
890  if( pAlphaReadAcc )
891  aAlpha.ReleaseAccess( pAlphaReadAcc );
892 
893  bHasAlpha = bIsAlpha;
894 
895 }
896 
897  uno::Sequence< sal_Int8 > CanvasExtractBitmapData(BitmapEx const & rBitmapEx, const geometry::IntegerRectangle2D& rect)
898  {
899  Bitmap aBitmap( rBitmapEx.GetBitmap() );
900  Bitmap aAlpha( rBitmapEx.GetAlpha().GetBitmap() );
901 
902  Bitmap::ScopedReadAccess pReadAccess( aBitmap );
903  Bitmap::ScopedReadAccess pAlphaReadAccess( aAlpha.IsEmpty() ?
904  nullptr : aAlpha.AcquireReadAccess(),
905  aAlpha );
906 
907  assert( pReadAccess );
908 
909  // TODO(F1): Support more formats.
910  const Size aBmpSize( aBitmap.GetSizePixel() );
911 
912  // for the time being, always return as BGRA
913  uno::Sequence< sal_Int8 > aRes( 4*aBmpSize.Width()*aBmpSize.Height() );
914  sal_Int8* pRes = aRes.getArray();
915 
916  int nCurrPos(0);
917  for( tools::Long y=rect.Y1;
918  y<aBmpSize.Height() && y<rect.Y2;
919  ++y )
920  {
921  if( pAlphaReadAccess.get() != nullptr )
922  {
923  Scanline pScanlineReadAlpha = pAlphaReadAccess->GetScanline( y );
924  for( tools::Long x=rect.X1;
925  x<aBmpSize.Width() && x<rect.X2;
926  ++x )
927  {
928  pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetRed();
929  pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetGreen();
930  pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetBlue();
931  pRes[ nCurrPos++ ] = pAlphaReadAccess->GetIndexFromData( pScanlineReadAlpha, x );
932  }
933  }
934  else
935  {
936  for( tools::Long x=rect.X1;
937  x<aBmpSize.Width() && x<rect.X2;
938  ++x )
939  {
940  pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetRed();
941  pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetGreen();
942  pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetBlue();
943  pRes[ nCurrPos++ ] = sal_uInt8(255);
944  }
945  }
946  }
947  return aRes;
948  }
949 
950  BitmapEx createHistorical8x8FromArray(std::array<sal_uInt8,64> const & pArray, Color aColorPix, Color aColorBack)
951  {
952  BitmapPalette aPalette(2);
953 
954  aPalette[0] = BitmapColor(aColorBack);
955  aPalette[1] = BitmapColor(aColorPix);
956 
957  Bitmap aBitmap(Size(8, 8), vcl::PixelFormat::N1_BPP, &aPalette);
958  BitmapScopedWriteAccess pContent(aBitmap);
959 
960  for(sal_uInt16 a(0); a < 8; a++)
961  {
962  for(sal_uInt16 b(0); b < 8; b++)
963  {
964  if(pArray[(a * 8) + b])
965  {
966  pContent->SetPixelIndex(a, b, 1);
967  }
968  else
969  {
970  pContent->SetPixelIndex(a, b, 0);
971  }
972  }
973  }
974 
975  return BitmapEx(aBitmap);
976  }
977 
978  bool isHistorical8x8(const BitmapEx& rBitmapEx, Color& o_rBack, Color& o_rFront)
979  {
980  bool bRet(false);
981 
982  if(!rBitmapEx.IsAlpha())
983  {
984  Bitmap aBitmap(rBitmapEx.GetBitmap());
985 
986  if(8 == aBitmap.GetSizePixel().Width() && 8 == aBitmap.GetSizePixel().Height())
987  {
988  if (aBitmap.getPixelFormat() == vcl::PixelFormat::N1_BPP)
989  {
990  BitmapReadAccess* pRead = aBitmap.AcquireReadAccess();
991 
992  if(pRead)
993  {
994  if(pRead->HasPalette() && 2 == pRead->GetPaletteEntryCount())
995  {
996  const BitmapPalette& rPalette = pRead->GetPalette();
997  o_rFront = rPalette[1];
998  o_rBack = rPalette[0];
999 
1000  bRet = true;
1001  }
1002 
1003  Bitmap::ReleaseAccess(pRead);
1004  }
1005  }
1006  else
1007  {
1008  // Historical 1bpp images are getting really historical,
1009  // even to the point that e.g. the png loader actually loads
1010  // them as RGB. But the pattern code in svx relies on this
1011  // assumption that any 2-color 1bpp bitmap is a pattern, and so it would
1012  // get confused by RGB. Try to detect if this image is really
1013  // just two colors and say it's a pattern bitmap if so.
1014  Bitmap::ScopedReadAccess access(aBitmap);
1015  o_rBack = access->GetColor(0,0);
1016  bool foundSecondColor = false;;
1017  for(tools::Long y = 0; y < access->Height(); ++y)
1018  for(tools::Long x = 0; x < access->Width(); ++x)
1019  {
1020  if(!foundSecondColor)
1021  {
1022  if( access->GetColor(y,x) != o_rBack )
1023  {
1024  o_rFront = access->GetColor(y,x);
1025  foundSecondColor = true;
1026  // Hard to know which of the two colors is the background,
1027  // select the lighter one.
1028  if( o_rFront.GetLuminance() > o_rBack.GetLuminance())
1029  std::swap( o_rFront, o_rBack );
1030  }
1031  }
1032  else
1033  {
1034  if( access->GetColor(y,x) != o_rBack && access->GetColor(y,x) != o_rFront)
1035  return false;
1036  }
1037  }
1038  return true;
1039  }
1040  }
1041  }
1042 
1043  return bRet;
1044  }
1045 
1047  {
1048  return get_unpremultiply_table()[a][c];
1049  }
1050 
1052  {
1053  return (a == 0) ? 0 : (c * 255 + a / 2) / a;
1054  }
1055 
1057  {
1058  return get_premultiply_table()[a][c];
1059  }
1060 
1062  {
1063  return (c * a + 127) / 255;
1064  }
1065 
1066  template<int... Is> static constexpr std::array<sal_uInt8, 256> make_unpremultiply_table_row_(
1067  int a, std::integer_sequence<int, Is...>)
1068  {
1069  return {unpremultiplyImpl(Is, a)...};
1070  }
1071 
1072  template<int... Is> static constexpr lookup_table make_unpremultiply_table_(
1073  std::integer_sequence<int, Is...>)
1074  {
1075  return {make_unpremultiply_table_row_(Is, std::make_integer_sequence<int, 256>{})...};
1076  }
1077 
1079  {
1080  static constexpr auto unpremultiply_table = make_unpremultiply_table_(
1081  std::make_integer_sequence<int, 256>{});
1082  return unpremultiply_table;
1083  }
1084 
1085  template<int... Is> static constexpr std::array<sal_uInt8, 256> make_premultiply_table_row_(
1086  int a, std::integer_sequence<int, Is...>)
1087  {
1088  return {premultiplyImpl(Is, a)...};
1089  }
1090 
1091  template<int... Is> static constexpr lookup_table make_premultiply_table_(
1092  std::integer_sequence<int, Is...>)
1093  {
1094  return {make_premultiply_table_row_(Is, std::make_integer_sequence<int, 256>{})...};
1095  }
1096 
1098  {
1099  static constexpr auto premultiply_table = make_premultiply_table_(
1100  std::make_integer_sequence<int, 256>{});
1101  return premultiply_table;
1102  }
1103 
1104 bool convertBitmap32To24Plus8(BitmapEx const & rInput, BitmapEx & rResult)
1105 {
1106  Bitmap aBitmap(rInput.GetBitmap());
1107  if (aBitmap.getPixelFormat() != vcl::PixelFormat::N32_BPP)
1108  return false;
1109 
1110  Size aSize = aBitmap.GetSizePixel();
1111  Bitmap aResultBitmap(aSize, vcl::PixelFormat::N24_BPP);
1112  AlphaMask aResultAlpha(aSize);
1113  {
1114  BitmapScopedWriteAccess pResultBitmapAccess(aResultBitmap);
1115  AlphaScopedWriteAccess pResultAlphaAccess(aResultAlpha);
1116 
1117  Bitmap::ScopedReadAccess pReadAccess(aBitmap);
1118 
1119  for (tools::Long nY = 0; nY < aSize.Height(); ++nY)
1120  {
1121  Scanline aResultScan = pResultBitmapAccess->GetScanline(nY);
1122  Scanline aResultScanAlpha = pResultAlphaAccess->GetScanline(nY);
1123 
1124  Scanline aReadScan = pReadAccess->GetScanline(nY);
1125 
1126  for (tools::Long nX = 0; nX < aSize.Width(); ++nX)
1127  {
1128  const BitmapColor aColor = pReadAccess->GetPixelFromData(aReadScan, nX);
1129  BitmapColor aResultColor(aColor.GetRed(), aColor.GetGreen(), aColor.GetBlue());
1130  BitmapColor aResultColorAlpha(255 - aColor.GetAlpha(), 255 - aColor.GetAlpha(), 255 - aColor.GetAlpha());
1131 
1132  pResultBitmapAccess->SetPixelOnData(aResultScan, nX, aResultColor);
1133  pResultAlphaAccess->SetPixelOnData(aResultScanAlpha, nX, aResultColorAlpha);
1134  }
1135  }
1136  }
1137  if (rInput.IsAlpha())
1138  rResult = BitmapEx(aResultBitmap, rInput.GetAlpha());
1139  else
1140  rResult = BitmapEx(aResultBitmap, aResultAlpha);
1141  return true;
1142 }
1143 
1144 Bitmap GetDownsampledBitmap(Size const& rDstSizeTwip, Point const& rSrcPt, Size const& rSrcSz,
1145  Bitmap const& rBmp, tools::Long nMaxBmpDPIX, tools::Long nMaxBmpDPIY)
1146 {
1147  Bitmap aBmp(rBmp);
1148 
1149  if (!aBmp.IsEmpty())
1150  {
1151  const tools::Rectangle aBmpRect( Point(), aBmp.GetSizePixel() );
1152  tools::Rectangle aSrcRect( rSrcPt, rSrcSz );
1153 
1154  // do cropping if necessary
1155  if( aSrcRect.Intersection( aBmpRect ) != aBmpRect )
1156  {
1157  if( !aSrcRect.IsEmpty() )
1158  aBmp.Crop( aSrcRect );
1159  else
1160  aBmp.SetEmpty();
1161  }
1162 
1163  if( !aBmp.IsEmpty() )
1164  {
1165  // do downsampling if necessary
1166  // #103209# Normalize size (mirroring has to happen outside of this method)
1167  Size aDstSizeTwip(std::abs(rDstSizeTwip.Width()), std::abs(rDstSizeTwip.Height()));
1168 
1169  const Size aBmpSize( aBmp.GetSizePixel() );
1170  const double fBmpPixelX = aBmpSize.Width();
1171  const double fBmpPixelY = aBmpSize.Height();
1172  const double fMaxPixelX
1173  = o3tl::convert<double>(aDstSizeTwip.Width(), o3tl::Length::twip, o3tl::Length::in)
1174  * nMaxBmpDPIX;
1175  const double fMaxPixelY
1176  = o3tl::convert<double>(aDstSizeTwip.Height(), o3tl::Length::twip, o3tl::Length::in)
1177  * nMaxBmpDPIY;
1178 
1179  // check, if the bitmap DPI exceeds the maximum DPI (allow 4 pixel rounding tolerance)
1180  if (((fBmpPixelX > (fMaxPixelX + 4)) ||
1181  (fBmpPixelY > (fMaxPixelY + 4))) &&
1182  (fBmpPixelY > 0.0) && (fMaxPixelY > 0.0))
1183  {
1184  // do scaling
1185  Size aNewBmpSize;
1186  const double fBmpWH = fBmpPixelX / fBmpPixelY;
1187  const double fMaxWH = fMaxPixelX / fMaxPixelY;
1188 
1189  if (fBmpWH < fMaxWH)
1190  {
1191  aNewBmpSize.setWidth(FRound(fMaxPixelY * fBmpWH));
1192  aNewBmpSize.setHeight(FRound(fMaxPixelY));
1193  }
1194  else if (fBmpWH > 0.0)
1195  {
1196  aNewBmpSize.setWidth(FRound(fMaxPixelX));
1197  aNewBmpSize.setHeight(FRound(fMaxPixelX / fBmpWH));
1198  }
1199 
1200  if( aNewBmpSize.Width() && aNewBmpSize.Height() )
1201  aBmp.Scale(aNewBmpSize);
1202  else
1203  aBmp.SetEmpty();
1204  }
1205  }
1206  }
1207 
1208  return aBmp;
1209 }
1210 
1211 } // end vcl::bitmap
1212 
1213 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
PixelFormat
Pixel format of the bitmap in bits per pixel.
Definition: BitmapTypes.hxx:19
void loadFromSvg(SvStream &rStream, const OUString &sPath, BitmapEx &rBitmapEx, double fScalingFactor)
Definition: BitmapTools.cxx:72
sal_uInt8 premultiply(sal_uInt8 c, sal_uInt8 a)
double getY() const
ImageLoadFlags
Definition: ImageTree.hxx:31
sal_uInt8 GetIndex() const
Definition: BitmapColor.hxx:70
void expand(const B2DTuple &rTuple)
tools::Long Height() const
sal_uInt8 GetAlpha() const
sal_uInt8 GetRed() const
double getHeight() const
void setWidth(tools::Long nWidth)
OUString DetermineIconTheme() const
Determine which icon theme should be used.
void DrawAlphaBitmapAndAlphaGradient(BitmapEx &rBitmapEx, bool bFixedTransparence, float fTransparence, AlphaMask &rNewMask)
signed char sal_Int8
sal_uInt8 unpremultiply(sal_uInt8 c, sal_uInt8 a)
Bitmap const & GetBitmap() const
Definition: alpha.cxx:73
long Long
const StyleSettings & GetStyleSettings() const
static const AllSettings & GetSettings()
Gets the application's settings.
Definition: svapp.cxx:733
sal_uInt8 GetLuminance() const
B2DVector getRange() const
Bitmap GetDownsampledBitmap(Size const &rDstSizeTwip, Point const &rSrcPt, Size const &rSrcSz, Bitmap const &rBmp, tools::Long nMaxBmpDPIX, tools::Long nMaxBmpDPIY)
Retrieve downsampled and cropped bitmap.
BitmapReadAccess * AcquireReadAccess()
std::array< std::array< sal_uInt8, 256 >, 256 > lookup_table
Definition: BitmapTools.hxx:29
This template handles BitmapAccess the RAII way.
Size GetSizePixel() const
static constexpr lookup_table make_unpremultiply_table_(std::integer_sequence< int, Is... >)
static constexpr lookup_table make_premultiply_table_(std::integer_sequence< int, Is... >)
::BitmapEx bitmapExFromXBitmap(const uno::Reference< rendering::XIntegerReadOnlyBitmap > &xInputBitmap)
float x
double getMaxX() const
constexpr tools::Long Width() const
bool Crop(const tools::Rectangle &rRectPixel)
Crop the bitmap.
static VCL_DLLPUBLIC ImageTree & get()
Definition: ImageTree.cxx:16
bool IsAlpha() const
Definition: BitmapEx.cxx:193
double getWidth() const
void DrawAndClipBitmap(const Point &rPos, const Size &rSize, const BitmapEx &rBitmap, BitmapEx &aBmpEx, basegfx::B2DPolyPolygon const &rClipPath)
Scanline GetScanline(tools::Long nY) const
sal_uInt64 remainingSize()
double getMaxY() const
sal_uInt8 GetBlue() const
B2IRange fround(const B2DRange &rRange)
float y
constexpr OUStringLiteral aData
css::uno::Sequence< Primitive2DReference > Primitive2DSequence
BitmapEx CreateFromData(RawBitmap &&rawBitmap)
Copy block of image data into the bitmap.
VCL_DLLPUBLIC bool loadImage(OUString const &name, OUString const &style, BitmapEx &bitmap, bool localized, const ImageLoadFlags eFlags=ImageLoadFlags::NONE)
Definition: ImageTree.cxx:45
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
void SetScaleX(const Fraction &rScaleX)
Definition: mapmod.cxx:110
bool IsEmpty() const
bool HasPalette() const
uno_Any a
ScanlineFormat GetScanlineFormat() const
tools::Long FRound(double fVal)
BitmapColor GetColor(tools::Long nY, tools::Long nX) const
void SetOrigin(const Point &rOrigin)
Definition: mapmod.cxx:104
void CanvasCairoExtractBitmapData(BitmapEx const &aBmpEx, Bitmap &aBitmap, unsigned char *&data, bool &bHasAlpha, tools::Long &rnWidth, tools::Long &rnHeight)
tools::Long Width() const
void SetScaleY(const Fraction &rScaleY)
Definition: mapmod.cxx:117
bool isHistorical8x8(const BitmapEx &rBitmapEx, Color &o_rBack, Color &o_rFront)
css::uno::Sequence< sal_Int8 > GetMaskDIB(BitmapEx const &aBmpEx)
static void ReleaseAccess(BitmapInfoAccess *pAccess)
static constexpr std::array< sal_uInt8, 256 > make_unpremultiply_table_row_(int a, std::integer_sequence< int, Is... >)
struct _cairo cairo_t
Definition: svpgdi.hxx:71
uno::Sequence< sal_Int8 > CanvasExtractBitmapData(BitmapEx const &rBitmapEx, const geometry::IntegerRectangle2D &rect)
Intended to be used to feed into CreateFromData to create a BitmapEx.
Definition: RawBitmap.hxx:21
short nBitCount
Definition: ipict.cxx:80
BitmapEx CanvasTransformBitmap(const BitmapEx &rBitmap, const ::basegfx::B2DHomMatrix &rTransform,::basegfx::B2DRectangle const &rDestRect,::basegfx::B2DHomMatrix const &rLocalTransform)
sal_uInt16 GetPaletteEntryCount() const
void ReleaseAccess(BitmapReadAccess *pAccess)
Definition: alpha.cxx:115
std::size_t ReadBytes(void *pData, std::size_t nSize)
void SetEmpty()
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:203
sal_uInt8 GetGreen() const
BitmapEx createHistorical8x8FromArray(std::array< sal_uInt8, 64 > const &pArray, Color aColorPix, Color aColorBack)
#define ENSURE_OR_THROW(c, m)
lookup_table const & get_unpremultiply_table()
css::uno::Reference< css::graphic::XPrimitive2D > Primitive2DReference
vcl::ScopedBitmapAccess< BitmapWriteAccess, AlphaMask,&AlphaMask::AcquireAlphaWriteAccess > AlphaScopedWriteAccess
std::unique_ptr< char[]> aBuffer
double getMinY() const
AlphaMask GetAlpha() const
Definition: BitmapEx.cxx:215
static constexpr sal_uInt8 unpremultiplyImpl(sal_uInt8 c, sal_uInt8 a)
#define SAL_WARN_IF(condition, area, stream)
constexpr tools::Long Height() const
unsigned char sal_uInt8
bool Scale(const Size &rNewSize, BmpScaleFlag nScaleFlag=BmpScaleFlag::Default)
Scale the bitmap.
static constexpr std::array< sal_uInt8, 256 > make_premultiply_table_row_(int a, std::integer_sequence< int, Is... >)
lookup_table const & get_premultiply_table()
static constexpr sal_uInt8 premultiplyImpl(sal_uInt8 c, sal_uInt8 a)
const BitmapPalette & GetPalette() const
#define SAL_INFO(area, stream)
bool convertBitmap32To24Plus8(BitmapEx const &rInput, BitmapEx &rResult)
bool IsEmpty() const
static bool readAlpha(BitmapReadAccess const *pAlphaReadAcc, tools::Long nY, const tools::Long nWidth, unsigned char *data, tools::Long nOff)
sal_uInt64 Tell() const
void * p
Reference< XComponentContext > getProcessComponentContext()
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_BLACK
BitmapColor GetPixelFromData(const sal_uInt8 *pData, tools::Long nX) const
void setHeight(tools::Long nHeight)
BitmapEx loadFromName(const OUString &rFileName, const ImageLoadFlags eFlags)
Definition: BitmapTools.cxx:52
double getX() const
double getMinX() const
const BitmapColor & GetPaletteColor(sal_uInt16 nColor) const
bool WriteDIB(const Bitmap &rSource, SvStream &rOStm, bool bCompressed, bool bFileHeader)
Definition: dibtools.cxx:1818
const Size & GetSizePixel() const
Definition: bitmapex.hxx:73
struct _cairo_surface cairo_surface_t
Definition: svpgdi.hxx:72
BitmapColor GetPixel(tools::Long nY, tools::Long nX) const
sal_Int16 nValue
const void * GetData()