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>
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
40#include <tools/fract.hxx>
41#include <tools/stream.hxx>
43
44using namespace css;
45
48
49namespace vcl::bitmap
50{
51
52BitmapEx 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
72void 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 (css::uno::Reference<css::graphic::XPrimitive2D> 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
132BitmapEx 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
265BitmapEx* 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 cairo_surface_t *pPixels = cairo_surface_create_similar_image(pSurface,
271 CAIRO_FORMAT_ARGB32, aSize.Width(), aSize.Height());
272 cairo_t *pCairo = cairo_create( pPixels );
273 if( !pPixels || !pCairo || cairo_status(pCairo) != CAIRO_STATUS_SUCCESS )
274 return nullptr;
275
276 // suck ourselves from the X server to this buffer so then we can fiddle with
277 // Alpha to turn it into the ultra-lame vcl required format and then push it
278 // all back again later at vast expense [ urgh ]
279 cairo_set_source_surface( pCairo, pSurface, 0, 0 );
280 cairo_set_operator( pCairo, CAIRO_OPERATOR_SOURCE );
281 cairo_paint( pCairo );
282
284 ::AlphaMask aMask( aSize );
285
286 BitmapScopedWriteAccess pRGBWrite(aRGB);
287 assert(pRGBWrite);
288 if (!pRGBWrite)
289 return nullptr;
290
291 AlphaScopedWriteAccess pMaskWrite(aMask);
292 assert(pMaskWrite);
293 if (!pMaskWrite)
294 return nullptr;
295
296 cairo_surface_flush(pPixels);
297 unsigned char *pSrc = cairo_image_surface_get_data( pPixels );
298 unsigned int nStride = cairo_image_surface_get_stride( pPixels );
299#if !ENABLE_WASM_STRIP_PREMULTIPLY
301#endif
302 for( tools::Long y = 0; y < aSize.Height(); y++ )
303 {
304 sal_uInt32 *pPix = reinterpret_cast<sal_uInt32 *>(pSrc + nStride * y);
305 for( tools::Long x = 0; x < aSize.Width(); x++ )
306 {
307#if defined OSL_BIGENDIAN
308 sal_uInt8 nB = (*pPix >> 24);
309 sal_uInt8 nG = (*pPix >> 16) & 0xff;
310 sal_uInt8 nR = (*pPix >> 8) & 0xff;
311 sal_uInt8 nAlpha = *pPix & 0xff;
312#else
313 sal_uInt8 nAlpha = (*pPix >> 24);
314 sal_uInt8 nR = (*pPix >> 16) & 0xff;
315 sal_uInt8 nG = (*pPix >> 8) & 0xff;
316 sal_uInt8 nB = *pPix & 0xff;
317#endif
318 if( nAlpha != 0 && nAlpha != 255 )
319 {
320 // Cairo uses pre-multiplied alpha - we do not => re-multiply
321#if ENABLE_WASM_STRIP_PREMULTIPLY
322 nR = vcl::bitmap::unpremultiply(nAlpha, nR);
323 nG = vcl::bitmap::unpremultiply(nAlpha, nG);
324 nB = vcl::bitmap::unpremultiply(nAlpha, nB);
325#else
326 nR = unpremultiply_table[nAlpha][nR];
327 nG = unpremultiply_table[nAlpha][nG];
328 nB = unpremultiply_table[nAlpha][nB];
329#endif
330 }
331 pRGBWrite->SetPixel( y, x, BitmapColor( nR, nG, nB ) );
332 pMaskWrite->SetPixelIndex( y, x, 255 - nAlpha );
333 pPix++;
334 }
335 }
336
337 // ignore potential errors above. will get caller a
338 // uniformly white bitmap, but not that there would
339 // be error handling in calling code ...
340 ::BitmapEx *pBitmapEx = new ::BitmapEx( aRGB, aMask );
341
342 cairo_destroy( pCairo );
343 cairo_surface_destroy( pPixels );
344 return pBitmapEx;
345}
346#endif
347
349 const ::basegfx::B2DHomMatrix& rTransform,
350 ::basegfx::B2DRectangle const & rDestRect,
351 ::basegfx::B2DHomMatrix const & rLocalTransform )
352{
353 const Size aBmpSize( rBitmap.GetSizePixel() );
354 Bitmap aSrcBitmap( rBitmap.GetBitmap() );
355 Bitmap aSrcAlpha;
356
357 // differentiate mask and alpha channel (on-off
358 // vs. multi-level transparency)
359 if( rBitmap.IsAlpha() )
360 {
361 aSrcAlpha = rBitmap.GetAlpha().GetBitmap();
362 }
363
364 Bitmap::ScopedReadAccess pReadAccess( aSrcBitmap );
365 Bitmap::ScopedReadAccess pAlphaReadAccess( rBitmap.IsAlpha() ?
366 aSrcAlpha.AcquireReadAccess() :
367 nullptr,
368 aSrcAlpha );
369
370 if( pReadAccess.get() == nullptr ||
371 (pAlphaReadAccess.get() == nullptr && rBitmap.IsAlpha()) )
372 {
373 // TODO(E2): Error handling!
374 ENSURE_OR_THROW( false,
375 "transformBitmap(): could not access source bitmap" );
376 }
377
378 // mapping table, to translate pAlphaReadAccess' pixel
379 // values into destination alpha values (needed e.g. for
380 // paletted 1-bit masks).
381 sal_uInt8 aAlphaMap[256];
382
383 if( rBitmap.IsAlpha() )
384 {
385 // source already has alpha channel - 1:1 mapping,
386 // i.e. aAlphaMap[0]=0,...,aAlphaMap[255]=255.
387 sal_uInt8 val=0;
388 sal_uInt8* pCur=aAlphaMap;
389 sal_uInt8* const pEnd=&aAlphaMap[256];
390 while(pCur != pEnd)
391 *pCur++ = val++;
392 }
393 // else: mapping table is not used
394
395 const Size aDestBmpSize( ::basegfx::fround( rDestRect.getWidth() ),
396 ::basegfx::fround( rDestRect.getHeight() ) );
397
398 if( aDestBmpSize.IsEmpty() )
399 return BitmapEx();
400
401 Bitmap aDstBitmap(aDestBmpSize, aSrcBitmap.getPixelFormat(), &pReadAccess->GetPalette());
402 Bitmap aDstAlpha( AlphaMask( aDestBmpSize ).GetBitmap() );
403
404 {
405 // just to be on the safe side: let the
406 // ScopedAccessors get destructed before
407 // copy-constructing the resulting bitmap. This will
408 // rule out the possibility that cached accessor data
409 // is not yet written back.
410 BitmapScopedWriteAccess pWriteAccess( aDstBitmap );
411 BitmapScopedWriteAccess pAlphaWriteAccess( aDstAlpha );
412
413
414 if( pWriteAccess.get() != nullptr &&
415 pAlphaWriteAccess.get() != nullptr &&
416 rTransform.isInvertible() )
417 {
418 // we're doing inverse mapping here, i.e. mapping
419 // points from the destination bitmap back to the
420 // source
421 ::basegfx::B2DHomMatrix aTransform( rLocalTransform );
422 aTransform.invert();
423
424 // for the time being, always read as ARGB
425 for( tools::Long y=0; y<aDestBmpSize.Height(); ++y )
426 {
427 // differentiate mask and alpha channel (on-off
428 // vs. multi-level transparency)
429 if( rBitmap.IsAlpha() )
430 {
431 Scanline pScan = pWriteAccess->GetScanline( y );
432 Scanline pScanAlpha = pAlphaWriteAccess->GetScanline( y );
433 // Handling alpha and mask just the same...
434 for( tools::Long x=0; x<aDestBmpSize.Width(); ++x )
435 {
436 ::basegfx::B2DPoint aPoint(x,y);
437 aPoint *= aTransform;
438
439 const int nSrcX( ::basegfx::fround( aPoint.getX() ) );
440 const int nSrcY( ::basegfx::fround( aPoint.getY() ) );
441 if( nSrcX < 0 || nSrcX >= aBmpSize.Width() ||
442 nSrcY < 0 || nSrcY >= aBmpSize.Height() )
443 {
444 pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x, BitmapColor(255) );
445 }
446 else
447 {
448 const sal_uInt8 cAlphaIdx = pAlphaReadAccess->GetPixelIndex( nSrcY, nSrcX );
449 pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x, BitmapColor(aAlphaMap[ cAlphaIdx ]) );
450 pWriteAccess->SetPixelOnData( pScan, x, pReadAccess->GetPixel( nSrcY, nSrcX ) );
451 }
452 }
453 }
454 else
455 {
456 Scanline pScan = pWriteAccess->GetScanline( y );
457 Scanline pScanAlpha = pAlphaWriteAccess->GetScanline( y );
458 for( tools::Long x=0; x<aDestBmpSize.Width(); ++x )
459 {
460 ::basegfx::B2DPoint aPoint(x,y);
461 aPoint *= aTransform;
462
463 const int nSrcX( ::basegfx::fround( aPoint.getX() ) );
464 const int nSrcY( ::basegfx::fround( aPoint.getY() ) );
465 if( nSrcX < 0 || nSrcX >= aBmpSize.Width() ||
466 nSrcY < 0 || nSrcY >= aBmpSize.Height() )
467 {
468 pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x, BitmapColor(255) );
469 }
470 else
471 {
472 pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x, BitmapColor(0) );
473 pWriteAccess->SetPixelOnData( pScan, x, pReadAccess->GetPixel( nSrcY,
474 nSrcX ) );
475 }
476 }
477 }
478 }
479 }
480 else
481 {
482 // TODO(E2): Error handling!
483 ENSURE_OR_THROW( false,
484 "transformBitmap(): could not access bitmap" );
485 }
486 }
487
488 return BitmapEx(aDstBitmap, AlphaMask(aDstAlpha));
489}
490
491
492void DrawAlphaBitmapAndAlphaGradient(BitmapEx & rBitmapEx, bool bFixedTransparence, float fTransparence, AlphaMask & rNewMask)
493{
494 // mix existing and new alpha mask
495 AlphaMask aOldMask;
496
497 if(rBitmapEx.IsAlpha())
498 {
499 aOldMask = rBitmapEx.GetAlpha();
500 }
501
502 {
503 AlphaScopedWriteAccess pOld(aOldMask);
504
505 assert(pOld && "Got no access to old alpha mask (!)");
506
507 const double fFactor(1.0 / 255.0);
508
509 if(bFixedTransparence)
510 {
511 const double fOpNew(1.0 - fTransparence);
512
513 for(tools::Long y(0); y < pOld->Height(); y++)
514 {
515 Scanline pScanline = pOld->GetScanline( y );
516 for(tools::Long x(0); x < pOld->Width(); x++)
517 {
518 const double fOpOld(1.0 - (pOld->GetIndexFromData(pScanline, x) * fFactor));
519 const sal_uInt8 aCol(basegfx::fround((1.0 - (fOpOld * fOpNew)) * 255.0));
520
521 pOld->SetPixelOnData(pScanline, x, BitmapColor(aCol));
522 }
523 }
524 }
525 else
526 {
527 AlphaMask::ScopedReadAccess pNew(rNewMask);
528
529 assert(pNew && "Got no access to new alpha mask (!)");
530
531 assert(pOld->Width() == pNew->Width() && pOld->Height() == pNew->Height() &&
532 "Alpha masks have different sizes (!)");
533
534 for(tools::Long y(0); y < pOld->Height(); y++)
535 {
536 Scanline pScanline = pOld->GetScanline( y );
537 for(tools::Long x(0); x < pOld->Width(); x++)
538 {
539 const double fOpOld(1.0 - (pOld->GetIndexFromData(pScanline, x) * fFactor));
540 const double fOpNew(1.0 - (pNew->GetIndexFromData(pScanline, x) * fFactor));
541 const sal_uInt8 aCol(basegfx::fround((1.0 - (fOpOld * fOpNew)) * 255.0));
542
543 pOld->SetPixelOnData(pScanline, x, BitmapColor(aCol));
544 }
545 }
546 }
547
548 }
549
550 // apply combined bitmap as mask
551 rBitmapEx = BitmapEx(rBitmapEx.GetBitmap(), aOldMask);
552}
553
554
555void DrawAndClipBitmap(const Point& rPos, const Size& rSize, const BitmapEx& rBitmap, BitmapEx & aBmpEx, basegfx::B2DPolyPolygon const & rClipPath)
556{
558 MapMode aMapMode( MapUnit::Map100thMM );
559 aMapMode.SetOrigin( Point( -rPos.X(), -rPos.Y() ) );
560 const Size aOutputSizePixel( pVDev->LogicToPixel( rSize, aMapMode ) );
561 const Size aSizePixel( rBitmap.GetSizePixel() );
562 if ( aOutputSizePixel.Width() && aOutputSizePixel.Height() )
563 {
564 aMapMode.SetScaleX( Fraction( aSizePixel.Width(), aOutputSizePixel.Width() ) );
565 aMapMode.SetScaleY( Fraction( aSizePixel.Height(), aOutputSizePixel.Height() ) );
566 }
567 pVDev->SetMapMode( aMapMode );
568 pVDev->SetOutputSizePixel( aSizePixel );
569 pVDev->SetFillColor( COL_BLACK );
570 const tools::PolyPolygon aClip( rClipPath );
571 pVDev->DrawPolyPolygon( aClip );
572
573 // #i50672# Extract whole VDev content (to match size of rBitmap)
574 pVDev->EnableMapMode( false );
575 const Bitmap aVDevMask(pVDev->GetBitmap(Point(), aSizePixel));
576
577 if(aBmpEx.IsAlpha())
578 {
579 // bitmap already uses a Mask or Alpha, we need to blend that with
580 // the new masking in pVDev.
581 // need to blend in AlphaMask quality (8Bit)
582 AlphaMask fromVDev(aVDevMask);
583 AlphaMask fromBmpEx(aBmpEx.GetAlpha());
584 AlphaMask::ScopedReadAccess pR(fromVDev);
585 AlphaScopedWriteAccess pW(fromBmpEx);
586
587 if(pR && pW)
588 {
589 const tools::Long nWidth(std::min(pR->Width(), pW->Width()));
590 const tools::Long nHeight(std::min(pR->Height(), pW->Height()));
591
592 for(tools::Long nY(0); nY < nHeight; nY++)
593 {
594 Scanline pScanlineR = pR->GetScanline( nY );
595 Scanline pScanlineW = pW->GetScanline( nY );
596 for(tools::Long nX(0); nX < nWidth; nX++)
597 {
598 const sal_uInt8 nIndR(pR->GetIndexFromData(pScanlineR, nX));
599 const sal_uInt8 nIndW(pW->GetIndexFromData(pScanlineW, nX));
600
601 // these values represent transparency (0 == no, 255 == fully transparent),
602 // so to blend these we have to multiply the inverse (opacity)
603 // and re-invert the result to transparence
604 const sal_uInt8 nCombined(0x00ff - (((0x00ff - nIndR) * (0x00ff - nIndW)) >> 8));
605
606 pW->SetPixelOnData(pScanlineW, nX, BitmapColor(nCombined));
607 }
608 }
609 }
610
611 pR.reset();
612 pW.reset();
613 aBmpEx = BitmapEx(aBmpEx.GetBitmap(), fromBmpEx);
614 }
615 else
616 {
617 // no mask yet, create and add new mask. For better quality, use Alpha,
618 // this allows the drawn mask being processed with AntiAliasing (AAed)
619 aBmpEx = BitmapEx(rBitmap.GetBitmap(), aVDevMask);
620 }
621}
622
623
624css::uno::Sequence< sal_Int8 > GetMaskDIB(BitmapEx const & aBmpEx)
625{
626 if ( aBmpEx.IsAlpha() )
627 {
628 SvMemoryStream aMem;
629 WriteDIB(aBmpEx.GetAlpha().GetBitmap(), aMem, false, true);
630 return css::uno::Sequence< sal_Int8 >( static_cast<sal_Int8 const *>(aMem.GetData()), aMem.Tell() );
631 }
632
633 return css::uno::Sequence< sal_Int8 >();
634}
635
636static bool readAlpha( BitmapReadAccess const * pAlphaReadAcc, tools::Long nY, const tools::Long nWidth, unsigned char* data, tools::Long nOff )
637{
638 bool bIsAlpha = false;
639 tools::Long nX;
640 int nAlpha;
641 Scanline pReadScan;
642
643 nOff += 3;
644
645 switch( pAlphaReadAcc->GetScanlineFormat() )
646 {
648 pReadScan = pAlphaReadAcc->GetScanline( nY );
649 for( nX = 0; nX < nWidth; nX++ )
650 {
651 BitmapColor const& rColor(
652 pAlphaReadAcc->GetPaletteColor(*pReadScan));
653 pReadScan++;
654 nAlpha = data[ nOff ] = 255 - rColor.GetIndex();
655 if( nAlpha != 255 )
656 bIsAlpha = true;
657 nOff += 4;
658 }
659 break;
660 default:
661 SAL_INFO( "canvas.cairo", "fallback to GetColor for alpha - slow, format: " << static_cast<int>(pAlphaReadAcc->GetScanlineFormat()) );
662 for( nX = 0; nX < nWidth; nX++ )
663 {
664 nAlpha = data[ nOff ] = 255 - pAlphaReadAcc->GetColor( nY, nX ).GetIndex();
665 if( nAlpha != 255 )
666 bIsAlpha = true;
667 nOff += 4;
668 }
669 }
670
671 return bIsAlpha;
672}
673
674
675
680void CanvasCairoExtractBitmapData( BitmapEx const & aBmpEx, Bitmap & aBitmap, unsigned char*& data, bool& bHasAlpha, tools::Long& rnWidth, tools::Long& rnHeight )
681{
682 AlphaMask aAlpha = aBmpEx.GetAlpha();
683
684 ::BitmapReadAccess* pBitmapReadAcc = aBitmap.AcquireReadAccess();
685 ::BitmapReadAccess* pAlphaReadAcc = nullptr;
686 const tools::Long nWidth = rnWidth = pBitmapReadAcc->Width();
687 const tools::Long nHeight = rnHeight = pBitmapReadAcc->Height();
688 tools::Long nX, nY;
689 bool bIsAlpha = false;
690
691 if( aBmpEx.IsAlpha() )
692 pAlphaReadAcc = aAlpha.AcquireReadAccess();
693
694 data = static_cast<unsigned char*>(malloc( nWidth*nHeight*4 ));
695
696 tools::Long nOff = 0;
697 ::Color aColor;
698 unsigned int nAlpha = 255;
699
700#if !ENABLE_WASM_STRIP_PREMULTIPLY
702#endif
703 for( nY = 0; nY < nHeight; nY++ )
704 {
705 ::Scanline pReadScan;
706
707 switch( pBitmapReadAcc->GetScanlineFormat() )
708 {
710 pReadScan = pBitmapReadAcc->GetScanline( nY );
711 if( pAlphaReadAcc )
712 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
713 bIsAlpha = true;
714
715 for( nX = 0; nX < nWidth; nX++ )
716 {
717#ifdef OSL_BIGENDIAN
718 if( pAlphaReadAcc )
719 nAlpha = data[ nOff++ ];
720 else
721 nAlpha = data[ nOff++ ] = 255;
722#else
723 if( pAlphaReadAcc )
724 nAlpha = data[ nOff + 3 ];
725 else
726 nAlpha = data[ nOff + 3 ] = 255;
727#endif
728 aColor = pBitmapReadAcc->GetPaletteColor(*pReadScan++);
729
730#ifdef OSL_BIGENDIAN
731#if ENABLE_WASM_STRIP_PREMULTIPLY
732 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, aColor.GetRed());
733 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, aColor.GetGreen());
734 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, aColor.GetBlue());
735#else
736 data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetRed()];
737 data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetGreen()];
738 data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetBlue()];
739#endif
740#else
741#if ENABLE_WASM_STRIP_PREMULTIPLY
742 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, aColor.GetBlue());
743 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, aColor.GetGreen());
744 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, aColor.GetRed());
745#else
746 data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetBlue()];
747 data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetGreen()];
748 data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetRed()];
749#endif
750 nOff++;
751#endif
752 }
753 break;
755 pReadScan = pBitmapReadAcc->GetScanline( nY );
756 if( pAlphaReadAcc )
757 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
758 bIsAlpha = true;
759
760 for( nX = 0; nX < nWidth; nX++ )
761 {
762#ifdef OSL_BIGENDIAN
763 if( pAlphaReadAcc )
764 nAlpha = data[ nOff ];
765 else
766 nAlpha = data[ nOff ] = 255;
767#if ENABLE_WASM_STRIP_PREMULTIPLY
768 data[ nOff + 3 ] = vcl::bitmap::premultiply(nAlpha, *pReadScan++);
769 data[ nOff + 2 ] = vcl::bitmap::premultiply(nAlpha, *pReadScan++);
770 data[ nOff + 1 ] = vcl::bitmap::premultiply(nAlpha, *pReadScan++);
771#else
772 data[ nOff + 3 ] = premultiply_table[nAlpha][*pReadScan++];
773 data[ nOff + 2 ] = premultiply_table[nAlpha][*pReadScan++];
774 data[ nOff + 1 ] = premultiply_table[nAlpha][*pReadScan++];
775#endif
776 nOff += 4;
777#else
778 if( pAlphaReadAcc )
779 nAlpha = data[ nOff + 3 ];
780 else
781 nAlpha = data[ nOff + 3 ] = 255;
782#if ENABLE_WASM_STRIP_PREMULTIPLY
783 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, *pReadScan++);
784 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, *pReadScan++);
785 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, *pReadScan++);
786#else
787 data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
788 data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
789 data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
790#endif
791 nOff++;
792#endif
793 }
794 break;
796 pReadScan = pBitmapReadAcc->GetScanline( nY );
797 if( pAlphaReadAcc )
798 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
799 bIsAlpha = true;
800
801 for( nX = 0; nX < nWidth; nX++ )
802 {
803#ifdef OSL_BIGENDIAN
804 if( pAlphaReadAcc )
805 nAlpha = data[ nOff++ ];
806 else
807 nAlpha = data[ nOff++ ] = 255;
808#if ENABLE_WASM_STRIP_PREMULTIPLY
809 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, *pReadScan++);
810 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, *pReadScan++);
811 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, *pReadScan++);
812#else
813 data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
814 data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
815 data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
816#endif
817#else
818 if( pAlphaReadAcc )
819 nAlpha = data[ nOff + 3 ];
820 else
821 nAlpha = data[ nOff + 3 ] = 255;
822#if ENABLE_WASM_STRIP_PREMULTIPLY
823 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, pReadScan[ 2 ]);
824 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, pReadScan[ 1 ]);
825 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, pReadScan[ 0 ]);
826#else
827 data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 2 ]];
828 data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 1 ]];
829 data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 0 ]];
830#endif
831 pReadScan += 3;
832 nOff++;
833#endif
834 }
835 break;
837 pReadScan = pBitmapReadAcc->GetScanline( nY );
838 if( pAlphaReadAcc )
839 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
840 bIsAlpha = true;
841
842 for( nX = 0; nX < nWidth; nX++ )
843 {
844#ifdef OSL_BIGENDIAN
845 if( pAlphaReadAcc )
846 nAlpha = data[ nOff++ ];
847 else
848 nAlpha = data[ nOff++ ] = 255;
849#if ENABLE_WASM_STRIP_PREMULTIPLY
850 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, pReadScan[ 2 ]);
851 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, pReadScan[ 1 ]);
852 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, pReadScan[ 0 ]);
853#else
854 data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 2 ]];
855 data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 1 ]];
856 data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 0 ]];
857#endif
858 pReadScan += 4;
859#else
860 if( pAlphaReadAcc )
861 nAlpha = data[ nOff + 3 ];
862 else
863 nAlpha = data[ nOff + 3 ] = 255;
864#if ENABLE_WASM_STRIP_PREMULTIPLY
865 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, *pReadScan++);
866 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, *pReadScan++);
867 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, *pReadScan++);
868#else
869 data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
870 data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
871 data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
872#endif
873 pReadScan++;
874 nOff++;
875#endif
876 }
877 break;
879 pReadScan = pBitmapReadAcc->GetScanline( nY );
880 if( pAlphaReadAcc )
881 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
882 bIsAlpha = true;
883
884 for( nX = 0; nX < nWidth; nX++ )
885 {
886#ifdef OSL_BIGENDIAN
887 if( pAlphaReadAcc )
888 nAlpha = data[ nOff ++ ];
889 else
890 nAlpha = data[ nOff ++ ] = 255;
891#if ENABLE_WASM_STRIP_PREMULTIPLY
892 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, *pReadScan++);
893 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, *pReadScan++);
894 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, *pReadScan++);
895#else
896 data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
897 data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
898 data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
899#endif
900 pReadScan++;
901#else
902 if( pAlphaReadAcc )
903 nAlpha = data[ nOff + 3 ];
904 else
905 nAlpha = data[ nOff + 3 ] = 255;
906#if ENABLE_WASM_STRIP_PREMULTIPLY
907 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, pReadScan[ 2 ]);
908 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, pReadScan[ 1 ]);
909 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, pReadScan[ 0 ]);
910#else
911 data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 2 ]];
912 data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 1 ]];
913 data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 0 ]];
914#endif
915 pReadScan += 4;
916 nOff++;
917#endif
918 }
919 break;
920 default:
921 SAL_INFO( "canvas.cairo", "fallback to GetColor - slow, format: " << static_cast<int>(pBitmapReadAcc->GetScanlineFormat()) );
922
923 if( pAlphaReadAcc )
924 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
925 bIsAlpha = true;
926
927 for( nX = 0; nX < nWidth; nX++ )
928 {
929 aColor = pBitmapReadAcc->GetColor( nY, nX );
930
931 // cairo need premultiplied color values
932 // TODO(rodo) handle endianness
933#ifdef OSL_BIGENDIAN
934 if( pAlphaReadAcc )
935 nAlpha = data[ nOff++ ];
936 else
937 nAlpha = data[ nOff++ ] = 255;
938#if ENABLE_WASM_STRIP_PREMULTIPLY
939 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, aColor.GetRed());
940 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, aColor.GetGreen());
941 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, aColor.GetBlue());
942#else
943 data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetRed()];
944 data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetGreen()];
945 data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetBlue()];
946#endif
947#else
948 if( pAlphaReadAcc )
949 nAlpha = data[ nOff + 3 ];
950 else
951 nAlpha = data[ nOff + 3 ] = 255;
952#if ENABLE_WASM_STRIP_PREMULTIPLY
953 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, aColor.GetBlue());
954 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, aColor.GetGreen());
955 data[ nOff++ ] = vcl::bitmap::premultiply(nAlpha, aColor.GetRed());
956#else
957 data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetBlue()];
958 data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetGreen()];
959 data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetRed()];
960#endif
961 nOff ++;
962#endif
963 }
964 }
965 }
966
967 ::Bitmap::ReleaseAccess( pBitmapReadAcc );
968 if( pAlphaReadAcc )
969 aAlpha.ReleaseAccess( pAlphaReadAcc );
970
971 bHasAlpha = bIsAlpha;
972
973}
974
975 uno::Sequence< sal_Int8 > CanvasExtractBitmapData(BitmapEx const & rBitmapEx, const geometry::IntegerRectangle2D& rect)
976 {
977 Bitmap aBitmap( rBitmapEx.GetBitmap() );
978 Bitmap aAlpha( rBitmapEx.GetAlpha().GetBitmap() );
979
980 Bitmap::ScopedReadAccess pReadAccess( aBitmap );
981 Bitmap::ScopedReadAccess pAlphaReadAccess( aAlpha.IsEmpty() ?
982 nullptr : aAlpha.AcquireReadAccess(),
983 aAlpha );
984
985 assert( pReadAccess );
986
987 // TODO(F1): Support more formats.
988 const Size aBmpSize( aBitmap.GetSizePixel() );
989
990 // for the time being, always return as BGRA
991 uno::Sequence< sal_Int8 > aRes( 4*aBmpSize.Width()*aBmpSize.Height() );
992 sal_Int8* pRes = aRes.getArray();
993
994 int nCurrPos(0);
995 for( tools::Long y=rect.Y1;
996 y<aBmpSize.Height() && y<rect.Y2;
997 ++y )
998 {
999 if( pAlphaReadAccess.get() != nullptr )
1000 {
1001 Scanline pScanlineReadAlpha = pAlphaReadAccess->GetScanline( y );
1002 for( tools::Long x=rect.X1;
1003 x<aBmpSize.Width() && x<rect.X2;
1004 ++x )
1005 {
1006 pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetRed();
1007 pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetGreen();
1008 pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetBlue();
1009 pRes[ nCurrPos++ ] = pAlphaReadAccess->GetIndexFromData( pScanlineReadAlpha, x );
1010 }
1011 }
1012 else
1013 {
1014 for( tools::Long x=rect.X1;
1015 x<aBmpSize.Width() && x<rect.X2;
1016 ++x )
1017 {
1018 pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetRed();
1019 pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetGreen();
1020 pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetBlue();
1021 pRes[ nCurrPos++ ] = sal_uInt8(255);
1022 }
1023 }
1024 }
1025 return aRes;
1026 }
1027
1028 BitmapEx createHistorical8x8FromArray(std::array<sal_uInt8,64> const & pArray, Color aColorPix, Color aColorBack)
1029 {
1030 BitmapPalette aPalette(2);
1031
1032 aPalette[0] = BitmapColor(aColorBack);
1033 aPalette[1] = BitmapColor(aColorPix);
1034
1035 Bitmap aBitmap(Size(8, 8), vcl::PixelFormat::N1_BPP, &aPalette);
1036 BitmapScopedWriteAccess pContent(aBitmap);
1037
1038 for(sal_uInt16 a(0); a < 8; a++)
1039 {
1040 for(sal_uInt16 b(0); b < 8; b++)
1041 {
1042 if(pArray[(a * 8) + b])
1043 {
1044 pContent->SetPixelIndex(a, b, 1);
1045 }
1046 else
1047 {
1048 pContent->SetPixelIndex(a, b, 0);
1049 }
1050 }
1051 }
1052
1053 return BitmapEx(aBitmap);
1054 }
1055
1056 bool isHistorical8x8(const BitmapEx& rBitmapEx, Color& o_rBack, Color& o_rFront)
1057 {
1058 bool bRet(false);
1059
1060 if(!rBitmapEx.IsAlpha())
1061 {
1062 Bitmap aBitmap(rBitmapEx.GetBitmap());
1063
1064 if(8 == aBitmap.GetSizePixel().Width() && 8 == aBitmap.GetSizePixel().Height())
1065 {
1067 {
1068 BitmapReadAccess* pRead = aBitmap.AcquireReadAccess();
1069
1070 if(pRead)
1071 {
1072 if(pRead->HasPalette() && 2 == pRead->GetPaletteEntryCount())
1073 {
1074 const BitmapPalette& rPalette = pRead->GetPalette();
1075 o_rFront = rPalette[1];
1076 o_rBack = rPalette[0];
1077
1078 bRet = true;
1079 }
1080
1081 Bitmap::ReleaseAccess(pRead);
1082 }
1083 }
1084 else
1085 {
1086 // Historical 1bpp images are getting really historical,
1087 // even to the point that e.g. the png loader actually loads
1088 // them as RGB. But the pattern code in svx relies on this
1089 // assumption that any 2-color 1bpp bitmap is a pattern, and so it would
1090 // get confused by RGB. Try to detect if this image is really
1091 // just two colors and say it's a pattern bitmap if so.
1092 Bitmap::ScopedReadAccess access(aBitmap);
1093 o_rBack = access->GetColor(0,0);
1094 bool foundSecondColor = false;;
1095 for(tools::Long y = 0; y < access->Height(); ++y)
1096 for(tools::Long x = 0; x < access->Width(); ++x)
1097 {
1098 if(!foundSecondColor)
1099 {
1100 if( access->GetColor(y,x) != o_rBack )
1101 {
1102 o_rFront = access->GetColor(y,x);
1103 foundSecondColor = true;
1104 // Hard to know which of the two colors is the background,
1105 // select the lighter one.
1106 if( o_rFront.GetLuminance() > o_rBack.GetLuminance())
1107 std::swap( o_rFront, o_rBack );
1108 }
1109 }
1110 else
1111 {
1112 if( access->GetColor(y,x) != o_rBack && access->GetColor(y,x) != o_rFront)
1113 return false;
1114 }
1115 }
1116 return true;
1117 }
1118 }
1119 }
1120
1121 return bRet;
1122 }
1123
1124#if ENABLE_WASM_STRIP_PREMULTIPLY
1126 {
1127 return (a == 0) ? 0 : (c * 255 + a / 2) / a;
1128 }
1129
1131 {
1132 return (c * a + 127) / 255;
1133 }
1134#else
1136 {
1137 return get_unpremultiply_table()[a][c];
1138 }
1139
1141 {
1142 return (a == 0) ? 0 : (c * 255 + a / 2) / a;
1143 }
1144
1146 {
1147 return get_premultiply_table()[a][c];
1148 }
1149
1151 {
1152 return (c * a + 127) / 255;
1153 }
1154
1155 template<int... Is> static constexpr std::array<sal_uInt8, 256> make_unpremultiply_table_row_(
1156 int a, std::integer_sequence<int, Is...>)
1157 {
1158 return {unpremultiplyImpl(Is, a)...};
1159 }
1160
1161 template<int... Is> static constexpr lookup_table make_unpremultiply_table_(
1162 std::integer_sequence<int, Is...>)
1163 {
1164 return {make_unpremultiply_table_row_(Is, std::make_integer_sequence<int, 256>{})...};
1165 }
1166
1168 {
1169 static constexpr auto unpremultiply_table = make_unpremultiply_table_(
1170 std::make_integer_sequence<int, 256>{});
1171 return unpremultiply_table;
1172 }
1173
1174 template<int... Is> static constexpr std::array<sal_uInt8, 256> make_premultiply_table_row_(
1175 int a, std::integer_sequence<int, Is...>)
1176 {
1177 return {premultiplyImpl(Is, a)...};
1178 }
1179
1180 template<int... Is> static constexpr lookup_table make_premultiply_table_(
1181 std::integer_sequence<int, Is...>)
1182 {
1183 return {make_premultiply_table_row_(Is, std::make_integer_sequence<int, 256>{})...};
1184 }
1185
1187 {
1188 static constexpr auto premultiply_table = make_premultiply_table_(
1189 std::make_integer_sequence<int, 256>{});
1190 return premultiply_table;
1191 }
1192#endif
1193
1194bool convertBitmap32To24Plus8(BitmapEx const & rInput, BitmapEx & rResult)
1195{
1196 Bitmap aBitmap(rInput.GetBitmap());
1198 return false;
1199
1200 Size aSize = aBitmap.GetSizePixel();
1201 Bitmap aResultBitmap(aSize, vcl::PixelFormat::N24_BPP);
1202 AlphaMask aResultAlpha(aSize);
1203 {
1204 BitmapScopedWriteAccess pResultBitmapAccess(aResultBitmap);
1205 AlphaScopedWriteAccess pResultAlphaAccess(aResultAlpha);
1206
1207 Bitmap::ScopedReadAccess pReadAccess(aBitmap);
1208
1209 for (tools::Long nY = 0; nY < aSize.Height(); ++nY)
1210 {
1211 Scanline aResultScan = pResultBitmapAccess->GetScanline(nY);
1212 Scanline aResultScanAlpha = pResultAlphaAccess->GetScanline(nY);
1213
1214 Scanline aReadScan = pReadAccess->GetScanline(nY);
1215
1216 for (tools::Long nX = 0; nX < aSize.Width(); ++nX)
1217 {
1218 const BitmapColor aColor = pReadAccess->GetPixelFromData(aReadScan, nX);
1219 BitmapColor aResultColor(aColor.GetRed(), aColor.GetGreen(), aColor.GetBlue());
1220 BitmapColor aResultColorAlpha(255 - aColor.GetAlpha(), 255 - aColor.GetAlpha(), 255 - aColor.GetAlpha());
1221
1222 pResultBitmapAccess->SetPixelOnData(aResultScan, nX, aResultColor);
1223 pResultAlphaAccess->SetPixelOnData(aResultScanAlpha, nX, aResultColorAlpha);
1224 }
1225 }
1226 }
1227 if (rInput.IsAlpha())
1228 rResult = BitmapEx(aResultBitmap, rInput.GetAlpha());
1229 else
1230 rResult = BitmapEx(aResultBitmap, aResultAlpha);
1231 return true;
1232}
1233
1234Bitmap GetDownsampledBitmap(Size const& rDstSizeTwip, Point const& rSrcPt, Size const& rSrcSz,
1235 Bitmap const& rBmp, tools::Long nMaxBmpDPIX, tools::Long nMaxBmpDPIY)
1236{
1237 Bitmap aBmp(rBmp);
1238
1239 if (!aBmp.IsEmpty())
1240 {
1241 const tools::Rectangle aBmpRect( Point(), aBmp.GetSizePixel() );
1242 tools::Rectangle aSrcRect( rSrcPt, rSrcSz );
1243
1244 // do cropping if necessary
1245 if( aSrcRect.Intersection( aBmpRect ) != aBmpRect )
1246 {
1247 if( !aSrcRect.IsEmpty() )
1248 aBmp.Crop( aSrcRect );
1249 else
1250 aBmp.SetEmpty();
1251 }
1252
1253 if( !aBmp.IsEmpty() )
1254 {
1255 // do downsampling if necessary
1256 // #103209# Normalize size (mirroring has to happen outside of this method)
1257 Size aDstSizeTwip(std::abs(rDstSizeTwip.Width()), std::abs(rDstSizeTwip.Height()));
1258
1259 const Size aBmpSize( aBmp.GetSizePixel() );
1260 const double fBmpPixelX = aBmpSize.Width();
1261 const double fBmpPixelY = aBmpSize.Height();
1262 const double fMaxPixelX
1263 = o3tl::convert<double>(aDstSizeTwip.Width(), o3tl::Length::twip, o3tl::Length::in)
1264 * nMaxBmpDPIX;
1265 const double fMaxPixelY
1266 = o3tl::convert<double>(aDstSizeTwip.Height(), o3tl::Length::twip, o3tl::Length::in)
1267 * nMaxBmpDPIY;
1268
1269 // check, if the bitmap DPI exceeds the maximum DPI (allow 4 pixel rounding tolerance)
1270 if (((fBmpPixelX > (fMaxPixelX + 4)) ||
1271 (fBmpPixelY > (fMaxPixelY + 4))) &&
1272 (fBmpPixelY > 0.0) && (fMaxPixelY > 0.0))
1273 {
1274 // do scaling
1275 Size aNewBmpSize;
1276 const double fBmpWH = fBmpPixelX / fBmpPixelY;
1277 const double fMaxWH = fMaxPixelX / fMaxPixelY;
1278
1279 if (fBmpWH < fMaxWH)
1280 {
1281 aNewBmpSize.setWidth(FRound(fMaxPixelY * fBmpWH));
1282 aNewBmpSize.setHeight(FRound(fMaxPixelY));
1283 }
1284 else if (fBmpWH > 0.0)
1285 {
1286 aNewBmpSize.setWidth(FRound(fMaxPixelX));
1287 aNewBmpSize.setHeight(FRound(fMaxPixelX / fBmpWH));
1288 }
1289
1290 if( aNewBmpSize.Width() && aNewBmpSize.Height() )
1291 aBmp.Scale(aNewBmpSize);
1292 else
1293 aBmp.SetEmpty();
1294 }
1295 }
1296 }
1297
1298 return aBmp;
1299}
1300
1301} // end vcl::bitmap
1302
1303/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
vcl::ScopedBitmapAccess< BitmapWriteAccess, AlphaMask, &AlphaMask::AcquireAlphaWriteAccess > AlphaScopedWriteAccess
struct _cairo_surface cairo_surface_t
Definition: CairoCommon.hxx:72
struct _cairo cairo_t
Definition: CairoCommon.hxx:71
ImageLoadFlags
Definition: ImageTree.hxx:32
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
const StyleSettings & GetStyleSettings() const
Bitmap const & GetBitmap() const
Definition: alpha.cxx:73
void ReleaseAccess(BitmapReadAccess *pAccess)
Definition: alpha.cxx:143
static const AllSettings & GetSettings()
Gets the application's settings.
Definition: svapp.cxx:761
sal_uInt8 GetIndex() const
Definition: BitmapColor.hxx:70
AlphaMask GetAlpha() const
Definition: BitmapEx.cxx:215
bool IsAlpha() const
Definition: BitmapEx.cxx:193
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:203
const Size & GetSizePixel() const
Definition: bitmapex.hxx:72
tools::Long Height() const
tools::Long Width() const
const BitmapPalette & GetPalette() const
bool HasPalette() const
ScanlineFormat GetScanlineFormat() const
sal_uInt16 GetPaletteEntryCount() const
const BitmapColor & GetPaletteColor(sal_uInt16 nColor) const
sal_uInt8 GetPixelIndex(tools::Long nY, tools::Long nX) const
BitmapColor GetPixel(tools::Long nY, tools::Long nX) const
BitmapColor GetColor(tools::Long nY, tools::Long nX) const
BitmapColor GetPixelFromData(const sal_uInt8 *pData, tools::Long nX) const
sal_uInt8 GetIndexFromData(const sal_uInt8 *pData, tools::Long nX) const
Scanline GetScanline(tools::Long nY) const
bool Crop(const tools::Rectangle &rRectPixel)
Crop the bitmap.
Size GetSizePixel() const
static void ReleaseAccess(BitmapInfoAccess *pAccess)
bool Scale(const Size &rNewSize, BmpScaleFlag nScaleFlag=BmpScaleFlag::Default)
Scale the bitmap.
bool IsEmpty() const
BitmapReadAccess * AcquireReadAccess()
vcl::PixelFormat getPixelFormat() const
void SetEmpty()
sal_uInt8 GetLuminance() const
sal_uInt8 GetBlue() const
sal_uInt8 GetAlpha() const
sal_uInt8 GetRed() const
sal_uInt8 GetGreen() const
static VCL_DLLPUBLIC ImageTree & get()
Definition: ImageTree.cxx:16
VCL_DLLPUBLIC bool loadImage(OUString const &name, OUString const &style, BitmapEx &bitmap, bool localized, const ImageLoadFlags eFlags=ImageLoadFlags::NONE)
Definition: ImageTree.cxx:50
void SetOrigin(const Point &rOrigin)
Definition: mapmod.cxx:103
void SetScaleY(const Fraction &rScaleY)
Definition: mapmod.cxx:115
void SetScaleX(const Fraction &rScaleX)
Definition: mapmod.cxx:109
bool IsEmpty() const
constexpr tools::Long Height() const
void setWidth(tools::Long nWidth)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
OUString DetermineIconTheme() const
Determine which icon theme should be used.
const void * GetData()
sal_uInt64 Tell() const
std::size_t ReadBytes(void *pData, std::size_t nSize)
sal_uInt64 remainingSize()
B2DVector getRange() const
TYPE getMaxX() const
TYPE getWidth() const
TYPE getMinX() const
TYPE getMinY() const
void expand(const Tuple2D< TYPE > &rTuple)
TYPE getMaxY() const
TYPE getHeight() const
TYPE getX() const
TYPE getY() const
tools::Rectangle & Intersection(const tools::Rectangle &rRect)
constexpr bool IsEmpty() const
This template handles BitmapAccess the RAII way.
Intended to be used to feed into CreateFromData to create a BitmapEx.
Definition: RawBitmap.hxx:22
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
#define ENSURE_OR_THROW(c, m)
bool WriteDIB(const Bitmap &rSource, SvStream &rOStm, bool bCompressed, bool bFileHeader)
Definition: dibtools.cxx:1832
float y
float x
sal_Int16 nValue
tools::Long FRound(double fVal)
short nBitCount
Definition: ipict.cxx:80
void * p
uno_Any a
#define SAL_WARN_IF(condition, area, stream)
#define SAL_INFO(area, stream)
std::unique_ptr< sal_Int32[]> pData
constexpr OUStringLiteral aData
B2IRange fround(const B2DRange &rRange)
Reference< XComponentContext > getProcessComponentContext()
rtl::Reference< BasePrimitive2D > Primitive2DReference
css::uno::Sequence< css::uno::Reference< css::graphic::XPrimitive2D > > Primitive2DSequence
long Long
void CanvasCairoExtractBitmapData(BitmapEx const &aBmpEx, Bitmap &aBitmap, unsigned char *&data, bool &bHasAlpha, tools::Long &rnWidth, tools::Long &rnHeight)
bool isHistorical8x8(const BitmapEx &rBitmapEx, Color &o_rBack, Color &o_rFront)
BitmapEx loadFromName(const OUString &rFileName, const ImageLoadFlags eFlags)
Definition: BitmapTools.cxx:52
lookup_table const & get_unpremultiply_table()
static constexpr lookup_table make_unpremultiply_table_(std::integer_sequence< int, Is... >)
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.
static constexpr std::array< sal_uInt8, 256 > make_premultiply_table_row_(int a, std::integer_sequence< int, Is... >)
BitmapEx CanvasTransformBitmap(const BitmapEx &rBitmap, const ::basegfx::B2DHomMatrix &rTransform, ::basegfx::B2DRectangle const &rDestRect, ::basegfx::B2DHomMatrix const &rLocalTransform)
void DrawAlphaBitmapAndAlphaGradient(BitmapEx &rBitmapEx, bool bFixedTransparence, float fTransparence, AlphaMask &rNewMask)
void loadFromSvg(SvStream &rStream, const OUString &sPath, BitmapEx &rBitmapEx, double fScalingFactor)
Definition: BitmapTools.cxx:72
static constexpr std::array< sal_uInt8, 256 > make_unpremultiply_table_row_(int a, std::integer_sequence< int, Is... >)
void DrawAndClipBitmap(const Point &rPos, const Size &rSize, const BitmapEx &rBitmap, BitmapEx &aBmpEx, basegfx::B2DPolyPolygon const &rClipPath)
sal_uInt8 unpremultiply(sal_uInt8 c, sal_uInt8 a)
static constexpr sal_uInt8 premultiplyImpl(sal_uInt8 c, sal_uInt8 a)
BitmapEx CreateFromData(sal_uInt8 const *pData, sal_Int32 nWidth, sal_Int32 nHeight, sal_Int32 nStride, vcl::PixelFormat ePixelFormat, bool bReversColors, bool bReverseAlpha)
Copy block of image data into the bitmap.
BitmapEx createHistorical8x8FromArray(std::array< sal_uInt8, 64 > const &pArray, Color aColorPix, Color aColorBack)
sal_uInt8 premultiply(sal_uInt8 c, sal_uInt8 a)
static bool readAlpha(BitmapReadAccess const *pAlphaReadAcc, tools::Long nY, const tools::Long nWidth, unsigned char *data, tools::Long nOff)
css::uno::Sequence< sal_Int8 > GetMaskDIB(BitmapEx const &aBmpEx)
uno::Sequence< sal_Int8 > CanvasExtractBitmapData(BitmapEx const &rBitmapEx, const geometry::IntegerRectangle2D &rect)
lookup_table const & get_premultiply_table()
std::array< std::array< sal_uInt8, 256 >, 256 > lookup_table
Definition: BitmapTools.hxx:32
bool convertBitmap32To24Plus8(BitmapEx const &rInput, BitmapEx &rResult)
static constexpr lookup_table make_premultiply_table_(std::integer_sequence< int, Is... >)
static constexpr sal_uInt8 unpremultiplyImpl(sal_uInt8 c, sal_uInt8 a)
::BitmapEx bitmapExFromXBitmap(const uno::Reference< rendering::XIntegerReadOnlyBitmap > &xInputBitmap)
PixelFormat
Pixel format of the bitmap in bits per pixel.
Definition: BitmapTypes.hxx:20
unsigned char sal_uInt8
signed char sal_Int8
std::unique_ptr< char[]> aBuffer