Merge "Implemented basic CPU image masking" into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / event / images / pixel-data-impl.cpp
1 /*
2  * Copyright (c) 2016 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
18 // CLASS HEADER
19 #include <dali/internal/event/images/pixel-data-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <stdlib.h>
23
24 // INTERNAL INCLUDES
25 #include <dali/internal/event/images/pixel-manipulation.h>
26
27 namespace Dali
28 {
29
30 namespace Internal
31 {
32
33 PixelData::PixelData( unsigned char* buffer,
34                       unsigned int bufferSize,
35                       unsigned int width,
36                       unsigned int height,
37                       Dali::Pixel::Format pixelFormat,
38                       Dali::PixelData::ReleaseFunction releaseFunction )
39 : mBuffer( buffer ),
40   mBufferSize( bufferSize ),
41   mWidth( width ),
42   mHeight( height ),
43   mPixelFormat( pixelFormat ),
44   mReleaseFunction( releaseFunction )
45 {
46 }
47
48 PixelData::~PixelData()
49 {
50   if( mBuffer )
51   {
52     ReleaseBuffer();
53   }
54 }
55
56 PixelDataPtr PixelData::New(unsigned char* buffer,
57                             unsigned int bufferSize,
58                             unsigned int width,
59                             unsigned int height,
60                             Dali::Pixel::Format pixelFormat,
61                             Dali::PixelData::ReleaseFunction releaseFunction)
62 {
63   return new PixelData( buffer, bufferSize, width, height, pixelFormat, releaseFunction );
64 }
65
66 unsigned int PixelData::GetWidth() const
67 {
68   return mWidth;
69 }
70
71 unsigned int PixelData::GetHeight() const
72 {
73   return mHeight;
74 }
75
76 Dali::Pixel::Format PixelData::GetPixelFormat() const
77 {
78   return mPixelFormat;
79 }
80
81 unsigned char* PixelData::GetBuffer() const
82 {
83   return mBuffer;
84 }
85
86 unsigned int PixelData::GetBufferSize() const
87 {
88   return mBufferSize;
89 }
90
91 void PixelData::ReleaseBuffer()
92 {
93   if( mReleaseFunction == Dali::PixelData::FREE)
94   {
95     free( mBuffer );
96   }
97   else
98   {
99     delete[] mBuffer;
100   }
101 }
102
103 void PixelData::ApplyMask( const PixelData& mask )
104 {
105   int byteOffset=0;
106   int bitMask=0;
107   Dali::Pixel::GetAlphaOffsetAndMask(mPixelFormat, byteOffset, bitMask);
108
109   if( Dali::Pixel::HasAlpha( mPixelFormat ) && bitMask == 255 )
110   {
111     ApplyMaskToAlphaChannel( mask );
112   }
113   else
114   {
115     AddAlphaChannel(mask);
116   }
117 }
118
119 void PixelData::ApplyMaskToAlphaChannel( const PixelData& mask )
120 {
121   const float rowFactor = float(mask.mHeight) / (1.0f * mHeight);
122   const float colFactor = float(mask.mWidth) / (1.0f * mWidth) ;
123
124   int numSamples = 1;
125   if( mask.mHeight > mHeight || mask.mWidth > mWidth )
126   {
127     numSamples = 4;
128   }
129
130   int srcAlphaByteOffset=0;
131   int srcAlphaMask=0;
132   Dali::Pixel::GetAlphaOffsetAndMask( mask.mPixelFormat, srcAlphaByteOffset, srcAlphaMask );
133
134   int destAlphaByteOffset=0;
135   int destAlphaMask=0;
136   Dali::Pixel::GetAlphaOffsetAndMask( mPixelFormat, destAlphaByteOffset, destAlphaMask );
137
138   unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel( mask.mPixelFormat );
139   unsigned int destBytesPerPixel = Dali::Pixel::GetBytesPerPixel( mPixelFormat );
140   int srcStride = mask.mWidth * srcBytesPerPixel;
141
142   int srcOffset=0;
143   int destOffset=0;
144
145   float srcAlphaValue = 1.0f;
146
147   for( unsigned int row = 0; row < mHeight; ++row )
148   {
149     for( unsigned int col = 0; col < mWidth; ++col )
150     {
151       if( numSamples == 1 )
152       {
153         srcOffset = floorf(row * rowFactor) * srcStride + floorf(col * colFactor) * srcBytesPerPixel;
154         unsigned char alpha = mask.mBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
155         srcAlphaValue = float(alpha)/255.0f;
156       }
157       else
158       {
159         srcAlphaValue = mask.ReadWeightedSample( col*colFactor, row*rowFactor );
160       }
161
162       unsigned char destAlpha = mBuffer[destOffset + destAlphaByteOffset] & destAlphaMask;
163       float destAlphaValue = Clamp(float(destAlpha) * srcAlphaValue, 0.0f, 255.0f);
164       destAlpha = destAlphaValue;
165       mBuffer[destOffset + destAlphaByteOffset] &= ~destAlphaMask;
166       mBuffer[destOffset + destAlphaByteOffset] |= ( destAlpha & destAlphaMask );
167
168       destOffset += destBytesPerPixel;
169     }
170   }
171 }
172
173 void PixelData::AddAlphaChannel( const PixelData& mask )
174 {
175   const float rowFactor = float(mask.mHeight) / (1.0f * mHeight);
176   const float colFactor = float(mask.mWidth) / (1.0f * mWidth) ;
177
178   int numSamples = 1;
179   if( mask.mHeight > mHeight || mask.mWidth > mWidth )
180   {
181     numSamples = 4;
182   }
183
184   // Set up source alpha offsets
185   int srcAlphaByteOffset=0;
186   int srcAlphaMask=0;
187   Dali::Pixel::GetAlphaOffsetAndMask( mask.mPixelFormat, srcAlphaByteOffset, srcAlphaMask );
188
189   unsigned int srcAlphaBytesPerPixel = Dali::Pixel::GetBytesPerPixel( mask.mPixelFormat );
190   int srcAlphaStride = mask.mWidth * srcAlphaBytesPerPixel;
191
192   // Set up source color offsets
193   unsigned int srcColorBytesPerPixel = Dali::Pixel::GetBytesPerPixel( mPixelFormat );
194
195   // Setup destination offsets
196   Dali::Pixel::Format destPixelFormat = Dali::Pixel::RGBA8888;
197   unsigned int destBytesPerPixel = Dali::Pixel::GetBytesPerPixel( destPixelFormat );
198   int destAlphaByteOffset=0;
199   int destAlphaMask=0;
200   Dali::Pixel::GetAlphaOffsetAndMask( destPixelFormat, destAlphaByteOffset, destAlphaMask );
201
202   int destBufferSize = mWidth * mHeight * destBytesPerPixel;
203   unsigned char* destBuffer = static_cast<unsigned char*>( malloc( destBufferSize ) );
204
205   int srcAlphaOffset=0;
206   int srcColorOffset=0;
207   int destOffset=0;
208   bool hasAlpha = Dali::Pixel::HasAlpha(mPixelFormat);
209
210   float srcAlphaValue = 1.0f;
211   unsigned char destAlpha = 0;
212
213   for( unsigned int row = 0; row < mHeight; ++row )
214   {
215     for( unsigned int col = 0; col < mWidth; ++col )
216     {
217       if( numSamples == 1 )
218       {
219         srcAlphaOffset = floorf(row * rowFactor) * srcAlphaStride + floorf(col * colFactor) * srcAlphaBytesPerPixel;
220         unsigned char alpha = mask.mBuffer[srcAlphaOffset + srcAlphaByteOffset] & srcAlphaMask;
221         srcAlphaValue = float(alpha)/255.0f;
222       }
223       else
224       {
225         srcAlphaValue = mask.ReadWeightedSample( col*colFactor, row*rowFactor );
226       }
227
228       Pixel::ConvertColorChannelsToRGBA8888(mBuffer, srcColorOffset, mPixelFormat, destBuffer, destOffset );
229
230       if( hasAlpha )
231       {
232         destAlpha = mBuffer[destOffset + destAlphaByteOffset] & destAlphaMask;
233         float destAlphaValue = Clamp(float(destAlpha) * srcAlphaValue, 0.0f, 255.0f);
234         destAlpha = destAlphaValue;
235       }
236       else
237       {
238         destAlpha = floorf(Clamp(srcAlphaValue * 255.0f, 0.0f, 255.0f));
239       }
240
241       destBuffer[destOffset + destAlphaByteOffset] &= ~destAlphaMask;
242       destBuffer[destOffset + destAlphaByteOffset] |= ( destAlpha & destAlphaMask );
243
244       srcColorOffset += srcColorBytesPerPixel;
245       destOffset += destBytesPerPixel;
246     }
247   }
248
249   ReleaseBuffer();
250
251   mBuffer = destBuffer;
252   mBufferSize = destBufferSize;
253   mPixelFormat = Dali::Pixel::RGBA8888;
254   mReleaseFunction = Dali::PixelData::FREE;
255 }
256
257 float PixelData::ReadWeightedSample( float x, float y ) const
258 {
259   unsigned int srcRow = floorf( y );
260   unsigned int srcCol = floorf( x );
261
262   int bytesPerPixel = Dali::Pixel::GetBytesPerPixel( mPixelFormat );
263   int stride = mWidth * bytesPerPixel;
264   int srcOffset = srcRow * stride + srcCol * bytesPerPixel;
265   float samples[4];
266
267   samples[0] = ReadChannel( mBuffer + srcOffset, mPixelFormat, Pixel::ALPHA );
268
269   if( srcCol < mWidth-1 )
270   {
271     samples[1] = ReadChannel( mBuffer + srcOffset+bytesPerPixel, mPixelFormat, Pixel::ALPHA );
272   }
273   else
274   {
275     samples[1] = samples[0];
276   }
277
278   if( srcRow < mHeight-1 )
279   {
280     samples[2] = ReadChannel( mBuffer + stride + srcOffset, mPixelFormat, Pixel::ALPHA );
281   }
282   else
283   {
284     samples[2] = samples[0];
285   }
286
287   if( srcRow < mHeight-1 && srcCol < mWidth-1 )
288   {
289     samples[3] = ReadChannel( mBuffer + stride + srcOffset + bytesPerPixel, mPixelFormat, Pixel::ALPHA );
290   }
291   else
292   {
293     samples[3] = samples[2];
294   }
295
296   // Bilinear interpolation:
297   float weight[4];
298   weight[0] = float(srcRow+1.0f) - y;
299   weight[1] = y - float(srcRow);
300   weight[2] = float(srcCol+1.0f) - x;
301   weight[3] = x - float(srcCol);
302
303   return ( weight[2] * (samples[0] * weight[0] + samples[1] * weight[1]) +
304            weight[3] * (samples[2] * weight[0] + samples[3] * weight[1]) ) / 256.0f;
305 }
306
307
308 }// namespace Internal
309
310 }// namespace Dali