2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #ifndef DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H
19 #define DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H
25 #include <dali/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>
37 * @brief Identify which combination of x and y dimensions matter in terminating iterative box filtering.
41 BoxDimensionTestEither,
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.
52 typedef Uint16Pair ImageDimensions;
55 * @brief Work out the true desired width and height, accounting for special
56 * rules for zeros in either or both input requested dimensions.
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.
62 ImageDimensions CalculateDesiredDimensions(ImageDimensions rawDimensions, ImageDimensions requestedDimensions);
65 * @defgroup BitmapOperations Bitmap-to-Bitmap Image operations.
70 * @brief Apply requested attributes to bitmap.
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,
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
83 Dali::Devel::PixelBuffer ApplyAttributesToBitmap(Dali::Devel::PixelBuffer bitmap, ImageDimensions dimensions, FittingMode::Type fittingMode = FittingMode::DEFAULT, SamplingMode::Type samplingMode = SamplingMode::DEFAULT);
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.
89 Dali::Devel::PixelBuffer DownscaleBitmap(Dali::Devel::PixelBuffer bitmap,
90 ImageDimensions desired,
91 FittingMode::Type fittingMode,
92 SamplingMode::Type samplingMode);
96 * @defgroup ImageBufferScalingAlgorithms Pixel buffer-level scaling algorithms.
101 * @brief Destructive in-place downscaling by a power of 2 factor.
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
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.
117 void DownscaleInPlacePow2(uint8_t* const pixels,
118 Pixel::Format pixelFormat,
120 uint32_t inputHeight,
121 uint32_t inputStride,
122 uint32_t desiredWidth,
123 uint32_t desiredHeight,
124 FittingMode::Type fittingMode,
125 SamplingMode::Type samplingMode,
128 unsigned& outStride);
131 * @brief Destructive in-place downscaling by a power of 2 factor.
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
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.
146 void DownscaleInPlacePow2RGB888(uint8_t* pixels,
148 uint32_t inputHeight,
149 uint32_t inputStride,
150 uint32_t desiredWidth,
151 uint32_t desiredHeight,
152 BoxDimensionTest dimensionTest,
155 uint32_t& outStride);
158 * @copydoc DownscaleInPlacePow2RGB888
160 void DownscaleInPlacePow2RGBA8888(uint8_t* pixels,
162 uint32_t inputHeight,
163 uint32_t inputStride,
164 uint32_t desiredWidth,
165 uint32_t desiredHeight,
166 BoxDimensionTest dimensionTest,
169 uint32_t& outStride);
172 * @copydoc DownscaleInPlacePow2RGB888
174 * For the 2-byte packed 16 bit format RGB565.
176 void DownscaleInPlacePow2RGB565(uint8_t* pixels,
178 uint32_t inputHeight,
179 uint32_t inputStride,
180 uint32_t desiredWidth,
181 uint32_t desiredHeight,
182 BoxDimensionTest dimensionTest,
185 uint32_t& outStride);
188 * @copydoc DownscaleInPlacePow2RGB888
190 * For 2-byte formats such as lum8alpha8, but not packed 16 bit formats like RGB565.
192 void DownscaleInPlacePow2ComponentPair(uint8_t* pixels,
194 uint32_t inputHeight,
195 uint32_t inputStride,
196 uint32_t desiredWidth,
197 uint32_t desiredHeight,
198 BoxDimensionTest dimensionTest,
201 uint32_t& outStride);
204 * @copydoc DownscaleInPlacePow2RGB888
206 * For single-byte formats such as lum8 or alpha8.
208 void DownscaleInPlacePow2SingleBytePerPixel(uint8_t* pixels,
210 uint32_t inputHeight,
211 uint32_t inputStride,
212 uint32_t desiredWidth,
213 uint32_t desiredHeight,
214 BoxDimensionTest dimensionTest,
217 uint32_t& outStride);
220 * @brief Rescales an input image into the exact output dimensions passed-in.
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.
227 void PointSample(const uint8_t* inPixels,
229 uint32_t inputHeight,
230 uint32_t inputStride,
231 Pixel::Format pixelFormat,
233 uint32_t desiredWidth,
234 uint32_t desiredHeight);
237 * @copydoc PointSample
239 * Specialised for 4-byte formats like RGBA8888 and BGRA8888.
241 void PointSample4BPP(const uint8_t* inPixels,
243 uint32_t inputHeight,
244 uint32_t inputStride,
246 uint32_t desiredWidth,
247 uint32_t desiredHeight);
250 * @copydoc PointSample
252 * Specialised for 3-byte formats like RGB888 and BGR888.
254 void PointSample3BPP(const uint8_t* inPixels,
256 uint32_t inputHeight,
257 uint32_t inputStride,
259 uint32_t desiredWidth,
260 uint32_t desiredHeight);
263 * @copydoc PointSample
265 * Specialised for 2-byte formats like LA88.
267 void PointSample2BPP(const uint8_t* inPixels,
269 uint32_t inputHeight,
270 uint32_t inputStride,
272 uint32_t desiredWidth,
273 uint32_t desiredHeight);
276 * @copydoc PointSample
278 * Specialised for 1-byte formats like L8 and A8.
280 void PointSample1BPP(const uint8_t* inPixels,
282 uint32_t inputHeight,
283 uint32_t inputStride,
285 uint32_t desiredWidth,
286 uint32_t desiredHeight);
289 * @brief Resample input image to output image using a bilinear filter.
291 * Each output pixel is formed of a weighted sum of a 2x2 block of four input
293 * @pre inPixels must not alias outPixels. The input image should be a totally
294 * separate buffer from the input one.
296 void LinearSample(const uint8_t* __restrict__ inPixels,
297 ImageDimensions inDimensions,
299 Pixel::Format pixelFormat,
300 uint8_t* __restrict__ outPixels,
301 ImageDimensions outDimensions);
304 * @copydoc LinearSample
306 * Specialised for one byte per pixel formats.
308 void LinearSample1BPP(const uint8_t* __restrict__ inPixels,
309 ImageDimensions inputDimensions,
310 uint32_t inputStride,
311 uint8_t* __restrict__ outPixels,
312 ImageDimensions desiredDimensions);
315 * @copydoc LinearSample
317 * Specialised for two byte per pixel formats.
319 void LinearSample2BPP(const uint8_t* __restrict__ inPixels,
320 ImageDimensions inputDimensions,
321 uint32_t inputStride,
322 uint8_t* __restrict__ outPixels,
323 ImageDimensions desiredDimensions);
326 * @copydoc LinearSample
328 * Specialised for RGB565 16 bit pixel format.
330 void LinearSampleRGB565(const uint8_t* __restrict__ inPixels,
331 ImageDimensions inputDimensions,
332 uint32_t inputStride,
333 uint8_t* __restrict__ outPixels,
334 ImageDimensions desiredDimensions);
337 * @copydoc LinearSample
339 * Specialised for three byte per pixel formats like RGB888.
341 void LinearSample3BPP(const uint8_t* __restrict__ inPixels,
342 ImageDimensions inputDimensions,
343 uint32_t inputStride,
344 uint8_t* __restrict__ outPixels,
345 ImageDimensions desiredDimensions);
348 * @copydoc LinearSample
350 * Specialised for four byte per pixel formats like RGBA8888.
351 * @note, If used on RGBA8888, the A component will be blended independently.
353 void LinearSample4BPP(const uint8_t* __restrict__ inPixels,
354 ImageDimensions inputDimensions,
355 uint32_t inputStride,
356 uint8_t* __restrict__ outPixels,
357 ImageDimensions desiredDimensions);
360 * @brief Resample input image to output image using a Lanczos algorithm.
362 * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
363 * separate buffer from the output buffer.
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.
372 void LanczosSample(const uint8_t* __restrict__ inPixels,
373 ImageDimensions inDimensions,
375 Pixel::Format pixelFormat,
376 uint8_t* __restrict__ outPixels,
377 ImageDimensions outDimensions);
380 * @brief Resamples the input image with the Lanczos algorithm.
382 * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
383 * separate buffer from the output buffer.
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.
391 void LanczosSample4BPP(const uint8_t* __restrict__ inPixels,
392 ImageDimensions inputDimensions,
393 uint32_t inputStride,
394 uint8_t* __restrict__ outPixels,
395 ImageDimensions desiredDimensions);
398 * @brief Resamples the input image with the Lanczos algorithm.
400 * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
401 * separate buffer from the output buffer.
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.
409 void LanczosSample1BPP(const uint8_t* __restrict__ inPixels,
410 ImageDimensions inputDimensions,
411 uint32_t inputStride,
412 uint8_t* __restrict__ outPixels,
413 ImageDimensions desiredDimensions);
416 * @brief Resamples the input image with the Lanczos algorithm.
418 * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
419 * separate buffer from the output buffer.
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.
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,
437 * @brief Rotates the input image with an implementation of the 'Rotate by Shear' algorithm.
439 * @pre @p pixelsIn must not alias @p pixelsOut. The input image should be a totally
440 * separate buffer from the output buffer.
442 * @note This function allocates memory in @p pixelsOut which has to be released by calling @e free()
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.
454 void RotateByShear(const uint8_t* const pixelsIn,
462 uint32_t& heightOut);
465 * @brief Applies to the input image a horizontal shear transformation.
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).
471 * @note This function allocates memory in @p pixelsOut which has to be released by calling @e free()
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.
483 void HorizontalShear(const uint8_t* const pixelsIn,
491 uint32_t& heightOut);
496 * @defgroup ScalingAlgorithmFragments Composable subunits of the scaling algorithms.
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.
505 void HalveScanlineInPlaceRGB888(uint8_t* pixels, uint32_t width);
508 * @copydoc HalveScanlineInPlaceRGB888
510 void HalveScanlineInPlaceRGBA8888(uint8_t* pixels, uint32_t width);
513 * @copydoc HalveScanlineInPlaceRGB888
515 void HalveScanlineInPlaceRGB565(uint8_t* pixels, uint32_t width);
518 * @copydoc HalveScanlineInPlaceRGB888
520 void HalveScanlineInPlace2Bytes(uint8_t* pixels, uint32_t width);
523 * @copydoc HalveScanlineInPlaceRGB888
525 void HalveScanlineInPlace1Byte(uint8_t* pixels, uint32_t width);
528 * @brief Average pixels at corresponding offsets in two scanlines.
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.
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).*/
543 * @copydoc AverageScanlines1
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).*/
552 * @copydoc AverageScanlines1
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).*/
561 * @copydoc AverageScanlines1
563 void AverageScanlinesRGBA8888(const uint8_t* scanline1,
564 const uint8_t* scanline2,
565 uint8_t* outputScanline,
569 * @copydoc AverageScanlines1
571 void AverageScanlinesRGB565(const uint8_t* scanline1,
572 const uint8_t* scanline2,
573 uint8_t* outputScanline,
578 * @defgroup TestableInlines Inline functions exposed in header to allow unit testing.
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.
588 inline uint32_t AverageComponent(uint32_t a, uint32_t b)
590 uint32_t avg = (a + b) >> 1u;
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
600 inline uint32_t AveragePixelRGBA8888(uint32_t a, uint32_t b)
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);
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.
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.
622 inline uint32_t AveragePixelRGB565(uint32_t a, uint32_t b)
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));
633 return (((a ^ b) & 0xf7deu) >> 1) + (a & b);
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)
639 DALI_ASSERT_DEBUG(fractBlend <= 65535u && "Factor should be in 0.16 fixed-point.");
642 * const uint32_t weightedAFixed = a * (65535u - fractBlend);
643 * const uint32_t weightedBFixed = b * fractBlend;
644 * const unsigned blended = (weightedAFixed + weightedBFixed);
647 const uint32_t blended = (a << 16) - a + (static_cast<int32_t>(b) - static_cast<int32_t>(a)) * fractBlend;
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)
654 DALI_ASSERT_DEBUG(fractBlend <= 65535u && "Factor should be in 0.16 fixed-point.");
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);
663 const uint64_t blended = (static_cast<uint64_t>(a) << 16) - a + (static_cast<int64_t>(b) - static_cast<int64_t>(a)) * fractBlend;
668 * @brief Blend 4 taps into one value using horizontal and vertical weights.
670 inline uint32_t BilinearFilter1Component(uint32_t tl, uint32_t tr, uint32_t bl, uint32_t br, uint32_t fractBlendHorizontal, uint32_t fractBlendVertical)
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.");
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;
685 * Hard-coding optimize!
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
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
700 * C = (tl - tr - bl + br) * x * y;
703 * (tl << 32) - (D << 16) + tl + A + B + C
705 * Becareful of overflow and negative value.
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);
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);
718 * @brief Fast multiply & divide by 255. It wiil be useful when we applying alpha value in color
720 * @param x The value between [0..255]
721 * @param y The value between [0..255]
724 inline uint8_t MultiplyAndNormalizeColor(const uint8_t x, const uint8_t y) noexcept
726 const uint32_t xy = static_cast<const uint32_t>(x) * y;
727 return ((xy << 15) + (xy << 7) + xy) >> 23;
731 * @brief Fast division by 17 and roundup. It will be useful when we compress 8bit luminance value as 4bit for text glyph.
733 * @param x The value between [0..255]
734 * @return round(x / 17.0f).(same as (x+8)/17)
736 inline uint8_t CompressBitPerPixel8To4(const uint8_t x) noexcept
738 return ((((static_cast<const uint16_t>(x) << 4) - x + (x >> 4)) >> 7) + 1) >> 1;
743 } /* namespace Platform */
744 } /* namespace Internal */
745 } /* namespace Dali */
747 #endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H */