[4.0] Rotate() method added to the PixelBuffer.
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / portable / image-operations.h
1 /*
2  * Copyright (c) 2018 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 <resampler.h>
28
29 #ifdef DALI_ADAPTOR_COMPILATION
30 #include <adaptors/devel-api/adaptor-framework/pixel-buffer.h>
31 #else
32 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
33 #endif
34
35
36 namespace Dali
37 {
38 namespace Internal
39 {
40 namespace Platform
41 {
42
43 /**
44  * @brief Identify which combination of x and y dimensions matter in terminating iterative box filtering.
45  */
46 enum BoxDimensionTest
47 {
48   BoxDimensionTestEither,
49   BoxDimensionTestBoth,
50   BoxDimensionTestX,
51   BoxDimensionTestY
52 };
53
54 /**
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.
58   */
59 typedef Uint16Pair ImageDimensions;
60
61 /**
62  * @brief Work out the true desired width and height, accounting for special
63  * rules for zeros in either or both input requested dimensions.
64  *
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.
68  */
69 ImageDimensions CalculateDesiredDimensions( ImageDimensions rawDimensions, ImageDimensions requestedDimensions );
70
71 /**
72  * @defgroup BitmapOperations Bitmap-to-Bitmap Image operations.
73  * @{
74  */
75
76 /**
77  * @brief Apply requested attributes to bitmap.
78  *
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,
82  * ready for use.
83  *
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
88  *         have no effect.
89  */
90 Dali::Devel::PixelBuffer ApplyAttributesToBitmap( Dali::Devel::PixelBuffer bitmap, ImageDimensions dimensions, FittingMode::Type fittingMode = FittingMode::DEFAULT, SamplingMode::Type samplingMode = SamplingMode::DEFAULT );
91
92 /**
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.
95  **/
96 Dali::Devel::PixelBuffer DownscaleBitmap( Dali::Devel::PixelBuffer bitmap,
97                                           ImageDimensions desired,
98                                           FittingMode::Type fittingMode,
99                                           SamplingMode::Type samplingMode );
100 /**@}*/
101
102 /**
103  * @defgroup ImageBufferScalingAlgorithms Pixel buffer-level scaling algorithms.
104  * @{
105  */
106
107 /**
108  * @brief Destructive in-place downscaling by a power of 2 factor.
109  *
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
112  * dimensions.
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.
121  */
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,
130                            unsigned& outWidth,
131                            unsigned& outHeight );
132
133 /**
134  * @brief Destructive in-place downscaling by a power of 2 factor.
135  *
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
138  * dimensions.
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.
146  */
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 );
155
156 /**
157  * @copydoc DownscaleInPlacePow2RGB888
158  */
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 );
167
168 /**
169  * @copydoc DownscaleInPlacePow2RGB888
170  *
171  * For the 2-byte packed 16 bit format RGB565.
172  */
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 );
181
182 /**
183  * @copydoc DownscaleInPlacePow2RGB888
184  *
185  * For 2-byte formats such as lum8alpha8, but not packed 16 bit formats like RGB565.
186  */
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 );
195
196 /**
197  * @copydoc DownscaleInPlacePow2RGB888
198  *
199  * For single-byte formats such as lum8 or alpha8.
200  */
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 );
209
210 /**
211  * @brief Rescales an input image into the exact output dimensions passed-in.
212  *
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.
217  */
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 );
225
226 /**
227  * @copydoc PointSample
228  *
229  * Specialised for 4-byte formats like RGBA8888 and BGRA8888.
230  */
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 );
237
238 /**
239  * @copydoc PointSample
240  *
241  * Specialised for 3-byte formats like RGB888 and BGR888.
242  */
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 );
249
250 /**
251  * @copydoc PointSample
252  *
253  * Specialised for 2-byte formats like LA88.
254  */
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 );
261
262 /**
263  * @copydoc PointSample
264  *
265  * Specialised for 1-byte formats like L8 and A8.
266  */
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 );
273
274 /**
275  * @brief Resample input image to output image using a bilinear filter.
276  *
277  * Each output pixel is formed of a weighted sum of a 2x2 block of four input
278  * pixels
279  * @pre inPixels must not alias outPixels. The input image should be a totally
280  * separate buffer from the input one.
281  */
282 void LinearSample( const unsigned char * __restrict__ inPixels,
283                    ImageDimensions inDimensions,
284                    Pixel::Format pixelFormat,
285                    unsigned char * __restrict__ outPixels,
286                    ImageDimensions outDimensions );
287
288 /**
289  * @copydoc LinearSample
290  *
291  * Specialised for one byte per pixel formats.
292  */
293 void LinearSample1BPP( const unsigned char * __restrict__ inPixels,
294                        ImageDimensions inputDimensions,
295                        unsigned char * __restrict__ outPixels,
296                        ImageDimensions desiredDimensions );
297
298 /**
299  * @copydoc LinearSample
300  *
301  * Specialised for two byte per pixel formats.
302  */
303 void LinearSample2BPP( const unsigned char * __restrict__ inPixels,
304                        ImageDimensions inputDimensions,
305                        unsigned char * __restrict__ outPixels,
306                        ImageDimensions desiredDimensions );
307
308 /**
309  * @copydoc LinearSample
310  *
311  * Specialised for RGB565 16 bit pixel format.
312  */
313 void LinearSampleRGB565( const unsigned char * __restrict__ inPixels,
314                        ImageDimensions inputDimensions,
315                        unsigned char * __restrict__ outPixels,
316                        ImageDimensions desiredDimensions );
317
318 /**
319  * @copydoc LinearSample
320  *
321  * Specialised for three byte per pixel formats like RGB888.
322  */
323 void LinearSample3BPP( const unsigned char * __restrict__ inPixels,
324                        ImageDimensions inputDimensions,
325                        unsigned char * __restrict__ outPixels,
326                        ImageDimensions desiredDimensions );
327
328 /**
329  * @copydoc LinearSample
330  *
331  * Specialised for four byte per pixel formats like RGBA8888.
332  * @note, If used on RGBA8888, the A component will be blended independently.
333  */
334 void LinearSample4BPP( const unsigned char * __restrict__ inPixels,
335                        ImageDimensions inputDimensions,
336                        unsigned char * __restrict__ outPixels,
337                        ImageDimensions desiredDimensions );
338
339 /**
340  * @brief Resamples the input image with the Lanczos algorithm.
341  *
342  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
343  * separate buffer from the output buffer.
344  *
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.
349  */
350 void LanczosSample4BPP( const unsigned char * __restrict__ inPixels,
351                         ImageDimensions inputDimensions,
352                         unsigned char * __restrict__ outPixels,
353                         ImageDimensions desiredDimensions );
354
355 /**
356  * @brief Resamples the input image with the Lanczos algorithm.
357  *
358  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
359  * separate buffer from the output buffer.
360  *
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.
365  */
366 void LanczosSample1BPP( const unsigned char * __restrict__ inPixels,
367                         ImageDimensions inputDimensions,
368                         unsigned char * __restrict__ outPixels,
369                         ImageDimensions desiredDimensions );
370
371 /**
372  * @brief Resamples the input image with the Lanczos algorithm.
373  *
374  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
375  * separate buffer from the output buffer.
376  *
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.
381  */
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 );
388
389
390 /**
391  * @brief Rotates the input image with an implementation of the 'Rotate by Shear' algorithm.
392  *
393  * @param[in] pixelsIn The input buffer.
394  * @param[in] widthIn The width of the input buffer.
395  * @param[in] heightIn The height of the input buffer.
396  * @param[in] pixelSize The size of the pixel.
397  * @param[in] radians The rotation angle in radians.
398  * @param[out] pixelsOut The rotated output buffer.
399  * @param[out] widthOut The width of the output buffer.
400  * @param[out] heightOut The height of the output buffer.
401  */
402 void RotateByShear( const uint8_t* const pixelsIn,
403                     unsigned int widthIn,
404                     unsigned int heightIn,
405                     unsigned int pixelSize,
406                     float radians,
407                     uint8_t*& pixelsOut,
408                     unsigned int& widthOut,
409                     unsigned int& heightOut );
410
411 /**@}*/
412
413 /**
414  * @defgroup ScalingAlgorithmFragments Composable subunits of the scaling algorithms.
415  * @{
416  */
417
418 /**
419  * @brief Average adjacent pairs of pixels, overwriting the input array.
420  * @param[in,out] pixels The array of pixels to work on.
421  * @param[i]      width  The number of pixels in the array passed-in.
422  */
423 void HalveScanlineInPlaceRGB888( unsigned char * pixels, unsigned int width );
424
425 /**
426  * @copydoc HalveScanlineInPlaceRGB888
427  */
428 void HalveScanlineInPlaceRGBA8888( unsigned char * pixels, unsigned int width );
429
430 /**
431  * @copydoc HalveScanlineInPlaceRGB888
432  */
433 void HalveScanlineInPlaceRGB565( unsigned char * pixels, unsigned int width );
434
435 /**
436  * @copydoc HalveScanlineInPlaceRGB888
437  */
438 void HalveScanlineInPlace2Bytes( unsigned char * pixels, unsigned int width );
439
440 /**
441  * @copydoc HalveScanlineInPlaceRGB888
442  */
443 void HalveScanlineInPlace1Byte( unsigned char * pixels, unsigned int width );
444
445 /**
446  * @brief Average pixels at corresponding offsets in two scanlines.
447  *
448  * outputScanline is allowed to alias scanline1.
449  * @param[in] scanline1 First scanline of pixels to average.
450  * @param[in] scanline2 Second scanline of pixels to average.
451  * @param[out] outputScanline Destination for the averaged pixels.
452  * @param[in] width The widths of all the scanlines passed-in.
453  */
454 void AverageScanlines1( const unsigned char * scanline1,
455                         const unsigned char * scanline2,
456                         unsigned char* outputScanline,
457                         /** Image width in pixels (1 byte == 1 pixel: e.g. lum8 or alpha8).*/
458                         unsigned int width );
459
460 /**
461  * @copydoc AverageScanlines1
462  */
463 void AverageScanlines2( const unsigned char * scanline1,
464                         const unsigned char * scanline2,
465                         unsigned char* outputScanline,
466                         /** Image width in pixels (2 bytes == 1 pixel: e.g. lum8alpha8).*/
467                         unsigned int width );
468
469 /**
470  * @copydoc AverageScanlines1
471  */
472 void AverageScanlines3( const unsigned char * scanline1,
473                         const unsigned char * scanline2,
474                         unsigned char* outputScanline,
475                         /** Image width in pixels (3 bytes == 1 pixel: e.g. RGB888).*/
476                         unsigned int width );
477
478 /**
479  * @copydoc AverageScanlines1
480  */
481 void AverageScanlinesRGBA8888( const unsigned char * scanline1,
482                                const unsigned char * scanline2,
483                                unsigned char * outputScanline,
484                                unsigned int width );
485
486 /**
487  * @copydoc AverageScanlines1
488  */
489 void AverageScanlinesRGB565( const unsigned char * scanline1,
490                              const unsigned char * scanline2,
491                              unsigned char* outputScanline,
492                              unsigned int width );
493 /**@}*/
494
495 /**
496  * @defgroup TestableInlines Inline functions exposed in header to allow unit testing.
497  * @{
498  */
499
500 /**
501  * @brief Average two integer arguments.
502  * @return The average of two uint arguments.
503  * @param[in] a First component to average.
504  * @param[in] b Second component to average.
505  **/
506 inline unsigned int AverageComponent( unsigned int a, unsigned int b )
507 {
508   unsigned int avg = (a + b) >> 1u;
509   return avg;
510 }
511
512 /**
513  * @brief Average a pair of RGBA8888 pixels.
514  * @return The average of two RGBA8888 pixels.
515  * @param[in] a First pixel to average.
516  * @param[in] b Second pixel to average
517  **/
518 inline uint32_t AveragePixelRGBA8888( uint32_t a, uint32_t b )
519 {
520   const unsigned int avg =
521     ((AverageComponent( (a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u ) << 1u) & 0xff000000 ) +
522     (AverageComponent( a & 0x00ff0000, b & 0x00ff0000 ) & 0x00ff0000 ) +
523     (AverageComponent( a & 0x0000ff00, b & 0x0000ff00 ) & 0x0000ff00 ) +
524     (AverageComponent( a & 0x000000ff, b & 0x000000ff ) );
525   return avg;
526   ///@ToDo: Optimise by trying return (((a ^ b) & 0xfefefefeUL) >> 1) + (a & b);
527   ///@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.
528 }
529
530 /**
531  * @brief Average a pair of RGB565 pixels.
532  * @param a[in] Low 16 bits hold a color value as RGB565 to average with parameter b.
533  * @param b[in] Low 16 bits hold a color value as RGB565 to average with parameter a.
534  * @return The average color of the two RGB565 pixels passed in, in the low 16 bits of the returned value.
535  **/
536 inline uint32_t AveragePixelRGB565( uint32_t a, uint32_t b )
537 {
538   const unsigned int avg =
539     (AverageComponent( a & 0xf800, b & 0xf800 ) & 0xf800 ) +
540     (AverageComponent( a & 0x7e0,  b & 0x7e0 )  & 0x7e0 ) +
541     (AverageComponent( a & 0x1f,   b & 0x1f ) );
542   return avg;
543 }
544
545 /** @return The weighted blend of two integers as a 16.16 fixed-point number, given a 0.16 fixed-point blending factor. */
546 inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b, unsigned int fractBlend )
547 {
548   DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
549   const unsigned int weightedAFixed = a * (65535u - fractBlend);
550   const unsigned int weightedBFixed = b * fractBlend;
551   const unsigned blended = (weightedAFixed + weightedBFixed);
552   return blended;
553 }
554
555 /** @brief Blend two 16.16 inputs to give a 16.32 output. */
556 inline uint64_t WeightedBlendFixed1616ToFixed1632(unsigned int a, unsigned int b, unsigned int fractBlend )
557 {
558   DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
559   // Blend while promoting intermediates to 16.32 fixed point:
560   const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
561   const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
562   const uint64_t blended = (weightedAFixed + weightedBFixed);
563   return blended;
564 }
565
566 /**
567  * @brief Blend 4 taps into one value using horizontal and vertical weights.
568  */
569 inline unsigned int BilinearFilter1Component(unsigned int tl, unsigned int tr, unsigned int bl, unsigned int br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
570 {
571   DALI_ASSERT_DEBUG( fractBlendHorizontal <= 65535u && "Factor should be in 0.16 fixed-point." );
572   DALI_ASSERT_DEBUG( fractBlendVertical   <= 65535u && "Factor should be in 0.16 fixed-point." );
573
574   const unsigned int topBlend = WeightedBlendIntToFixed1616( tl, tr, fractBlendHorizontal );
575   const unsigned int botBlend = WeightedBlendIntToFixed1616( bl, br, fractBlendHorizontal );
576   const uint64_t blended2x2 = WeightedBlendFixed1616ToFixed1632( topBlend, botBlend, fractBlendVertical );
577   const unsigned int rounded = (blended2x2 + (1u << 31u) ) >> 32u;
578   return rounded;
579 }
580
581 /**@}*/
582
583 } /* namespace Platform */
584 } /* namespace Internal */
585 } /* namespace Dali */
586
587 #endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_ */