Merge "[4.0] DALi version 1.2.79" into tizen_4.0
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / portable / image-operations.h
1 /*
2  * Copyright (c) 2017 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 namespace Dali
30 {
31 namespace Internal
32 {
33 namespace Platform
34 {
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 Integration::BitmapPtr ApplyAttributesToBitmap( Integration::BitmapPtr 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 Integration::BitmapPtr DownscaleBitmap( Integration::Bitmap& bitmap, ImageDimensions desired, FittingMode::Type fittingMode, SamplingMode::Type samplingMode );
90 /**@}*/
91
92 /**
93  * @defgroup ImageBufferScalingAlgorithms Pixel buffer-level scaling algorithms.
94  * @{
95  */
96
97 /**
98  * @brief Destructive in-place downscaling by a power of 2 factor.
99  *
100  * A box filter with a 2x2 kernel is repeatedly applied as long as the result
101  * of the next downscaling step would not be smaller than the desired
102  * dimensions.
103  * @param[in,out] pixels The buffer both to read from and write the result to.
104  * @param[in]     pixelFormat The format of the image pointed at by pixels.
105  * @param[in]     inputWidth The width of the input image.
106  * @param[in]     inputHeight The height of the input image.
107  * @param[in]     desiredWidth The width the client is requesting.
108  * @param[in]     desiredHeight The height the client is requesting.
109  * @param[out]    outWidth  The resulting width after downscaling.
110  * @param[out]    outHeight The resulting height after downscaling.
111  */
112 void DownscaleInPlacePow2( unsigned char * const pixels,
113                            Pixel::Format pixelFormat,
114                            unsigned int inputWidth,
115                            unsigned int inputHeight,
116                            unsigned int desiredWidth,
117                            unsigned int desiredHeight,
118                            FittingMode::Type fittingMode,
119                            SamplingMode::Type samplingMode,
120                            unsigned& outWidth,
121                            unsigned& outHeight );
122
123 /**
124  * @brief Destructive in-place downscaling by a power of 2 factor.
125  *
126  * A box filter with a 2x2 kernel is repeatedly applied as long as the result
127  * of the next downscaling step would not be smaller than the desired
128  * dimensions.
129  * @param[in,out] pixels The buffer both to read from and write the result to.
130  * @param[in]     inputWidth The width of the input image.
131  * @param[in]     inputHeight The height of the input image.
132  * @param[in]     desiredWidth The width the client is requesting.
133  * @param[in]     desiredHeight The height the client is requesting.
134  * @param[out]    outWidth  The resulting width after downscaling.
135  * @param[out]    outHeight The resulting height after downscaling.
136  */
137 void DownscaleInPlacePow2RGB888( unsigned char * pixels,
138                                  unsigned int inputWidth,
139                                  unsigned int inputHeight,
140                                  unsigned int desiredWidth,
141                                  unsigned int desiredHeight,
142                                  BoxDimensionTest dimensionTest,
143                                  unsigned int& outWidth,
144                                  unsigned int& outHeight );
145
146 /**
147  * @copydoc DownscaleInPlacePow2RGB888
148  */
149 void DownscaleInPlacePow2RGBA8888( unsigned char * pixels,
150                                    unsigned int inputWidth,
151                                    unsigned int inputHeight,
152                                    unsigned int desiredWidth,
153                                    unsigned int desiredHeight,
154                                    BoxDimensionTest dimensionTest,
155                                    unsigned int& outWidth,
156                                    unsigned int& outHeight );
157
158 /**
159  * @copydoc DownscaleInPlacePow2RGB888
160  *
161  * For the 2-byte packed 16 bit format RGB565.
162  */
163 void DownscaleInPlacePow2RGB565( unsigned char * pixels,
164                                  unsigned int inputWidth,
165                                  unsigned int inputHeight,
166                                  unsigned int desiredWidth,
167                                  unsigned int desiredHeight,
168                                  BoxDimensionTest dimensionTest,
169                                  unsigned int& outWidth,
170                                  unsigned int& outHeight );
171
172 /**
173  * @copydoc DownscaleInPlacePow2RGB888
174  *
175  * For 2-byte formats such as lum8alpha8, but not packed 16 bit formats like RGB565.
176  */
177 void DownscaleInPlacePow2ComponentPair( unsigned char * pixels,
178                                         unsigned int inputWidth,
179                                         unsigned int inputHeight,
180                                         unsigned int desiredWidth,
181                                         unsigned int desiredHeight,
182                                         BoxDimensionTest dimensionTest,
183                                         unsigned int& outWidth,
184                                         unsigned int& outHeight );
185
186 /**
187  * @copydoc DownscaleInPlacePow2RGB888
188  *
189  * For single-byte formats such as lum8 or alpha8.
190  */
191 void DownscaleInPlacePow2SingleBytePerPixel( unsigned char * pixels,
192                                              unsigned int inputWidth,
193                                              unsigned int inputHeight,
194                                              unsigned int desiredWidth,
195                                              unsigned int desiredHeight,
196                                              BoxDimensionTest dimensionTest,
197                                              unsigned int& outWidth,
198                                              unsigned int& outHeight );
199
200 /**
201  * @brief Rescales an input image into the exact output dimensions passed-in.
202  *
203  * Uses point sampling, equivalent to GL_NEAREST texture filter mode, for the
204  * fastest results, at the expense of aliasing (noisy images) when downscaling.
205  * @note inPixels is allowed to alias outPixels if this is a downscaling,
206  * but not for upscaling.
207  */
208 void PointSample( const unsigned char * inPixels,
209                   unsigned int inputWidth,
210                   unsigned int inputHeight,
211                   Pixel::Format pixelFormat,
212                   unsigned char * outPixels,
213                   unsigned int desiredWidth,
214                   unsigned int desiredHeight );
215
216 /**
217  * @copydoc PointSample
218  *
219  * Specialised for 4-byte formats like RGBA8888 and BGRA8888.
220  */
221 void PointSample4BPP( const unsigned char * inPixels,
222                       unsigned int inputWidth,
223                       unsigned int inputHeight,
224                       unsigned char * outPixels,
225                       unsigned int desiredWidth,
226                       unsigned int desiredHeight );
227
228 /**
229  * @copydoc PointSample
230  *
231  * Specialised for 3-byte formats like RGB888 and BGR888.
232  */
233 void PointSample3BPP( const unsigned char * inPixels,
234                       unsigned int inputWidth,
235                       unsigned int inputHeight,
236                       unsigned char * outPixels,
237                       unsigned int desiredWidth,
238                       unsigned int desiredHeight );
239
240 /**
241  * @copydoc PointSample
242  *
243  * Specialised for 2-byte formats like LA88.
244  */
245 void PointSample2BPP( const unsigned char * inPixels,
246                       unsigned int inputWidth,
247                       unsigned int inputHeight,
248                       unsigned char * outPixels,
249                       unsigned int desiredWidth,
250                       unsigned int desiredHeight );
251
252 /**
253  * @copydoc PointSample
254  *
255  * Specialised for 1-byte formats like L8 and A8.
256  */
257 void PointSample1BPP( const unsigned char * inPixels,
258                       unsigned int inputWidth,
259                       unsigned int inputHeight,
260                       unsigned char * outPixels,
261                       unsigned int desiredWidth,
262                       unsigned int desiredHeight );
263
264 /**
265  * @brief Resample input image to output image using a bilinear filter.
266  *
267  * Each output pixel is formed of a weighted sum of a 2x2 block of four input
268  * pixels
269  * @pre inPixels must not alias outPixels. The input image should be a totally
270  * separate buffer from the input one.
271  */
272 void LinearSample( const unsigned char * __restrict__ inPixels,
273                    ImageDimensions inDimensions,
274                    Pixel::Format pixelFormat,
275                    unsigned char * __restrict__ outPixels,
276                    ImageDimensions outDimensions );
277
278 /**
279  * @copydoc LinearSample
280  *
281  * Specialised for one byte per pixel formats.
282  */
283 void LinearSample1BPP( const unsigned char * __restrict__ inPixels,
284                        ImageDimensions inputDimensions,
285                        unsigned char * __restrict__ outPixels,
286                        ImageDimensions desiredDimensions );
287
288 /**
289  * @copydoc LinearSample
290  *
291  * Specialised for two byte per pixel formats.
292  */
293 void LinearSample2BPP( 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 RGB565 16 bit pixel format.
302  */
303 void LinearSampleRGB565( 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 three byte per pixel formats like RGB888.
312  */
313 void LinearSample3BPP( 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 four byte per pixel formats like RGBA8888.
322  * @note, If used on RGBA8888, the A component will be blended independently.
323  */
324 void LinearSample4BPP( const unsigned char * __restrict__ inPixels,
325                        ImageDimensions inputDimensions,
326                        unsigned char * __restrict__ outPixels,
327                        ImageDimensions desiredDimensions );
328
329 /**
330  * @brief Resamples the input image with the Lanczos algorithm.
331  *
332  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
333  * separate buffer from the output buffer.
334  *
335  * @param[in] inPixels Pointer to the input image buffer.
336  * @param[in] inputDimensions The input dimensions of the image.
337  * @param[out] outPixels Pointer to the output image buffer.
338  * @param[in] desiredDimensions The output dimensions of the image.
339  */
340 void LanczosSample4BPP( const unsigned char * __restrict__ inPixels,
341                         ImageDimensions inputDimensions,
342                         unsigned char * __restrict__ outPixels,
343                         ImageDimensions desiredDimensions );
344
345 /**
346  * @brief Resamples the input image with the Lanczos algorithm.
347  *
348  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
349  * separate buffer from the output buffer.
350  *
351  * @param[in] inPixels Pointer to the input image buffer.
352  * @param[in] inputDimensions The input dimensions of the image.
353  * @param[out] outPixels Pointer to the output image buffer.
354  * @param[in] desiredDimensions The output dimensions of the image.
355  */
356 void LanczosSample1BPP( const unsigned char * __restrict__ inPixels,
357                         ImageDimensions inputDimensions,
358                         unsigned char * __restrict__ outPixels,
359                         ImageDimensions desiredDimensions );
360
361 /**
362  * @brief Resamples the input image with the Lanczos algorithm.
363  *
364  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
365  * separate buffer from the output buffer.
366  *
367  * @param[in] inPixels Pointer to the input image buffer.
368  * @param[in] inputDimensions The input dimensions of the image.
369  * @param[out] outPixels Pointer to the output image buffer.
370  * @param[in] desiredDimensions The output dimensions of the image.
371  */
372 void Resample( const unsigned char * __restrict__ inPixels,
373                ImageDimensions inputDimensions,
374                unsigned char * __restrict__ outPixels,
375                ImageDimensions desiredDimensions,
376                Resampler::Filter filterType,
377                int numChannels, bool hasAlpha );
378
379
380 /**@}*/
381
382 /**
383  * @defgroup ScalingAlgorithmFragments Composable subunits of the scaling algorithms.
384  * @{
385  */
386
387 /**
388  * @brief Average adjacent pairs of pixels, overwriting the input array.
389  * @param[in,out] pixels The array of pixels to work on.
390  * @param[i]      width  The number of pixels in the array passed-in.
391  */
392 void HalveScanlineInPlaceRGB888( unsigned char * pixels, unsigned int width );
393
394 /**
395  * @copydoc HalveScanlineInPlaceRGB888
396  */
397 void HalveScanlineInPlaceRGBA8888( unsigned char * pixels, unsigned int width );
398
399 /**
400  * @copydoc HalveScanlineInPlaceRGB888
401  */
402 void HalveScanlineInPlaceRGB565( unsigned char * pixels, unsigned int width );
403
404 /**
405  * @copydoc HalveScanlineInPlaceRGB888
406  */
407 void HalveScanlineInPlace2Bytes( unsigned char * pixels, unsigned int width );
408
409 /**
410  * @copydoc HalveScanlineInPlaceRGB888
411  */
412 void HalveScanlineInPlace1Byte( unsigned char * pixels, unsigned int width );
413
414 /**
415  * @brief Average pixels at corresponding offsets in two scanlines.
416  *
417  * outputScanline is allowed to alias scanline1.
418  * @param[in] scanline1 First scanline of pixels to average.
419  * @param[in] scanline2 Second scanline of pixels to average.
420  * @param[out] outputScanline Destination for the averaged pixels.
421  * @param[in] width The widths of all the scanlines passed-in.
422  */
423 void AverageScanlines1( const unsigned char * scanline1,
424                         const unsigned char * scanline2,
425                         unsigned char* outputScanline,
426                         /** Image width in pixels (1 byte == 1 pixel: e.g. lum8 or alpha8).*/
427                         unsigned int width );
428
429 /**
430  * @copydoc AverageScanlines1
431  */
432 void AverageScanlines2( const unsigned char * scanline1,
433                         const unsigned char * scanline2,
434                         unsigned char* outputScanline,
435                         /** Image width in pixels (2 bytes == 1 pixel: e.g. lum8alpha8).*/
436                         unsigned int width );
437
438 /**
439  * @copydoc AverageScanlines1
440  */
441 void AverageScanlines3( const unsigned char * scanline1,
442                         const unsigned char * scanline2,
443                         unsigned char* outputScanline,
444                         /** Image width in pixels (3 bytes == 1 pixel: e.g. RGB888).*/
445                         unsigned int width );
446
447 /**
448  * @copydoc AverageScanlines1
449  */
450 void AverageScanlinesRGBA8888( const unsigned char * scanline1,
451                                const unsigned char * scanline2,
452                                unsigned char * outputScanline,
453                                unsigned int width );
454
455 /**
456  * @copydoc AverageScanlines1
457  */
458 void AverageScanlinesRGB565( const unsigned char * scanline1,
459                              const unsigned char * scanline2,
460                              unsigned char* outputScanline,
461                              unsigned int width );
462 /**@}*/
463
464 /**
465  * @defgroup TestableInlines Inline functions exposed in header to allow unit testing.
466  * @{
467  */
468
469 /**
470  * @brief Average two integer arguments.
471  * @return The average of two uint arguments.
472  * @param[in] a First component to average.
473  * @param[in] b Second component to average.
474  **/
475 inline unsigned int AverageComponent( unsigned int a, unsigned int b )
476 {
477   unsigned int avg = (a + b) >> 1u;
478   return avg;
479 }
480
481 /**
482  * @brief Average a pair of RGBA8888 pixels.
483  * @return The average of two RGBA8888 pixels.
484  * @param[in] a First pixel to average.
485  * @param[in] b Second pixel to average
486  **/
487 inline uint32_t AveragePixelRGBA8888( uint32_t a, uint32_t b )
488 {
489   const unsigned int avg =
490     ((AverageComponent( (a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u ) << 1u) & 0xff000000 ) +
491     (AverageComponent( a & 0x00ff0000, b & 0x00ff0000 ) & 0x00ff0000 ) +
492     (AverageComponent( a & 0x0000ff00, b & 0x0000ff00 ) & 0x0000ff00 ) +
493     (AverageComponent( a & 0x000000ff, b & 0x000000ff ) );
494   return avg;
495   ///@ToDo: Optimise by trying return (((a ^ b) & 0xfefefefeUL) >> 1) + (a & b);
496   ///@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.
497 }
498
499 /**
500  * @brief Average a pair of RGB565 pixels.
501  * @param a[in] Low 16 bits hold a color value as RGB565 to average with parameter b.
502  * @param b[in] Low 16 bits hold a color value as RGB565 to average with parameter a.
503  * @return The average color of the two RGB565 pixels passed in, in the low 16 bits of the returned value.
504  **/
505 inline uint32_t AveragePixelRGB565( uint32_t a, uint32_t b )
506 {
507   const unsigned int avg =
508     (AverageComponent( a & 0xf800, b & 0xf800 ) & 0xf800 ) +
509     (AverageComponent( a & 0x7e0,  b & 0x7e0 )  & 0x7e0 ) +
510     (AverageComponent( a & 0x1f,   b & 0x1f ) );
511   return avg;
512 }
513
514 /** @return The weighted blend of two integers as a 16.16 fixed-point number, given a 0.16 fixed-point blending factor. */
515 inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b, unsigned int fractBlend )
516 {
517   DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
518   const unsigned int weightedAFixed = a * (65535u - fractBlend);
519   const unsigned int weightedBFixed = b * fractBlend;
520   const unsigned blended = (weightedAFixed + weightedBFixed);
521   return blended;
522 }
523
524 /** @brief Blend two 16.16 inputs to give a 16.32 output. */
525 inline uint64_t WeightedBlendFixed1616ToFixed1632(unsigned int a, unsigned int b, unsigned int fractBlend )
526 {
527   DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
528   // Blend while promoting intermediates to 16.32 fixed point:
529   const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
530   const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
531   const uint64_t blended = (weightedAFixed + weightedBFixed);
532   return blended;
533 }
534
535 /**
536  * @brief Blend 4 taps into one value using horizontal and vertical weights.
537  */
538 inline unsigned int BilinearFilter1Component(unsigned int tl, unsigned int tr, unsigned int bl, unsigned int br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
539 {
540   DALI_ASSERT_DEBUG( fractBlendHorizontal <= 65535u && "Factor should be in 0.16 fixed-point." );
541   DALI_ASSERT_DEBUG( fractBlendVertical   <= 65535u && "Factor should be in 0.16 fixed-point." );
542
543   const unsigned int topBlend = WeightedBlendIntToFixed1616( tl, tr, fractBlendHorizontal );
544   const unsigned int botBlend = WeightedBlendIntToFixed1616( bl, br, fractBlendHorizontal );
545   const uint64_t blended2x2 = WeightedBlendFixed1616ToFixed1632( topBlend, botBlend, fractBlendVertical );
546   const unsigned int rounded = (blended2x2 + (1u << 31u) ) >> 32u;
547   return rounded;
548 }
549
550 /**@}*/
551
552 } /* namespace Platform */
553 } /* namespace Internal */
554 } /* namespace Dali */
555
556 #endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_ */