Updated all code to new format
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / common / pixel-buffer-impl.cpp
1 /*
2  * Copyright (c) 2021 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/alpha-mask.h>
27 #include <dali/internal/imaging/common/gaussian-blur.h>
28 #include <dali/internal/imaging/common/image-operations.h>
29 #include <dali/internal/imaging/common/pixel-manipulation.h>
30
31 namespace Dali
32 {
33 namespace Internal
34 {
35 namespace Adaptor
36 {
37 namespace
38 {
39 const float TWO_PI = 2.f * Math::PI; ///< 360 degrees in radians
40 } // namespace
41
42 PixelBuffer::PixelBuffer(unsigned char*      buffer,
43                          unsigned int        bufferSize,
44                          unsigned int        width,
45                          unsigned int        height,
46                          Dali::Pixel::Format pixelFormat)
47 : mMetadata(),
48   mBuffer(buffer),
49   mBufferSize(bufferSize),
50   mWidth(width),
51   mHeight(height),
52   mPixelFormat(pixelFormat),
53   mPreMultiplied(false)
54 {
55 }
56
57 PixelBuffer::~PixelBuffer()
58 {
59   ReleaseBuffer();
60 }
61
62 PixelBufferPtr PixelBuffer::New(unsigned int        width,
63                                 unsigned int        height,
64                                 Dali::Pixel::Format pixelFormat)
65 {
66   unsigned int   bufferSize = width * height * Dali::Pixel::GetBytesPerPixel(pixelFormat);
67   unsigned char* buffer     = NULL;
68   if(bufferSize > 0)
69   {
70     buffer = static_cast<unsigned char*>(malloc(bufferSize));
71   }
72   return new PixelBuffer(buffer, bufferSize, width, height, pixelFormat);
73 }
74
75 PixelBufferPtr PixelBuffer::New(unsigned char*      buffer,
76                                 unsigned int        bufferSize,
77                                 unsigned int        width,
78                                 unsigned int        height,
79                                 Dali::Pixel::Format pixelFormat)
80 {
81   return new PixelBuffer(buffer, bufferSize, width, height, pixelFormat);
82 }
83
84 Dali::PixelData PixelBuffer::Convert(PixelBuffer& pixelBuffer)
85 {
86   Dali::PixelData pixelData = Dali::PixelData::New(pixelBuffer.mBuffer,
87                                                    pixelBuffer.mBufferSize,
88                                                    pixelBuffer.mWidth,
89                                                    pixelBuffer.mHeight,
90                                                    pixelBuffer.mPixelFormat,
91                                                    Dali::PixelData::FREE);
92   pixelBuffer.mBuffer       = NULL;
93   pixelBuffer.mWidth        = 0;
94   pixelBuffer.mHeight       = 0;
95   pixelBuffer.mBufferSize   = 0;
96
97   return pixelData;
98 }
99
100 unsigned int PixelBuffer::GetWidth() const
101 {
102   return mWidth;
103 }
104
105 unsigned int PixelBuffer::GetHeight() const
106 {
107   return mHeight;
108 }
109
110 Dali::Pixel::Format PixelBuffer::GetPixelFormat() const
111 {
112   return mPixelFormat;
113 }
114
115 unsigned char* PixelBuffer::GetBuffer() const
116 {
117   return mBuffer;
118 }
119
120 const unsigned char* const PixelBuffer::GetConstBuffer() const
121 {
122   return mBuffer;
123 }
124
125 unsigned int PixelBuffer::GetBufferSize() const
126 {
127   return mBufferSize;
128 }
129
130 Dali::PixelData PixelBuffer::CreatePixelData() const
131 {
132   unsigned char* destBuffer = NULL;
133
134   if(mBufferSize > 0)
135   {
136     destBuffer = static_cast<unsigned char*>(malloc(mBufferSize));
137     memcpy(destBuffer, mBuffer, mBufferSize);
138   }
139
140   Dali::PixelData pixelData = Dali::PixelData::New(destBuffer, mBufferSize, mWidth, mHeight, mPixelFormat, 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 void PixelBuffer::SetMetadata(const Property::Map& map)
355 {
356   mMetadata.reset(new Property::Map(map));
357 }
358
359 bool PixelBuffer::GetMetadata(Property::Map& outMetadata) const
360 {
361   if(!mMetadata)
362   {
363     return false;
364   }
365   outMetadata = *mMetadata;
366   return true;
367 }
368
369 void PixelBuffer::SetMetadata(std::unique_ptr<Property::Map> metadata)
370 {
371   mMetadata = std::move(metadata);
372 }
373
374 void PixelBuffer::Resize(ImageDimensions outDimensions)
375 {
376   if(mWidth != outDimensions.GetWidth() || mHeight != outDimensions.GetHeight())
377   {
378     PixelBufferPtr outBuffer = NewResize(*this, outDimensions);
379     TakeOwnershipOfBuffer(*outBuffer);
380   }
381 }
382
383 PixelBufferPtr PixelBuffer::NewResize(const PixelBuffer& inBuffer, ImageDimensions outDimensions)
384 {
385   PixelBufferPtr  outBuffer = PixelBuffer::New(outDimensions.GetWidth(), outDimensions.GetHeight(), inBuffer.GetPixelFormat());
386   ImageDimensions inDimensions(inBuffer.mWidth, inBuffer.mHeight);
387
388   bool hasAlpha      = Pixel::HasAlpha(inBuffer.mPixelFormat);
389   int  bytesPerPixel = Pixel::GetBytesPerPixel(inBuffer.mPixelFormat);
390
391   Resampler::Filter filterType = Resampler::LANCZOS4;
392   if(inDimensions.GetWidth() < outDimensions.GetWidth() && inDimensions.GetHeight() < outDimensions.GetHeight())
393   {
394     filterType = Resampler::MITCHELL;
395   }
396
397   // This method only really works for 8 bit wide channels.
398   // (But could be expanded to work)
399   if(inBuffer.mPixelFormat == Pixel::A8 ||
400      inBuffer.mPixelFormat == Pixel::L8 ||
401      inBuffer.mPixelFormat == Pixel::LA88 ||
402      inBuffer.mPixelFormat == Pixel::RGB888 ||
403      inBuffer.mPixelFormat == Pixel::RGB8888 ||
404      inBuffer.mPixelFormat == Pixel::BGR8888 ||
405      inBuffer.mPixelFormat == Pixel::RGBA8888 ||
406      inBuffer.mPixelFormat == Pixel::BGRA8888)
407   {
408     Dali::Internal::Platform::Resample(inBuffer.mBuffer, inDimensions, outBuffer->GetBuffer(), outDimensions, filterType, bytesPerPixel, hasAlpha);
409   }
410   else
411   {
412     DALI_LOG_ERROR("Trying to resize an image with too narrow a channel width");
413   }
414
415   return outBuffer;
416 }
417
418 void PixelBuffer::ApplyGaussianBlur(const float blurRadius)
419 {
420   // This method only works for pixel buffer in RGBA format.
421   if(mWidth > 0 && mHeight > 0 && mPixelFormat == Pixel::RGBA8888)
422   {
423     if(blurRadius > Math::MACHINE_EPSILON_1)
424     {
425       PerformGaussianBlurRGBA(*this, blurRadius);
426     }
427   }
428   else
429   {
430     DALI_LOG_ERROR("Trying to apply gaussian blur to an empty pixel buffer or a pixel buffer not in RGBA format");
431   }
432 }
433
434 void PixelBuffer::MultiplyColorByAlpha()
435 {
436   auto bytesPerPixel = Pixel::GetBytesPerPixel(mPixelFormat);
437
438   // Compressed textures have unknown size of the pixel. Alpha premultiplication
439   // must be skipped in such case
440   if(Pixel::GetBytesPerPixel(mPixelFormat) && Pixel::HasAlpha(mPixelFormat))
441   {
442     unsigned char*     pixel      = mBuffer;
443     const unsigned int bufferSize = mWidth * mHeight;
444
445     for(unsigned int i = 0; i < bufferSize; ++i)
446     {
447       unsigned int alpha = ReadChannel(pixel, mPixelFormat, Adaptor::ALPHA);
448       {
449         auto red       = ReadChannel(pixel, mPixelFormat, Adaptor::RED);
450         auto green     = ReadChannel(pixel, mPixelFormat, Adaptor::GREEN);
451         auto blue      = ReadChannel(pixel, mPixelFormat, Adaptor::BLUE);
452         auto luminance = ReadChannel(pixel, mPixelFormat, Adaptor::LUMINANCE);
453         WriteChannel(pixel, mPixelFormat, Adaptor::RED, red * alpha / 255);
454         WriteChannel(pixel, mPixelFormat, Adaptor::GREEN, green * alpha / 255);
455         WriteChannel(pixel, mPixelFormat, Adaptor::BLUE, blue * alpha / 255);
456         WriteChannel(pixel, mPixelFormat, Adaptor::LUMINANCE, luminance * alpha / 255);
457       }
458       pixel += bytesPerPixel;
459     }
460   }
461   mPreMultiplied = true;
462 }
463
464 bool PixelBuffer::IsAlphaPreMultiplied() const
465 {
466   return mPreMultiplied;
467 }
468
469 } // namespace Adaptor
470 } // namespace Internal
471 } // namespace Dali