2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "pixel-buffer-impl.h"
26 #include "pixel-manipulation.h"
27 #include "alpha-mask.h"
28 #include <platform-abstractions/portable/image-operations.h>
39 PixelBuffer::PixelBuffer( unsigned char* buffer,
40 unsigned int bufferSize,
43 Dali::Pixel::Format pixelFormat )
45 mBufferSize( bufferSize ),
48 mPixelFormat( pixelFormat )
52 PixelBuffer::~PixelBuffer()
57 PixelBufferPtr PixelBuffer::New( unsigned int width,
59 Dali::Pixel::Format pixelFormat )
61 unsigned int bufferSize = width * height * Dali::Pixel::GetBytesPerPixel( pixelFormat );
62 unsigned char* buffer = NULL;
65 buffer = static_cast<unsigned char*>( malloc ( bufferSize ) );
67 return new PixelBuffer( buffer, bufferSize, width, height, pixelFormat );
70 PixelBufferPtr PixelBuffer::New( unsigned char* buffer,
71 unsigned int bufferSize,
74 Dali::Pixel::Format pixelFormat )
76 return new PixelBuffer( buffer, bufferSize, width, height, pixelFormat );
79 Dali::PixelData PixelBuffer::Convert( PixelBuffer& pixelBuffer )
81 Dali::PixelData pixelData = Dali::PixelData::New( pixelBuffer.mBuffer,
82 pixelBuffer.mBufferSize,
85 pixelBuffer.mPixelFormat,
86 Dali::PixelData::FREE );
87 pixelBuffer.mBuffer = NULL;
88 pixelBuffer.mWidth = 0;
89 pixelBuffer.mHeight = 0;
90 pixelBuffer.mBufferSize = 0;
95 unsigned int PixelBuffer::GetWidth() const
100 unsigned int PixelBuffer::GetHeight() const
105 Dali::Pixel::Format PixelBuffer::GetPixelFormat() const
110 unsigned char* PixelBuffer::GetBuffer() const
115 unsigned int PixelBuffer::GetBufferSize() const
120 Dali::PixelData PixelBuffer::CreatePixelData() const
122 unsigned char* destBuffer = NULL;
124 if( mBufferSize > 0 )
126 destBuffer = static_cast<unsigned char*>( malloc( mBufferSize ) );
127 memcpy( destBuffer, mBuffer, mBufferSize );
130 Dali::PixelData pixelData = Dali::PixelData::New( destBuffer, mBufferSize,
133 Dali::PixelData::FREE );
137 void PixelBuffer::ApplyMask( const PixelBuffer& inMask, float contentScale, bool cropToMask )
141 // First scale this buffer by the contentScale, and crop to the mask size
142 // If it's too small, then scale the mask to match the image size
143 // Then apply the mask
144 ScaleAndCrop( contentScale, ImageDimensions( inMask.GetWidth(), inMask.GetHeight() ) );
146 if( inMask.mWidth > mWidth || inMask.mHeight > mHeight )
148 PixelBufferPtr mask = NewResize( inMask, ImageDimensions( mWidth, mHeight ) );
149 ApplyMaskInternal( *mask );
153 ApplyMaskInternal( inMask );
158 // First, scale the mask to match the image size,
159 // then apply the mask.
160 PixelBufferPtr mask = NewResize( inMask, ImageDimensions( mWidth, mHeight ) );
161 ApplyMaskInternal( *mask );
165 void PixelBuffer::ApplyMaskInternal( const PixelBuffer& mask )
170 Dali::Pixel::GetAlphaOffsetAndMask(mPixelFormat, byteOffset, bitMask);
171 if( Dali::Pixel::HasAlpha( mPixelFormat ) && bitMask == 255 )
173 ApplyMaskToAlphaChannel( *this, mask );
177 PixelBufferPtr newPixelBuffer = CreateNewMaskedBuffer( *this, mask );
178 TakeOwnershipOfBuffer( *newPixelBuffer );
179 // On leaving scope, newPixelBuffer will get destroyed.
183 void PixelBuffer::TakeOwnershipOfBuffer( PixelBuffer& pixelBuffer )
187 // Take ownership of new buffer
188 mBuffer = pixelBuffer.mBuffer;
189 pixelBuffer.mBuffer = NULL;
190 mBufferSize = pixelBuffer.mBufferSize;
191 mWidth = pixelBuffer.mWidth;
192 mHeight = pixelBuffer.mHeight;
193 mPixelFormat = pixelBuffer.mPixelFormat;
196 void PixelBuffer::ReleaseBuffer()
204 void PixelBuffer::ScaleAndCrop( float scaleFactor, ImageDimensions cropDimensions )
206 ImageDimensions outDimensions( float(mWidth) * scaleFactor,
207 float(mHeight) * scaleFactor );
209 if( outDimensions.GetWidth() != mWidth || outDimensions.GetHeight() != mHeight )
211 Resize( outDimensions );
214 ImageDimensions postCropDimensions(
215 std::min(cropDimensions.GetWidth(), outDimensions.GetWidth()),
216 std::min(cropDimensions.GetHeight(), outDimensions.GetHeight()));
218 if( postCropDimensions.GetWidth() < outDimensions.GetWidth() ||
219 postCropDimensions.GetHeight() < outDimensions.GetHeight() )
221 uint16_t x = ( outDimensions.GetWidth() - postCropDimensions.GetWidth() ) / 2;
222 uint16_t y = ( outDimensions.GetHeight() - postCropDimensions.GetHeight() ) / 2;
223 Crop( x, y, postCropDimensions );
227 void PixelBuffer::Crop( uint16_t x, uint16_t y, ImageDimensions cropDimensions )
229 PixelBufferPtr outBuffer = NewCrop( *this, x, y, cropDimensions );
230 TakeOwnershipOfBuffer( *outBuffer );
233 PixelBufferPtr PixelBuffer::NewCrop( const PixelBuffer& inBuffer, uint16_t x, uint16_t y, ImageDimensions cropDimensions )
235 PixelBufferPtr outBuffer = PixelBuffer::New( cropDimensions.GetWidth(), cropDimensions.GetHeight(), inBuffer.GetPixelFormat() );
236 int bytesPerPixel = Pixel::GetBytesPerPixel( inBuffer.mPixelFormat );
237 int srcStride = inBuffer.mWidth * bytesPerPixel;
238 int destStride = cropDimensions.GetWidth() * bytesPerPixel;
240 // Clamp crop to right edge
241 if( x + cropDimensions.GetWidth() > inBuffer.mWidth )
243 destStride = ( inBuffer.mWidth - x ) * bytesPerPixel;
246 int srcOffset = x * bytesPerPixel + y * srcStride;
248 unsigned char* destBuffer = outBuffer->mBuffer;
250 // Clamp crop to last row
251 unsigned int endRow = y + cropDimensions.GetHeight();
252 if( endRow > inBuffer.mHeight )
254 endRow = inBuffer.mHeight - 1 ;
256 for( uint16_t row = y; row < endRow; ++row )
258 memcpy(destBuffer + destOffset, inBuffer.mBuffer + srcOffset, destStride );
259 srcOffset += srcStride;
260 destOffset += destStride;
266 void PixelBuffer::Resize( ImageDimensions outDimensions )
268 if( mWidth != outDimensions.GetWidth() || mHeight != outDimensions.GetHeight() )
270 PixelBufferPtr outBuffer = NewResize( *this, outDimensions );
271 TakeOwnershipOfBuffer( *outBuffer );
275 PixelBufferPtr PixelBuffer::NewResize( const PixelBuffer& inBuffer, ImageDimensions outDimensions )
277 PixelBufferPtr outBuffer = PixelBuffer::New( outDimensions.GetWidth(), outDimensions.GetHeight(), inBuffer.GetPixelFormat() );
278 ImageDimensions inDimensions( inBuffer.mWidth, inBuffer.mHeight );
280 bool hasAlpha = Pixel::HasAlpha( inBuffer.mPixelFormat );
281 int bytesPerPixel = Pixel::GetBytesPerPixel( inBuffer.mPixelFormat );
283 Resampler::Filter filterType = Resampler::LANCZOS4;
284 if( inDimensions.GetWidth() < outDimensions.GetWidth() && inDimensions.GetHeight() < outDimensions.GetHeight() )
286 filterType = Resampler::MITCHELL;
289 // This method only really works for 8 bit wide channels.
290 // (But could be expanded to work)
291 if( inBuffer.mPixelFormat == Pixel::A8 ||
292 inBuffer.mPixelFormat == Pixel::L8 ||
293 inBuffer.mPixelFormat == Pixel::LA88 ||
294 inBuffer.mPixelFormat == Pixel::RGB888 ||
295 inBuffer.mPixelFormat == Pixel::RGB8888 ||
296 inBuffer.mPixelFormat == Pixel::BGR8888 ||
297 inBuffer.mPixelFormat == Pixel::RGBA8888 ||
298 inBuffer.mPixelFormat == Pixel::BGRA8888 )
300 Dali::Internal::Platform::Resample( inBuffer.mBuffer, inDimensions,
301 outBuffer->GetBuffer(), outDimensions,
302 filterType, bytesPerPixel, hasAlpha );
306 DALI_LOG_ERROR( "Trying to resize an image with too narrow a channel width" );
312 }// namespace Adaptor
313 }// namespace Internal