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.
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 <resampler.h>
29 #ifdef DALI_ADAPTOR_COMPILATION
30 #include <adaptors/devel-api/adaptor-framework/pixel-buffer.h>
32 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
44 * @brief Identify which combination of x and y dimensions matter in terminating iterative box filtering.
48 BoxDimensionTestEither,
55 * @brief The integer dimensions of an image or a region of an image packed into
56 * 16 bits per component.
57 * @note This can only be used for images of up to 65535 x 65535 pixels.
59 typedef Uint16Pair ImageDimensions;
62 * @brief Work out the true desired width and height, accounting for special
63 * rules for zeros in either or both input requested dimensions.
65 * @param[in] rawDimensions Width and height of image before processing.
66 * @param[in] requestedDimensions Width and height of area to scale image into. Can be zero.
67 * @return Dimensions of area to scale image into after special rules are applied.
69 ImageDimensions CalculateDesiredDimensions( ImageDimensions rawDimensions, ImageDimensions requestedDimensions );
72 * @defgroup BitmapOperations Bitmap-to-Bitmap Image operations.
77 * @brief Apply requested attributes to bitmap.
79 * This is the top-level function which runs the on-load image post-processing
80 * pipeline. Bitmaps enter here as loaded from the file system by the file
81 * loaders and leave downscaled and filtered as requested by the application,
84 * @param[in] bitmap The input bitmap.
85 * @param[in] requestedAttributes Attributes which should be applied to bitmap.
86 * @return A bitmap which results from applying the requested attributes to the
87 * bitmap passed-in, or the original bitmap passed in if the attributes
90 Dali::Devel::PixelBuffer ApplyAttributesToBitmap( Dali::Devel::PixelBuffer bitmap, ImageDimensions dimensions, FittingMode::Type fittingMode = FittingMode::DEFAULT, SamplingMode::Type samplingMode = SamplingMode::DEFAULT );
93 * @brief Apply downscaling to a bitmap according to requested attributes.
94 * @note The input bitmap pixel buffer may be modified and used as scratch working space for efficiency, so it must be discarded.
96 Dali::Devel::PixelBuffer DownscaleBitmap( Dali::Devel::PixelBuffer bitmap,
97 ImageDimensions desired,
98 FittingMode::Type fittingMode,
99 SamplingMode::Type samplingMode );
103 * @defgroup ImageBufferScalingAlgorithms Pixel buffer-level scaling algorithms.
108 * @brief Destructive in-place downscaling by a power of 2 factor.
110 * A box filter with a 2x2 kernel is repeatedly applied as long as the result
111 * of the next downscaling step would not be smaller than the desired
113 * @param[in,out] pixels The buffer both to read from and write the result to.
114 * @param[in] pixelFormat The format of the image pointed at by pixels.
115 * @param[in] inputWidth The width of the input image.
116 * @param[in] inputHeight The height of the input image.
117 * @param[in] desiredWidth The width the client is requesting.
118 * @param[in] desiredHeight The height the client is requesting.
119 * @param[out] outWidth The resulting width after downscaling.
120 * @param[out] outHeight The resulting height after downscaling.
122 void DownscaleInPlacePow2( unsigned char * const pixels,
123 Pixel::Format pixelFormat,
124 unsigned int inputWidth,
125 unsigned int inputHeight,
126 unsigned int desiredWidth,
127 unsigned int desiredHeight,
128 FittingMode::Type fittingMode,
129 SamplingMode::Type samplingMode,
131 unsigned& outHeight );
134 * @brief Destructive in-place downscaling by a power of 2 factor.
136 * A box filter with a 2x2 kernel is repeatedly applied as long as the result
137 * of the next downscaling step would not be smaller than the desired
139 * @param[in,out] pixels The buffer both to read from and write the result to.
140 * @param[in] inputWidth The width of the input image.
141 * @param[in] inputHeight The height of the input image.
142 * @param[in] desiredWidth The width the client is requesting.
143 * @param[in] desiredHeight The height the client is requesting.
144 * @param[out] outWidth The resulting width after downscaling.
145 * @param[out] outHeight The resulting height after downscaling.
147 void DownscaleInPlacePow2RGB888( unsigned char * pixels,
148 unsigned int inputWidth,
149 unsigned int inputHeight,
150 unsigned int desiredWidth,
151 unsigned int desiredHeight,
152 BoxDimensionTest dimensionTest,
153 unsigned int& outWidth,
154 unsigned int& outHeight );
157 * @copydoc DownscaleInPlacePow2RGB888
159 void DownscaleInPlacePow2RGBA8888( unsigned char * pixels,
160 unsigned int inputWidth,
161 unsigned int inputHeight,
162 unsigned int desiredWidth,
163 unsigned int desiredHeight,
164 BoxDimensionTest dimensionTest,
165 unsigned int& outWidth,
166 unsigned int& outHeight );
169 * @copydoc DownscaleInPlacePow2RGB888
171 * For the 2-byte packed 16 bit format RGB565.
173 void DownscaleInPlacePow2RGB565( unsigned char * pixels,
174 unsigned int inputWidth,
175 unsigned int inputHeight,
176 unsigned int desiredWidth,
177 unsigned int desiredHeight,
178 BoxDimensionTest dimensionTest,
179 unsigned int& outWidth,
180 unsigned int& outHeight );
183 * @copydoc DownscaleInPlacePow2RGB888
185 * For 2-byte formats such as lum8alpha8, but not packed 16 bit formats like RGB565.
187 void DownscaleInPlacePow2ComponentPair( unsigned char * pixels,
188 unsigned int inputWidth,
189 unsigned int inputHeight,
190 unsigned int desiredWidth,
191 unsigned int desiredHeight,
192 BoxDimensionTest dimensionTest,
193 unsigned int& outWidth,
194 unsigned int& outHeight );
197 * @copydoc DownscaleInPlacePow2RGB888
199 * For single-byte formats such as lum8 or alpha8.
201 void DownscaleInPlacePow2SingleBytePerPixel( unsigned char * pixels,
202 unsigned int inputWidth,
203 unsigned int inputHeight,
204 unsigned int desiredWidth,
205 unsigned int desiredHeight,
206 BoxDimensionTest dimensionTest,
207 unsigned int& outWidth,
208 unsigned int& outHeight );
211 * @brief Rescales an input image into the exact output dimensions passed-in.
213 * Uses point sampling, equivalent to GL_NEAREST texture filter mode, for the
214 * fastest results, at the expense of aliasing (noisy images) when downscaling.
215 * @note inPixels is allowed to alias outPixels if this is a downscaling,
216 * but not for upscaling.
218 void PointSample( const unsigned char * inPixels,
219 unsigned int inputWidth,
220 unsigned int inputHeight,
221 Pixel::Format pixelFormat,
222 unsigned char * outPixels,
223 unsigned int desiredWidth,
224 unsigned int desiredHeight );
227 * @copydoc PointSample
229 * Specialised for 4-byte formats like RGBA8888 and BGRA8888.
231 void PointSample4BPP( const unsigned char * inPixels,
232 unsigned int inputWidth,
233 unsigned int inputHeight,
234 unsigned char * outPixels,
235 unsigned int desiredWidth,
236 unsigned int desiredHeight );
239 * @copydoc PointSample
241 * Specialised for 3-byte formats like RGB888 and BGR888.
243 void PointSample3BPP( const unsigned char * inPixels,
244 unsigned int inputWidth,
245 unsigned int inputHeight,
246 unsigned char * outPixels,
247 unsigned int desiredWidth,
248 unsigned int desiredHeight );
251 * @copydoc PointSample
253 * Specialised for 2-byte formats like LA88.
255 void PointSample2BPP( const unsigned char * inPixels,
256 unsigned int inputWidth,
257 unsigned int inputHeight,
258 unsigned char * outPixels,
259 unsigned int desiredWidth,
260 unsigned int desiredHeight );
263 * @copydoc PointSample
265 * Specialised for 1-byte formats like L8 and A8.
267 void PointSample1BPP( const unsigned char * inPixels,
268 unsigned int inputWidth,
269 unsigned int inputHeight,
270 unsigned char * outPixels,
271 unsigned int desiredWidth,
272 unsigned int desiredHeight );
275 * @brief Resample input image to output image using a bilinear filter.
277 * Each output pixel is formed of a weighted sum of a 2x2 block of four input
279 * @pre inPixels must not alias outPixels. The input image should be a totally
280 * separate buffer from the input one.
282 void LinearSample( const unsigned char * __restrict__ inPixels,
283 ImageDimensions inDimensions,
284 Pixel::Format pixelFormat,
285 unsigned char * __restrict__ outPixels,
286 ImageDimensions outDimensions );
289 * @copydoc LinearSample
291 * Specialised for one byte per pixel formats.
293 void LinearSample1BPP( const unsigned char * __restrict__ inPixels,
294 ImageDimensions inputDimensions,
295 unsigned char * __restrict__ outPixels,
296 ImageDimensions desiredDimensions );
299 * @copydoc LinearSample
301 * Specialised for two byte per pixel formats.
303 void LinearSample2BPP( const unsigned char * __restrict__ inPixels,
304 ImageDimensions inputDimensions,
305 unsigned char * __restrict__ outPixels,
306 ImageDimensions desiredDimensions );
309 * @copydoc LinearSample
311 * Specialised for RGB565 16 bit pixel format.
313 void LinearSampleRGB565( const unsigned char * __restrict__ inPixels,
314 ImageDimensions inputDimensions,
315 unsigned char * __restrict__ outPixels,
316 ImageDimensions desiredDimensions );
319 * @copydoc LinearSample
321 * Specialised for three byte per pixel formats like RGB888.
323 void LinearSample3BPP( const unsigned char * __restrict__ inPixels,
324 ImageDimensions inputDimensions,
325 unsigned char * __restrict__ outPixels,
326 ImageDimensions desiredDimensions );
329 * @copydoc LinearSample
331 * Specialised for four byte per pixel formats like RGBA8888.
332 * @note, If used on RGBA8888, the A component will be blended independently.
334 void LinearSample4BPP( const unsigned char * __restrict__ inPixels,
335 ImageDimensions inputDimensions,
336 unsigned char * __restrict__ outPixels,
337 ImageDimensions desiredDimensions );
340 * @brief Resamples the input image with the Lanczos algorithm.
342 * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
343 * separate buffer from the output buffer.
345 * @param[in] inPixels Pointer to the input image buffer.
346 * @param[in] inputDimensions The input dimensions of the image.
347 * @param[out] outPixels Pointer to the output image buffer.
348 * @param[in] desiredDimensions The output dimensions of the image.
350 void LanczosSample4BPP( const unsigned char * __restrict__ inPixels,
351 ImageDimensions inputDimensions,
352 unsigned char * __restrict__ outPixels,
353 ImageDimensions desiredDimensions );
356 * @brief Resamples the input image with the Lanczos algorithm.
358 * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
359 * separate buffer from the output buffer.
361 * @param[in] inPixels Pointer to the input image buffer.
362 * @param[in] inputDimensions The input dimensions of the image.
363 * @param[out] outPixels Pointer to the output image buffer.
364 * @param[in] desiredDimensions The output dimensions of the image.
366 void LanczosSample1BPP( const unsigned char * __restrict__ inPixels,
367 ImageDimensions inputDimensions,
368 unsigned char * __restrict__ outPixels,
369 ImageDimensions desiredDimensions );
372 * @brief Resamples the input image with the Lanczos algorithm.
374 * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
375 * separate buffer from the output buffer.
377 * @param[in] inPixels Pointer to the input image buffer.
378 * @param[in] inputDimensions The input dimensions of the image.
379 * @param[out] outPixels Pointer to the output image buffer.
380 * @param[in] desiredDimensions The output dimensions of the image.
382 void Resample( const unsigned char * __restrict__ inPixels,
383 ImageDimensions inputDimensions,
384 unsigned char * __restrict__ outPixels,
385 ImageDimensions desiredDimensions,
386 Resampler::Filter filterType,
387 int numChannels, bool hasAlpha );
393 * @defgroup ScalingAlgorithmFragments Composable subunits of the scaling algorithms.
398 * @brief Average adjacent pairs of pixels, overwriting the input array.
399 * @param[in,out] pixels The array of pixels to work on.
400 * @param[i] width The number of pixels in the array passed-in.
402 void HalveScanlineInPlaceRGB888( unsigned char * pixels, unsigned int width );
405 * @copydoc HalveScanlineInPlaceRGB888
407 void HalveScanlineInPlaceRGBA8888( unsigned char * pixels, unsigned int width );
410 * @copydoc HalveScanlineInPlaceRGB888
412 void HalveScanlineInPlaceRGB565( unsigned char * pixels, unsigned int width );
415 * @copydoc HalveScanlineInPlaceRGB888
417 void HalveScanlineInPlace2Bytes( unsigned char * pixels, unsigned int width );
420 * @copydoc HalveScanlineInPlaceRGB888
422 void HalveScanlineInPlace1Byte( unsigned char * pixels, unsigned int width );
425 * @brief Average pixels at corresponding offsets in two scanlines.
427 * outputScanline is allowed to alias scanline1.
428 * @param[in] scanline1 First scanline of pixels to average.
429 * @param[in] scanline2 Second scanline of pixels to average.
430 * @param[out] outputScanline Destination for the averaged pixels.
431 * @param[in] width The widths of all the scanlines passed-in.
433 void AverageScanlines1( const unsigned char * scanline1,
434 const unsigned char * scanline2,
435 unsigned char* outputScanline,
436 /** Image width in pixels (1 byte == 1 pixel: e.g. lum8 or alpha8).*/
437 unsigned int width );
440 * @copydoc AverageScanlines1
442 void AverageScanlines2( const unsigned char * scanline1,
443 const unsigned char * scanline2,
444 unsigned char* outputScanline,
445 /** Image width in pixels (2 bytes == 1 pixel: e.g. lum8alpha8).*/
446 unsigned int width );
449 * @copydoc AverageScanlines1
451 void AverageScanlines3( const unsigned char * scanline1,
452 const unsigned char * scanline2,
453 unsigned char* outputScanline,
454 /** Image width in pixels (3 bytes == 1 pixel: e.g. RGB888).*/
455 unsigned int width );
458 * @copydoc AverageScanlines1
460 void AverageScanlinesRGBA8888( const unsigned char * scanline1,
461 const unsigned char * scanline2,
462 unsigned char * outputScanline,
463 unsigned int width );
466 * @copydoc AverageScanlines1
468 void AverageScanlinesRGB565( const unsigned char * scanline1,
469 const unsigned char * scanline2,
470 unsigned char* outputScanline,
471 unsigned int width );
475 * @defgroup TestableInlines Inline functions exposed in header to allow unit testing.
480 * @brief Average two integer arguments.
481 * @return The average of two uint arguments.
482 * @param[in] a First component to average.
483 * @param[in] b Second component to average.
485 inline unsigned int AverageComponent( unsigned int a, unsigned int b )
487 unsigned int avg = (a + b) >> 1u;
492 * @brief Average a pair of RGBA8888 pixels.
493 * @return The average of two RGBA8888 pixels.
494 * @param[in] a First pixel to average.
495 * @param[in] b Second pixel to average
497 inline uint32_t AveragePixelRGBA8888( uint32_t a, uint32_t b )
499 const unsigned int avg =
500 ((AverageComponent( (a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u ) << 1u) & 0xff000000 ) +
501 (AverageComponent( a & 0x00ff0000, b & 0x00ff0000 ) & 0x00ff0000 ) +
502 (AverageComponent( a & 0x0000ff00, b & 0x0000ff00 ) & 0x0000ff00 ) +
503 (AverageComponent( a & 0x000000ff, b & 0x000000ff ) );
505 ///@ToDo: Optimise by trying return (((a ^ b) & 0xfefefefeUL) >> 1) + (a & b);
506 ///@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.
510 * @brief Average a pair of RGB565 pixels.
511 * @param a[in] Low 16 bits hold a color value as RGB565 to average with parameter b.
512 * @param b[in] Low 16 bits hold a color value as RGB565 to average with parameter a.
513 * @return The average color of the two RGB565 pixels passed in, in the low 16 bits of the returned value.
515 inline uint32_t AveragePixelRGB565( uint32_t a, uint32_t b )
517 const unsigned int avg =
518 (AverageComponent( a & 0xf800, b & 0xf800 ) & 0xf800 ) +
519 (AverageComponent( a & 0x7e0, b & 0x7e0 ) & 0x7e0 ) +
520 (AverageComponent( a & 0x1f, b & 0x1f ) );
524 /** @return The weighted blend of two integers as a 16.16 fixed-point number, given a 0.16 fixed-point blending factor. */
525 inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b, unsigned int fractBlend )
527 DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
528 const unsigned int weightedAFixed = a * (65535u - fractBlend);
529 const unsigned int weightedBFixed = b * fractBlend;
530 const unsigned blended = (weightedAFixed + weightedBFixed);
534 /** @brief Blend two 16.16 inputs to give a 16.32 output. */
535 inline uint64_t WeightedBlendFixed1616ToFixed1632(unsigned int a, unsigned int b, unsigned int fractBlend )
537 DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
538 // Blend while promoting intermediates to 16.32 fixed point:
539 const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
540 const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
541 const uint64_t blended = (weightedAFixed + weightedBFixed);
546 * @brief Blend 4 taps into one value using horizontal and vertical weights.
548 inline unsigned int BilinearFilter1Component(unsigned int tl, unsigned int tr, unsigned int bl, unsigned int br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
550 DALI_ASSERT_DEBUG( fractBlendHorizontal <= 65535u && "Factor should be in 0.16 fixed-point." );
551 DALI_ASSERT_DEBUG( fractBlendVertical <= 65535u && "Factor should be in 0.16 fixed-point." );
553 const unsigned int topBlend = WeightedBlendIntToFixed1616( tl, tr, fractBlendHorizontal );
554 const unsigned int botBlend = WeightedBlendIntToFixed1616( bl, br, fractBlendHorizontal );
555 const uint64_t blended2x2 = WeightedBlendFixed1616ToFixed1632( topBlend, botBlend, fractBlendVertical );
556 const unsigned int rounded = (blended2x2 + (1u << 31u) ) >> 32u;
562 } /* namespace Platform */
563 } /* namespace Internal */
564 } /* namespace Dali */
566 #endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_ */