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