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