Text improvement
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / common / image-operations.h
1 /*
2  * Copyright (c) 2019 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/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>
29
30 namespace Dali
31 {
32 namespace Internal
33 {
34 namespace Platform
35 {
36
37 /**
38  * @brief Identify which combination of x and y dimensions matter in terminating iterative box filtering.
39  */
40 enum BoxDimensionTest
41 {
42   BoxDimensionTestEither,
43   BoxDimensionTestBoth,
44   BoxDimensionTestX,
45   BoxDimensionTestY
46 };
47
48 /**
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.
52   */
53 typedef Uint16Pair ImageDimensions;
54
55 /**
56  * @brief Work out the true desired width and height, accounting for special
57  * rules for zeros in either or both input requested dimensions.
58  *
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.
62  */
63 ImageDimensions CalculateDesiredDimensions( ImageDimensions rawDimensions, ImageDimensions requestedDimensions );
64
65 /**
66  * @defgroup BitmapOperations Bitmap-to-Bitmap Image operations.
67  * @{
68  */
69
70 /**
71  * @brief Apply requested attributes to bitmap.
72  *
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,
76  * ready for use.
77  *
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
82  *         have no effect.
83  */
84 Dali::Devel::PixelBuffer ApplyAttributesToBitmap( Dali::Devel::PixelBuffer bitmap, ImageDimensions dimensions, FittingMode::Type fittingMode = FittingMode::DEFAULT, SamplingMode::Type samplingMode = SamplingMode::DEFAULT );
85
86 /**
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.
89  **/
90 Dali::Devel::PixelBuffer DownscaleBitmap( Dali::Devel::PixelBuffer bitmap,
91                                           ImageDimensions desired,
92                                           FittingMode::Type fittingMode,
93                                           SamplingMode::Type samplingMode );
94 /**@}*/
95
96 /**
97  * @defgroup ImageBufferScalingAlgorithms Pixel buffer-level scaling algorithms.
98  * @{
99  */
100
101 /**
102  * @brief Destructive in-place downscaling by a power of 2 factor.
103  *
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
106  * dimensions.
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.
115  */
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,
124                            unsigned& outWidth,
125                            unsigned& outHeight );
126
127 /**
128  * @brief Destructive in-place downscaling by a power of 2 factor.
129  *
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
132  * dimensions.
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.
140  */
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 );
149
150 /**
151  * @copydoc DownscaleInPlacePow2RGB888
152  */
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 );
161
162 /**
163  * @copydoc DownscaleInPlacePow2RGB888
164  *
165  * For the 2-byte packed 16 bit format RGB565.
166  */
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 );
175
176 /**
177  * @copydoc DownscaleInPlacePow2RGB888
178  *
179  * For 2-byte formats such as lum8alpha8, but not packed 16 bit formats like RGB565.
180  */
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 );
189
190 /**
191  * @copydoc DownscaleInPlacePow2RGB888
192  *
193  * For single-byte formats such as lum8 or alpha8.
194  */
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 );
203
204 /**
205  * @brief Rescales an input image into the exact output dimensions passed-in.
206  *
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.
211  */
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 );
219
220 /**
221  * @copydoc PointSample
222  *
223  * Specialised for 4-byte formats like RGBA8888 and BGRA8888.
224  */
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 );
231
232 /**
233  * @copydoc PointSample
234  *
235  * Specialised for 3-byte formats like RGB888 and BGR888.
236  */
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 );
243
244 /**
245  * @copydoc PointSample
246  *
247  * Specialised for 2-byte formats like LA88.
248  */
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 );
255
256 /**
257  * @copydoc PointSample
258  *
259  * Specialised for 1-byte formats like L8 and A8.
260  */
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 );
267
268 /**
269  * @brief Resample input image to output image using a bilinear filter.
270  *
271  * Each output pixel is formed of a weighted sum of a 2x2 block of four input
272  * pixels
273  * @pre inPixels must not alias outPixels. The input image should be a totally
274  * separate buffer from the input one.
275  */
276 void LinearSample( const unsigned char * __restrict__ inPixels,
277                    ImageDimensions inDimensions,
278                    Pixel::Format pixelFormat,
279                    unsigned char * __restrict__ outPixels,
280                    ImageDimensions outDimensions );
281
282 /**
283  * @copydoc LinearSample
284  *
285  * Specialised for one byte per pixel formats.
286  */
287 void LinearSample1BPP( const unsigned char * __restrict__ inPixels,
288                        ImageDimensions inputDimensions,
289                        unsigned char * __restrict__ outPixels,
290                        ImageDimensions desiredDimensions );
291
292 /**
293  * @copydoc LinearSample
294  *
295  * Specialised for two byte per pixel formats.
296  */
297 void LinearSample2BPP( const unsigned char * __restrict__ inPixels,
298                        ImageDimensions inputDimensions,
299                        unsigned char * __restrict__ outPixels,
300                        ImageDimensions desiredDimensions );
301
302 /**
303  * @copydoc LinearSample
304  *
305  * Specialised for RGB565 16 bit pixel format.
306  */
307 void LinearSampleRGB565( const unsigned char * __restrict__ inPixels,
308                        ImageDimensions inputDimensions,
309                        unsigned char * __restrict__ outPixels,
310                        ImageDimensions desiredDimensions );
311
312 /**
313  * @copydoc LinearSample
314  *
315  * Specialised for three byte per pixel formats like RGB888.
316  */
317 void LinearSample3BPP( const unsigned char * __restrict__ inPixels,
318                        ImageDimensions inputDimensions,
319                        unsigned char * __restrict__ outPixels,
320                        ImageDimensions desiredDimensions );
321
322 /**
323  * @copydoc LinearSample
324  *
325  * Specialised for four byte per pixel formats like RGBA8888.
326  * @note, If used on RGBA8888, the A component will be blended independently.
327  */
328 void LinearSample4BPP( const unsigned char * __restrict__ inPixels,
329                        ImageDimensions inputDimensions,
330                        unsigned char * __restrict__ outPixels,
331                        ImageDimensions desiredDimensions );
332
333 /**
334  * @brief Resamples the input image with the Lanczos algorithm.
335  *
336  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
337  * separate buffer from the output buffer.
338  *
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.
343  */
344 void LanczosSample4BPP( const unsigned char * __restrict__ inPixels,
345                         ImageDimensions inputDimensions,
346                         unsigned char * __restrict__ outPixels,
347                         ImageDimensions desiredDimensions );
348
349 /**
350  * @brief Resamples the input image with the Lanczos algorithm.
351  *
352  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
353  * separate buffer from the output buffer.
354  *
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.
359  */
360 void LanczosSample1BPP( const unsigned char * __restrict__ inPixels,
361                         ImageDimensions inputDimensions,
362                         unsigned char * __restrict__ outPixels,
363                         ImageDimensions desiredDimensions );
364
365 /**
366  * @brief Resamples the input image with the Lanczos algorithm.
367  *
368  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
369  * separate buffer from the output buffer.
370  *
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.
375  */
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 );
382
383
384 /**
385  * @brief Rotates the input image with an implementation of the 'Rotate by Shear' algorithm.
386  *
387  * @pre @p pixelsIn must not alias @p pixelsOut. The input image should be a totally
388  * separate buffer from the output buffer.
389  *
390  * @note This function allocates memory in @p pixelsOut which has to be released by calling @e free()
391  *
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.
400  */
401 void RotateByShear( const uint8_t* const pixelsIn,
402                     unsigned int widthIn,
403                     unsigned int heightIn,
404                     unsigned int pixelSize,
405                     float radians,
406                     uint8_t*& pixelsOut,
407                     unsigned int& widthOut,
408                     unsigned int& heightOut );
409
410 /**
411  * @brief Applies to the input image a horizontal shear transformation.
412  *
413  * @pre @p pixelsIn must not alias @p pixelsOut. The input image should be a totally
414  * separate buffer from the output buffer.
415  * @pre The maximun/minimum shear angle is +/-45 degrees (PI/4 around 0.79 radians).
416  *
417  * @note This function allocates memory in @p pixelsOut which has to be released by calling @e free()
418  *
419  * @param[in] pixelsIn The input buffer.
420  * @param[in] widthIn The width of the input buffer.
421  * @param[in] heightIn The height of the input buffer.
422  * @param[in] pixelSize The size of the pixel.
423  * @param[in] radians The shear angle in radians.
424  * @param[out] pixelsOut The rotated output buffer.
425  * @param[out] widthOut The width of the output buffer.
426  * @param[out] heightOut The height of the output buffer.
427  */
428 void HorizontalShear( const uint8_t* const pixelsIn,
429                       unsigned int widthIn,
430                       unsigned int heightIn,
431                       unsigned int pixelSize,
432                       float radians,
433                       uint8_t*& pixelsOut,
434                       unsigned int& widthOut,
435                       unsigned int& heightOut );
436
437 /**@}*/
438
439 /**
440  * @defgroup ScalingAlgorithmFragments Composable subunits of the scaling algorithms.
441  * @{
442  */
443
444 /**
445  * @brief Average adjacent pairs of pixels, overwriting the input array.
446  * @param[in,out] pixels The array of pixels to work on.
447  * @param[i]      width  The number of pixels in the array passed-in.
448  */
449 void HalveScanlineInPlaceRGB888( unsigned char * pixels, unsigned int width );
450
451 /**
452  * @copydoc HalveScanlineInPlaceRGB888
453  */
454 void HalveScanlineInPlaceRGBA8888( unsigned char * pixels, unsigned int width );
455
456 /**
457  * @copydoc HalveScanlineInPlaceRGB888
458  */
459 void HalveScanlineInPlaceRGB565( unsigned char * pixels, unsigned int width );
460
461 /**
462  * @copydoc HalveScanlineInPlaceRGB888
463  */
464 void HalveScanlineInPlace2Bytes( unsigned char * pixels, unsigned int width );
465
466 /**
467  * @copydoc HalveScanlineInPlaceRGB888
468  */
469 void HalveScanlineInPlace1Byte( unsigned char * pixels, unsigned int width );
470
471 /**
472  * @brief Average pixels at corresponding offsets in two scanlines.
473  *
474  * outputScanline is allowed to alias scanline1.
475  * @param[in] scanline1 First scanline of pixels to average.
476  * @param[in] scanline2 Second scanline of pixels to average.
477  * @param[out] outputScanline Destination for the averaged pixels.
478  * @param[in] width The widths of all the scanlines passed-in.
479  */
480 void AverageScanlines1( const unsigned char * scanline1,
481                         const unsigned char * scanline2,
482                         unsigned char* outputScanline,
483                         /** Image width in pixels (1 byte == 1 pixel: e.g. lum8 or alpha8).*/
484                         unsigned int width );
485
486 /**
487  * @copydoc AverageScanlines1
488  */
489 void AverageScanlines2( const unsigned char * scanline1,
490                         const unsigned char * scanline2,
491                         unsigned char* outputScanline,
492                         /** Image width in pixels (2 bytes == 1 pixel: e.g. lum8alpha8).*/
493                         unsigned int width );
494
495 /**
496  * @copydoc AverageScanlines1
497  */
498 void AverageScanlines3( const unsigned char * scanline1,
499                         const unsigned char * scanline2,
500                         unsigned char* outputScanline,
501                         /** Image width in pixels (3 bytes == 1 pixel: e.g. RGB888).*/
502                         unsigned int width );
503
504 /**
505  * @copydoc AverageScanlines1
506  */
507 void AverageScanlinesRGBA8888( const unsigned char * scanline1,
508                                const unsigned char * scanline2,
509                                unsigned char * outputScanline,
510                                unsigned int width );
511
512 /**
513  * @copydoc AverageScanlines1
514  */
515 void AverageScanlinesRGB565( const unsigned char * scanline1,
516                              const unsigned char * scanline2,
517                              unsigned char* outputScanline,
518                              unsigned int width );
519 /**@}*/
520
521 /**
522  * @defgroup TestableInlines Inline functions exposed in header to allow unit testing.
523  * @{
524  */
525
526 /**
527  * @brief Average two integer arguments.
528  * @return The average of two uint arguments.
529  * @param[in] a First component to average.
530  * @param[in] b Second component to average.
531  **/
532 inline unsigned int AverageComponent( unsigned int a, unsigned int b )
533 {
534   unsigned int avg = (a + b) >> 1u;
535   return avg;
536 }
537
538 /**
539  * @brief Average a pair of RGBA8888 pixels.
540  * @return The average of two RGBA8888 pixels.
541  * @param[in] a First pixel to average.
542  * @param[in] b Second pixel to average
543  **/
544 inline uint32_t AveragePixelRGBA8888( uint32_t a, uint32_t b )
545 {
546   const unsigned int avg =
547     ((AverageComponent( (a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u ) << 1u) & 0xff000000 ) +
548     (AverageComponent( a & 0x00ff0000, b & 0x00ff0000 ) & 0x00ff0000 ) +
549     (AverageComponent( a & 0x0000ff00, b & 0x0000ff00 ) & 0x0000ff00 ) +
550     (AverageComponent( a & 0x000000ff, b & 0x000000ff ) );
551   return avg;
552   ///@ToDo: Optimise by trying return (((a ^ b) & 0xfefefefeUL) >> 1) + (a & b);
553   ///@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.
554 }
555
556 /**
557  * @brief Average a pair of RGB565 pixels.
558  * @param a[in] Low 16 bits hold a color value as RGB565 to average with parameter b.
559  * @param b[in] Low 16 bits hold a color value as RGB565 to average with parameter a.
560  * @return The average color of the two RGB565 pixels passed in, in the low 16 bits of the returned value.
561  **/
562 inline uint32_t AveragePixelRGB565( uint32_t a, uint32_t b )
563 {
564   const unsigned int avg =
565     (AverageComponent( a & 0xf800, b & 0xf800 ) & 0xf800 ) +
566     (AverageComponent( a & 0x7e0,  b & 0x7e0 )  & 0x7e0 ) +
567     (AverageComponent( a & 0x1f,   b & 0x1f ) );
568   return avg;
569 }
570
571 /** @return The weighted blend of two integers as a 16.16 fixed-point number, given a 0.16 fixed-point blending factor. */
572 inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b, unsigned int fractBlend )
573 {
574   DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
575   const unsigned int weightedAFixed = a * (65535u - fractBlend);
576   const unsigned int weightedBFixed = b * fractBlend;
577   const unsigned blended = (weightedAFixed + weightedBFixed);
578   return blended;
579 }
580
581 /** @brief Blend two 16.16 inputs to give a 16.32 output. */
582 inline uint64_t WeightedBlendFixed1616ToFixed1632(unsigned int a, unsigned int b, unsigned int fractBlend )
583 {
584   DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
585   // Blend while promoting intermediates to 16.32 fixed point:
586   const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
587   const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
588   const uint64_t blended = (weightedAFixed + weightedBFixed);
589   return blended;
590 }
591
592 /**
593  * @brief Blend 4 taps into one value using horizontal and vertical weights.
594  */
595 inline unsigned int BilinearFilter1Component(unsigned int tl, unsigned int tr, unsigned int bl, unsigned int br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
596 {
597   DALI_ASSERT_DEBUG( fractBlendHorizontal <= 65535u && "Factor should be in 0.16 fixed-point." );
598   DALI_ASSERT_DEBUG( fractBlendVertical   <= 65535u && "Factor should be in 0.16 fixed-point." );
599
600   const unsigned int topBlend = WeightedBlendIntToFixed1616( tl, tr, fractBlendHorizontal );
601   const unsigned int botBlend = WeightedBlendIntToFixed1616( bl, br, fractBlendHorizontal );
602   const uint64_t blended2x2 = WeightedBlendFixed1616ToFixed1632( topBlend, botBlend, fractBlendVertical );
603   const unsigned int rounded = (blended2x2 + (1u << 31u) ) >> 32u;
604   return rounded;
605 }
606
607 /**@}*/
608
609 } /* namespace Platform */
610 } /* namespace Internal */
611 } /* namespace Dali */
612
613 #endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H */