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