1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
11 #include <sal/config.h>
16 #include <tools/helpers.hxx>
17 #include <vcl/BitmapTools.hxx>
19 #include <sal/log.hxx>
20 #include <comphelper/processfactory.hxx>
21 #include <comphelper/seqstream.hxx>
22 #include <vcl/canvastools.hxx>
23 #include <basegfx/matrix/b2dhommatrix.hxx>
25 #include <com/sun/star/graphic/SvgTools.hpp>
26 #include <com/sun/star/graphic/Primitive2DTools.hpp>
28 #include <drawinglayer/primitive2d/baseprimitive2d.hxx>
30 #include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp>
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
39 #include <comphelper/diagnose_ex.hxx>
40 #include <tools/fract.hxx>
41 #include <tools/stream.hxx>
42 #include <vcl/BitmapWriteAccess.hxx>
46 using drawinglayer::primitive2d::Primitive2DSequence
;
47 using drawinglayer::primitive2d::Primitive2DReference
;
52 BitmapEx
loadFromName(const OUString
& rFileName
, const ImageLoadFlags eFlags
)
59 aIconTheme
= Application::GetSettings().GetStyleSettings().DetermineIconTheme();
60 ImageTree::get().loadImage(rFileName
, aIconTheme
, aBitmapEx
, true, eFlags
);
67 SAL_WARN_IF(!bSuccess
, "vcl", "vcl::bitmap::loadFromName : could not load image " << rFileName
<< " via icon theme " << aIconTheme
);
72 void loadFromSvg(SvStream
& rStream
, const OUString
& sPath
, BitmapEx
& rBitmapEx
, double fScalingFactor
)
74 const uno::Reference
<uno::XComponentContext
>& xContext(comphelper::getProcessComponentContext());
75 const uno::Reference
<graphic::XSvgParser
> xSvgParser
= graphic::SvgTools::create(xContext
);
77 std::size_t nSize
= rStream
.remainingSize();
78 std::vector
<sal_Int8
> aBuffer(nSize
+ 1);
79 rStream
.ReadBytes(aBuffer
.data(), nSize
);
82 uno::Sequence
<sal_Int8
> aData(aBuffer
.data(), nSize
+ 1);
83 uno::Reference
<io::XInputStream
> aInputStream(new comphelper::SequenceInputStream(aData
));
85 const Primitive2DSequence aPrimitiveSequence
= xSvgParser
->getDecomposition(aInputStream
, sPath
);
87 if (!aPrimitiveSequence
.hasElements())
90 uno::Sequence
<beans::PropertyValue
> aViewParameters
;
92 geometry::RealRectangle2D aRealRect
;
93 basegfx::B2DRange aRange
;
94 for (css::uno::Reference
<css::graphic::XPrimitive2D
> const & xReference
: aPrimitiveSequence
)
98 aRealRect
= xReference
->getRange(aViewParameters
);
99 aRange
.expand(basegfx::B2DRange(aRealRect
.X1
, aRealRect
.Y1
, aRealRect
.X2
, aRealRect
.Y2
));
103 aRealRect
.X1
= aRange
.getMinX();
104 aRealRect
.Y1
= aRange
.getMinY();
105 aRealRect
.X2
= aRange
.getMaxX();
106 aRealRect
.Y2
= aRange
.getMaxY();
108 double nDPI
= 96 * fScalingFactor
;
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));
116 const css::uno::Reference
<css::rendering::XIntegerReadOnlyBitmap
> xIntBmp(xBitmap
, uno::UNO_QUERY_THROW
);
117 rBitmapEx
= vcl::unotools::bitmapExFromXBitmap(xIntBmp
);
122 /** Copy block of image data into the bitmap.
123 Assumes that the Bitmap has been constructed with the desired size.
126 The block of data to copy
128 The number of bytes in a scanline, must >= (width * nBitCount / 8)
130 In case the endianness of pData is wrong, you could reverse colors
132 BitmapEx
CreateFromData(sal_uInt8
const *pData
, sal_Int32 nWidth
, sal_Int32 nHeight
,
133 sal_Int32 nStride
, sal_Int8 nBitCount
,
134 bool bReversColors
, bool bReverseAlpha
)
136 assert(nStride
>= (nWidth
* nBitCount
/ 8));
137 assert(nBitCount
== 1 || nBitCount
== 8 || nBitCount
== 24 || nBitCount
== 32);
139 PixelFormat ePixelFormat
;
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
;
153 BitmapPalette aBiLevelPalette
{ COL_BLACK
, COL_WHITE
};
154 aBmp
= Bitmap(Size(nWidth
, nHeight
), PixelFormat::N8_BPP
, &aBiLevelPalette
);
157 aBmp
= Bitmap(Size(nWidth
, nHeight
), ePixelFormat
);
159 BitmapScopedWriteAccess
pWrite(aBmp
);
160 assert(pWrite
.get());
163 std::optional
<AlphaMask
> pAlphaMask
;
164 BitmapScopedWriteAccess xMaskAcc
;
167 pAlphaMask
.emplace( Size(nWidth
, nHeight
) );
168 xMaskAcc
= *pAlphaMask
;
172 for( tools::Long y
= 0; y
< nHeight
; ++y
)
174 sal_uInt8
const *p
= pData
+ y
* nStride
/ 8;
175 Scanline pScanline
= pWrite
->GetScanline(y
);
176 for (tools::Long x
= 0; x
< nWidth
; ++x
)
178 int bitIndex
= (y
* nStride
+ x
) % 8;
180 pWrite
->SetPixelOnData(pScanline
, x
, BitmapColor((*p
>> bitIndex
) & 1));
186 for( tools::Long y
= 0; y
< nHeight
; ++y
)
188 sal_uInt8
const *p
= pData
+ (y
* nStride
);
189 Scanline pScanline
= pWrite
->GetScanline(y
);
190 for (tools::Long x
= 0; x
< nWidth
; ++x
)
194 col
= BitmapColor( *p
);
195 else if ( bReversColors
)
196 col
= BitmapColor( p
[2], p
[1], p
[0] );
198 col
= BitmapColor( p
[0], p
[1], p
[2] );
199 pWrite
->SetPixelOnData(pScanline
, x
, col
);
204 p
= pData
+ (y
* nStride
) + 3;
205 Scanline pMaskScanLine
= xMaskAcc
->GetScanline(y
);
206 for (tools::Long x
= 0; x
< nWidth
; ++x
)
208 // FIXME this parameter is badly named
209 const sal_uInt8 nValue
= bReverseAlpha
? *p
: 0xff - *p
;
210 xMaskAcc
->SetPixelOnData(pMaskScanLine
, x
, BitmapColor(nValue
));
216 // Avoid further bitmap use with unfinished write access
220 return BitmapEx(aBmp
, *pAlphaMask
);
222 return BitmapEx(aBmp
);
225 /** Copy block of image data into the bitmap.
226 Assumes that the Bitmap has been constructed with the desired size.
228 BitmapEx
CreateFromData( RawBitmap
&& rawBitmap
)
230 auto nBitCount
= rawBitmap
.GetBitCount();
231 assert( nBitCount
== 24 || nBitCount
== 32);
233 auto ePixelFormat
= vcl::PixelFormat::INVALID
;
236 ePixelFormat
= vcl::PixelFormat::N24_BPP
;
237 else if (nBitCount
== 32)
238 ePixelFormat
= vcl::PixelFormat::N32_BPP
;
240 assert(ePixelFormat
!= vcl::PixelFormat::INVALID
);
242 Bitmap
aBmp(rawBitmap
.maSize
, ePixelFormat
);
244 BitmapScopedWriteAccess
pWrite(aBmp
);
245 assert(pWrite
.get());
248 std::optional
<AlphaMask
> pAlphaMask
;
249 BitmapScopedWriteAccess xMaskAcc
;
252 pAlphaMask
.emplace( rawBitmap
.maSize
);
253 xMaskAcc
= *pAlphaMask
;
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
)
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
)
265 BitmapColor
col(p
[0], p
[1], p
[2]);
266 pWrite
->SetPixelOnData(pScanline
, x
, col
);
271 p
= rawBitmap
.mpData
.get() + (y
* nStride
) + 3;
272 Scanline pMaskScanLine
= xMaskAcc
->GetScanline(y
);
273 for (tools::Long x
= 0; x
< nWidth
; ++x
)
275 xMaskAcc
->SetPixelOnData(pMaskScanLine
, x
, BitmapColor(*p
));
285 return BitmapEx(aBmp
, *pAlphaMask
);
287 return BitmapEx(aBmp
);
290 void fillWithData(sal_uInt8
* pData
, BitmapEx
const& rBitmapEx
)
292 const Bitmap
& aBitmap
= rBitmapEx
.GetBitmap();
293 const AlphaMask
& aAlphaMask
= rBitmapEx
.GetAlphaMask();
294 BitmapScopedReadAccess
aReadAccessBitmap(aBitmap
);
295 BitmapScopedReadAccess
aReadAccessAlpha(aAlphaMask
);
297 assert(!aReadAccessAlpha
|| aReadAccessBitmap
->Height() == aReadAccessAlpha
->Height());
298 assert(!aReadAccessAlpha
|| aReadAccessBitmap
->Width() == aReadAccessAlpha
->Width());
300 sal_uInt8
* p
= pData
;
302 for (tools::Long y
= 0; y
< aReadAccessBitmap
->Height(); ++y
)
304 Scanline dataBitmap
= aReadAccessBitmap
->GetScanline(y
);
305 Scanline dataAlpha
= aReadAccessAlpha
? aReadAccessAlpha
->GetScanline(y
) : nullptr;
307 for (tools::Long x
= 0; x
< aReadAccessBitmap
->Width(); ++x
)
309 BitmapColor aColor
= aReadAccessBitmap
->GetPixelFromData(dataBitmap
, x
);
310 sal_uInt8 aAlpha
= dataAlpha
? aReadAccessAlpha
->GetPixelFromData(dataAlpha
, x
).GetBlue() : 255;
311 *p
++ = aColor
.GetBlue();
312 *p
++ = aColor
.GetGreen();
313 *p
++ = aColor
.GetRed();
320 #if ENABLE_CAIRO_CANVAS
321 BitmapEx
* CreateFromCairoSurface(Size aSize
, cairo_surface_t
* pSurface
)
323 // FIXME: if we could teach VCL/ about cairo handles, life could
324 // be significantly better here perhaps.
326 cairo_surface_t
*pPixels
= cairo_surface_create_similar_image(pSurface
,
327 CAIRO_FORMAT_ARGB32
, aSize
.Width(), aSize
.Height());
328 cairo_t
*pCairo
= cairo_create( pPixels
);
329 if( !pPixels
|| !pCairo
|| cairo_status(pCairo
) != CAIRO_STATUS_SUCCESS
)
332 // suck ourselves from the X server to this buffer so then we can fiddle with
333 // Alpha to turn it into the ultra-lame vcl required format and then push it
334 // all back again later at vast expense [ urgh ]
335 cairo_set_source_surface( pCairo
, pSurface
, 0, 0 );
336 cairo_set_operator( pCairo
, CAIRO_OPERATOR_SOURCE
);
337 cairo_paint( pCairo
);
339 Bitmap
aRGB(aSize
, vcl::PixelFormat::N24_BPP
);
340 ::AlphaMask
aMask( aSize
);
342 BitmapScopedWriteAccess
pRGBWrite(aRGB
);
347 BitmapScopedWriteAccess
pMaskWrite(aMask
);
352 cairo_surface_flush(pPixels
);
353 unsigned char *pSrc
= cairo_image_surface_get_data( pPixels
);
354 unsigned int nStride
= cairo_image_surface_get_stride( pPixels
);
355 #if !ENABLE_WASM_STRIP_PREMULTIPLY
356 vcl::bitmap::lookup_table
const & unpremultiply_table
= vcl::bitmap::get_unpremultiply_table();
358 for( tools::Long y
= 0; y
< aSize
.Height(); y
++ )
360 sal_uInt32
*pPix
= reinterpret_cast<sal_uInt32
*>(pSrc
+ nStride
* y
);
361 for( tools::Long x
= 0; x
< aSize
.Width(); x
++ )
363 #if defined OSL_BIGENDIAN
364 sal_uInt8 nB
= (*pPix
>> 24);
365 sal_uInt8 nG
= (*pPix
>> 16) & 0xff;
366 sal_uInt8 nR
= (*pPix
>> 8) & 0xff;
367 sal_uInt8 nAlpha
= *pPix
& 0xff;
369 sal_uInt8 nAlpha
= (*pPix
>> 24);
370 sal_uInt8 nR
= (*pPix
>> 16) & 0xff;
371 sal_uInt8 nG
= (*pPix
>> 8) & 0xff;
372 sal_uInt8 nB
= *pPix
& 0xff;
374 if( nAlpha
!= 0 && nAlpha
!= 255 )
376 // Cairo uses pre-multiplied alpha - we do not => re-multiply
377 #if ENABLE_WASM_STRIP_PREMULTIPLY
378 nR
= vcl::bitmap::unpremultiply(nR
, nAlpha
);
379 nG
= vcl::bitmap::unpremultiply(nG
, nAlpha
);
380 nB
= vcl::bitmap::unpremultiply(nB
, nAlpha
);
382 nR
= unpremultiply_table
[nAlpha
][nR
];
383 nG
= unpremultiply_table
[nAlpha
][nG
];
384 nB
= unpremultiply_table
[nAlpha
][nB
];
387 pRGBWrite
->SetPixel( y
, x
, BitmapColor( nR
, nG
, nB
) );
388 pMaskWrite
->SetPixelIndex( y
, x
, nAlpha
);
393 // ignore potential errors above. will get caller a
394 // uniformly white bitmap, but not that there would
395 // be error handling in calling code ...
396 ::BitmapEx
*pBitmapEx
= new ::BitmapEx( aRGB
, aMask
);
398 cairo_destroy( pCairo
);
399 cairo_surface_destroy( pPixels
);
404 BitmapEx
CanvasTransformBitmap( const BitmapEx
& rBitmap
,
405 const ::basegfx::B2DHomMatrix
& rTransform
,
406 ::basegfx::B2DRectangle
const & rDestRect
,
407 ::basegfx::B2DHomMatrix
const & rLocalTransform
)
409 const Size
aDestBmpSize( ::basegfx::fround
<tools::Long
>( rDestRect
.getWidth() ),
410 ::basegfx::fround
<tools::Long
>( rDestRect
.getHeight() ) );
412 if( aDestBmpSize
.IsEmpty() )
415 const Size
aBmpSize( rBitmap
.GetSizePixel() );
416 const Bitmap
& aSrcBitmap( rBitmap
.GetBitmap() );
419 // differentiate mask and alpha channel (on-off
420 // vs. multi-level transparency)
421 if( rBitmap
.IsAlpha() )
423 aSrcAlpha
= rBitmap
.GetAlphaMask().GetBitmap();
426 BitmapScopedReadAccess
pReadAccess( aSrcBitmap
);
427 BitmapScopedReadAccess pAlphaReadAccess
;
428 if (rBitmap
.IsAlpha())
429 pAlphaReadAccess
= aSrcAlpha
;
431 if( !pReadAccess
|| (!pAlphaReadAccess
&& rBitmap
.IsAlpha()) )
433 // TODO(E2): Error handling!
434 ENSURE_OR_THROW( false,
435 "transformBitmap(): could not access source bitmap" );
438 // mapping table, to translate pAlphaReadAccess' pixel
439 // values into destination alpha values (needed e.g. for
440 // paletted 1-bit masks).
441 sal_uInt8 aAlphaMap
[256];
443 if( rBitmap
.IsAlpha() )
445 // source already has alpha channel - 1:1 mapping,
446 // i.e. aAlphaMap[0]=0,...,aAlphaMap[255]=255.
448 sal_uInt8
* pCur
=aAlphaMap
;
449 sal_uInt8
* const pEnd
=&aAlphaMap
[256];
453 // else: mapping table is not used
455 Bitmap
aDstBitmap(aDestBmpSize
, aSrcBitmap
.getPixelFormat(), &pReadAccess
->GetPalette());
456 Bitmap
aDstAlpha( AlphaMask( aDestBmpSize
).GetBitmap() );
459 // just to be on the safe side: let the
460 // ScopedAccessors get destructed before
461 // copy-constructing the resulting bitmap. This will
462 // rule out the possibility that cached accessor data
463 // is not yet written back.
464 BitmapScopedWriteAccess
pWriteAccess( aDstBitmap
);
465 BitmapScopedWriteAccess
pAlphaWriteAccess( aDstAlpha
);
468 if( pWriteAccess
.get() != nullptr &&
469 pAlphaWriteAccess
.get() != nullptr &&
470 rTransform
.isInvertible() )
472 // we're doing inverse mapping here, i.e. mapping
473 // points from the destination bitmap back to the
475 ::basegfx::B2DHomMatrix
aTransform( rLocalTransform
);
478 // for the time being, always read as ARGB
479 for( tools::Long y
=0; y
<aDestBmpSize
.Height(); ++y
)
481 // differentiate mask and alpha channel (on-off
482 // vs. multi-level transparency)
483 if( rBitmap
.IsAlpha() )
485 Scanline pScan
= pWriteAccess
->GetScanline( y
);
486 Scanline pScanAlpha
= pAlphaWriteAccess
->GetScanline( y
);
487 // Handling alpha and mask just the same...
488 for( tools::Long x
=0; x
<aDestBmpSize
.Width(); ++x
)
490 ::basegfx::B2DPoint
aPoint(x
,y
);
491 aPoint
*= aTransform
;
493 const tools::Long
nSrcX( ::basegfx::fround
<tools::Long
>( aPoint
.getX() ) );
494 const tools::Long
nSrcY( ::basegfx::fround
<tools::Long
>( aPoint
.getY() ) );
495 if( nSrcX
< 0 || nSrcX
>= aBmpSize
.Width() ||
496 nSrcY
< 0 || nSrcY
>= aBmpSize
.Height() )
498 pAlphaWriteAccess
->SetPixelOnData( pScanAlpha
, x
, BitmapColor(0) );
502 const sal_uInt8 cAlphaIdx
= pAlphaReadAccess
->GetPixelIndex( nSrcY
, nSrcX
);
503 pAlphaWriteAccess
->SetPixelOnData( pScanAlpha
, x
, BitmapColor(aAlphaMap
[ cAlphaIdx
]) );
504 pWriteAccess
->SetPixelOnData( pScan
, x
, pReadAccess
->GetPixel( nSrcY
, nSrcX
) );
510 Scanline pScan
= pWriteAccess
->GetScanline( y
);
511 Scanline pScanAlpha
= pAlphaWriteAccess
->GetScanline( y
);
512 for( tools::Long x
=0; x
<aDestBmpSize
.Width(); ++x
)
514 ::basegfx::B2DPoint
aPoint(x
,y
);
515 aPoint
*= aTransform
;
517 const tools::Long
nSrcX( ::basegfx::fround
<tools::Long
>( aPoint
.getX() ) );
518 const tools::Long
nSrcY( ::basegfx::fround
<tools::Long
>( aPoint
.getY() ) );
519 if( nSrcX
< 0 || nSrcX
>= aBmpSize
.Width() ||
520 nSrcY
< 0 || nSrcY
>= aBmpSize
.Height() )
522 pAlphaWriteAccess
->SetPixelOnData( pScanAlpha
, x
, BitmapColor(0) );
526 pAlphaWriteAccess
->SetPixelOnData( pScanAlpha
, x
, BitmapColor(255) );
527 pWriteAccess
->SetPixelOnData( pScan
, x
, pReadAccess
->GetPixel( nSrcY
,
536 // TODO(E2): Error handling!
537 ENSURE_OR_THROW( false,
538 "transformBitmap(): could not access bitmap" );
542 return BitmapEx(aDstBitmap
, AlphaMask(aDstAlpha
));
545 void DrawAlphaBitmapAndAlphaGradient(BitmapEx
& rBitmapEx
, bool bFixedTransparence
, float fTransparence
, AlphaMask
& rNewMask
)
547 // mix existing and new alpha mask
550 if(rBitmapEx
.IsAlpha())
552 aOldMask
= rBitmapEx
.GetAlphaMask();
557 BitmapScopedWriteAccess
pOld(aOldMask
);
559 assert(pOld
&& "Got no access to old alpha mask (!)");
561 const double fFactor(1.0 / 255.0);
563 if(bFixedTransparence
)
565 const double fOpNew(1.0 - fTransparence
);
567 for(tools::Long
y(0); y
< pOld
->Height(); y
++)
569 Scanline pScanline
= pOld
->GetScanline( y
);
570 for(tools::Long
x(0); x
< pOld
->Width(); x
++)
572 const double fOpOld(pOld
->GetIndexFromData(pScanline
, x
) * fFactor
);
573 const sal_uInt8
aCol(basegfx::fround((fOpOld
* fOpNew
) * 255.0));
575 pOld
->SetPixelOnData(pScanline
, x
, BitmapColor(aCol
));
581 BitmapScopedReadAccess
pNew(rNewMask
);
583 assert(pNew
&& "Got no access to new alpha mask (!)");
585 assert(pOld
->Width() == pNew
->Width() && pOld
->Height() == pNew
->Height() &&
586 "Alpha masks have different sizes (!)");
588 for(tools::Long
y(0); y
< pOld
->Height(); y
++)
590 Scanline pScanline
= pOld
->GetScanline( y
);
591 for(tools::Long
x(0); x
< pOld
->Width(); x
++)
593 const double fOpOld(pOld
->GetIndexFromData(pScanline
, x
) * fFactor
);
594 const double fOpNew(pNew
->GetIndexFromData(pScanline
, x
) * fFactor
);
595 const sal_uInt8
aCol(basegfx::fround((fOpOld
* fOpNew
) * 255.0));
597 pOld
->SetPixelOnData(pScanline
, x
, BitmapColor(aCol
));
604 // apply combined bitmap as mask
605 rBitmapEx
= BitmapEx(rBitmapEx
.GetBitmap(), aOldMask
);
609 void DrawAndClipBitmap(const Point
& rPos
, const Size
& rSize
, const BitmapEx
& rBitmap
, BitmapEx
& aBmpEx
, basegfx::B2DPolyPolygon
const & rClipPath
)
611 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
612 MapMode
aMapMode( MapUnit::Map100thMM
);
613 aMapMode
.SetOrigin( Point( -rPos
.X(), -rPos
.Y() ) );
614 const Size
aOutputSizePixel( pVDev
->LogicToPixel( rSize
, aMapMode
) );
615 const Size
aSizePixel( rBitmap
.GetSizePixel() );
616 if ( aOutputSizePixel
.Width() && aOutputSizePixel
.Height() )
618 aMapMode
.SetScaleX( Fraction( aSizePixel
.Width(), aOutputSizePixel
.Width() ) );
619 aMapMode
.SetScaleY( Fraction( aSizePixel
.Height(), aOutputSizePixel
.Height() ) );
621 pVDev
->SetMapMode( aMapMode
);
622 pVDev
->SetOutputSizePixel( aSizePixel
);
623 pVDev
->SetFillColor( COL_BLACK
);
624 const tools::PolyPolygon
aClip( rClipPath
);
625 pVDev
->DrawPolyPolygon( aClip
);
627 // #i50672# Extract whole VDev content (to match size of rBitmap)
628 pVDev
->EnableMapMode( false );
629 const Bitmap
aVDevMask(pVDev
->GetBitmap(Point(), aSizePixel
));
633 // bitmap already uses a Mask or Alpha, we need to blend that with
634 // the new masking in pVDev.
635 // need to blend in AlphaMask quality (8Bit)
636 AlphaMask
fromVDev(aVDevMask
);
637 AlphaMask
fromBmpEx(aBmpEx
.GetAlphaMask());
638 BitmapScopedReadAccess
pR(fromVDev
);
639 BitmapScopedWriteAccess
pW(fromBmpEx
);
643 const tools::Long
nWidth(std::min(pR
->Width(), pW
->Width()));
644 const tools::Long
nHeight(std::min(pR
->Height(), pW
->Height()));
646 for(tools::Long
nY(0); nY
< nHeight
; nY
++)
648 Scanline pScanlineR
= pR
->GetScanline( nY
);
649 Scanline pScanlineW
= pW
->GetScanline( nY
);
650 for(tools::Long
nX(0); nX
< nWidth
; nX
++)
652 const sal_uInt8
nIndR(pR
->GetIndexFromData(pScanlineR
, nX
));
653 const sal_uInt8
nIndW(pW
->GetIndexFromData(pScanlineW
, nX
));
655 // these values represent alpha (255 == no, 0 == fully transparent),
656 // so to blend these we have to multiply
657 const sal_uInt8
nCombined((nIndR
* nIndW
) >> 8);
659 pW
->SetPixelOnData(pScanlineW
, nX
, BitmapColor(nCombined
));
666 aBmpEx
= BitmapEx(aBmpEx
.GetBitmap(), fromBmpEx
);
670 // no mask yet, create and add new mask. For better quality, use Alpha,
671 // this allows the drawn mask being processed with AntiAliasing (AAed)
672 aBmpEx
= BitmapEx(rBitmap
.GetBitmap(), aVDevMask
);
676 css::uno::Sequence
< sal_Int8
> GetMaskDIB(BitmapEx
const & aBmpEx
)
678 if ( aBmpEx
.IsAlpha() )
681 WriteDIB(aBmpEx
.GetAlphaMask().GetBitmap(), aMem
, false, true);
682 return css::uno::Sequence
< sal_Int8
>( static_cast<sal_Int8
const *>(aMem
.GetData()), aMem
.Tell() );
685 return css::uno::Sequence
< sal_Int8
>();
688 static bool readAlpha( BitmapReadAccess
const * pAlphaReadAcc
, tools::Long nY
, const tools::Long nWidth
, unsigned char* data
, tools::Long nOff
)
690 bool bIsAlpha
= false;
697 switch( pAlphaReadAcc
->GetScanlineFormat() )
699 case ScanlineFormat::N8BitPal
:
700 pReadScan
= pAlphaReadAcc
->GetScanline( nY
);
701 for( nX
= 0; nX
< nWidth
; nX
++ )
703 BitmapColor
const& rColor(
704 pAlphaReadAcc
->GetPaletteColor(*pReadScan
));
706 nAlpha
= data
[ nOff
] = rColor
.GetIndex();
713 SAL_INFO( "canvas.cairo", "fallback to GetColor for alpha - slow, format: " << static_cast<int>(pAlphaReadAcc
->GetScanlineFormat()) );
714 for( nX
= 0; nX
< nWidth
; nX
++ )
716 nAlpha
= data
[ nOff
] = pAlphaReadAcc
->GetColor( nY
, nX
).GetIndex();
729 * @param data will be filled with alpha data, if xBitmap is alpha/transparent image
730 * @param bHasAlpha will be set to true if resulting surface has alpha
732 void CanvasCairoExtractBitmapData( BitmapEx
const & aBmpEx
, Bitmap
& aBitmap
, unsigned char*& data
, bool& bHasAlpha
, tools::Long
& rnWidth
, tools::Long
& rnHeight
)
734 const AlphaMask
& aAlpha
= aBmpEx
.GetAlphaMask();
736 BitmapScopedReadAccess
pBitmapReadAcc( aBitmap
);
737 BitmapScopedReadAccess pAlphaReadAcc
;
738 const tools::Long nWidth
= rnWidth
= pBitmapReadAcc
->Width();
739 const tools::Long nHeight
= rnHeight
= pBitmapReadAcc
->Height();
741 bool bIsAlpha
= false;
743 if( aBmpEx
.IsAlpha() )
744 pAlphaReadAcc
= aAlpha
;
746 data
= static_cast<unsigned char*>(malloc( nWidth
*nHeight
*4 ));
748 tools::Long nOff
= 0;
750 unsigned int nAlpha
= 255;
752 #if !ENABLE_WASM_STRIP_PREMULTIPLY
753 vcl::bitmap::lookup_table
const & premultiply_table
= vcl::bitmap::get_premultiply_table();
755 for( nY
= 0; nY
< nHeight
; nY
++ )
757 ::Scanline pReadScan
;
759 switch( pBitmapReadAcc
->GetScanlineFormat() )
761 case ScanlineFormat::N8BitPal
:
762 pReadScan
= pBitmapReadAcc
->GetScanline( nY
);
764 if( readAlpha( pAlphaReadAcc
.get(), nY
, nWidth
, data
, nOff
) )
767 for( nX
= 0; nX
< nWidth
; nX
++ )
771 nAlpha
= data
[ nOff
++ ];
773 nAlpha
= data
[ nOff
++ ] = 255;
776 nAlpha
= data
[ nOff
+ 3 ];
778 nAlpha
= data
[ nOff
+ 3 ] = 255;
780 aColor
= pBitmapReadAcc
->GetPaletteColor(*pReadScan
++);
783 #if ENABLE_WASM_STRIP_PREMULTIPLY
784 data
[ nOff
++ ] = vcl::bitmap::premultiply(aColor
.GetRed(), nAlpha
);
785 data
[ nOff
++ ] = vcl::bitmap::premultiply(aColor
.GetGreen(), nAlpha
);
786 data
[ nOff
++ ] = vcl::bitmap::premultiply(aColor
.GetBlue(), nAlpha
);
788 data
[ nOff
++ ] = premultiply_table
[nAlpha
][aColor
.GetRed()];
789 data
[ nOff
++ ] = premultiply_table
[nAlpha
][aColor
.GetGreen()];
790 data
[ nOff
++ ] = premultiply_table
[nAlpha
][aColor
.GetBlue()];
793 #if ENABLE_WASM_STRIP_PREMULTIPLY
794 data
[ nOff
++ ] = vcl::bitmap::premultiply(aColor
.GetBlue(), nAlpha
);
795 data
[ nOff
++ ] = vcl::bitmap::premultiply(aColor
.GetGreen(), nAlpha
);
796 data
[ nOff
++ ] = vcl::bitmap::premultiply(aColor
.GetRed(), nAlpha
);
798 data
[ nOff
++ ] = premultiply_table
[nAlpha
][aColor
.GetBlue()];
799 data
[ nOff
++ ] = premultiply_table
[nAlpha
][aColor
.GetGreen()];
800 data
[ nOff
++ ] = premultiply_table
[nAlpha
][aColor
.GetRed()];
806 case ScanlineFormat::N24BitTcBgr
:
807 pReadScan
= pBitmapReadAcc
->GetScanline( nY
);
809 if( readAlpha( pAlphaReadAcc
.get(), nY
, nWidth
, data
, nOff
) )
812 for( nX
= 0; nX
< nWidth
; nX
++ )
816 nAlpha
= data
[ nOff
];
818 nAlpha
= data
[ nOff
] = 255;
819 #if ENABLE_WASM_STRIP_PREMULTIPLY
820 data
[ nOff
+ 3 ] = vcl::bitmap::premultiply(*pReadScan
++, nAlpha
);
821 data
[ nOff
+ 2 ] = vcl::bitmap::premultiply(*pReadScan
++, nAlpha
);
822 data
[ nOff
+ 1 ] = vcl::bitmap::premultiply(*pReadScan
++, nAlpha
);
824 data
[ nOff
+ 3 ] = premultiply_table
[nAlpha
][*pReadScan
++];
825 data
[ nOff
+ 2 ] = premultiply_table
[nAlpha
][*pReadScan
++];
826 data
[ nOff
+ 1 ] = premultiply_table
[nAlpha
][*pReadScan
++];
831 nAlpha
= data
[ nOff
+ 3 ];
833 nAlpha
= data
[ nOff
+ 3 ] = 255;
834 #if ENABLE_WASM_STRIP_PREMULTIPLY
835 data
[ nOff
++ ] = vcl::bitmap::premultiply(*pReadScan
++, nAlpha
);
836 data
[ nOff
++ ] = vcl::bitmap::premultiply(*pReadScan
++, nAlpha
);
837 data
[ nOff
++ ] = vcl::bitmap::premultiply(*pReadScan
++, nAlpha
);
839 data
[ nOff
++ ] = premultiply_table
[nAlpha
][*pReadScan
++];
840 data
[ nOff
++ ] = premultiply_table
[nAlpha
][*pReadScan
++];
841 data
[ nOff
++ ] = premultiply_table
[nAlpha
][*pReadScan
++];
847 case ScanlineFormat::N24BitTcRgb
:
848 pReadScan
= pBitmapReadAcc
->GetScanline( nY
);
850 if( readAlpha( pAlphaReadAcc
.get(), nY
, nWidth
, data
, nOff
) )
853 for( nX
= 0; nX
< nWidth
; nX
++ )
857 nAlpha
= data
[ nOff
++ ];
859 nAlpha
= data
[ nOff
++ ] = 255;
860 #if ENABLE_WASM_STRIP_PREMULTIPLY
861 data
[ nOff
++ ] = vcl::bitmap::premultiply(*pReadScan
++, nAlpha
);
862 data
[ nOff
++ ] = vcl::bitmap::premultiply(*pReadScan
++, nAlpha
);
863 data
[ nOff
++ ] = vcl::bitmap::premultiply(*pReadScan
++, nAlpha
);
865 data
[ nOff
++ ] = premultiply_table
[nAlpha
][*pReadScan
++];
866 data
[ nOff
++ ] = premultiply_table
[nAlpha
][*pReadScan
++];
867 data
[ nOff
++ ] = premultiply_table
[nAlpha
][*pReadScan
++];
871 nAlpha
= data
[ nOff
+ 3 ];
873 nAlpha
= data
[ nOff
+ 3 ] = 255;
874 #if ENABLE_WASM_STRIP_PREMULTIPLY
875 data
[ nOff
++ ] = vcl::bitmap::premultiply(pReadScan
[ 2 ], nAlpha
);
876 data
[ nOff
++ ] = vcl::bitmap::premultiply(pReadScan
[ 1 ], nAlpha
);
877 data
[ nOff
++ ] = vcl::bitmap::premultiply(pReadScan
[ 0 ], nAlpha
);
879 data
[ nOff
++ ] = premultiply_table
[nAlpha
][pReadScan
[ 2 ]];
880 data
[ nOff
++ ] = premultiply_table
[nAlpha
][pReadScan
[ 1 ]];
881 data
[ nOff
++ ] = premultiply_table
[nAlpha
][pReadScan
[ 0 ]];
888 case ScanlineFormat::N32BitTcBgra
:
889 pReadScan
= pBitmapReadAcc
->GetScanline( nY
);
891 if( readAlpha( pAlphaReadAcc
.get(), nY
, nWidth
, data
, nOff
) )
894 for( nX
= 0; nX
< nWidth
; nX
++ )
898 nAlpha
= data
[ nOff
++ ];
900 nAlpha
= data
[ nOff
++ ] = 255;
901 #if ENABLE_WASM_STRIP_PREMULTIPLY
902 data
[ nOff
++ ] = vcl::bitmap::premultiply(pReadScan
[ 2 ], nAlpha
);
903 data
[ nOff
++ ] = vcl::bitmap::premultiply(pReadScan
[ 1 ], nAlpha
);
904 data
[ nOff
++ ] = vcl::bitmap::premultiply(pReadScan
[ 0 ], nAlpha
);
906 data
[ nOff
++ ] = premultiply_table
[nAlpha
][pReadScan
[ 2 ]];
907 data
[ nOff
++ ] = premultiply_table
[nAlpha
][pReadScan
[ 1 ]];
908 data
[ nOff
++ ] = premultiply_table
[nAlpha
][pReadScan
[ 0 ]];
913 nAlpha
= data
[ nOff
+ 3 ];
915 nAlpha
= data
[ nOff
+ 3 ] = 255;
916 #if ENABLE_WASM_STRIP_PREMULTIPLY
917 data
[ nOff
++ ] = vcl::bitmap::premultiply(*pReadScan
++, nAlpha
);
918 data
[ nOff
++ ] = vcl::bitmap::premultiply(*pReadScan
++, nAlpha
);
919 data
[ nOff
++ ] = vcl::bitmap::premultiply(*pReadScan
++, nAlpha
);
921 data
[ nOff
++ ] = premultiply_table
[nAlpha
][*pReadScan
++];
922 data
[ nOff
++ ] = premultiply_table
[nAlpha
][*pReadScan
++];
923 data
[ nOff
++ ] = premultiply_table
[nAlpha
][*pReadScan
++];
930 case ScanlineFormat::N32BitTcRgba
:
931 pReadScan
= pBitmapReadAcc
->GetScanline( nY
);
933 if( readAlpha( pAlphaReadAcc
.get(), nY
, nWidth
, data
, nOff
) )
936 for( nX
= 0; nX
< nWidth
; nX
++ )
940 nAlpha
= data
[ nOff
++ ];
942 nAlpha
= data
[ nOff
++ ] = 255;
943 #if ENABLE_WASM_STRIP_PREMULTIPLY
944 data
[ nOff
++ ] = vcl::bitmap::premultiply(*pReadScan
++, nAlpha
);
945 data
[ nOff
++ ] = vcl::bitmap::premultiply(*pReadScan
++, nAlpha
);
946 data
[ nOff
++ ] = vcl::bitmap::premultiply(*pReadScan
++, nAlpha
);
948 data
[ nOff
++ ] = premultiply_table
[nAlpha
][*pReadScan
++];
949 data
[ nOff
++ ] = premultiply_table
[nAlpha
][*pReadScan
++];
950 data
[ nOff
++ ] = premultiply_table
[nAlpha
][*pReadScan
++];
955 nAlpha
= data
[ nOff
+ 3 ];
957 nAlpha
= data
[ nOff
+ 3 ] = 255;
958 #if ENABLE_WASM_STRIP_PREMULTIPLY
959 data
[ nOff
++ ] = vcl::bitmap::premultiply(pReadScan
[ 2 ], nAlpha
);
960 data
[ nOff
++ ] = vcl::bitmap::premultiply(pReadScan
[ 1 ], nAlpha
);
961 data
[ nOff
++ ] = vcl::bitmap::premultiply(pReadScan
[ 0 ], nAlpha
);
963 data
[ nOff
++ ] = premultiply_table
[nAlpha
][pReadScan
[ 2 ]];
964 data
[ nOff
++ ] = premultiply_table
[nAlpha
][pReadScan
[ 1 ]];
965 data
[ nOff
++ ] = premultiply_table
[nAlpha
][pReadScan
[ 0 ]];
973 SAL_INFO( "canvas.cairo", "fallback to GetColor - slow, format: " << static_cast<int>(pBitmapReadAcc
->GetScanlineFormat()) );
976 if( readAlpha( pAlphaReadAcc
.get(), nY
, nWidth
, data
, nOff
) )
979 for( nX
= 0; nX
< nWidth
; nX
++ )
981 aColor
= pBitmapReadAcc
->GetColor( nY
, nX
);
983 // cairo need premultiplied color values
984 // TODO(rodo) handle endianness
987 nAlpha
= data
[ nOff
++ ];
989 nAlpha
= data
[ nOff
++ ] = 255;
990 #if ENABLE_WASM_STRIP_PREMULTIPLY
991 data
[ nOff
++ ] = vcl::bitmap::premultiply(aColor
.GetRed(), nAlpha
);
992 data
[ nOff
++ ] = vcl::bitmap::premultiply(aColor
.GetGreen(), nAlpha
);
993 data
[ nOff
++ ] = vcl::bitmap::premultiply(aColor
.GetBlue(), nAlpha
);
995 data
[ nOff
++ ] = premultiply_table
[nAlpha
][aColor
.GetRed()];
996 data
[ nOff
++ ] = premultiply_table
[nAlpha
][aColor
.GetGreen()];
997 data
[ nOff
++ ] = premultiply_table
[nAlpha
][aColor
.GetBlue()];
1001 nAlpha
= data
[ nOff
+ 3 ];
1003 nAlpha
= data
[ nOff
+ 3 ] = 255;
1004 #if ENABLE_WASM_STRIP_PREMULTIPLY
1005 data
[ nOff
++ ] = vcl::bitmap::premultiply(aColor
.GetBlue(), nAlpha
);
1006 data
[ nOff
++ ] = vcl::bitmap::premultiply(aColor
.GetGreen(), nAlpha
);
1007 data
[ nOff
++ ] = vcl::bitmap::premultiply(aColor
.GetRed(), nAlpha
);
1009 data
[ nOff
++ ] = premultiply_table
[nAlpha
][aColor
.GetBlue()];
1010 data
[ nOff
++ ] = premultiply_table
[nAlpha
][aColor
.GetGreen()];
1011 data
[ nOff
++ ] = premultiply_table
[nAlpha
][aColor
.GetRed()];
1019 bHasAlpha
= bIsAlpha
;
1023 uno::Sequence
< sal_Int8
> CanvasExtractBitmapData(BitmapEx
const & rBitmapEx
, const geometry::IntegerRectangle2D
& rect
)
1025 const Bitmap
& aBitmap( rBitmapEx
.GetBitmap() );
1026 Bitmap
aAlpha( rBitmapEx
.GetAlphaMask().GetBitmap() );
1028 BitmapScopedReadAccess
pReadAccess( aBitmap
);
1029 BitmapScopedReadAccess pAlphaReadAccess
;
1030 if (!aAlpha
.IsEmpty())
1031 pAlphaReadAccess
= aAlpha
;
1033 assert( pReadAccess
);
1035 // TODO(F1): Support more formats.
1036 const Size
aBmpSize( aBitmap
.GetSizePixel() );
1038 // for the time being, always return as BGRA
1039 uno::Sequence
< sal_Int8
> aRes( 4*aBmpSize
.Width()*aBmpSize
.Height() );
1040 sal_Int8
* pRes
= aRes
.getArray();
1043 for( tools::Long y
=rect
.Y1
;
1044 y
<aBmpSize
.Height() && y
<rect
.Y2
;
1047 if( pAlphaReadAccess
.get() != nullptr )
1049 Scanline pScanlineReadAlpha
= pAlphaReadAccess
->GetScanline( y
);
1050 for( tools::Long x
=rect
.X1
;
1051 x
<aBmpSize
.Width() && x
<rect
.X2
;
1054 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetRed();
1055 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetGreen();
1056 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetBlue();
1057 pRes
[ nCurrPos
++ ] = 255 - pAlphaReadAccess
->GetIndexFromData( pScanlineReadAlpha
, x
);
1062 for( tools::Long x
=rect
.X1
;
1063 x
<aBmpSize
.Width() && x
<rect
.X2
;
1066 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetRed();
1067 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetGreen();
1068 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetBlue();
1069 pRes
[ nCurrPos
++ ] = sal_uInt8(255);
1076 BitmapEx
createHistorical8x8FromArray(std::array
<sal_uInt8
,64> const & pArray
, Color aColorPix
, Color aColorBack
)
1078 BitmapPalette
aPalette(2);
1080 aPalette
[0] = BitmapColor(aColorBack
);
1081 aPalette
[1] = BitmapColor(aColorPix
);
1083 Bitmap
aBitmap(Size(8, 8), vcl::PixelFormat::N8_BPP
, &aPalette
);
1084 BitmapScopedWriteAccess
pContent(aBitmap
);
1086 for(sal_uInt16
a(0); a
< 8; a
++)
1088 for(sal_uInt16
b(0); b
< 8; b
++)
1090 if(pArray
[(a
* 8) + b
])
1092 pContent
->SetPixelIndex(a
, b
, 1);
1096 pContent
->SetPixelIndex(a
, b
, 0);
1101 return BitmapEx(aBitmap
);
1104 bool isHistorical8x8(const BitmapEx
& rBitmapEx
, Color
& o_rBack
, Color
& o_rFront
)
1108 if(!rBitmapEx
.IsAlpha())
1110 const Bitmap
& aBitmap(rBitmapEx
.GetBitmap());
1112 if(8 == aBitmap
.GetSizePixel().Width() && 8 == aBitmap
.GetSizePixel().Height())
1114 // Historical 1bpp images are getting really historical,
1115 // even to the point that e.g. the png loader actually loads
1116 // them as RGB. But the pattern code in svx relies on this
1117 // assumption that any 2-color 1bpp bitmap is a pattern, and so it would
1118 // get confused by RGB. Try to detect if this image is really
1119 // just two colors and say it's a pattern bitmap if so.
1120 BitmapScopedReadAccess
access(aBitmap
);
1121 o_rBack
= access
->GetColor(0,0);
1122 bool foundSecondColor
= false;;
1123 for(tools::Long y
= 0; y
< access
->Height(); ++y
)
1124 for(tools::Long x
= 0; x
< access
->Width(); ++x
)
1126 if(!foundSecondColor
)
1128 if( access
->GetColor(y
,x
) != o_rBack
)
1130 o_rFront
= access
->GetColor(y
,x
);
1131 foundSecondColor
= true;
1132 // Hard to know which of the two colors is the background,
1133 // select the lighter one.
1134 if( o_rFront
.GetLuminance() > o_rBack
.GetLuminance())
1135 std::swap( o_rFront
, o_rBack
);
1140 if( access
->GetColor(y
,x
) != o_rBack
&& access
->GetColor(y
,x
) != o_rFront
)
1151 #if ENABLE_WASM_STRIP_PREMULTIPLY
1152 sal_uInt8
unpremultiply(sal_uInt8 c
, sal_uInt8 a
)
1154 return (a
== 0) ? 0 : (c
* 255 + a
/ 2) / a
;
1157 sal_uInt8
premultiply(sal_uInt8 c
, sal_uInt8 a
)
1159 return (c
* a
+ 127) / 255;
1162 sal_uInt8
unpremultiply(sal_uInt8 c
, sal_uInt8 a
)
1164 return get_unpremultiply_table()[a
][c
];
1167 static constexpr sal_uInt8
unpremultiplyImpl(sal_uInt8 c
, sal_uInt8 a
)
1169 return (a
== 0) ? 0 : (c
* 255 + a
/ 2) / a
;
1172 sal_uInt8
premultiply(sal_uInt8 c
, sal_uInt8 a
)
1174 return get_premultiply_table()[a
][c
];
1177 static constexpr sal_uInt8
premultiplyImpl(sal_uInt8 c
, sal_uInt8 a
)
1179 return (c
* a
+ 127) / 255;
1182 template<int... Is
> static constexpr std::array
<sal_uInt8
, 256> make_unpremultiply_table_row_(
1183 int a
, std::integer_sequence
<int, Is
...>)
1185 return {unpremultiplyImpl(Is
, a
)...};
1188 template<int... Is
> static constexpr lookup_table
make_unpremultiply_table_(
1189 std::integer_sequence
<int, Is
...>)
1191 return {make_unpremultiply_table_row_(Is
, std::make_integer_sequence
<int, 256>{})...};
1194 lookup_table
const & get_unpremultiply_table()
1196 static constexpr auto unpremultiply_table
= make_unpremultiply_table_(
1197 std::make_integer_sequence
<int, 256>{});
1198 return unpremultiply_table
;
1201 template<int... Is
> static constexpr std::array
<sal_uInt8
, 256> make_premultiply_table_row_(
1202 int a
, std::integer_sequence
<int, Is
...>)
1204 return {premultiplyImpl(Is
, a
)...};
1207 template<int... Is
> static constexpr lookup_table
make_premultiply_table_(
1208 std::integer_sequence
<int, Is
...>)
1210 return {make_premultiply_table_row_(Is
, std::make_integer_sequence
<int, 256>{})...};
1213 lookup_table
const & get_premultiply_table()
1215 static constexpr auto premultiply_table
= make_premultiply_table_(
1216 std::make_integer_sequence
<int, 256>{});
1217 return premultiply_table
;
1221 bool convertBitmap32To24Plus8(BitmapEx
const & rInput
, BitmapEx
& rResult
)
1223 const Bitmap
& aBitmap(rInput
.GetBitmap());
1224 if (aBitmap
.getPixelFormat() != vcl::PixelFormat::N32_BPP
)
1227 Size aSize
= aBitmap
.GetSizePixel();
1228 Bitmap
aResultBitmap(aSize
, vcl::PixelFormat::N24_BPP
);
1229 AlphaMask
aResultAlpha(aSize
);
1231 BitmapScopedWriteAccess
pResultBitmapAccess(aResultBitmap
);
1232 BitmapScopedWriteAccess
pResultAlphaAccess(aResultAlpha
);
1234 BitmapScopedReadAccess
pReadAccess(aBitmap
);
1236 for (tools::Long nY
= 0; nY
< aSize
.Height(); ++nY
)
1238 Scanline aResultScan
= pResultBitmapAccess
->GetScanline(nY
);
1239 Scanline aResultScanAlpha
= pResultAlphaAccess
->GetScanline(nY
);
1241 Scanline aReadScan
= pReadAccess
->GetScanline(nY
);
1243 for (tools::Long nX
= 0; nX
< aSize
.Width(); ++nX
)
1245 const BitmapColor aColor
= pReadAccess
->GetPixelFromData(aReadScan
, nX
);
1246 BitmapColor
aResultColor(aColor
.GetRed(), aColor
.GetGreen(), aColor
.GetBlue());
1247 BitmapColor
aResultColorAlpha(aColor
.GetAlpha(), aColor
.GetAlpha(), aColor
.GetAlpha());
1249 pResultBitmapAccess
->SetPixelOnData(aResultScan
, nX
, aResultColor
);
1250 pResultAlphaAccess
->SetPixelOnData(aResultScanAlpha
, nX
, aResultColorAlpha
);
1254 if (rInput
.IsAlpha())
1255 rResult
= BitmapEx(aResultBitmap
, rInput
.GetAlphaMask());
1257 rResult
= BitmapEx(aResultBitmap
, aResultAlpha
);
1261 Bitmap
GetDownsampledBitmap(Size
const& rDstSizeTwip
, Point
const& rSrcPt
, Size
const& rSrcSz
,
1262 Bitmap
const& rBmp
, tools::Long nMaxBmpDPIX
, tools::Long nMaxBmpDPIY
)
1266 if (!aBmp
.IsEmpty())
1268 const tools::Rectangle
aBmpRect( Point(), aBmp
.GetSizePixel() );
1269 tools::Rectangle
aSrcRect( rSrcPt
, rSrcSz
);
1271 // do cropping if necessary
1272 if( aSrcRect
.Intersection( aBmpRect
) != aBmpRect
)
1274 if( !aSrcRect
.IsEmpty() )
1275 aBmp
.Crop( aSrcRect
);
1280 if( !aBmp
.IsEmpty() )
1282 // do downsampling if necessary
1283 // #103209# Normalize size (mirroring has to happen outside of this method)
1284 Size
aDstSizeTwip(std::abs(rDstSizeTwip
.Width()), std::abs(rDstSizeTwip
.Height()));
1286 const Size
aBmpSize( aBmp
.GetSizePixel() );
1287 const double fBmpPixelX
= aBmpSize
.Width();
1288 const double fBmpPixelY
= aBmpSize
.Height();
1289 const double fMaxPixelX
1290 = o3tl::convert
<double>(aDstSizeTwip
.Width(), o3tl::Length::twip
, o3tl::Length::in
)
1292 const double fMaxPixelY
1293 = o3tl::convert
<double>(aDstSizeTwip
.Height(), o3tl::Length::twip
, o3tl::Length::in
)
1296 // check, if the bitmap DPI exceeds the maximum DPI (allow 4 pixel rounding tolerance)
1297 if (((fBmpPixelX
> (fMaxPixelX
+ 4)) ||
1298 (fBmpPixelY
> (fMaxPixelY
+ 4))) &&
1299 (fBmpPixelY
> 0.0) && (fMaxPixelY
> 0.0))
1303 const double fBmpWH
= fBmpPixelX
/ fBmpPixelY
;
1304 const double fMaxWH
= fMaxPixelX
/ fMaxPixelY
;
1306 if (fBmpWH
< fMaxWH
)
1308 aNewBmpSize
.setWidth(basegfx::fround
<tools::Long
>(fMaxPixelY
* fBmpWH
));
1309 aNewBmpSize
.setHeight(basegfx::fround
<tools::Long
>(fMaxPixelY
));
1311 else if (fBmpWH
> 0.0)
1313 aNewBmpSize
.setWidth(basegfx::fround
<tools::Long
>(fMaxPixelX
));
1314 aNewBmpSize
.setHeight(basegfx::fround
<tools::Long
>(fMaxPixelX
/ fBmpWH
));
1317 if( aNewBmpSize
.Width() && aNewBmpSize
.Height() )
1318 aBmp
.Scale(aNewBmpSize
);
1328 BitmapColor
premultiply(const BitmapColor c
)
1330 return BitmapColor(ColorAlpha
, premultiply(c
.GetRed(), c
.GetAlpha()),
1331 premultiply(c
.GetGreen(), c
.GetAlpha()),
1332 premultiply(c
.GetBlue(), c
.GetAlpha()), c
.GetAlpha());
1335 BitmapColor
unpremultiply(const BitmapColor c
)
1337 return BitmapColor(ColorAlpha
, unpremultiply(c
.GetRed(), c
.GetAlpha()),
1338 unpremultiply(c
.GetGreen(), c
.GetAlpha()),
1339 unpremultiply(c
.GetBlue(), c
.GetAlpha()), c
.GetAlpha());
1342 } // end vcl::bitmap
1344 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */