Merge "Revert "Enable indicator in tizen 5.0"" into devel/master
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / common / pixel-buffer-impl.cpp
1 /*
2  * Copyright (c) 2018 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/imaging/common/pixel-buffer-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <stdlib.h>
23 #include <cstring>
24
25 // INTERNAL INCLUDES
26 #include <dali/internal/imaging/common/pixel-manipulation.h>
27 #include <dali/internal/imaging/common/alpha-mask.h>
28 #include <dali/internal/imaging/common/gaussian-blur.h>
29 #include <dali/internal/imaging/common/image-operations.h>
30
31 namespace Dali
32 {
33
34 namespace Internal
35 {
36
37 namespace Adaptor
38 {
39
40 namespace
41 {
42 const float TWO_PI = 2.f * Math::PI; ///< 360 degrees in radians
43 } // namespace
44
45 PixelBuffer::PixelBuffer( unsigned char* buffer,
46                           unsigned int bufferSize,
47                           unsigned int width,
48                           unsigned int height,
49                           Dali::Pixel::Format pixelFormat )
50 : mMetadata(),
51   mBuffer( buffer ),
52   mBufferSize( bufferSize ),
53   mWidth( width ),
54   mHeight( height ),
55   mPixelFormat( pixelFormat )
56 {
57 }
58
59 PixelBuffer::~PixelBuffer()
60 {
61   ReleaseBuffer();
62 }
63
64 PixelBufferPtr PixelBuffer::New( unsigned int width,
65                                  unsigned int height,
66                                  Dali::Pixel::Format pixelFormat )
67 {
68   unsigned int bufferSize = width * height * Dali::Pixel::GetBytesPerPixel( pixelFormat );
69   unsigned char* buffer = NULL;
70   if( bufferSize > 0 )
71   {
72     buffer = static_cast<unsigned char*>( malloc ( bufferSize ) );
73   }
74   return new PixelBuffer( buffer, bufferSize, width, height, pixelFormat );
75 }
76
77 PixelBufferPtr PixelBuffer::New( unsigned char* buffer,
78                                  unsigned int bufferSize,
79                                  unsigned int width,
80                                  unsigned int height,
81                                  Dali::Pixel::Format pixelFormat )
82 {
83   return new PixelBuffer( buffer, bufferSize, width, height, pixelFormat );
84 }
85
86 Dali::PixelData PixelBuffer::Convert( PixelBuffer& pixelBuffer )
87 {
88   Dali::PixelData pixelData = Dali::PixelData::New( pixelBuffer.mBuffer,
89                                                     pixelBuffer.mBufferSize,
90                                                     pixelBuffer.mWidth,
91                                                     pixelBuffer.mHeight,
92                                                     pixelBuffer.mPixelFormat,
93                                                     Dali::PixelData::FREE );
94   pixelBuffer.mBuffer = NULL;
95   pixelBuffer.mWidth = 0;
96   pixelBuffer.mHeight = 0;
97   pixelBuffer.mBufferSize = 0;
98
99   return pixelData;
100 }
101
102 unsigned int PixelBuffer::GetWidth() const
103 {
104   return mWidth;
105 }
106
107 unsigned int PixelBuffer::GetHeight() const
108 {
109   return mHeight;
110 }
111
112 Dali::Pixel::Format PixelBuffer::GetPixelFormat() const
113 {
114   return mPixelFormat;
115 }
116
117 unsigned char* PixelBuffer::GetBuffer() const
118 {
119   return mBuffer;
120 }
121
122 unsigned int PixelBuffer::GetBufferSize() const
123 {
124   return mBufferSize;
125 }
126
127 Dali::PixelData PixelBuffer::CreatePixelData() const
128 {
129   unsigned char* destBuffer = NULL;
130
131   if( mBufferSize > 0 )
132   {
133     destBuffer = static_cast<unsigned char*>( malloc( mBufferSize ) );
134     memcpy( destBuffer, mBuffer, mBufferSize );
135   }
136
137   Dali::PixelData pixelData = Dali::PixelData::New( destBuffer, mBufferSize,
138                                                     mWidth, mHeight,
139                                                     mPixelFormat,
140                                                     Dali::PixelData::FREE );
141   return pixelData;
142 }
143
144 void PixelBuffer::ApplyMask( const PixelBuffer& inMask, float contentScale, bool cropToMask )
145 {
146   if( cropToMask )
147   {
148     // First scale this buffer by the contentScale, and crop to the mask size
149     // If it's too small, then scale the mask to match the image size
150     // Then apply the mask
151     ScaleAndCrop( contentScale, ImageDimensions( inMask.GetWidth(), inMask.GetHeight() ) );
152
153     if( inMask.mWidth > mWidth || inMask.mHeight > mHeight )
154     {
155       PixelBufferPtr mask = NewResize( inMask, ImageDimensions( mWidth, mHeight ) );
156       ApplyMaskInternal( *mask );
157     }
158     else
159     {
160       ApplyMaskInternal( inMask );
161     }
162   }
163   else
164   {
165     // First, scale the mask to match the image size,
166     // then apply the mask.
167     PixelBufferPtr mask = NewResize( inMask, ImageDimensions( mWidth, mHeight ) );
168     ApplyMaskInternal( *mask );
169   }
170 }
171
172 void PixelBuffer::ApplyMaskInternal( const PixelBuffer& mask )
173 {
174   int byteOffset=0;
175   int bitMask=0;
176
177   Dali::Pixel::GetAlphaOffsetAndMask(mPixelFormat, byteOffset, bitMask);
178   if( Dali::Pixel::HasAlpha( mPixelFormat ) && bitMask == 255 )
179   {
180     ApplyMaskToAlphaChannel( *this, mask );
181   }
182   else
183   {
184     PixelBufferPtr newPixelBuffer = CreateNewMaskedBuffer( *this, mask );
185     TakeOwnershipOfBuffer( *newPixelBuffer );
186     // On leaving scope, newPixelBuffer will get destroyed.
187   }
188 }
189
190 void PixelBuffer::TakeOwnershipOfBuffer( PixelBuffer& pixelBuffer )
191 {
192   ReleaseBuffer();
193
194   // Take ownership of new buffer
195   mBuffer = pixelBuffer.mBuffer;
196   pixelBuffer.mBuffer = NULL;
197   mBufferSize = pixelBuffer.mBufferSize;
198   mWidth = pixelBuffer.mWidth;
199   mHeight = pixelBuffer.mHeight;
200   mPixelFormat = pixelBuffer.mPixelFormat;
201 }
202
203 void PixelBuffer::ReleaseBuffer()
204 {
205   if( mBuffer )
206   {
207     free( mBuffer );
208   }
209 }
210
211 void PixelBuffer::AllocateFixedSize( uint32_t size )
212 {
213   ReleaseBuffer();
214   mBuffer = reinterpret_cast<unsigned char*>(malloc( size ));
215   mBufferSize = size;
216 }
217
218 bool PixelBuffer::Rotate( Degree angle )
219 {
220   // Check first if Rotate() can perform the operation in the current pixel buffer.
221
222   bool validPixelFormat = false;
223   switch( mPixelFormat )
224   {
225     case Pixel::A8:
226     case Pixel::L8:
227     case Pixel::LA88:
228     case Pixel::RGB888:
229     case Pixel::RGB8888:
230     case Pixel::BGR8888:
231     case Pixel::RGBA8888:
232     case Pixel::BGRA8888: // FALL THROUGH
233     {
234       validPixelFormat = true;
235       break;
236     }
237     default:
238     {
239       // This pixel format is not supported for this operation.
240       validPixelFormat = false;
241       break;
242     }
243   }
244
245   if( !validPixelFormat )
246   {
247     // Can't rotate the pixel buffer with the current pixel format.
248     DALI_LOG_ERROR( "Can't rotate the pixel buffer with the current pixel format\n" );
249     return false;
250   }
251
252   float radians = Radian( angle ).radian;
253
254   // Transform the input angle into the range [0..2PI]
255   radians = fmod( radians, TWO_PI );
256   radians += ( radians < 0.f ) ? TWO_PI : 0.f;
257
258   if( radians < Dali::Math::MACHINE_EPSILON_10 )
259   {
260     // Nothing to do if the angle is zero.
261     return true;
262   }
263
264   const unsigned int pixelSize = Pixel::GetBytesPerPixel( mPixelFormat );
265
266   uint8_t* pixelsOut = nullptr;
267   Platform::RotateByShear( mBuffer,
268                            mWidth,
269                            mHeight,
270                            pixelSize,
271                            radians,
272                            pixelsOut,
273                            mWidth,
274                            mHeight );
275
276   // Check whether the rotation succedded and set the new pixel buffer data.
277   const bool success = nullptr != pixelsOut;
278
279   if( success )
280   {
281     // Release the memory of the current pixel buffer.
282     ReleaseBuffer();
283
284     // Set the new pixel buffer.
285     mBuffer = pixelsOut;
286     pixelsOut = nullptr;
287     mBufferSize = mWidth * mHeight * pixelSize;
288   }
289
290   return success;
291 }
292
293 void PixelBuffer::ScaleAndCrop( float scaleFactor, ImageDimensions cropDimensions )
294 {
295   ImageDimensions outDimensions( float(mWidth) * scaleFactor,
296                                  float(mHeight) * scaleFactor );
297
298   if( outDimensions.GetWidth() != mWidth || outDimensions.GetHeight() != mHeight )
299   {
300     Resize( outDimensions );
301   }
302
303   ImageDimensions postCropDimensions(
304     std::min(cropDimensions.GetWidth(), outDimensions.GetWidth()),
305     std::min(cropDimensions.GetHeight(), outDimensions.GetHeight()));
306
307   if( postCropDimensions.GetWidth() < outDimensions.GetWidth() ||
308       postCropDimensions.GetHeight() < outDimensions.GetHeight() )
309   {
310     uint16_t x = ( outDimensions.GetWidth()  - postCropDimensions.GetWidth() ) / 2;
311     uint16_t y = ( outDimensions.GetHeight() - postCropDimensions.GetHeight() ) / 2;
312     Crop( x, y, postCropDimensions );
313   }
314 }
315
316 void PixelBuffer::Crop( uint16_t x, uint16_t y, ImageDimensions cropDimensions )
317 {
318   PixelBufferPtr outBuffer = NewCrop( *this, x, y, cropDimensions );
319   TakeOwnershipOfBuffer( *outBuffer );
320 }
321
322 PixelBufferPtr PixelBuffer::NewCrop( const PixelBuffer& inBuffer, uint16_t x, uint16_t y, ImageDimensions cropDimensions )
323 {
324   PixelBufferPtr outBuffer = PixelBuffer::New( cropDimensions.GetWidth(), cropDimensions.GetHeight(), inBuffer.GetPixelFormat() );
325   int bytesPerPixel = Pixel::GetBytesPerPixel( inBuffer.mPixelFormat );
326   int srcStride = inBuffer.mWidth * bytesPerPixel;
327   int destStride = cropDimensions.GetWidth() * bytesPerPixel;
328
329   // Clamp crop to right edge
330   if( x + cropDimensions.GetWidth() > inBuffer.mWidth )
331   {
332     destStride = ( inBuffer.mWidth - x ) * bytesPerPixel;
333   }
334
335   int srcOffset = x * bytesPerPixel + y * srcStride;
336   int destOffset = 0;
337   unsigned char* destBuffer = outBuffer->mBuffer;
338
339   // Clamp crop to last row
340   unsigned int endRow = y + cropDimensions.GetHeight();
341   if( endRow > inBuffer.mHeight )
342   {
343     endRow = inBuffer.mHeight - 1 ;
344   }
345   for( uint16_t row = y; row < endRow; ++row )
346   {
347     memcpy(destBuffer + destOffset, inBuffer.mBuffer + srcOffset, destStride );
348     srcOffset += srcStride;
349     destOffset += destStride;
350   }
351   return outBuffer;
352
353 }
354
355 void PixelBuffer::SetMetadata( const Property::Map& map )
356 {
357   mMetadata.reset(new Property::Map(map));
358 }
359
360 bool PixelBuffer::GetMetadata(Property::Map& outMetadata) const
361 {
362   if( !mMetadata )
363   {
364     return false;
365   }
366   outMetadata = *mMetadata;
367   return true;
368 }
369
370 void PixelBuffer::SetMetadata(std::unique_ptr<Property::Map> metadata)
371 {
372   mMetadata = std::move(metadata);
373 }
374
375 void PixelBuffer::Resize( ImageDimensions outDimensions )
376 {
377   if( mWidth != outDimensions.GetWidth() || mHeight != outDimensions.GetHeight() )
378   {
379     PixelBufferPtr outBuffer = NewResize( *this, outDimensions );
380     TakeOwnershipOfBuffer( *outBuffer );
381   }
382 }
383
384 PixelBufferPtr PixelBuffer::NewResize( const PixelBuffer& inBuffer, ImageDimensions outDimensions )
385 {
386   PixelBufferPtr outBuffer = PixelBuffer::New( outDimensions.GetWidth(), outDimensions.GetHeight(), inBuffer.GetPixelFormat() );
387   ImageDimensions inDimensions( inBuffer.mWidth, inBuffer.mHeight );
388
389   bool hasAlpha = Pixel::HasAlpha( inBuffer.mPixelFormat );
390   int bytesPerPixel = Pixel::GetBytesPerPixel( inBuffer.mPixelFormat );
391
392   Resampler::Filter filterType = Resampler::LANCZOS4;
393   if( inDimensions.GetWidth() < outDimensions.GetWidth() && inDimensions.GetHeight() < outDimensions.GetHeight() )
394   {
395     filterType = Resampler::MITCHELL;
396   }
397
398   // This method only really works for 8 bit wide channels.
399   // (But could be expanded to work)
400   if( inBuffer.mPixelFormat == Pixel::A8 ||
401       inBuffer.mPixelFormat == Pixel::L8 ||
402       inBuffer.mPixelFormat == Pixel::LA88 ||
403       inBuffer.mPixelFormat == Pixel::RGB888 ||
404       inBuffer.mPixelFormat == Pixel::RGB8888 ||
405       inBuffer.mPixelFormat == Pixel::BGR8888 ||
406       inBuffer.mPixelFormat == Pixel::RGBA8888 ||
407       inBuffer.mPixelFormat == Pixel::BGRA8888 )
408   {
409     Dali::Internal::Platform::Resample( inBuffer.mBuffer, inDimensions,
410                                         outBuffer->GetBuffer(), outDimensions,
411                                         filterType, bytesPerPixel, hasAlpha );
412   }
413   else
414   {
415     DALI_LOG_ERROR( "Trying to resize an image with too narrow a channel width" );
416   }
417
418   return outBuffer;
419 }
420
421 void PixelBuffer::ApplyGaussianBlur( const float blurRadius )
422 {
423   // This method only works for pixel buffer in RGBA format.
424   if( mWidth > 0 && mHeight > 0 && mPixelFormat == Pixel::RGBA8888 )
425   {
426     if ( blurRadius > Math::MACHINE_EPSILON_1 )
427     {
428       PerformGaussianBlurRGBA( *this, blurRadius );
429     }
430   }
431   else
432   {
433     DALI_LOG_ERROR( "Trying to apply gaussian blur to an empty pixel buffer or a pixel buffer not in RGBA format" );
434   }
435 }
436
437 void PixelBuffer::MultiplyColorByAlpha()
438 {
439   auto bytesPerPixel = Pixel::GetBytesPerPixel( mPixelFormat );
440
441   // Compressed textures have unknown size of the pixel. Alpha premultiplication
442   // must be skipped in such case
443   if( Pixel::GetBytesPerPixel(mPixelFormat) && Pixel::HasAlpha(mPixelFormat) )
444   {
445     unsigned char* pixel = mBuffer;
446     const unsigned int bufferSize = mWidth * mHeight;
447
448     for( unsigned int i=0; i<bufferSize; ++i )
449     {
450       unsigned int alpha = ReadChannel( pixel, mPixelFormat, Adaptor::ALPHA );
451       {
452         auto red       = ReadChannel( pixel, mPixelFormat, Adaptor::RED);
453         auto green     = ReadChannel( pixel, mPixelFormat, Adaptor::GREEN);
454         auto blue      = ReadChannel( pixel, mPixelFormat, Adaptor::BLUE);
455         auto luminance = ReadChannel( pixel, mPixelFormat, Adaptor::LUMINANCE);
456         WriteChannel( pixel, mPixelFormat, Adaptor::RED, red*alpha / 255 );
457         WriteChannel( pixel, mPixelFormat, Adaptor::GREEN, green*alpha/255 );
458         WriteChannel( pixel, mPixelFormat, Adaptor::BLUE, blue*alpha/255 );
459         WriteChannel( pixel, mPixelFormat, Adaptor::LUMINANCE, luminance*alpha/255 );
460       }
461       pixel += bytesPerPixel;
462     }
463   }
464 }
465
466 }// namespace Adaptor
467 }// namespace Internal
468 }// namespace Dali