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