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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <tools/color.hxx>
23 #include <vcl/alpha.hxx>
25 #include <vcl/BitmapWriteAccess.hxx>
26 #include <salinst.hxx>
29 #include <sal/log.hxx>
31 #include <vcl/skia/SkiaHelper.hxx>
35 AlphaMask::AlphaMask() = default;
37 AlphaMask::AlphaMask( const Bitmap
& rBitmap
) :
40 if ( !rBitmap
.IsEmpty() )
41 maBitmap
.Convert( BmpConversion::N8BitNoConversion
);
43 // Related tdf#156866 force snapshot of alpha mask when using Skia
44 // In release builds, tdf#156629 and tdf#156630 reappear in many
45 // cases because a BitmapInfoAccess is in a debug block. So, instead
46 // of relying on other code to a create a BitmapInfoAccess instance,
47 // create one here to force the alpha mask to handle any pending
48 // scaling and make the alpha mask immutable.
49 else if ( SkiaHelper::isVCLSkiaEnabled() )
50 BitmapInfoAccess
aInfoAccess( maBitmap
);
52 assert( (IsEmpty() || maBitmap
.getPixelFormat() == vcl::PixelFormat::N8_BPP
) && "alpha bitmap should be 8bpp" );
53 assert( (IsEmpty() || maBitmap
.HasGreyPalette8Bit()) && "alpha bitmap should have greyscale palette" );
56 AlphaMask::AlphaMask( const AlphaMask
& ) = default;
58 AlphaMask::AlphaMask( AlphaMask
&& ) = default;
60 AlphaMask::AlphaMask( const Size
& rSizePixel
, const sal_uInt8
* pEraseTransparency
)
61 : maBitmap(rSizePixel
, vcl::PixelFormat::N8_BPP
, &Bitmap::GetGreyPalette(256))
63 if( pEraseTransparency
)
65 sal_uInt8 nAlpha
= 255 - *pEraseTransparency
;
66 maBitmap
.Erase( Color( nAlpha
, nAlpha
, nAlpha
) );
69 maBitmap
.Erase( COL_ALPHA_OPAQUE
);
72 AlphaMask::~AlphaMask() = default;
74 AlphaMask
& AlphaMask::operator=( const Bitmap
& rBitmap
)
78 if( !rBitmap
.IsEmpty() )
79 maBitmap
.Convert( BmpConversion::N8BitNoConversion
);
81 assert( maBitmap
.getPixelFormat() == vcl::PixelFormat::N8_BPP
&& "alpha bitmap should be 8bpp" );
82 assert( maBitmap
.HasGreyPalette8Bit() && "alpha bitmap should have greyscale palette" );
87 void AlphaMask::Erase( sal_uInt8 cTransparency
)
89 sal_uInt8 nAlpha
= 255 - cTransparency
;
90 maBitmap
.Erase( Color( nAlpha
, nAlpha
, nAlpha
) );
93 void AlphaMask::BlendWith(const AlphaMask
& rOther
)
95 std::shared_ptr
<SalBitmap
> xImpBmp(ImplGetSVData()->mpDefInst
->CreateSalBitmap());
96 if (xImpBmp
->Create(*maBitmap
.ImplGetSalBitmap()) && xImpBmp
->AlphaBlendWith(*rOther
.maBitmap
.ImplGetSalBitmap()))
98 maBitmap
.ImplSetSalBitmap(xImpBmp
);
99 assert( maBitmap
.getPixelFormat() == vcl::PixelFormat::N8_BPP
&& "alpha bitmap should be 8bpp" );
100 assert( maBitmap
.HasGreyPalette8Bit() && "alpha bitmap should have greyscale palette" );
103 BitmapScopedReadAccess
pOtherAcc(rOther
);
104 BitmapScopedWriteAccess
pAcc(*this);
105 assert (pOtherAcc
&& pAcc
&& pOtherAcc
->GetBitCount() == 8 && pAcc
->GetBitCount() == 8 && "cannot BlendWith this combination");
106 if (!(pOtherAcc
&& pAcc
&& pOtherAcc
->GetBitCount() == 8 && pAcc
->GetBitCount() == 8))
108 SAL_WARN("vcl", "cannot BlendWith this combination");
112 const tools::Long nHeight
= std::min(pOtherAcc
->Height(), pAcc
->Height());
113 const tools::Long nWidth
= std::min(pOtherAcc
->Width(), pAcc
->Width());
114 for (tools::Long y
= 0; y
< nHeight
; ++y
)
116 Scanline scanline
= pAcc
->GetScanline( y
);
117 ConstScanline otherScanline
= pOtherAcc
->GetScanline( y
);
118 for (tools::Long x
= 0; x
< nWidth
; ++x
)
120 // Use sal_uInt16 for following multiplication
121 const sal_uInt16 nGrey1
= *scanline
;
122 const sal_uInt16 nGrey2
= *otherScanline
;
123 // Awkward calculation because the original used transparency, and to replicate
124 // the logic we need to translate into transparency, perform the original logic,
125 // then translate back to alpha.
126 // The original looked like:
127 // auto tmp = nGrey1 + nGrey2 - (nGrey1 * nGrey2 / 255)
128 // which, when converted to using alpha looks like
129 // auto tmp = 255 - ((255 - nGrey1) + (255 - nGrey2) - (255 - nGrey1) * (255 - nGrey2) / 255);
130 // which then simplifies to:
131 auto tmp
= nGrey1
* nGrey2
/ 255;
132 *scanline
= static_cast<sal_uInt8
>(tmp
);
138 assert( maBitmap
.getPixelFormat() == vcl::PixelFormat::N8_BPP
&& "alpha bitmap should be 8bpp" );
139 assert( maBitmap
.HasGreyPalette8Bit() && "alpha bitmap should have greyscale palette" );
142 bool AlphaMask::hasAlpha() const
144 // no content, no alpha
148 BitmapScopedReadAccess
pAcc(*this);
149 const tools::Long
nHeight(pAcc
->Height());
150 const tools::Long
nWidth(pAcc
->Width());
152 // no content, no alpha
153 if(0 == nHeight
|| 0 == nWidth
)
156 for (tools::Long y
= 0; y
< nHeight
; ++y
)
158 for (tools::Long x
= 0; x
< nWidth
; ++x
)
160 if (255 != pAcc
->GetColor(y
, x
).GetRed())
170 bool AlphaMask::AlphaCombineOr(const AlphaMask
& rMask
)
172 BitmapScopedReadAccess
pMaskAcc(rMask
);
173 BitmapScopedWriteAccess
pAcc(*this);
175 if (!pMaskAcc
|| !pAcc
)
178 assert (pMaskAcc
->GetBitCount() == 8 && pAcc
->GetBitCount() == 8);
180 const tools::Long nWidth
= std::min(pMaskAcc
->Width(), pAcc
->Width());
181 const tools::Long nHeight
= std::min(pMaskAcc
->Height(), pAcc
->Height());
183 for (tools::Long nY
= 0; nY
< nHeight
; nY
++)
185 Scanline pScanline
= pAcc
->GetScanline(nY
);
186 ConstScanline pScanlineMask
= pMaskAcc
->GetScanline(nY
);
187 for (tools::Long nX
= 0; nX
< nWidth
; nX
++)
189 if (*pScanlineMask
!= 255 || *pScanline
!= 255)
201 bool AlphaMask::Invert()
205 bool b
= maBitmap
.Invert();
206 assert( maBitmap
.getPixelFormat() == vcl::PixelFormat::N8_BPP
&& "alpha bitmap should be 8bpp" );
207 assert( maBitmap
.HasGreyPalette8Bit() && "alpha bitmap should have greyscale palette" );
211 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */