2 * Copyright (c) 2018 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-operations.h>
27 #include <third-party/resampler/resampler.h>
28 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
38 * @brief Identify which combination of x and y dimensions matter in terminating iterative box filtering.
42 BoxDimensionTestEither,
49 * @brief The integer dimensions of an image or a region of an image packed into
50 * 16 bits per component.
51 * @note This can only be used for images of up to 65535 x 65535 pixels.
53 typedef Uint16Pair ImageDimensions;
56 * @brief Work out the true desired width and height, accounting for special
57 * rules for zeros in either or both input requested dimensions.
59 * @param[in] rawDimensions Width and height of image before processing.
60 * @param[in] requestedDimensions Width and height of area to scale image into. Can be zero.
61 * @return Dimensions of area to scale image into after special rules are applied.
63 ImageDimensions CalculateDesiredDimensions( ImageDimensions rawDimensions, ImageDimensions requestedDimensions );
66 * @defgroup BitmapOperations Bitmap-to-Bitmap Image operations.
71 * @brief Apply requested attributes to bitmap.
73 * This is the top-level function which runs the on-load image post-processing
74 * pipeline. Bitmaps enter here as loaded from the file system by the file
75 * loaders and leave downscaled and filtered as requested by the application,
78 * @param[in] bitmap The input bitmap.
79 * @param[in] requestedAttributes Attributes which should be applied to bitmap.
80 * @return A bitmap which results from applying the requested attributes to the
81 * bitmap passed-in, or the original bitmap passed in if the attributes
84 Dali::Devel::PixelBuffer ApplyAttributesToBitmap( Dali::Devel::PixelBuffer bitmap, ImageDimensions dimensions, FittingMode::Type fittingMode = FittingMode::DEFAULT, SamplingMode::Type samplingMode = SamplingMode::DEFAULT );
87 * @brief Apply downscaling to a bitmap according to requested attributes.
88 * @note The input bitmap pixel buffer may be modified and used as scratch working space for efficiency, so it must be discarded.
90 Dali::Devel::PixelBuffer DownscaleBitmap( Dali::Devel::PixelBuffer bitmap,
91 ImageDimensions desired,
92 FittingMode::Type fittingMode,
93 SamplingMode::Type samplingMode );
97 * @defgroup ImageBufferScalingAlgorithms Pixel buffer-level scaling algorithms.
102 * @brief Destructive in-place downscaling by a power of 2 factor.
104 * A box filter with a 2x2 kernel is repeatedly applied as long as the result
105 * of the next downscaling step would not be smaller than the desired
107 * @param[in,out] pixels The buffer both to read from and write the result to.
108 * @param[in] pixelFormat The format of the image pointed at by pixels.
109 * @param[in] inputWidth The width of the input image.
110 * @param[in] inputHeight The height of the input image.
111 * @param[in] desiredWidth The width the client is requesting.
112 * @param[in] desiredHeight The height the client is requesting.
113 * @param[out] outWidth The resulting width after downscaling.
114 * @param[out] outHeight The resulting height after downscaling.
116 void DownscaleInPlacePow2( unsigned char * const pixels,
117 Pixel::Format pixelFormat,
118 unsigned int inputWidth,
119 unsigned int inputHeight,
120 unsigned int desiredWidth,
121 unsigned int desiredHeight,
122 FittingMode::Type fittingMode,
123 SamplingMode::Type samplingMode,
125 unsigned& outHeight );
128 * @brief Destructive in-place downscaling by a power of 2 factor.
130 * A box filter with a 2x2 kernel is repeatedly applied as long as the result
131 * of the next downscaling step would not be smaller than the desired
133 * @param[in,out] pixels The buffer both to read from and write the result to.
134 * @param[in] inputWidth The width of the input image.
135 * @param[in] inputHeight The height of the input image.
136 * @param[in] desiredWidth The width the client is requesting.
137 * @param[in] desiredHeight The height the client is requesting.
138 * @param[out] outWidth The resulting width after downscaling.
139 * @param[out] outHeight The resulting height after downscaling.
141 void DownscaleInPlacePow2RGB888( unsigned char * pixels,
142 unsigned int inputWidth,
143 unsigned int inputHeight,
144 unsigned int desiredWidth,
145 unsigned int desiredHeight,
146 BoxDimensionTest dimensionTest,
147 unsigned int& outWidth,
148 unsigned int& outHeight );
151 * @copydoc DownscaleInPlacePow2RGB888
153 void DownscaleInPlacePow2RGBA8888( unsigned char * pixels,
154 unsigned int inputWidth,
155 unsigned int inputHeight,
156 unsigned int desiredWidth,
157 unsigned int desiredHeight,
158 BoxDimensionTest dimensionTest,
159 unsigned int& outWidth,
160 unsigned int& outHeight );
163 * @copydoc DownscaleInPlacePow2RGB888
165 * For the 2-byte packed 16 bit format RGB565.
167 void DownscaleInPlacePow2RGB565( unsigned char * pixels,
168 unsigned int inputWidth,
169 unsigned int inputHeight,
170 unsigned int desiredWidth,
171 unsigned int desiredHeight,
172 BoxDimensionTest dimensionTest,
173 unsigned int& outWidth,
174 unsigned int& outHeight );
177 * @copydoc DownscaleInPlacePow2RGB888
179 * For 2-byte formats such as lum8alpha8, but not packed 16 bit formats like RGB565.
181 void DownscaleInPlacePow2ComponentPair( unsigned char * pixels,
182 unsigned int inputWidth,
183 unsigned int inputHeight,
184 unsigned int desiredWidth,
185 unsigned int desiredHeight,
186 BoxDimensionTest dimensionTest,
187 unsigned int& outWidth,
188 unsigned int& outHeight );
191 * @copydoc DownscaleInPlacePow2RGB888
193 * For single-byte formats such as lum8 or alpha8.
195 void DownscaleInPlacePow2SingleBytePerPixel( unsigned char * pixels,
196 unsigned int inputWidth,
197 unsigned int inputHeight,
198 unsigned int desiredWidth,
199 unsigned int desiredHeight,
200 BoxDimensionTest dimensionTest,
201 unsigned int& outWidth,
202 unsigned int& outHeight );
205 * @brief Rescales an input image into the exact output dimensions passed-in.
207 * Uses point sampling, equivalent to GL_NEAREST texture filter mode, for the
208 * fastest results, at the expense of aliasing (noisy images) when downscaling.
209 * @note inPixels is allowed to alias outPixels if this is a downscaling,
210 * but not for upscaling.
212 void PointSample( const unsigned char * inPixels,
213 unsigned int inputWidth,
214 unsigned int inputHeight,
215 Pixel::Format pixelFormat,
216 unsigned char * outPixels,
217 unsigned int desiredWidth,
218 unsigned int desiredHeight );
221 * @copydoc PointSample
223 * Specialised for 4-byte formats like RGBA8888 and BGRA8888.
225 void PointSample4BPP( const unsigned char * inPixels,
226 unsigned int inputWidth,
227 unsigned int inputHeight,
228 unsigned char * outPixels,
229 unsigned int desiredWidth,
230 unsigned int desiredHeight );
233 * @copydoc PointSample
235 * Specialised for 3-byte formats like RGB888 and BGR888.
237 void PointSample3BPP( const unsigned char * inPixels,
238 unsigned int inputWidth,
239 unsigned int inputHeight,
240 unsigned char * outPixels,
241 unsigned int desiredWidth,
242 unsigned int desiredHeight );
245 * @copydoc PointSample
247 * Specialised for 2-byte formats like LA88.
249 void PointSample2BPP( const unsigned char * inPixels,
250 unsigned int inputWidth,
251 unsigned int inputHeight,
252 unsigned char * outPixels,
253 unsigned int desiredWidth,
254 unsigned int desiredHeight );
257 * @copydoc PointSample
259 * Specialised for 1-byte formats like L8 and A8.
261 void PointSample1BPP( const unsigned char * inPixels,
262 unsigned int inputWidth,
263 unsigned int inputHeight,
264 unsigned char * outPixels,
265 unsigned int desiredWidth,
266 unsigned int desiredHeight );
269 * @brief Resample input image to output image using a bilinear filter.
271 * Each output pixel is formed of a weighted sum of a 2x2 block of four input
273 * @pre inPixels must not alias outPixels. The input image should be a totally
274 * separate buffer from the input one.
276 void LinearSample( const unsigned char * __restrict__ inPixels,
277 ImageDimensions inDimensions,
278 Pixel::Format pixelFormat,
279 unsigned char * __restrict__ outPixels,
280 ImageDimensions outDimensions );
283 * @copydoc LinearSample
285 * Specialised for one byte per pixel formats.
287 void LinearSample1BPP( const unsigned char * __restrict__ inPixels,
288 ImageDimensions inputDimensions,
289 unsigned char * __restrict__ outPixels,
290 ImageDimensions desiredDimensions );
293 * @copydoc LinearSample
295 * Specialised for two byte per pixel formats.
297 void LinearSample2BPP( const unsigned char * __restrict__ inPixels,
298 ImageDimensions inputDimensions,
299 unsigned char * __restrict__ outPixels,
300 ImageDimensions desiredDimensions );
303 * @copydoc LinearSample
305 * Specialised for RGB565 16 bit pixel format.
307 void LinearSampleRGB565( const unsigned char * __restrict__ inPixels,
308 ImageDimensions inputDimensions,
309 unsigned char * __restrict__ outPixels,
310 ImageDimensions desiredDimensions );
313 * @copydoc LinearSample
315 * Specialised for three byte per pixel formats like RGB888.
317 void LinearSample3BPP( const unsigned char * __restrict__ inPixels,
318 ImageDimensions inputDimensions,
319 unsigned char * __restrict__ outPixels,
320 ImageDimensions desiredDimensions );
323 * @copydoc LinearSample
325 * Specialised for four byte per pixel formats like RGBA8888.
326 * @note, If used on RGBA8888, the A component will be blended independently.
328 void LinearSample4BPP( const unsigned char * __restrict__ inPixels,
329 ImageDimensions inputDimensions,
330 unsigned char * __restrict__ outPixels,
331 ImageDimensions desiredDimensions );
334 * @brief Resamples the input image with the Lanczos algorithm.
336 * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
337 * separate buffer from the output buffer.
339 * @param[in] inPixels Pointer to the input image buffer.
340 * @param[in] inputDimensions The input dimensions of the image.
341 * @param[out] outPixels Pointer to the output image buffer.
342 * @param[in] desiredDimensions The output dimensions of the image.
344 void LanczosSample4BPP( const unsigned char * __restrict__ inPixels,
345 ImageDimensions inputDimensions,
346 unsigned char * __restrict__ outPixels,
347 ImageDimensions desiredDimensions );
350 * @brief Resamples the input image with the Lanczos algorithm.
352 * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
353 * separate buffer from the output buffer.
355 * @param[in] inPixels Pointer to the input image buffer.
356 * @param[in] inputDimensions The input dimensions of the image.
357 * @param[out] outPixels Pointer to the output image buffer.
358 * @param[in] desiredDimensions The output dimensions of the image.
360 void LanczosSample1BPP( const unsigned char * __restrict__ inPixels,
361 ImageDimensions inputDimensions,
362 unsigned char * __restrict__ outPixels,
363 ImageDimensions desiredDimensions );
366 * @brief Resamples the input image with the Lanczos algorithm.
368 * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
369 * separate buffer from the output buffer.
371 * @param[in] inPixels Pointer to the input image buffer.
372 * @param[in] inputDimensions The input dimensions of the image.
373 * @param[out] outPixels Pointer to the output image buffer.
374 * @param[in] desiredDimensions The output dimensions of the image.
376 void Resample( const unsigned char * __restrict__ inPixels,
377 ImageDimensions inputDimensions,
378 unsigned char * __restrict__ outPixels,
379 ImageDimensions desiredDimensions,
380 Resampler::Filter filterType,
381 int numChannels, bool hasAlpha );
385 * @brief Rotates the input image with an implementation of the 'Rotate by Shear' algorithm.
387 * @pre @p pixelsIn must not alias @p pixelsOut. The input image should be a totally
388 * separate buffer from the output buffer.
390 * @note This function allocates memory in @p pixelsOut which has to be released by calling @e free()
392 * @param[in] pixelsIn The input buffer.
393 * @param[in] widthIn The width of the input buffer.
394 * @param[in] heightIn The height of the input buffer.
395 * @param[in] pixelSize The size of the pixel.
396 * @param[in] radians The rotation angle in radians.
397 * @param[out] pixelsOut The rotated output buffer.
398 * @param[out] widthOut The width of the output buffer.
399 * @param[out] heightOut The height of the output buffer.
401 void RotateByShear( const uint8_t* const pixelsIn,
402 unsigned int widthIn,
403 unsigned int heightIn,
404 unsigned int pixelSize,
407 unsigned int& widthOut,
408 unsigned int& heightOut );
413 * @defgroup ScalingAlgorithmFragments Composable subunits of the scaling algorithms.
418 * @brief Average adjacent pairs of pixels, overwriting the input array.
419 * @param[in,out] pixels The array of pixels to work on.
420 * @param[i] width The number of pixels in the array passed-in.
422 void HalveScanlineInPlaceRGB888( unsigned char * pixels, unsigned int width );
425 * @copydoc HalveScanlineInPlaceRGB888
427 void HalveScanlineInPlaceRGBA8888( unsigned char * pixels, unsigned int width );
430 * @copydoc HalveScanlineInPlaceRGB888
432 void HalveScanlineInPlaceRGB565( unsigned char * pixels, unsigned int width );
435 * @copydoc HalveScanlineInPlaceRGB888
437 void HalveScanlineInPlace2Bytes( unsigned char * pixels, unsigned int width );
440 * @copydoc HalveScanlineInPlaceRGB888
442 void HalveScanlineInPlace1Byte( unsigned char * pixels, unsigned int width );
445 * @brief Average pixels at corresponding offsets in two scanlines.
447 * outputScanline is allowed to alias scanline1.
448 * @param[in] scanline1 First scanline of pixels to average.
449 * @param[in] scanline2 Second scanline of pixels to average.
450 * @param[out] outputScanline Destination for the averaged pixels.
451 * @param[in] width The widths of all the scanlines passed-in.
453 void AverageScanlines1( const unsigned char * scanline1,
454 const unsigned char * scanline2,
455 unsigned char* outputScanline,
456 /** Image width in pixels (1 byte == 1 pixel: e.g. lum8 or alpha8).*/
457 unsigned int width );
460 * @copydoc AverageScanlines1
462 void AverageScanlines2( const unsigned char * scanline1,
463 const unsigned char * scanline2,
464 unsigned char* outputScanline,
465 /** Image width in pixels (2 bytes == 1 pixel: e.g. lum8alpha8).*/
466 unsigned int width );
469 * @copydoc AverageScanlines1
471 void AverageScanlines3( const unsigned char * scanline1,
472 const unsigned char * scanline2,
473 unsigned char* outputScanline,
474 /** Image width in pixels (3 bytes == 1 pixel: e.g. RGB888).*/
475 unsigned int width );
478 * @copydoc AverageScanlines1
480 void AverageScanlinesRGBA8888( const unsigned char * scanline1,
481 const unsigned char * scanline2,
482 unsigned char * outputScanline,
483 unsigned int width );
486 * @copydoc AverageScanlines1
488 void AverageScanlinesRGB565( const unsigned char * scanline1,
489 const unsigned char * scanline2,
490 unsigned char* outputScanline,
491 unsigned int width );
495 * @defgroup TestableInlines Inline functions exposed in header to allow unit testing.
500 * @brief Average two integer arguments.
501 * @return The average of two uint arguments.
502 * @param[in] a First component to average.
503 * @param[in] b Second component to average.
505 inline unsigned int AverageComponent( unsigned int a, unsigned int b )
507 unsigned int avg = (a + b) >> 1u;
512 * @brief Average a pair of RGBA8888 pixels.
513 * @return The average of two RGBA8888 pixels.
514 * @param[in] a First pixel to average.
515 * @param[in] b Second pixel to average
517 inline uint32_t AveragePixelRGBA8888( uint32_t a, uint32_t b )
519 const unsigned int avg =
520 ((AverageComponent( (a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u ) << 1u) & 0xff000000 ) +
521 (AverageComponent( a & 0x00ff0000, b & 0x00ff0000 ) & 0x00ff0000 ) +
522 (AverageComponent( a & 0x0000ff00, b & 0x0000ff00 ) & 0x0000ff00 ) +
523 (AverageComponent( a & 0x000000ff, b & 0x000000ff ) );
525 ///@ToDo: Optimise by trying return (((a ^ b) & 0xfefefefeUL) >> 1) + (a & b);
526 ///@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.
530 * @brief Average a pair of RGB565 pixels.
531 * @param a[in] Low 16 bits hold a color value as RGB565 to average with parameter b.
532 * @param b[in] Low 16 bits hold a color value as RGB565 to average with parameter a.
533 * @return The average color of the two RGB565 pixels passed in, in the low 16 bits of the returned value.
535 inline uint32_t AveragePixelRGB565( uint32_t a, uint32_t b )
537 const unsigned int avg =
538 (AverageComponent( a & 0xf800, b & 0xf800 ) & 0xf800 ) +
539 (AverageComponent( a & 0x7e0, b & 0x7e0 ) & 0x7e0 ) +
540 (AverageComponent( a & 0x1f, b & 0x1f ) );
544 /** @return The weighted blend of two integers as a 16.16 fixed-point number, given a 0.16 fixed-point blending factor. */
545 inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b, unsigned int fractBlend )
547 DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
548 const unsigned int weightedAFixed = a * (65535u - fractBlend);
549 const unsigned int weightedBFixed = b * fractBlend;
550 const unsigned blended = (weightedAFixed + weightedBFixed);
554 /** @brief Blend two 16.16 inputs to give a 16.32 output. */
555 inline uint64_t WeightedBlendFixed1616ToFixed1632(unsigned int a, unsigned int b, unsigned int fractBlend )
557 DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
558 // Blend while promoting intermediates to 16.32 fixed point:
559 const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
560 const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
561 const uint64_t blended = (weightedAFixed + weightedBFixed);
566 * @brief Blend 4 taps into one value using horizontal and vertical weights.
568 inline unsigned int BilinearFilter1Component(unsigned int tl, unsigned int tr, unsigned int bl, unsigned int br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
570 DALI_ASSERT_DEBUG( fractBlendHorizontal <= 65535u && "Factor should be in 0.16 fixed-point." );
571 DALI_ASSERT_DEBUG( fractBlendVertical <= 65535u && "Factor should be in 0.16 fixed-point." );
573 const unsigned int topBlend = WeightedBlendIntToFixed1616( tl, tr, fractBlendHorizontal );
574 const unsigned int botBlend = WeightedBlendIntToFixed1616( bl, br, fractBlendHorizontal );
575 const uint64_t blended2x2 = WeightedBlendFixed1616ToFixed1632( topBlend, botBlend, fractBlendVertical );
576 const unsigned int rounded = (blended2x2 + (1u << 31u) ) >> 32u;
582 } /* namespace Platform */
583 } /* namespace Internal */
584 } /* namespace Dali */
586 #endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_ */