Merge branch 'devel/master' into tizen
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / common / alpha-mask.cpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <dali/internal/imaging/common/alpha-mask.h>
18 #include <dali/internal/imaging/common/image-operations.h>
19 #include <dali/internal/imaging/common/pixel-buffer-impl.h>
20 #include <dali/internal/imaging/common/pixel-manipulation.h>
21 #include <dali/public-api/images/image-operations.h> // For ImageDimensions and MultiplyAndNormalizeColor
22
23 namespace Dali
24 {
25 namespace Internal
26 {
27 namespace Adaptor
28 {
29 void ApplyMaskToAlphaChannel(PixelBuffer& buffer, const PixelBuffer& mask)
30 {
31   int                 srcAlphaByteOffset = 0;
32   int                 srcAlphaMask       = 0;
33   Dali::Pixel::Format srcPixelFormat     = mask.GetPixelFormat();
34
35   if(Pixel::HasAlpha(srcPixelFormat))
36   {
37     Dali::Pixel::GetAlphaOffsetAndMask(srcPixelFormat, srcAlphaByteOffset, srcAlphaMask);
38   }
39   else if(srcPixelFormat == Pixel::L8)
40   {
41     srcAlphaMask = 0xFF;
42   }
43
44   int                 destAlphaByteOffset = 0;
45   int                 destAlphaMask       = 0;
46   Dali::Pixel::Format destPixelFormat     = buffer.GetPixelFormat();
47   Dali::Pixel::GetAlphaOffsetAndMask(destPixelFormat, destAlphaByteOffset, destAlphaMask);
48
49   unsigned int   srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel(srcPixelFormat);
50   unsigned char* srcBuffer        = mask.GetBuffer();
51   unsigned char* destBuffer       = buffer.GetBuffer();
52
53   unsigned int destBytesPerPixel = Dali::Pixel::GetBytesPerPixel(buffer.GetPixelFormat());
54   unsigned int srcStrideBytes    = mask.GetStride() * srcBytesPerPixel;
55   unsigned int destStrideBytes   = buffer.GetStride() * destBytesPerPixel;
56
57   // if image is premultiplied, the other channels of the image need to multiply by alpha.
58   if(buffer.IsAlphaPreMultiplied())
59   {
60     // Collect all valid channel list before lookup whole buffer
61     std::vector<Channel> validChannelList;
62     for(const Channel& channel : {Adaptor::RED, Adaptor::GREEN, Adaptor::BLUE, Adaptor::LUMINANCE, Adaptor::ALPHA})
63     {
64       if(HasChannel(destPixelFormat, channel))
65       {
66         validChannelList.emplace_back(channel);
67       }
68     }
69     if(DALI_LIKELY(!validChannelList.empty()))
70     {
71       for(unsigned int row = 0; row < buffer.GetHeight(); ++row)
72       {
73         int srcOffset  = 0;
74         int destOffset = 0;
75
76         for(unsigned int col = 0; col < buffer.GetWidth(); ++col)
77         {
78           auto srcAlpha = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
79           if(srcAlpha < 255)
80           {
81             // If alpha is 255, we don't need to change color. Skip current pixel
82             // But if alpha is not 255, we should change color.
83             if(srcAlpha > 0)
84             {
85               for(const Channel& channel : validChannelList)
86               {
87                 auto color = ReadChannel(destBuffer + destOffset, destPixelFormat, channel);
88                 WriteChannel(destBuffer + destOffset, destPixelFormat, channel, Platform::MultiplyAndNormalizeColor(color, srcAlpha));
89               }
90             }
91             else
92             {
93               // If alpha is 0, just set all pixel as zero.
94               memset(destBuffer + destOffset, 0, destBytesPerPixel);
95             }
96           }
97
98           srcOffset += srcBytesPerPixel;
99           destOffset += destBytesPerPixel;
100         }
101         srcBuffer += srcStrideBytes;
102         destBuffer += destStrideBytes;
103       }
104     }
105   }
106   else
107   {
108     for(unsigned int row = 0; row < buffer.GetHeight(); ++row)
109     {
110       int srcOffset  = 0;
111       int destOffset = 0;
112
113       for(unsigned int col = 0; col < buffer.GetWidth(); ++col)
114       {
115         uint8_t srcAlpha  = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
116         uint8_t destAlpha = destBuffer[destOffset + destAlphaByteOffset] & destAlphaMask;
117
118         destAlpha = Platform::MultiplyAndNormalizeColor(srcAlpha, destAlpha);
119
120         destBuffer[destOffset + destAlphaByteOffset] &= ~destAlphaMask;
121         destBuffer[destOffset + destAlphaByteOffset] |= (destAlpha & destAlphaMask);
122
123         srcOffset += srcBytesPerPixel;
124         destOffset += destBytesPerPixel;
125       }
126       srcBuffer += srcStrideBytes;
127       destBuffer += destStrideBytes;
128     }
129   }
130 }
131
132 PixelBufferPtr CreateNewMaskedBuffer(const PixelBuffer& buffer, const PixelBuffer& mask)
133 {
134   // Set up source alpha offsets
135   int                 srcAlphaByteOffset = 0;
136   int                 srcAlphaMask       = 0;
137   Dali::Pixel::Format srcPixelFormat     = mask.GetPixelFormat();
138
139   if(Pixel::HasAlpha(srcPixelFormat))
140   {
141     Dali::Pixel::GetAlphaOffsetAndMask(srcPixelFormat, srcAlphaByteOffset, srcAlphaMask);
142   }
143   else if(srcPixelFormat == Pixel::L8)
144   {
145     srcAlphaMask = 0xFF;
146   }
147
148   unsigned char* srcBuffer        = mask.GetBuffer();
149   unsigned int   srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel(srcPixelFormat);
150   unsigned int   srcStrideBytes   = mask.GetStride() * srcBytesPerPixel;
151
152   // Set up source color offsets
153   Dali::Pixel::Format srcColorPixelFormat   = buffer.GetPixelFormat();
154   unsigned int        srcColorBytesPerPixel = Dali::Pixel::GetBytesPerPixel(srcColorPixelFormat);
155   unsigned int        srcColorStrideBytes   = buffer.GetStride() * srcColorBytesPerPixel;
156
157   // Setup destination offsets
158   Dali::Pixel::Format destPixelFormat     = Dali::Pixel::RGBA8888;
159   unsigned int        destBytesPerPixel   = Dali::Pixel::GetBytesPerPixel(destPixelFormat);
160   int                 destAlphaByteOffset = 0;
161   int                 destAlphaMask       = 0;
162   Dali::Pixel::GetAlphaOffsetAndMask(destPixelFormat, destAlphaByteOffset, destAlphaMask);
163
164   PixelBufferPtr newPixelBuffer  = PixelBuffer::New(buffer.GetWidth(), buffer.GetHeight(), destPixelFormat);
165   unsigned char* destBuffer      = newPixelBuffer->GetBuffer();
166   unsigned char* oldBuffer       = buffer.GetBuffer();
167   unsigned int   destStrideBytes = newPixelBuffer->GetStride() * destBytesPerPixel;
168
169   bool hasAlpha = Dali::Pixel::HasAlpha(buffer.GetPixelFormat());
170
171   unsigned char destAlpha = 0;
172
173   for(unsigned int row = 0; row < buffer.GetHeight(); ++row)
174   {
175     int srcAlphaOffset = 0;
176     int srcColorOffset = 0;
177     int destOffset     = 0;
178     for(unsigned int col = 0; col < buffer.GetWidth(); ++col)
179     {
180       unsigned char srcAlpha = srcBuffer[srcAlphaOffset + srcAlphaByteOffset] & srcAlphaMask;
181
182       ConvertColorChannelsToRGBA8888(oldBuffer, srcColorOffset, srcColorPixelFormat, destBuffer, destOffset);
183
184       if(hasAlpha)
185       {
186         destAlpha = ConvertAlphaChannelToA8(oldBuffer, srcColorOffset, srcColorPixelFormat);
187         destAlpha = Platform::MultiplyAndNormalizeColor(srcAlpha, destAlpha);
188       }
189       else
190       {
191         destAlpha = srcAlpha;
192       }
193
194       destBuffer[destOffset + destAlphaByteOffset] &= ~destAlphaMask;
195       destBuffer[destOffset + destAlphaByteOffset] |= (destAlpha & destAlphaMask);
196
197       srcColorOffset += srcColorBytesPerPixel;
198       srcAlphaOffset += srcBytesPerPixel;
199       destOffset += destBytesPerPixel;
200     }
201     oldBuffer += srcColorStrideBytes;
202     srcBuffer += srcStrideBytes;
203     destBuffer += destStrideBytes;
204   }
205
206   return newPixelBuffer;
207 }
208
209 } //namespace Adaptor
210
211 } // namespace Internal
212
213 } // namespace Dali