2 * Copyright (c) 2014 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.
18 #ifndef DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_
19 #define DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_
25 #include <dali/integration-api/bitmap.h>
26 #include <dali/public-api/images/image-attributes.h>
36 * @brief Identify which combination of x and y dimensions matter in terminating iterative box filtering.
40 BoxDimensionTestEither,
47 * @brief Simple class for passing around pairs of small ints.
49 * These are immutable. If you want to change a value, make a whole new object.
50 * @note One of these can be passed in a single 32 bit integer register on
51 * common architectures.
57 * @brief Default constructor for the (0, 0) vector.
59 Vector2Uint16() : mData(0) {}
62 * @brief Constructor taking separate x and y (width and height) parameters.
63 * @param[in] width The width or X dimension of the vector. Make sure it is less than 65536,
64 * @param[in] height The height or Y dimension of the vector. Make sure it is less than 65536,
66 Vector2Uint16( uint32_t width, uint32_t height )
68 DALI_ASSERT_DEBUG( width < ( 1u << 16 ) && "Width parameter not representable." );
69 DALI_ASSERT_DEBUG( height < ( 1u << 16 ) && "Height parameter not representable." );
71 /* Do equivalent of the code below with one aligned memory access:
72 * mComponents[0] = width;
73 * mComponents[1] = height;
74 * Unit tests make sure this is equivalent.
76 mData = (height << 16u) + width;
80 * @brief Copy constructor.
82 Vector2Uint16( const Vector2Uint16& rhs )
88 * @returns the x dimension stored in this 2-tuple.
90 uint16_t GetWidth() const
92 return mComponents[0];
96 * @returns the y dimension stored in this 2-tuple.
98 uint16_t GetHeight() const
100 return mComponents[1];
104 * @returns the x dimension stored in this 2-tuple.
106 uint16_t GetX() const
108 return mComponents[0];
112 * @returns the y dimension stored in this 2-tuple.
114 uint16_t GetY() const
116 return mComponents[1];
122 // Addressable view of X and Y:
123 uint16_t mComponents[2];
124 // Packed view of X and Y to force alignment and allow a faster copy:
130 * @brief The integer dimensions of an image or a region of an image packed into
131 * 16 bits per component.
132 * @note This can only be used for images of up to 65535 x 65535 pixels.
134 typedef Vector2Uint16 ImageDimensions;
137 * @defgroup BitmapOperations Bitmap-to-Bitmap Image operations.
142 * @brief Apply requested attributes to bitmap.
144 * This is the top-level function which runs the on-load image post-processing
145 * pipeline. Bitmaps enter here as loaded from the file system by the file
146 * loaders and leave downscaled and filtered as requested by the application,
149 * @param[in] bitmap The input bitmap.
150 * @param[in] requestedAttributes Attributes which should be applied to bitmap.
151 * @return A bitmap which results from applying the requested attributes to the
152 * bitmap passed-in, or the original bitmap passed in if the attributes
155 Integration::BitmapPtr ApplyAttributesToBitmap( Integration::BitmapPtr bitmap, const ImageAttributes& requestedAttributes );
158 * @brief Apply downscaling to a bitmap according to requested attributes.
159 * @note The input bitmap pixel buffer may be modified and used as scratch working space for efficiency, so it must be discarded.
161 Integration::BitmapPtr DownscaleBitmap( Integration::Bitmap& bitmap, ImageDimensions desired, ImageAttributes::ScalingMode scalingMode, ImageAttributes::FilterMode filterMode );
165 * @defgroup ImageBufferScalingAlgorithms Pixel buffer-level scaling algorithms.
170 * @brief Destructive in-place downscaling by a power of 2 factor.
172 * A box filter with a 2x2 kernel is repeatedly applied as long as the result
173 * of the next downscaling step would not be smaller than the desired
175 * @param[in,out] pixels The buffer both to read from and write the result to.
176 * @param[in] pixelFormat The format of the image pointed at by pixels.
177 * @param[in] inputWidth The width of the input image.
178 * @param[in] inputHeight The height of the input image.
179 * @param[in] desiredWidth The width the client is requesting.
180 * @param[in] desiredHeight The height the client is requesting.
181 * @param[out] outWidth The resulting width after downscaling.
182 * @param[out] outHeight The resulting height after downscaling.
184 void DownscaleInPlacePow2( unsigned char * const pixels,
185 Pixel::Format pixelFormat,
186 unsigned int inputWidth,
187 unsigned int inputHeight,
188 unsigned int desiredWidth,
189 unsigned int desiredHeight,
190 ImageAttributes::ScalingMode scalingMode,
191 ImageAttributes::FilterMode filterMode,
193 unsigned& outHeight );
196 * @brief Destructive in-place downscaling by a power of 2 factor.
198 * A box filter with a 2x2 kernel is repeatedly applied as long as the result
199 * of the next downscaling step would not be smaller than the desired
201 * @param[in,out] pixels The buffer both to read from and write the result to.
202 * @param[in] inputWidth The width of the input image.
203 * @param[in] inputHeight The height of the input image.
204 * @param[in] desiredWidth The width the client is requesting.
205 * @param[in] desiredHeight The height the client is requesting.
206 * @param[out] outWidth The resulting width after downscaling.
207 * @param[out] outHeight The resulting height after downscaling.
209 void DownscaleInPlacePow2RGB888( unsigned char * pixels,
210 unsigned int inputWidth,
211 unsigned int inputHeight,
212 unsigned int desiredWidth,
213 unsigned int desiredHeight,
214 BoxDimensionTest dimensionTest,
215 unsigned int& outWidth,
216 unsigned int& outHeight );
219 * @copydoc DownscaleInPlacePow2RGB888
221 void DownscaleInPlacePow2RGBA8888( unsigned char * pixels,
222 unsigned int inputWidth,
223 unsigned int inputHeight,
224 unsigned int desiredWidth,
225 unsigned int desiredHeight,
226 BoxDimensionTest dimensionTest,
227 unsigned int& outWidth,
228 unsigned int& outHeight );
231 * @copydoc DownscaleInPlacePow2RGB888
233 * For the 2-byte packed 16 bit format RGB565.
235 void DownscaleInPlacePow2RGB565( unsigned char * pixels,
236 unsigned int inputWidth,
237 unsigned int inputHeight,
238 unsigned int desiredWidth,
239 unsigned int desiredHeight,
240 BoxDimensionTest dimensionTest,
241 unsigned int& outWidth,
242 unsigned int& outHeight );
245 * @copydoc DownscaleInPlacePow2RGB888
247 * For 2-byte formats such as lum8alpha8, but not packed 16 bit formats like RGB565.
249 void DownscaleInPlacePow2ComponentPair( unsigned char * pixels,
250 unsigned int inputWidth,
251 unsigned int inputHeight,
252 unsigned int desiredWidth,
253 unsigned int desiredHeight,
254 BoxDimensionTest dimensionTest,
255 unsigned int& outWidth,
256 unsigned int& outHeight );
259 * @copydoc DownscaleInPlacePow2RGB888
261 * For single-byte formats such as lum8 or alpha8.
263 void DownscaleInPlacePow2SingleBytePerPixel( unsigned char * pixels,
264 unsigned int inputWidth,
265 unsigned int inputHeight,
266 unsigned int desiredWidth,
267 unsigned int desiredHeight,
268 BoxDimensionTest dimensionTest,
269 unsigned int& outWidth,
270 unsigned int& outHeight );
273 * @brief Rescales an input image into the exact output dimensions passed-in.
275 * Uses point sampling, equivalent to GL_NEAREST texture filter mode, for the
276 * fastest results, at the expense of aliasing (noisy images) when downscaling.
277 * @note inPixels is allowed to alias outPixels if this is a downscaling,
278 * but not for upscaling.
280 void PointSample( const unsigned char * inPixels,
281 unsigned int inputWidth,
282 unsigned int inputHeight,
283 Pixel::Format pixelFormat,
284 unsigned char * outPixels,
285 unsigned int desiredWidth,
286 unsigned int desiredHeight );
289 * @copydoc PointSample
291 * Specialised for 4-byte formats like RGBA8888 and BGRA8888.
293 void PointSample4BPP( const unsigned char * inPixels,
294 unsigned int inputWidth,
295 unsigned int inputHeight,
296 unsigned char * outPixels,
297 unsigned int desiredWidth,
298 unsigned int desiredHeight );
301 * @copydoc PointSample
303 * Specialised for 3-byte formats like RGB888 and BGR888.
305 void PointSample3BPP( const unsigned char * inPixels,
306 unsigned int inputWidth,
307 unsigned int inputHeight,
308 unsigned char * outPixels,
309 unsigned int desiredWidth,
310 unsigned int desiredHeight );
313 * @copydoc PointSample
315 * Specialised for 2-byte formats like LA88.
317 void PointSample2BPP( const unsigned char * inPixels,
318 unsigned int inputWidth,
319 unsigned int inputHeight,
320 unsigned char * outPixels,
321 unsigned int desiredWidth,
322 unsigned int desiredHeight );
325 * @copydoc PointSample
327 * Specialised for 1-byte formats like L8 and A8.
329 void PointSample1BPP( const unsigned char * inPixels,
330 unsigned int inputWidth,
331 unsigned int inputHeight,
332 unsigned char * outPixels,
333 unsigned int desiredWidth,
334 unsigned int desiredHeight );
337 * @brief Resample input image to output image using a bilinear filter.
339 * Each output pixel is formed of a weighted sum of a 2x2 block of four input
341 * @pre inPixels must not alias outPixels. The input image should be a totally
342 * separate buffer from the input one.
344 void LinearSample( const unsigned char * __restrict__ inPixels,
345 ImageDimensions inDimensions,
346 Pixel::Format pixelFormat,
347 unsigned char * __restrict__ outPixels,
348 ImageDimensions outDimensions );
351 * @copydoc LinearSample
353 * Specialised for one byte per pixel formats.
355 void LinearSample1BPP( const unsigned char * __restrict__ inPixels,
356 ImageDimensions inputDimensions,
357 unsigned char * __restrict__ outPixels,
358 ImageDimensions desiredDimensions );
361 * @copydoc LinearSample
363 * Specialised for two byte per pixel formats.
365 void LinearSample2BPP( const unsigned char * __restrict__ inPixels,
366 ImageDimensions inputDimensions,
367 unsigned char * __restrict__ outPixels,
368 ImageDimensions desiredDimensions );
371 * @copydoc LinearSample
373 * Specialised for RGB565 16 bit pixel format.
375 void LinearSampleRGB565( const unsigned char * __restrict__ inPixels,
376 ImageDimensions inputDimensions,
377 unsigned char * __restrict__ outPixels,
378 ImageDimensions desiredDimensions );
381 * @copydoc LinearSample
383 * Specialised for three byte per pixel formats like RGB888.
385 void LinearSample3BPP( const unsigned char * __restrict__ inPixels,
386 ImageDimensions inputDimensions,
387 unsigned char * __restrict__ outPixels,
388 ImageDimensions desiredDimensions );
391 * @copydoc LinearSample
393 * Specialised for four byte per pixel formats like RGBA888.
394 * @note, If used on RGBA8888, the A component will be blended independently.
396 void LinearSample4BPP( const unsigned char * __restrict__ inPixels,
397 ImageDimensions inputDimensions,
398 unsigned char * __restrict__ outPixels,
399 ImageDimensions desiredDimensions );
404 * @defgroup ScalingAlgorithmFragments Composable subunits of the scaling algorithms.
409 * @brief Average adjacent pairs of pixels, overwriting the input array.
410 * @param[in,out] pixels The array of pixels to work on.
411 * @param[i] width The number of pixels in the array passed-in.
413 void HalveScanlineInPlaceRGB888( unsigned char * pixels, unsigned int width );
416 * @copydoc HalveScanlineInPlaceRGB888
418 void HalveScanlineInPlaceRGBA8888( unsigned char * pixels, unsigned int width );
421 * @copydoc HalveScanlineInPlaceRGB888
423 void HalveScanlineInPlaceRGB565( unsigned char * pixels, unsigned int width );
426 * @copydoc HalveScanlineInPlaceRGB888
428 void HalveScanlineInPlace2Bytes( unsigned char * pixels, unsigned int width );
431 * @copydoc HalveScanlineInPlaceRGB888
433 void HalveScanlineInPlace1Byte( unsigned char * pixels, unsigned int width );
436 * @brief Average pixels at corresponding offsets in two scanlines.
438 * outputScanline is allowed to alias scanline1.
439 * @param[in] scanline1 First scanline of pixels to average.
440 * @param[in] scanline2 Second scanline of pixels to average.
441 * @param[out] outputScanline Destination for the averaged pixels.
442 * @param[in] width The widths of all the scanlines passed-in.
444 void AverageScanlines1( const unsigned char * scanline1,
445 const unsigned char * scanline2,
446 unsigned char* outputScanline,
447 /** Image width in pixels (1 byte == 1 pixel: e.g. lum8 or alpha8).*/
448 unsigned int width );
451 * @copydoc AverageScanlines1
453 void AverageScanlines2( const unsigned char * scanline1,
454 const unsigned char * scanline2,
455 unsigned char* outputScanline,
456 /** Image width in pixels (2 bytes == 1 pixel: e.g. lum8alpha8).*/
457 unsigned int width );
460 * @copydoc AverageScanlines1
462 void AverageScanlines3( const unsigned char * scanline1,
463 const unsigned char * scanline2,
464 unsigned char* outputScanline,
465 /** Image width in pixels (3 bytes == 1 pixel: e.g. RGB888).*/
466 unsigned int width );
469 * @copydoc AverageScanlines1
471 void AverageScanlinesRGBA8888( const unsigned char * scanline1,
472 const unsigned char * scanline2,
473 unsigned char * outputScanline,
474 unsigned int width );
477 * @copydoc AverageScanlines1
479 void AverageScanlinesRGB565( const unsigned char * scanline1,
480 const unsigned char * scanline2,
481 unsigned char* outputScanline,
482 unsigned int width );
486 * @defgroup TestableInlines Inline functions exposed in header to allow unit testing.
491 * @brief Average two integer arguments.
492 * @return The average of two uint arguments.
493 * @param[in] a First component to average.
494 * @param[in] b Second component to average.
496 inline unsigned int AverageComponent( unsigned int a, unsigned int b )
498 unsigned int avg = (a + b) >> 1u;
503 * @brief Average a pair of RGBA8888 pixels.
504 * @return The average of two RGBA8888 pixels.
505 * @param[in] a First pixel to average.
506 * @param[in] b Second pixel to average
508 inline uint32_t AveragePixelRGBA8888( uint32_t a, uint32_t b )
510 const unsigned int avg =
511 ((AverageComponent( (a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u ) << 1u) & 0xff000000 ) +
512 (AverageComponent( a & 0x00ff0000, b & 0x00ff0000 ) & 0x00ff0000 ) +
513 (AverageComponent( a & 0x0000ff00, b & 0x0000ff00 ) & 0x0000ff00 ) +
514 (AverageComponent( a & 0x000000ff, b & 0x000000ff ) );
516 ///@ToDo: Optimise by trying return (((a ^ b) & 0xfefefefeUL) >> 1) + (a & b);
517 ///@ToDo: Optimise for ARM using the single ARMV6 instruction: UHADD8 R4, R0, R5. This is not Neon. It runs in the normal integer pipeline so there is no downside like a stall moving between integer and copro.
521 * @brief Average a pair of RGB565 pixels.
522 * @param a[in] Low 16 bits hold a color value as RGB565 to average with parameter b.
523 * @param b[in] Low 16 bits hold a color value as RGB565 to average with parameter a.
524 * @return The average color of the two RGB565 pixels passed in, in the low 16 bits of the returned value.
526 inline uint32_t AveragePixelRGB565( uint32_t a, uint32_t b )
528 const unsigned int avg =
529 (AverageComponent( a & 0xf800, b & 0xf800 ) & 0xf800 ) +
530 (AverageComponent( a & 0x7e0, b & 0x7e0 ) & 0x7e0 ) +
531 (AverageComponent( a & 0x1f, b & 0x1f ) );
535 /** @return The weighted blend of two integers as a 16.16 fixed-point number, given a 0.16 fixed-point blending factor. */
536 inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b, unsigned int fractBlend )
538 DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
539 const unsigned int weightedAFixed = a * (65535u - fractBlend);
540 const unsigned int weightedBFixed = b * fractBlend;
541 const unsigned blended = (weightedAFixed + weightedBFixed);
545 /** @brief Blend two 16.16 inputs to give a 16.32 output. */
546 inline uint64_t WeightedBlendFixed1616ToFixed1632(unsigned int a, unsigned int b, unsigned int fractBlend )
548 DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
549 // Blend while promoting intermediates to 16.32 fixed point:
550 const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
551 const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
552 const uint64_t blended = (weightedAFixed + weightedBFixed);
557 * @brief Blend 4 taps into one value using horizontal and vertical weights.
559 inline unsigned int BilinearFilter1Component(unsigned int tl, unsigned int tr, unsigned int bl, unsigned int br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
561 DALI_ASSERT_DEBUG( fractBlendHorizontal <= 65535u && "Factor should be in 0.16 fixed-point." );
562 DALI_ASSERT_DEBUG( fractBlendVertical <= 65535u && "Factor should be in 0.16 fixed-point." );
564 const unsigned int topBlend = WeightedBlendIntToFixed1616( tl, tr, fractBlendHorizontal );
565 const unsigned int botBlend = WeightedBlendIntToFixed1616( bl, br, fractBlendHorizontal );
566 const uint64_t blended2x2 = WeightedBlendFixed1616ToFixed1632( topBlend, botBlend, fractBlendVertical );
567 const unsigned int rounded = (blended2x2 + (1u << 31u) ) >> 32u;
573 } /* namespace Platform */
574 } /* namespace Internal */
575 } /* namespace Dali */
577 #endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_ */