[dali_2.3.25] Merge branch 'devel/master'
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / common / image-operations.h
1 /*
2  * Copyright (c) 2023 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 #ifndef DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H
19 #define DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H
20
21 // EXTERNAL INCLUDES
22 #include <stdint.h>
23
24 // INTERNAL INCLUDES
25 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
26 #include <dali/integration-api/bitmap.h>
27 #include <dali/public-api/images/image-operations.h>
28 #include <third-party/resampler/resampler.h>
29
30 namespace Dali
31 {
32 namespace Internal
33 {
34 namespace Platform
35 {
36 /**
37  * @brief Identify which combination of x and y dimensions matter in terminating iterative box filtering.
38  */
39 enum BoxDimensionTest
40 {
41   BoxDimensionTestEither,
42   BoxDimensionTestBoth,
43   BoxDimensionTestX,
44   BoxDimensionTestY
45 };
46
47 /**
48  * @brief The integer dimensions of an image or a region of an image packed into
49  *        16 bits per component.
50  * @note  This can only be used for images of up to 65535 x 65535 pixels.
51   */
52 typedef Uint16Pair ImageDimensions;
53
54 /**
55  * @brief Work out the true desired width and height, accounting for special
56  * rules for zeros in either or both input requested dimensions.
57  *
58  * @param[in] rawDimensions Width and height of image before processing.
59  * @param[in] requestedDimensions Width and height of area to scale image into. Can be zero.
60  * @return Dimensions of area to scale image into after special rules are applied.
61  */
62 ImageDimensions CalculateDesiredDimensions(ImageDimensions rawDimensions, ImageDimensions requestedDimensions);
63
64 /**
65  * @defgroup BitmapOperations Bitmap-to-Bitmap Image operations.
66  * @{
67  */
68
69 /**
70  * @brief Apply requested attributes to bitmap.
71  *
72  * This is the top-level function which runs the on-load image post-processing
73  * pipeline. Bitmaps enter here as loaded from the file system by the file
74  * loaders and leave downscaled and filtered as requested by the application,
75  * ready for use.
76  *
77  * @param[in] bitmap The input bitmap.
78  * @param[in] requestedAttributes Attributes which should be applied to bitmap.
79  * @return A bitmap which results from applying the requested attributes to the
80  *         bitmap passed-in, or the original bitmap passed in if the attributes
81  *         have no effect.
82  */
83 Dali::Devel::PixelBuffer ApplyAttributesToBitmap(Dali::Devel::PixelBuffer bitmap, ImageDimensions dimensions, FittingMode::Type fittingMode = FittingMode::DEFAULT, SamplingMode::Type samplingMode = SamplingMode::DEFAULT);
84
85 /**
86  * @brief Apply downscaling to a bitmap according to requested attributes.
87  * @note The input bitmap pixel buffer may be modified and used as scratch working space for efficiency, so it must be discarded.
88  **/
89 Dali::Devel::PixelBuffer DownscaleBitmap(Dali::Devel::PixelBuffer bitmap,
90                                          ImageDimensions          desired,
91                                          FittingMode::Type        fittingMode,
92                                          SamplingMode::Type       samplingMode);
93 /**@}*/
94
95 /**
96  * @defgroup ImageBufferScalingAlgorithms Pixel buffer-level scaling algorithms.
97  * @{
98  */
99
100 /**
101  * @brief Destructive in-place downscaling by a power of 2 factor.
102  *
103  * A box filter with a 2x2 kernel is repeatedly applied as long as the result
104  * of the next downscaling step would not be smaller than the desired
105  * dimensions.
106  * @param[in,out] pixels The buffer both to read from and write the result to.
107  * @param[in]     pixelFormat The format of the image pointed at by pixels.
108  * @param[in]     inputWidth The width of the input image.
109  * @param[in]     inputHeight The height of the input image.
110  * @param[in]     inputStride The stride 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.
115  * @param[out]    outStride The resulting stride after downscaling.
116  */
117 void DownscaleInPlacePow2(uint8_t* const     pixels,
118                           Pixel::Format      pixelFormat,
119                           uint32_t           inputWidth,
120                           uint32_t           inputHeight,
121                           uint32_t           inputStride,
122                           uint32_t           desiredWidth,
123                           uint32_t           desiredHeight,
124                           FittingMode::Type  fittingMode,
125                           SamplingMode::Type samplingMode,
126                           unsigned&          outWidth,
127                           unsigned&          outHeight,
128                           unsigned&          outStride);
129
130 /**
131  * @brief Destructive in-place downscaling by a power of 2 factor.
132  *
133  * A box filter with a 2x2 kernel is repeatedly applied as long as the result
134  * of the next downscaling step would not be smaller than the desired
135  * dimensions.
136  * @param[in,out] pixels The buffer both to read from and write the result to.
137  * @param[in]     inputWidth The width of the input image.
138  * @param[in]     inputHeight The height of the input image.
139  * @param[in]     inputStride The stride of the input image.
140  * @param[in]     desiredWidth The width the client is requesting.
141  * @param[in]     desiredHeight The height the client is requesting.
142  * @param[out]    outWidth  The resulting width after downscaling.
143  * @param[out]    outHeight The resulting height after downscaling.
144  * @param[out]    outStride The resulting stride after downscaling.
145  */
146 void DownscaleInPlacePow2RGB888(uint8_t*         pixels,
147                                 uint32_t         inputWidth,
148                                 uint32_t         inputHeight,
149                                 uint32_t         inputStride,
150                                 uint32_t         desiredWidth,
151                                 uint32_t         desiredHeight,
152                                 BoxDimensionTest dimensionTest,
153                                 uint32_t&        outWidth,
154                                 uint32_t&        outHeight,
155                                 uint32_t&        outStride);
156
157 /**
158  * @copydoc DownscaleInPlacePow2RGB888
159  */
160 void DownscaleInPlacePow2RGBA8888(uint8_t*         pixels,
161                                   uint32_t         inputWidth,
162                                   uint32_t         inputHeight,
163                                   uint32_t         inputStride,
164                                   uint32_t         desiredWidth,
165                                   uint32_t         desiredHeight,
166                                   BoxDimensionTest dimensionTest,
167                                   uint32_t&        outWidth,
168                                   uint32_t&        outHeight,
169                                   uint32_t&        outStride);
170
171 /**
172  * @copydoc DownscaleInPlacePow2RGB888
173  *
174  * For the 2-byte packed 16 bit format RGB565.
175  */
176 void DownscaleInPlacePow2RGB565(uint8_t*         pixels,
177                                 uint32_t         inputWidth,
178                                 uint32_t         inputHeight,
179                                 uint32_t         inputStride,
180                                 uint32_t         desiredWidth,
181                                 uint32_t         desiredHeight,
182                                 BoxDimensionTest dimensionTest,
183                                 uint32_t&        outWidth,
184                                 uint32_t&        outHeight,
185                                 uint32_t&        outStride);
186
187 /**
188  * @copydoc DownscaleInPlacePow2RGB888
189  *
190  * For 2-byte formats such as lum8alpha8, but not packed 16 bit formats like RGB565.
191  */
192 void DownscaleInPlacePow2ComponentPair(uint8_t*         pixels,
193                                        uint32_t         inputWidth,
194                                        uint32_t         inputHeight,
195                                        uint32_t         inputStride,
196                                        uint32_t         desiredWidth,
197                                        uint32_t         desiredHeight,
198                                        BoxDimensionTest dimensionTest,
199                                        uint32_t&        outWidth,
200                                        uint32_t&        outHeight,
201                                        uint32_t&        outStride);
202
203 /**
204  * @copydoc DownscaleInPlacePow2RGB888
205  *
206  * For single-byte formats such as lum8 or alpha8.
207  */
208 void DownscaleInPlacePow2SingleBytePerPixel(uint8_t*         pixels,
209                                             uint32_t         inputWidth,
210                                             uint32_t         inputHeight,
211                                             uint32_t         inputStride,
212                                             uint32_t         desiredWidth,
213                                             uint32_t         desiredHeight,
214                                             BoxDimensionTest dimensionTest,
215                                             uint32_t&        outWidth,
216                                             uint32_t&        outHeight,
217                                             uint32_t&        outStride);
218
219 /**
220  * @brief Rescales an input image into the exact output dimensions passed-in.
221  *
222  * Uses point sampling, equivalent to GL_NEAREST texture filter mode, for the
223  * fastest results, at the expense of aliasing (noisy images) when downscaling.
224  * @note inPixels is allowed to alias outPixels if this is a downscaling,
225  * but not for upscaling.
226  */
227 void PointSample(const uint8_t* inPixels,
228                  uint32_t       inputWidth,
229                  uint32_t       inputHeight,
230                  uint32_t       inputStride,
231                  Pixel::Format  pixelFormat,
232                  uint8_t*       outPixels,
233                  uint32_t       desiredWidth,
234                  uint32_t       desiredHeight);
235
236 /**
237  * @copydoc PointSample
238  *
239  * Specialised for 4-byte formats like RGBA8888 and BGRA8888.
240  */
241 void PointSample4BPP(const uint8_t* inPixels,
242                      uint32_t       inputWidth,
243                      uint32_t       inputHeight,
244                      uint32_t       inputStride,
245                      uint8_t*       outPixels,
246                      uint32_t       desiredWidth,
247                      uint32_t       desiredHeight);
248
249 /**
250  * @copydoc PointSample
251  *
252  * Specialised for 3-byte formats like RGB888 and BGR888.
253  */
254 void PointSample3BPP(const uint8_t* inPixels,
255                      uint32_t       inputWidth,
256                      uint32_t       inputHeight,
257                      uint32_t       inputStride,
258                      uint8_t*       outPixels,
259                      uint32_t       desiredWidth,
260                      uint32_t       desiredHeight);
261
262 /**
263  * @copydoc PointSample
264  *
265  * Specialised for 2-byte formats like LA88.
266  */
267 void PointSample2BPP(const uint8_t* inPixels,
268                      uint32_t       inputWidth,
269                      uint32_t       inputHeight,
270                      uint32_t       inputStride,
271                      uint8_t*       outPixels,
272                      uint32_t       desiredWidth,
273                      uint32_t       desiredHeight);
274
275 /**
276  * @copydoc PointSample
277  *
278  * Specialised for 1-byte formats like L8 and A8.
279  */
280 void PointSample1BPP(const uint8_t* inPixels,
281                      uint32_t       inputWidth,
282                      uint32_t       inputHeight,
283                      uint32_t       inputStride,
284                      uint8_t*       outPixels,
285                      uint32_t       desiredWidth,
286                      uint32_t       desiredHeight);
287
288 /**
289  * @brief Resample input image to output image using a bilinear filter.
290  *
291  * Each output pixel is formed of a weighted sum of a 2x2 block of four input
292  * pixels
293  * @pre inPixels must not alias outPixels. The input image should be a totally
294  * separate buffer from the input one.
295  */
296 void LinearSample(const uint8_t* __restrict__ inPixels,
297                   ImageDimensions inDimensions,
298                   uint32_t        inStride,
299                   Pixel::Format   pixelFormat,
300                   uint8_t* __restrict__ outPixels,
301                   ImageDimensions outDimensions);
302
303 /**
304  * @copydoc LinearSample
305  *
306  * Specialised for one byte per pixel formats.
307  */
308 void LinearSample1BPP(const uint8_t* __restrict__ inPixels,
309                       ImageDimensions inputDimensions,
310                       uint32_t        inputStride,
311                       uint8_t* __restrict__ outPixels,
312                       ImageDimensions desiredDimensions);
313
314 /**
315  * @copydoc LinearSample
316  *
317  * Specialised for two byte per pixel formats.
318  */
319 void LinearSample2BPP(const uint8_t* __restrict__ inPixels,
320                       ImageDimensions inputDimensions,
321                       uint32_t        inputStride,
322                       uint8_t* __restrict__ outPixels,
323                       ImageDimensions desiredDimensions);
324
325 /**
326  * @copydoc LinearSample
327  *
328  * Specialised for RGB565 16 bit pixel format.
329  */
330 void LinearSampleRGB565(const uint8_t* __restrict__ inPixels,
331                         ImageDimensions inputDimensions,
332                         uint32_t        inputStride,
333                         uint8_t* __restrict__ outPixels,
334                         ImageDimensions desiredDimensions);
335
336 /**
337  * @copydoc LinearSample
338  *
339  * Specialised for three byte per pixel formats like RGB888.
340  */
341 void LinearSample3BPP(const uint8_t* __restrict__ inPixels,
342                       ImageDimensions inputDimensions,
343                       uint32_t        inputStride,
344                       uint8_t* __restrict__ outPixels,
345                       ImageDimensions desiredDimensions);
346
347 /**
348  * @copydoc LinearSample
349  *
350  * Specialised for four byte per pixel formats like RGBA8888.
351  * @note, If used on RGBA8888, the A component will be blended independently.
352  */
353 void LinearSample4BPP(const uint8_t* __restrict__ inPixels,
354                       ImageDimensions inputDimensions,
355                       uint32_t        inputStride,
356                       uint8_t* __restrict__ outPixels,
357                       ImageDimensions desiredDimensions);
358
359 /**
360  * @brief Resample input image to output image using a Lanczos algorithm.
361  *
362  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
363  * separate buffer from the output buffer.
364  *
365  * @param[in] inPixels Pointer to the input image buffer.
366  * @param[in] inputDimensions The input dimensions of the image.
367  * @param[in] inputStride The input stride of the image.
368  * @param[in] pixelFormat The format of the image pointed at by pixels.
369  * @param[out] outPixels Pointer to the output image buffer.
370  * @param[in] desiredDimensions The output dimensions of the image.
371  */
372 void LanczosSample(const uint8_t* __restrict__ inPixels,
373                    ImageDimensions inDimensions,
374                    uint32_t        inStride,
375                    Pixel::Format   pixelFormat,
376                    uint8_t* __restrict__ outPixels,
377                    ImageDimensions outDimensions);
378
379 /**
380  * @brief Resamples the input image with the Lanczos algorithm.
381  *
382  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
383  * separate buffer from the output buffer.
384  *
385  * @param[in] inPixels Pointer to the input image buffer.
386  * @param[in] inputDimensions The input dimensions of the image.
387  * @param[in] inputStride The input stride of the image.
388  * @param[out] outPixels Pointer to the output image buffer.
389  * @param[in] desiredDimensions The output dimensions of the image.
390  */
391 void LanczosSample4BPP(const uint8_t* __restrict__ inPixels,
392                        ImageDimensions inputDimensions,
393                        uint32_t        inputStride,
394                        uint8_t* __restrict__ outPixels,
395                        ImageDimensions desiredDimensions);
396
397 /**
398  * @brief Resamples the input image with the Lanczos algorithm.
399  *
400  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
401  * separate buffer from the output buffer.
402  *
403  * @param[in] inPixels Pointer to the input image buffer.
404  * @param[in] inputDimensions The input dimensions of the image.
405  * @param[in] inputStride The input stride of the image.
406  * @param[out] outPixels Pointer to the output image buffer.
407  * @param[in] desiredDimensions The output dimensions of the image.
408  */
409 void LanczosSample1BPP(const uint8_t* __restrict__ inPixels,
410                        ImageDimensions inputDimensions,
411                        uint32_t        inputStride,
412                        uint8_t* __restrict__ outPixels,
413                        ImageDimensions desiredDimensions);
414
415 /**
416  * @brief Resamples the input image with the Lanczos algorithm.
417  *
418  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
419  * separate buffer from the output buffer.
420  *
421  * @param[in] inPixels Pointer to the input image buffer.
422  * @param[in] inputDimensions The input dimensions of the image.
423  * @param[in] inputStride The input stride of the image.
424  * @param[out] outPixels Pointer to the output image buffer.
425  * @param[in] desiredDimensions The output dimensions of the image.
426  */
427 void Resample(const uint8_t* __restrict__ inPixels,
428               ImageDimensions inputDimensions,
429               uint32_t        inputStride,
430               uint8_t* __restrict__ outPixels,
431               ImageDimensions   desiredDimensions,
432               Resampler::Filter filterType,
433               int               numChannels,
434               bool              hasAlpha);
435
436 /**
437  * @brief Rotates the input image with an implementation of the 'Rotate by Shear' algorithm.
438  *
439  * @pre @p pixelsIn must not alias @p pixelsOut. The input image should be a totally
440  * separate buffer from the output buffer.
441  *
442  * @note This function allocates memory in @p pixelsOut which has to be released by calling @e free()
443  *
444  * @param[in] pixelsIn The input buffer.
445  * @param[in] widthIn The width of the input buffer.
446  * @param[in] heightIn The height of the input buffer.
447  * @param[in] strideIn The stride of the input buffer.
448  * @param[in] pixelSize The size of the pixel.
449  * @param[in] radians The rotation angle in radians.
450  * @param[out] pixelsOut The rotated output buffer.
451  * @param[out] widthOut The width of the output buffer.
452  * @param[out] heightOut The height of the output buffer.
453  */
454 void RotateByShear(const uint8_t* const pixelsIn,
455                    uint32_t             widthIn,
456                    uint32_t             heightIn,
457                    uint32_t             strideIn,
458                    uint32_t             pixelSize,
459                    float                radians,
460                    uint8_t*&            pixelsOut,
461                    uint32_t&            widthOut,
462                    uint32_t&            heightOut);
463
464 /**
465  * @brief Applies to the input image a horizontal shear transformation.
466  *
467  * @pre @p pixelsIn must not alias @p pixelsOut. The input image should be a totally
468  * separate buffer from the output buffer.
469  * @pre The maximun/minimum shear angle is +/-45 degrees (PI/4 around 0.79 radians).
470  *
471  * @note This function allocates memory in @p pixelsOut which has to be released by calling @e free()
472  *
473  * @param[in] pixelsIn The input buffer.
474  * @param[in] widthIn The width of the input buffer.
475  * @param[in] heightIn The height of the input buffer.
476  * @param[in] strideIn The stride of the input buffer.
477  * @param[in] pixelSize The size of the pixel.
478  * @param[in] radians The shear angle in radians.
479  * @param[out] pixelsOut The rotated output buffer.
480  * @param[out] widthOut The width of the output buffer.
481  * @param[out] heightOut The height of the output buffer.
482  */
483 void HorizontalShear(const uint8_t* const pixelsIn,
484                      uint32_t             widthIn,
485                      uint32_t             heightIn,
486                      uint32_t             strideIn,
487                      uint32_t             pixelSize,
488                      float                radians,
489                      uint8_t*&            pixelsOut,
490                      uint32_t&            widthOut,
491                      uint32_t&            heightOut);
492
493 /**@}*/
494
495 /**
496  * @defgroup ScalingAlgorithmFragments Composable subunits of the scaling algorithms.
497  * @{
498  */
499
500 /**
501  * @brief Average adjacent pairs of pixels, overwriting the input array.
502  * @param[in,out] pixels The array of pixels to work on.
503  * @param[i]      width  The number of pixels in the array passed-in.
504  */
505 void HalveScanlineInPlaceRGB888(uint8_t* pixels, uint32_t width);
506
507 /**
508  * @copydoc HalveScanlineInPlaceRGB888
509  */
510 void HalveScanlineInPlaceRGBA8888(uint8_t* pixels, uint32_t width);
511
512 /**
513  * @copydoc HalveScanlineInPlaceRGB888
514  */
515 void HalveScanlineInPlaceRGB565(uint8_t* pixels, uint32_t width);
516
517 /**
518  * @copydoc HalveScanlineInPlaceRGB888
519  */
520 void HalveScanlineInPlace2Bytes(uint8_t* pixels, uint32_t width);
521
522 /**
523  * @copydoc HalveScanlineInPlaceRGB888
524  */
525 void HalveScanlineInPlace1Byte(uint8_t* pixels, uint32_t width);
526
527 /**
528  * @brief Average pixels at corresponding offsets in two scanlines.
529  *
530  * outputScanline is allowed to alias scanline1.
531  * @param[in] scanline1 First scanline of pixels to average.
532  * @param[in] scanline2 Second scanline of pixels to average.
533  * @param[out] outputScanline Destination for the averaged pixels.
534  * @param[in] width The widths of all the scanlines passed-in.
535  */
536 void AverageScanlines1(const uint8_t* scanline1,
537                        const uint8_t* scanline2,
538                        uint8_t*       outputScanline,
539                        /** Image width in pixels (1 byte == 1 pixel: e.g. lum8 or alpha8).*/
540                        uint32_t width);
541
542 /**
543  * @copydoc AverageScanlines1
544  */
545 void AverageScanlines2(const uint8_t* scanline1,
546                        const uint8_t* scanline2,
547                        uint8_t*       outputScanline,
548                        /** Image width in pixels (2 bytes == 1 pixel: e.g. lum8alpha8).*/
549                        uint32_t width);
550
551 /**
552  * @copydoc AverageScanlines1
553  */
554 void AverageScanlines3(const uint8_t* scanline1,
555                        const uint8_t* scanline2,
556                        uint8_t*       outputScanline,
557                        /** Image width in pixels (3 bytes == 1 pixel: e.g. RGB888).*/
558                        uint32_t width);
559
560 /**
561  * @copydoc AverageScanlines1
562  */
563 void AverageScanlinesRGBA8888(const uint8_t* scanline1,
564                               const uint8_t* scanline2,
565                               uint8_t*       outputScanline,
566                               uint32_t       width);
567
568 /**
569  * @copydoc AverageScanlines1
570  */
571 void AverageScanlinesRGB565(const uint8_t* scanline1,
572                             const uint8_t* scanline2,
573                             uint8_t*       outputScanline,
574                             uint32_t       width);
575 /**@}*/
576
577 /**
578  * @defgroup TestableInlines Inline functions exposed in header to allow unit testing.
579  * @{
580  */
581
582 /**
583  * @brief Average two integer arguments.
584  * @return The average of two uint arguments.
585  * @param[in] a First component to average.
586  * @param[in] b Second component to average.
587  **/
588 inline uint32_t AverageComponent(uint32_t a, uint32_t b)
589 {
590   uint32_t avg = (a + b) >> 1u;
591   return avg;
592 }
593
594 /**
595  * @brief Average a pair of RGBA8888 pixels.
596  * @return The average of two RGBA8888 pixels.
597  * @param[in] a First pixel to average.
598  * @param[in] b Second pixel to average
599  **/
600 inline uint32_t AveragePixelRGBA8888(uint32_t a, uint32_t b)
601 {
602   /**
603    * @code
604    * const uint32_t avg =
605    *   (AverageComponent((a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u) << 1u) & 0xff000000) +
606    *   (AverageComponent(a & 0x00ff0000, b & 0x00ff0000) & 0x00ff0000) +
607    *   (AverageComponent(a & 0x0000ff00, b & 0x0000ff00) & 0x0000ff00) +
608    *   (AverageComponent(a & 0x000000ff, b & 0x000000ff);
609    * return avg;
610    * @endcode
611    */
612   return (((a ^ b) & 0xfefefefeu) >> 1) + (a & b);
613   ///@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.
614 }
615
616 /**
617  * @brief Average a pair of RGB565 pixels.
618  * @param a[in] Low 16 bits hold a color value as RGB565 to average with parameter b.
619  * @param b[in] Low 16 bits hold a color value as RGB565 to average with parameter a.
620  * @return The average color of the two RGB565 pixels passed in, in the low 16 bits of the returned value.
621  **/
622 inline uint32_t AveragePixelRGB565(uint32_t a, uint32_t b)
623 {
624   /**
625    * @code
626    * const uint32_t avg =
627    *   (AverageComponent(a & 0xf800, b & 0xf800) & 0xf800) +
628    *   (AverageComponent(a & 0x7e0, b & 0x7e0) & 0x7e0) +
629    *   (AverageComponent(a & 0x1f, b & 0x1f));
630    * return avg;
631    * @endcode
632    */
633   return (((a ^ b) & 0xf7deu) >> 1) + (a & b);
634 }
635
636 /** @return The weighted blend of two integers as a 16.16 fixed-point number, given a 0.16 fixed-point blending factor. */
637 inline uint32_t WeightedBlendIntToFixed1616(uint32_t a, uint32_t b, uint32_t fractBlend)
638 {
639   DALI_ASSERT_DEBUG(fractBlend <= 65535u && "Factor should be in 0.16 fixed-point.");
640   /**
641    * @code
642    * const uint32_t weightedAFixed = a * (65535u - fractBlend);
643    * const uint32_t weightedBFixed = b * fractBlend;
644    * const unsigned     blended        = (weightedAFixed + weightedBFixed);
645    * @endcode
646    */
647   const uint32_t blended = (a << 16) - a + (static_cast<int32_t>(b) - static_cast<int32_t>(a)) * fractBlend;
648   return blended;
649 }
650
651 /** @brief Blend two 16.16 inputs to give a 16.32 output. */
652 inline uint64_t WeightedBlendFixed1616ToFixed1632(uint32_t a, uint32_t b, uint32_t fractBlend)
653 {
654   DALI_ASSERT_DEBUG(fractBlend <= 65535u && "Factor should be in 0.16 fixed-point.");
655   /**
656    * @code
657    * // Blend while promoting intermediates to 16.32 fixed point:
658    * const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
659    * const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
660    * const uint64_t blended        = (weightedAFixed + weightedBFixed);
661    * @endcode
662    */
663   const uint64_t blended = (static_cast<uint64_t>(a) << 16) - a + (static_cast<int64_t>(b) - static_cast<int64_t>(a)) * fractBlend;
664   return blended;
665 }
666
667 /**
668  * @brief Blend 4 taps into one value using horizontal and vertical weights.
669  */
670 inline uint32_t BilinearFilter1Component(uint32_t tl, uint32_t tr, uint32_t bl, uint32_t br, uint32_t fractBlendHorizontal, uint32_t fractBlendVertical)
671 {
672   DALI_ASSERT_DEBUG(fractBlendHorizontal <= 65535u && "Factor should be in 0.16 fixed-point.");
673   DALI_ASSERT_DEBUG(fractBlendVertical <= 65535u && "Factor should be in 0.16 fixed-point.");
674
675   /**
676    * @code
677    * const uint32_t topBlend   = WeightedBlendIntToFixed1616(tl, tr, fractBlendHorizontal);
678    * const uint32_t botBlend   = WeightedBlendIntToFixed1616(bl, br, fractBlendHorizontal);
679    * const uint64_t     blended2x2 = WeightedBlendFixed1616ToFixed1632(topBlend, botBlend, fractBlendVertical);
680    * const uint32_t rounded    = (blended2x2 + (1u << 31u)) >> 32u;
681    * @endcode
682    */
683
684   /**
685    * Hard-coding optimize!
686    *
687    * Let p = 65536, s.t we can optimze it as << 16.
688    * Let x = fractBlendHorizontal, y = fractBlendVertical.
689    * topBlend = (tl*p - tl - tl*x + tr*x)
690    * botBlend = (bl*p - bl - bl*x + br*x)
691    * blended2x2 = topBlend*p - topBlend - topBlend*y + botBlend*y
692    *
693    * And now we can split all values.
694    * tl*p*p - tl*p - tl*x*p + tr*x*p  -  tl*p + tl + tl*x - tr*x  -  tl*y*p + tl*y + tl*x*y - tr*x*y  +  bl*y*p - bl*y - bl*x*y + br*x*y;
695    * --> (collect by p, x, and y)
696    * (tl)*p*p + (-2tl + (-tl + tr)*x + (-tl+bl)*y)*p + tl + (tl - tr)*x + (tl - bl)*y + (tl - tr - bl + br)*x*y
697    *
698    * A = (tl - tr) * x;
699    * B = (tl - bl) * y;
700    * C = (tl - tr - bl + br) * x * y;
701    * D = (2*tl + A + B)
702    * -->
703    * (tl << 32) - (D << 16) + tl + A + B + C
704    *
705    * Becareful of overflow and negative value.
706    */
707   const int32_t A = (static_cast<int32_t>(tl) - static_cast<int32_t>(tr)) * static_cast<int32_t>(fractBlendHorizontal);
708   const int32_t B = (static_cast<int32_t>(tl) - static_cast<int32_t>(bl)) * static_cast<int32_t>(fractBlendVertical);
709   const int64_t C = (static_cast<int64_t>(tl) - static_cast<int64_t>(tr) - static_cast<int64_t>(bl) + static_cast<int64_t>(br)) * static_cast<int64_t>(fractBlendHorizontal) * static_cast<int64_t>(fractBlendVertical);
710   const int64_t D = ((static_cast<int64_t>(tl) << 1) + A + B);
711
712   const uint64_t blended2x2 = (static_cast<int64_t>(tl) << 32u) - (D << 16u) + tl + A + B + C;
713   const uint32_t rounded    = static_cast<uint32_t>((blended2x2 + (1u << 31u)) >> 32u);
714   return rounded;
715 }
716
717 /**
718  * @brief Fast multiply & divide by 255. It wiil be useful when we applying alpha value in color
719  *
720  * @param x The value between [0..255]
721  * @param y The value between [0..255]
722  * @return (x*y)/255
723  */
724 inline uint8_t MultiplyAndNormalizeColor(const uint8_t x, const uint8_t y) noexcept
725 {
726   const uint32_t xy = static_cast<const uint32_t>(x) * y;
727   return ((xy << 15) + (xy << 7) + xy) >> 23;
728 }
729
730 /**
731  * @brief Fast division by 17 and roundup. It will be useful when we compress 8bit luminance value as 4bit for text glyph.
732  *
733  * @param x The value between [0..255]
734  * @return round(x / 17.0f).(same as (x+8)/17)
735  */
736 inline uint8_t CompressBitPerPixel8To4(const uint8_t x) noexcept
737 {
738   return ((((static_cast<const uint16_t>(x) << 4) - x + (x >> 4)) >> 7) + 1) >> 1;
739 }
740
741 /**@}*/
742
743 } /* namespace Platform */
744 } /* namespace Internal */
745 } /* namespace Dali */
746
747 #endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H */