From 26b41460bed23efc979e1e825d3b78abe66f0a9e Mon Sep 17 00:00:00 2001 From: zewu-feng Date: Fri, 27 May 2022 15:27:58 +0800 Subject: [PATCH 1/8] RGBA F16 feature Signed-off-by: zewu-feng --- .../common/include/pixel_map_utils.h | 1 + .../innerkitsimpl/common/src/pixel_map.cpp | 3 + .../converter/include/pixel_convert.h | 62 ++++++ .../converter/src/pixel_convert.cpp | 206 ++++++++++++++++++ .../src/pixel_convert_adapter.cpp | 97 +++++++-- .../kits/js/common/image_source_napi.cpp | 2 +- .../libjpegplugin/include/jpeg_encoder.h | 1 + .../image/libjpegplugin/src/jpeg_encoder.cpp | 32 ++- 8 files changed, 382 insertions(+), 22 deletions(-) diff --git a/frameworks/innerkitsimpl/common/include/pixel_map_utils.h b/frameworks/innerkitsimpl/common/include/pixel_map_utils.h index ae0b91b45..e4c48230b 100644 --- a/frameworks/innerkitsimpl/common/include/pixel_map_utils.h +++ b/frameworks/innerkitsimpl/common/include/pixel_map_utils.h @@ -27,6 +27,7 @@ constexpr int8_t ALPHA_8_BYTES = 1; constexpr int8_t RGB_565_BYTES = 2; constexpr int8_t RGB_888_BYTES = 3; constexpr int8_t ARGB_8888_BYTES = 4; +constexpr int8_t BGRA_F16_BYTES = 8; constexpr int8_t YUV420_BYTES = 2; // in fact NV21 one pixel used 1.5 bytes. // Define shift bits of bytes per pixel diff --git a/frameworks/innerkitsimpl/common/src/pixel_map.cpp b/frameworks/innerkitsimpl/common/src/pixel_map.cpp index f633593d1..48efc1353 100644 --- a/frameworks/innerkitsimpl/common/src/pixel_map.cpp +++ b/frameworks/innerkitsimpl/common/src/pixel_map.cpp @@ -453,6 +453,9 @@ bool PixelMap::GetPixelFormatDetail(const PixelFormat format) case PixelFormat::CMYK: pixelBytes_ = ARGB_8888_BYTES; break; + case PixelFormat::RGBA_F16: + pixelBytes_ = BGRA_F16_BYTES; + break; default: { HiLog::Error(LABEL, "pixel format:[%{public}d] not supported.", format); return false; diff --git a/frameworks/innerkitsimpl/converter/include/pixel_convert.h b/frameworks/innerkitsimpl/converter/include/pixel_convert.h index 71eab7280..310291886 100644 --- a/frameworks/innerkitsimpl/converter/include/pixel_convert.h +++ b/frameworks/innerkitsimpl/converter/include/pixel_convert.h @@ -17,6 +17,7 @@ #define PIXEL_CONVERT_H #include +#include #include #include "hilog/log.h" #include "image_type.h" @@ -46,6 +47,7 @@ constexpr uint32_t RGBA_8888 = 0x00000003; constexpr uint32_t BGRA_8888 = 0x00000004; constexpr uint32_t RGB_888 = 0x00000005; constexpr uint32_t ALPHA_8 = 0x00000006; /* Gray image, 8 bit = 255 color. */ +constexpr uint32_t RGBA_F16 = 0x00000007; constexpr uint32_t ABGR_8888 = 0x00000008; constexpr uint32_t BGR_888 = 0x40000002; constexpr uint32_t RGB_161616 = 0x40000007; @@ -73,6 +75,8 @@ constexpr uint8_t ALPHA_TRANSPARENT = 0x00; constexpr uint32_t GET_8_BIT = 0x80; constexpr uint32_t GET_1_BIT = 0x01; +constexpr uint32_t SHIFT_48_BIT = 0x30; +constexpr uint32_t SHIFT_32_BIT = 0x20; constexpr uint32_t SHIFT_24_BIT = 0x18; constexpr uint32_t SHIFT_16_BIT = 0x10; constexpr uint32_t SHIFT_8_BIT = 0x08; @@ -81,11 +85,27 @@ constexpr uint32_t SHIFT_5_BIT = 0x05; constexpr uint32_t SHIFT_3_BIT = 0x03; constexpr uint32_t SHIFT_2_BIT = 0x02; +constexpr uint32_t SHIFT_32_MASK = 0x80000000; +constexpr uint32_t SHIFT_16_MASK = 0x8000; +constexpr uint32_t SHIFT_7_MASK = 0x1C000; constexpr uint8_t SHIFT_5_MASK = 0x1F; constexpr uint8_t SHIFT_3_MASK = 0x07; +constexpr uint8_t SHIFT_HALF_BIT = 0x0D; +constexpr uint32_t SHIFT_HALF_MASK = 0x38000000; + constexpr uint16_t MAX_15_BIT_VALUE = 0x7FFF; +constexpr uint16_t MAX_16_BIT_VALUE = 0xFFFF; +constexpr uint32_t MAX_31_BIT_VALUE = 0x7FFFFFFF; constexpr float HALF_ONE = 0.5F; +constexpr float MAX_HALF = 65504; +constexpr float MIN_EPSILON = 1e-6; + +static inline bool FloatCompareTo(float val, float compare) +{ + return fabs(val - compare) < MIN_EPSILON; +} + static inline uint32_t Premul255(uint32_t colorComponent, uint32_t alpha) { if (colorComponent > MAX_15_BIT_VALUE || alpha > MAX_15_BIT_VALUE) { @@ -110,6 +130,48 @@ static inline uint32_t Unpremul255(uint32_t colorComponent, uint32_t alpha) return (result > ALPHA_OPAQUE) ? ALPHA_OPAQUE : result; } +static inline uint32_t FloatToUint(float f) +{ + uint32_t *p = reinterpret_cast(&f); + return *p; +} + +static inline float UintToFloat(uint32_t ui) +{ + float *pf = reinterpret_cast(&ui); + return *pf; +} + +static inline uint16_t FloatToHalf(float f) +{ + uint32_t u32 = FloatToUint(f); + uint16_t u16 = static_cast( + (((u32 & MAX_31_BIT_VALUE) >> SHIFT_HALF_BIT) - SHIFT_7_MASK) & MAX_16_BIT_VALUE); + u16 |= static_cast( + ((u32 & SHIFT_32_MASK) >> SHIFT_16_BIT) & MAX_16_BIT_VALUE); + return u16; +} + +static inline float HalfToFloat(uint16_t ui) +{ + uint32_t u32 = ((ui & MAX_15_BIT_VALUE) << SHIFT_HALF_BIT) + SHIFT_HALF_MASK; + u32 |= ((ui & SHIFT_16_MASK) << SHIFT_16_BIT); + return UintToFloat(u32); +} + +static inline uint16_t U8ToU16(uint8_t val1, uint8_t val2) +{ + uint16_t ret = val1; + return ((ret << SHIFT_8_BIT) | val2); +} + +static inline uint32_t HalfToUint32(const uint8_t* ui, bool isLittleEndian) +{ + uint16_t val = isLittleEndian?U8ToU16(*ui, *(ui + 1)):U8ToU16(*(ui + 1), *ui); + float fRet = HalfToFloat(val); + return static_cast (fRet); +} + using ProcFuncType = void (*)(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, const ProcFuncExtension &extension); class PixelConvert { diff --git a/frameworks/innerkitsimpl/converter/src/pixel_convert.cpp b/frameworks/innerkitsimpl/converter/src/pixel_convert.cpp index 08ee0cbca..99c6e9665 100644 --- a/frameworks/innerkitsimpl/converter/src/pixel_convert.cpp +++ b/frameworks/innerkitsimpl/converter/src/pixel_convert.cpp @@ -96,6 +96,18 @@ static uint16_t FillRGB565(uint32_t R, uint32_t G, uint32_t B) return ((R << SHIFT_11_BIT) | (G << SHIFT_5_BIT) | B); } +static uint64_t FillRGBAF16(float R, float G, float B, float A) +{ + uint64_t R16 = FloatToHalf(R); + uint64_t G16 = FloatToHalf(G); + uint64_t B16 = FloatToHalf(B); + uint64_t A16 = FloatToHalf(A); + if (IS_LITTLE_ENDIAN) { + return ((A16 << SHIFT_48_BIT) | (R16 << SHIFT_32_BIT) | (G16 << SHIFT_16_BIT) | B16); + } + return ((B16 << SHIFT_48_BIT) | (G16 << SHIFT_32_BIT) | (R16 << SHIFT_16_BIT) | A16); +} + constexpr uint8_t BYTE_BITS = 8; constexpr uint8_t BYTE_BITS_MAX_INDEX = 7; template @@ -215,6 +227,7 @@ constexpr uint32_t BRANCH_BGR888_TO_ARGB8888 = 0x20000001; constexpr uint32_t BRANCH_BGR888_TO_RGBA8888 = 0x20000002; constexpr uint32_t BRANCH_BGR888_TO_BGRA8888 = 0x20000003; constexpr uint32_t BRANCH_BGR888_TO_RGB565 = 0x20000004; +constexpr uint32_t BRANCH_BGR888_TO_RGBAF16 = 0x20000005; template static void BGR888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch) { @@ -234,6 +247,8 @@ static void BGR888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t G = G >> SHIFT_2_BIT; B = B >> SHIFT_3_BIT; destinationRow[i] = ((B << SHIFT_11_BIT) | (G << SHIFT_5_BIT) | R); + } else if (branch == BRANCH_BGR888_TO_RGBAF16) { + destinationRow[i] = FillRGBAF16(R, G, B, A); } else { break; } @@ -269,10 +284,19 @@ static void BGR888ConvertRGB565(void *destinationRow, const uint8_t *sourceRow, BGR888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGR888_TO_RGB565); } +static void BGR888ConvertRGBAF16(uint8_t *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + void* tmp = static_cast(destinationRow); + uint64_t *newDestinationRow = static_cast(tmp); + BGR888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGR888_TO_RGBAF16); +} + constexpr uint32_t BRANCH_RGB888_TO_ARGB8888 = 0x30000001; constexpr uint32_t BRANCH_RGB888_TO_RGBA8888 = 0x30000002; constexpr uint32_t BRANCH_RGB888_TO_BGRA8888 = 0x30000003; constexpr uint32_t BRANCH_RGB888_TO_RGB565 = 0x30000004; +constexpr uint32_t BRANCH_RGB888_TO_RGBAF16 = 0x30000005; template static void RGB888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch) { @@ -292,6 +316,8 @@ static void RGB888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t G = G >> SHIFT_2_BIT; B = B >> SHIFT_3_BIT; destinationRow[i] = FillRGB565(R, G, B); + } else if (branch == BRANCH_RGB888_TO_RGBAF16) { + destinationRow[i] = FillRGBAF16(R, G, B, A); } else { break; } @@ -325,10 +351,19 @@ static void RGB888ConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint16_t *newDestinationRow = static_cast(destinationRow); RGB888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB888_TO_RGB565); } + +static void RGB888ConvertRGBAF16(uint8_t *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + void* tmp = static_cast(destinationRow); + uint64_t *newDestinationRow = static_cast(tmp); + RGB888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB888_TO_RGBAF16); +} constexpr uint32_t BRANCH_RGBA8888_TO_RGBA8888_ALPHA = 0x40000001; constexpr uint32_t BRANCH_RGBA8888_TO_ARGB8888 = 0x40000002; constexpr uint32_t BRANCH_RGBA8888_TO_BGRA8888 = 0x40000003; constexpr uint32_t BRANCH_RGBA8888_TO_RGB565 = 0x40000004; +constexpr uint32_t BRANCH_RGBA8888_TO_RGBAF16 = 0x40000005; template static void RGBA8888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch, const ProcFuncExtension &extension) @@ -350,6 +385,8 @@ static void RGBA8888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_ G = G >> SHIFT_2_BIT; B = B >> SHIFT_3_BIT; destinationRow[i] = FillRGB565(R, G, B); + } else if (branch == BRANCH_RGBA8888_TO_RGBAF16) { + destinationRow[i] = FillRGBAF16(R, G, B, A); } else { break; } @@ -384,10 +421,18 @@ static void RGBA8888ConvertRGB565(void *destinationRow, const uint8_t *sourceRow RGBA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA8888_TO_RGB565, extension); } +static void RGBA8888ConvertRGBAF16(uint8_t *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + void* tmp = static_cast(destinationRow); + uint64_t *newDestinationRow = static_cast(tmp); + RGBA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA8888_TO_RGBAF16, extension); +} constexpr uint32_t BRANCH_BGRA8888_TO_BGRA8888_ALPHA = 0x80000001; constexpr uint32_t BRANCH_BGRA8888_TO_ARGB8888 = 0x80000002; constexpr uint32_t BRANCH_BGRA8888_TO_RGBA8888 = 0x80000003; constexpr uint32_t BRANCH_BGRA8888_TO_RGB565 = 0x80000004; +constexpr uint32_t BRANCH_BGRA8888_TO_RGBAF16 = 0x80000005; template static void BGRA8888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch, const ProcFuncExtension &extension) @@ -409,6 +454,8 @@ static void BGRA8888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_ G = G >> SHIFT_2_BIT; B = B >> SHIFT_3_BIT; destinationRow[i] = FillRGB565(R, G, B); + } else if (branch == BRANCH_BGRA8888_TO_RGBAF16) { + destinationRow[i] = FillRGBAF16(R, G, B, A); } else { break; } @@ -444,10 +491,19 @@ static void BGRA8888ConvertRGB565(void *destinationRow, const uint8_t *sourceRow BGRA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGRA8888_TO_RGB565, extension); } +static void BGRA8888ConvertRGBAF16(uint8_t *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + void* tmp = static_cast(destinationRow); + uint64_t *newDestinationRow = static_cast(tmp); + BGRA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGRA8888_TO_RGBAF16, extension); +} + constexpr uint32_t BRANCH_ARGB8888_TO_ARGB8888_ALPHA = 0x90000001; constexpr uint32_t BRANCH_ARGB8888_TO_RGBA8888 = 0x90000002; constexpr uint32_t BRANCH_ARGB8888_TO_BGRA8888 = 0x90000003; constexpr uint32_t BRANCH_ARGB8888_TO_RGB565 = 0x90000004; +constexpr uint32_t BRANCH_ARGB8888_TO_RGBAF16 = 0x90000005; template static void ARGB8888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch, const ProcFuncExtension &extension) @@ -469,6 +525,8 @@ static void ARGB8888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_ G = G >> SHIFT_2_BIT; B = B >> SHIFT_3_BIT; destinationRow[i] = FillRGB565(R, G, B); + } else if (branch == BRANCH_ARGB8888_TO_RGBAF16) { + destinationRow[i] = FillRGBAF16(R, G, B, A); } else { break; } @@ -504,11 +562,20 @@ static void ARGB8888ConvertRGB565(void *destinationRow, const uint8_t *sourceRow ARGB8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_ARGB8888_TO_RGB565, extension); } +static void ARGB8888ConvertRGBAF16(uint8_t *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + void* tmp = static_cast(destinationRow); + uint64_t *newDestinationRow = static_cast(tmp); + ARGB8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_ARGB8888_TO_RGBAF16, extension); +} + constexpr uint32_t BRANCH_RGB161616_TO_ARGB8888 = 0x50000001; constexpr uint32_t BRANCH_RGB161616_TO_ABGR8888 = 0x50000002; constexpr uint32_t BRANCH_RGB161616_TO_RGBA8888 = 0x50000003; constexpr uint32_t BRANCH_RGB161616_TO_BGRA8888 = 0x50000004; constexpr uint32_t BRANCH_RGB161616_TO_RGB565 = 0x50000005; +constexpr uint32_t BRANCH_RGB161616_TO_RGBAF16 = 0x50000006; template static void RGB161616Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch) { @@ -530,6 +597,8 @@ static void RGB161616Convert(T *destinationRow, const uint8_t *sourceRow, uint32 G = G >> SHIFT_2_BIT; B = B >> SHIFT_3_BIT; destinationRow[i] = FillRGB565(R, G, B); + } else if (branch == BRANCH_RGB161616_TO_RGBAF16) { + destinationRow[i] = FillRGBAF16(R, G, B, A); } else { break; } @@ -572,10 +641,19 @@ static void RGB161616ConvertRGB565(void *destinationRow, const uint8_t *sourceRo RGB161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB161616_TO_RGB565); } +static void RGB161616ConvertRGBAF16(uint8_t *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + void* tmp = static_cast(destinationRow); + uint64_t *newDestinationRow = static_cast(tmp); + RGB161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB161616_TO_RGBAF16); +} + constexpr uint32_t BRANCH_RGBA16161616_TO_ARGB8888 = 0x60000001; constexpr uint32_t BRANCH_RGBA16161616_TO_ABGR8888 = 0x60000002; constexpr uint32_t BRANCH_RGBA16161616_TO_RGBA8888 = 0x60000003; constexpr uint32_t BRANCH_RGBA16161616_TO_BGRA8888 = 0x60000004; +constexpr uint32_t BRANCH_RGBA16161616_TO_RGBAF16 = 0x60000005; template static void RGBA16161616Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch, const ProcFuncExtension &extension) @@ -594,6 +672,8 @@ static void RGBA16161616Convert(T *destinationRow, const uint8_t *sourceRow, uin destinationRow[i] = FillRGBA8888(A, B, G, R); } else if (branch == BRANCH_RGBA16161616_TO_BGRA8888) { destinationRow[i] = FillBGRA8888(A, B, G, R); + } else if (branch == BRANCH_RGBA16161616_TO_RGBAF16) { + destinationRow[i] = FillRGBAF16(R, G, B, A); } else { break; } @@ -629,6 +709,14 @@ static void RGBA16161616ConvertBGRA8888(void *destinationRow, const uint8_t *sou RGBA16161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA16161616_TO_BGRA8888, extension); } +static void RGBA16161616ConvertRGBAF16(uint8_t *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + void* tmp = static_cast(destinationRow); + uint64_t *newDestinationRow = static_cast(tmp); + RGBA16161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA16161616_TO_RGBAF16, extension); +} + constexpr uint32_t BRANCH_CMYK_TO_ARGB8888 = 0x70000001; constexpr uint32_t BRANCH_CMYK_TO_ABGR8888 = 0x70000002; constexpr uint32_t BRANCH_CMYK_TO_RGBA8888 = 0x70000003; @@ -704,6 +792,7 @@ static void CMYKConvertRGB565(void *destinationRow, const uint8_t *sourceRow, ui constexpr uint32_t BRANCH_RGB565_TO_ARGB8888 = 0x11000001; constexpr uint32_t BRANCH_RGB565_TO_RGBA8888 = 0x11000002; constexpr uint32_t BRANCH_RGB565_TO_BGRA8888 = 0x11000003; +constexpr uint32_t BRANCH_RGB565_TO_RGBAF16 = 0x11000004; template static void RGB565Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch) { @@ -718,6 +807,8 @@ static void RGB565Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t destinationRow[i] = FillRGBA8888(R, G, B, A); } else if (branch == BRANCH_RGB565_TO_BGRA8888) { destinationRow[i] = FillBGRA8888(B, G, R, A); + } else if (branch == BRANCH_RGB565_TO_RGBAF16) { + destinationRow[i] = FillRGBAF16(R, G, B, A); } else { break; } @@ -746,6 +837,89 @@ static void RGB565ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow RGB565Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB565_TO_BGRA8888); } +static void RGB565ConvertRGBAF16(uint8_t *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + void* tmp = static_cast(destinationRow); + uint64_t *newDestinationRow = static_cast(tmp); + RGB565Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB565_TO_RGBAF16); +} + +constexpr uint32_t BRANCH_RGBAF16_TO_ARGB8888 = 0x13000001; +constexpr uint32_t BRANCH_RGBAF16_TO_RGBA8888 = 0x13000002; +constexpr uint32_t BRANCH_RGBAF16_TO_BGRA8888 = 0x13000003; +constexpr uint32_t BRANCH_RGBAF16_TO_ABGR8888 = 0x13000004; +constexpr uint32_t BRANCH_RGBAF16_TO_RGB565 = 0x13000005; +template +static void RGBAF16Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch, + const ProcFuncExtension &extension) +{ + for (uint32_t i = 0; i < sourceWidth; i++) { + uint32_t R = HalfToUint32(sourceRow, IS_LITTLE_ENDIAN); + uint32_t G = HalfToUint32(sourceRow + 2, IS_LITTLE_ENDIAN); + uint32_t B = HalfToUint32(sourceRow + 4, IS_LITTLE_ENDIAN); + uint32_t A = HalfToUint32(sourceRow + 6, IS_LITTLE_ENDIAN); + AlphaTypeConvertOnRGB(A, R, G, B, extension); + if (branch == BRANCH_RGBAF16_TO_ARGB8888) { + destinationRow[i] = FillARGB8888(A, R, G, B); + } else if (branch == BRANCH_RGBAF16_TO_RGBA8888) { + destinationRow[i] = FillRGBA8888(R, G, B, A); + } else if (branch == BRANCH_RGBAF16_TO_BGRA8888) { + destinationRow[i] = FillBGRA8888(B, G, R, A); + } else if (branch == BRANCH_RGBAF16_TO_ABGR8888) { + destinationRow[i] = FillABGR8888(A, B, G, R); + } else if (branch == BRANCH_RGBAF16_TO_RGB565) { + R = R >> SHIFT_3_BIT; + G = G >> SHIFT_2_BIT; + B = B >> SHIFT_3_BIT; + destinationRow[i] = FillRGB565(R, G, B); + } else { + break; + } + sourceRow += SIZE_8_BYTE; + } +} + +static void RGBAF16ConvertARGB8888(uint8_t *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + void* tmp = static_cast(destinationRow); + uint32_t *newDestinationRow = static_cast(tmp); + RGBAF16Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBAF16_TO_ARGB8888, extension); +} + +static void RGBAF16ConvertRGBA8888(uint8_t *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + void* tmp = static_cast(destinationRow); + uint32_t *newDestinationRow = static_cast(tmp); + RGBAF16Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBAF16_TO_RGBA8888, extension); +} + +static void RGBAF16ConvertBGRA8888(uint8_t *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + void* tmp = static_cast(destinationRow); + uint32_t *newDestinationRow = static_cast(tmp); + RGBAF16Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBAF16_TO_BGRA8888, extension); +} + +static void RGBAF16ConvertABGR8888(uint8_t *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + void* tmp = static_cast(destinationRow); + uint32_t *newDestinationRow = static_cast(tmp); + RGBAF16Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBAF16_TO_ABGR8888, extension); +} + +static void RGBAF16ConvertRGB565(uint8_t *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + void* tmp = static_cast(destinationRow); + uint16_t *newDestinationRow = static_cast(tmp); + RGBAF16Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBAF16_TO_RGB565, extension); +} + static map g_procMapping; static mutex g_procMutex; @@ -822,6 +996,37 @@ static void InitCMYKProc() g_procMapping.emplace(MakeKey(CMKY, RGB_565), &CMYKConvertRGB565); } +static void InitF16Proc() +{ + g_procMapping.emplace(MakeKey(RGBA_F16, ARGB_8888), + reinterpret_cast(&RGBAF16ConvertARGB8888)); + g_procMapping.emplace(MakeKey(RGBA_F16, RGBA_8888), + reinterpret_cast(&RGBAF16ConvertRGBA8888)); + g_procMapping.emplace(MakeKey(RGBA_F16, BGRA_8888), + reinterpret_cast(&RGBAF16ConvertBGRA8888)); + g_procMapping.emplace(MakeKey(RGBA_F16, ABGR_8888), + reinterpret_cast(&RGBAF16ConvertABGR8888)); + g_procMapping.emplace(MakeKey(RGBA_F16, RGB_565), + reinterpret_cast(&RGBAF16ConvertRGB565)); + + g_procMapping.emplace(MakeKey(BGR_888, RGBA_F16), + reinterpret_cast(&BGR888ConvertRGBAF16)); + g_procMapping.emplace(MakeKey(RGB_888, RGBA_F16), + reinterpret_cast(&RGB888ConvertRGBAF16)); + g_procMapping.emplace(MakeKey(RGB_161616, RGBA_F16), + reinterpret_cast(&RGB161616ConvertRGBAF16)); + g_procMapping.emplace(MakeKey(ARGB_8888, RGBA_F16), + reinterpret_cast(&ARGB8888ConvertRGBAF16)); + g_procMapping.emplace(MakeKey(RGBA_8888, RGBA_F16), + reinterpret_cast(&RGBA8888ConvertRGBAF16)); + g_procMapping.emplace(MakeKey(BGRA_8888, RGBA_F16), + reinterpret_cast(&BGRA8888ConvertRGBAF16)); + g_procMapping.emplace(MakeKey(RGB_565, RGBA_F16), + reinterpret_cast(&RGB565ConvertRGBAF16)); + g_procMapping.emplace(MakeKey(RGBA_16161616, RGBA_F16), + reinterpret_cast(&RGBA16161616ConvertRGBAF16)); +} + static ProcFuncType GetProcFuncType(uint32_t srcPixelFormat, uint32_t dstPixelFormat) { unique_lock guard(g_procMutex); @@ -830,6 +1035,7 @@ static ProcFuncType GetProcFuncType(uint32_t srcPixelFormat, uint32_t dstPixelFo InitRGBProc(); InitRGBAProc(); InitCMYKProc(); + InitF16Proc(); } guard.unlock(); string procKey = MakeKey(srcPixelFormat, dstPixelFormat); diff --git a/frameworks/innerkitsimpl/pixelconverter/src/pixel_convert_adapter.cpp b/frameworks/innerkitsimpl/pixelconverter/src/pixel_convert_adapter.cpp index 8395dda72..6fbbf933a 100644 --- a/frameworks/innerkitsimpl/pixelconverter/src/pixel_convert_adapter.cpp +++ b/frameworks/innerkitsimpl/pixelconverter/src/pixel_convert_adapter.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "pixel_convert_adapter.h" +#include #include "include/core/SkBitmap.h" #include "include/core/SkCanvas.h" #include "include/core/SkColor.h" @@ -21,6 +21,7 @@ #include "include/core/SkImageInfo.h" #include "include/core/SkPaint.h" #include "include/core/SkPixmap.h" +#include "pixel_convert_adapter.h" #ifdef _WIN32 #include #endif @@ -28,30 +29,75 @@ namespace OHOS { namespace Media { using namespace OHOS::HiviewDFX; +using namespace std; static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "PixelConvertAdapter" }; +static const uint8_t NUM_0 = 0; +static const uint8_t NUM_1 = 1; +static const uint8_t NUM_2 = 2; +static const uint8_t NUM_3 = 3; +static const uint8_t NUM_4 = 4; + +static const map PIXEL_FORMAT_MAP = { + { PixelFormat::UNKNOWN, SkColorType::kUnknown_SkColorType}, + { PixelFormat::ARGB_8888, SkColorType::kRGBA_8888_SkColorType}, + { PixelFormat::ALPHA_8, SkColorType::kAlpha_8_SkColorType}, + { PixelFormat::RGB_565, SkColorType::kRGB_565_SkColorType}, + { PixelFormat::RGBA_F16, SkColorType::kRGBA_F16_SkColorType}, + { PixelFormat::RGBA_8888, SkColorType::kRGBA_8888_SkColorType}, + { PixelFormat::BGRA_8888, SkColorType::kBGRA_8888_SkColorType} +}; static SkColorType PixelFormatConvert(const PixelFormat &pixelFormat) { - SkColorType colorType; - switch (pixelFormat) { - case PixelFormat::BGRA_8888: - colorType = SkColorType::kBGRA_8888_SkColorType; - break; - case PixelFormat::RGBA_8888: - colorType = SkColorType::kRGBA_8888_SkColorType; - break; - case PixelFormat::RGB_565: - colorType = SkColorType::kRGB_565_SkColorType; - break; - case PixelFormat::ALPHA_8: - colorType = SkColorType::kAlpha_8_SkColorType; - break; - default: - colorType = SkColorType::kUnknown_SkColorType; - break; + auto formatSearch = PIXEL_FORMAT_MAP.find(pixelFormat); + return (formatSearch != PIXEL_FORMAT_MAP.end()) ? formatSearch->second : SkColorType::kUnknown_SkColorType; +} + +static void ARGBToRGBA(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount) +{ + if (byteCount % NUM_4 != NUM_0) { + HiLog::Error(LABEL, "Pixel count must multiple of 4."); + return; + } + uint8_t *src = srcPixels; + uint8_t *dst = dstPixels; + uint8_t A, R, G, B; + for (uint32_t i = NUM_0 ; i < byteCount; i += NUM_4) { + A = src[NUM_0]; + R = src[NUM_1]; + G = src[NUM_2]; + B = src[NUM_3]; + dst[NUM_0] = R; + dst[NUM_1] = G; + dst[NUM_2] = B; + dst[NUM_3] = A; + src += NUM_4; + dst += NUM_4; + } +} + +static void RGBAToARGB(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount) +{ + if (byteCount % NUM_4 != NUM_0) { + HiLog::Error(LABEL, "Pixel count must multiple of 4."); + return; + } + uint8_t *src = srcPixels; + uint8_t *dst = dstPixels; + uint8_t A, R, G, B; + for (uint32_t i = NUM_0 ; i < byteCount; i += NUM_4) { + R = src[NUM_0]; + G = src[NUM_1]; + B = src[NUM_2]; + A = src[NUM_3]; + dst[NUM_0] = A; + dst[NUM_1] = R; + dst[NUM_2] = G; + dst[NUM_3] = B; + src += NUM_4; + dst += NUM_4; } - return colorType; } bool PixelConvertAdapter::WritePixelsConvert(const void *srcPixels, uint32_t srcRowBytes, const ImageInfo &srcInfo, @@ -63,15 +109,21 @@ bool PixelConvertAdapter::WritePixelsConvert(const void *srcPixels, uint32_t src HiLog::Error(LABEL, "src or dst pixels invalid."); return false; } + SkAlphaType srcAlphaType = static_cast(srcInfo.alphaType); SkAlphaType dstAlphaType = static_cast(dstInfo.alphaType); SkColorType srcColorType = PixelFormatConvert(srcInfo.pixelFormat); SkColorType dstColorType = PixelFormatConvert(dstInfo.pixelFormat); SkImageInfo srcImageInfo = SkImageInfo::Make(srcInfo.size.width, srcInfo.size.height, srcColorType, srcAlphaType); SkImageInfo dstImageInfo = SkImageInfo::Make(dstInfo.size.width, dstInfo.size.height, dstColorType, dstAlphaType); - SkBitmap dstBitmap; SkPixmap srcPixmap(srcImageInfo, srcPixels, srcRowBytes); + + if (srcInfo.pixelFormat == PixelFormat::ARGB_8888) { + uint8_t* src = static_cast(srcPixmap.writable_addr()); + ARGBToRGBA(src, src, srcRowBytes * srcInfo.size.height); + } + if (!dstBitmap.installPixels(dstImageInfo, dstPixels, dstRowBytes)) { HiLog::Error(LABEL, "WritePixelsConvert dst bitmap install pixels failed."); return false; @@ -81,6 +133,11 @@ bool PixelConvertAdapter::WritePixelsConvert(const void *srcPixels, uint32_t src return false; } + if (dstInfo.pixelFormat == PixelFormat::ARGB_8888) { + uint32_t dstSize = dstRowBytes * dstInfo.size.height; + RGBAToARGB(static_cast(dstPixels), static_cast(dstPixels), dstSize); + } + return true; } diff --git a/frameworks/kits/js/common/image_source_napi.cpp b/frameworks/kits/js/common/image_source_napi.cpp index e990f931e..c97003651 100644 --- a/frameworks/kits/js/common/image_source_napi.cpp +++ b/frameworks/kits/js/common/image_source_napi.cpp @@ -381,7 +381,7 @@ static bool ParseRegion(napi_env env, napi_value root, Rect* region) static bool IsSupportPixelFormat(int32_t val) { if (val >= static_cast(PixelFormat::UNKNOWN) && - val <= static_cast(PixelFormat::BGRA_8888)) { + val <= static_cast(PixelFormat::RGBA_F16)) { return true; } diff --git a/plugins/common/libs/image/libjpegplugin/include/jpeg_encoder.h b/plugins/common/libs/image/libjpegplugin/include/jpeg_encoder.h index 63d1da005..46a15db65 100644 --- a/plugins/common/libs/image/libjpegplugin/include/jpeg_encoder.h +++ b/plugins/common/libs/image/libjpegplugin/include/jpeg_encoder.h @@ -43,6 +43,7 @@ private: void SetYuv420spExtraConfig(); uint32_t SequenceEncoder(const uint8_t *data); uint32_t Yuv420spEncoder(const uint8_t *data); + uint32_t RGBAF16Encoder(const uint8_t *data); static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "JpegEncoder" }; jpeg_compress_struct encodeInfo_; JpegDstMgr dstMgr_; diff --git a/plugins/common/libs/image/libjpegplugin/src/jpeg_encoder.cpp b/plugins/common/libs/image/libjpegplugin/src/jpeg_encoder.cpp index 88ae731c9..1c548bb0b 100644 --- a/plugins/common/libs/image/libjpegplugin/src/jpeg_encoder.cpp +++ b/plugins/common/libs/image/libjpegplugin/src/jpeg_encoder.cpp @@ -14,8 +14,9 @@ */ #include "jerror.h" -#include "jpeg_encoder.h" #include "media_errors.h" +#include "pixel_convert.h" +#include "jpeg_encoder.h" namespace OHOS { namespace ImagePlugin { @@ -28,6 +29,7 @@ constexpr uint32_t COMPONENT_NUM_RGBA = 4; constexpr uint32_t COMPONENT_NUM_BGRA = 4; constexpr uint32_t COMPONENT_NUM_RGB = 3; constexpr uint32_t COMPONENT_NUM_GRAY = 1; +constexpr uint32_t PIXEL_SIZE_RGBA_F16 = 8; // yuv format constexpr uint8_t COMPONENT_NUM_YUV420SP = 3; constexpr uint8_t Y_SAMPLE_ROW = 16; @@ -75,6 +77,7 @@ J_COLOR_SPACE JpegEncoder::GetEncodeFormat(PixelFormat format, int32_t &componen J_COLOR_SPACE colorSpace = JCS_UNKNOWN; int32_t components = 0; switch (format) { + case PixelFormat::RGBA_F16: case PixelFormat::RGBA_8888: { colorSpace = JCS_EXT_RGBA; components = COMPONENT_NUM_RGBA; @@ -145,6 +148,8 @@ uint32_t JpegEncoder::FinalizeEncode() PixelFormat pixelFormat = pixelMaps_[0]->GetPixelFormat(); if (pixelFormat == PixelFormat::NV21 || pixelFormat == PixelFormat::NV12) { errorCode = Yuv420spEncoder(data); + } else if (pixelFormat == PixelFormat::RGBA_F16) { + errorCode = RGBAF16Encoder(data); } else { errorCode = SequenceEncoder(data); } @@ -277,6 +282,31 @@ void JpegEncoder::Deinterweave(uint8_t *uvPlane, uint8_t *uPlane, uint8_t *vPlan } } +uint32_t JpegEncoder::RGBAF16Encoder(const uint8_t *data) +{ + if (setjmp(jerr_.setjmp_buffer)) { + HiLog::Error(LABEL, "encode image error."); + return ERR_IMAGE_ENCODE_FAILED; + } + jpeg_start_compress(&encodeInfo_, TRUE); + uint8_t *base = const_cast(data); + uint32_t rowStride = encodeInfo_.image_width * encodeInfo_.input_components; + uint32_t orgRowStride = encodeInfo_.image_width * PIXEL_SIZE_RGBA_F16; + uint8_t *buffer = nullptr; + auto rowBuffer = std::make_unique(rowStride); + while (encodeInfo_.next_scanline < encodeInfo_.image_height) { + buffer = base + encodeInfo_.next_scanline * orgRowStride; + for (uint32_t i = 0; i < rowStride;i++) { + float orgPlane = HalfToFloat(U8ToU16(buffer[i*2], buffer[i*2+1])); + rowBuffer[i] = static_cast(orgPlane/MAX_HALF*ALPHA_OPAQUE); + } + uint8_t *rowBufferPtr = rowBuffer.get(); + jpeg_write_scanlines(&encodeInfo_, &rowBufferPtr, RW_LINE_NUM); + } + jpeg_finish_compress(&encodeInfo_); + return SUCCESS; +} + JpegEncoder::~JpegEncoder() { jpeg_destroy_compress(&encodeInfo_); -- Gitee From 8635d188eec7a00e4899e68c95a5592631944538 Mon Sep 17 00:00:00 2001 From: zewu-feng Date: Fri, 27 May 2022 16:09:50 +0800 Subject: [PATCH 2/8] check_new_exifinfo and add webp encoder Signed-off-by: zewu-feng --- .../innerkitsimpl/codec/src/image_source.cpp | 2 +- .../kits/js/common/image_source_napi.cpp | 15 +- .../image/libjpegplugin/include/exif_info.h | 4 + .../image/libjpegplugin/src/exif_info.cpp | 8 + .../image/libjpegplugin/src/jpeg_decoder.cpp | 20 + .../common/libs/image/libwebpplugin/BUILD.gn | 4 + .../libwebpplugin/include/webp_encoder.h | 82 ++ .../image/libwebpplugin/src/plugin_export.cpp | 2 + .../image/libwebpplugin/src/webp_encoder.cpp | 721 ++++++++++++++++++ .../image/libwebpplugin/webpplugin.pluginmeta | 17 + 10 files changed, 873 insertions(+), 2 deletions(-) create mode 100644 plugins/common/libs/image/libwebpplugin/include/webp_encoder.h create mode 100644 plugins/common/libs/image/libwebpplugin/src/webp_encoder.cpp diff --git a/frameworks/innerkitsimpl/codec/src/image_source.cpp b/frameworks/innerkitsimpl/codec/src/image_source.cpp index b9d927e30..47b4e5be2 100644 --- a/frameworks/innerkitsimpl/codec/src/image_source.cpp +++ b/frameworks/innerkitsimpl/codec/src/image_source.cpp @@ -326,7 +326,7 @@ unique_ptr ImageSource::CreatePixelMap(uint32_t index, const DecodeOpt } DecodeContext context; - FinalOutputStep finalOutputStep; + FinalOutputStep finalOutputStep = FinalOutputStep::NO_CHANGE; if (!useSkia) { bool hasNinePatch = mainDecoder_->HasProperty(NINE_PATCH); finalOutputStep = GetFinalOutputStep(opts, *(pixelMap.get()), hasNinePatch); diff --git a/frameworks/kits/js/common/image_source_napi.cpp b/frameworks/kits/js/common/image_source_napi.cpp index c97003651..99ace31b3 100644 --- a/frameworks/kits/js/common/image_source_napi.cpp +++ b/frameworks/kits/js/common/image_source_napi.cpp @@ -500,7 +500,8 @@ napi_value ImageSourceNapi::CreateImageSource(napi_env env, napi_callback_info i if (!IMG_IS_OK(status)) { delete[] buffer; HiLog::Error(LABEL, "fail to get pathName"); - return nullptr; + napi_get_undefined(env, &result); + return result; } asyncContext->pathName = buffer; @@ -517,6 +518,12 @@ napi_value ImageSourceNapi::CreateImageSource(napi_env env, napi_callback_info i } else if (argCount == NUM_1) { status = napi_get_arraybuffer_info(env, argValue[NUM_0], &(asyncContext->sourceBuffer), &(asyncContext->sourceBufferSize)); + if (!IMG_IS_OK(status)) { + HiLog::Error(LABEL, "fail to getarraybuffer"); + napi_get_undefined(env, &result); + return result; + } + fileBuffer_ = asyncContext->sourceBuffer; fileBufferSize_ = asyncContext->sourceBufferSize; imageSource = ImageSource::CreateImageSource(static_cast(asyncContext->sourceBuffer), @@ -1220,6 +1227,12 @@ napi_value ImageSourceNapi::UpdateData(napi_env env, napi_callback_info info) HiLog::Debug(LABEL, "asyncContext->updataLength is [%{public}u]", asyncContext->updataLength); } + if (!IMG_IS_OK(status)) { + HiLog::Error(LABEL, "fail to UpdateData"); + napi_get_undefined(env, &result); + return result; + } + if (argCount == NUM_5 && ImageNapiUtils::getType(env, argValue[NUM_4]) == napi_function) { napi_create_reference(env, argValue[NUM_4], refCount, &asyncContext->callbackRef); } diff --git a/plugins/common/libs/image/libjpegplugin/include/exif_info.h b/plugins/common/libs/image/libjpegplugin/include/exif_info.h index fb1e9a1a2..79666b2e9 100644 --- a/plugins/common/libs/image/libjpegplugin/include/exif_info.h +++ b/plugins/common/libs/image/libjpegplugin/include/exif_info.h @@ -50,6 +50,10 @@ public: std::string gpsLatitudeRef_; std::string gpsLongitudeRef_; std::string dateTimeOriginal_; // Original date and time. + std::string exposureTime_; + std::string fNumber_; + std::string isoSpeedRatings_; + std::string sceneType_; private: void SetExifTagValues(const ExifTag &tag, const std::string &value); diff --git a/plugins/common/libs/image/libjpegplugin/src/exif_info.cpp b/plugins/common/libs/image/libjpegplugin/src/exif_info.cpp index 780174b55..7b7c01f8f 100644 --- a/plugins/common/libs/image/libjpegplugin/src/exif_info.cpp +++ b/plugins/common/libs/image/libjpegplugin/src/exif_info.cpp @@ -114,6 +114,14 @@ void EXIFInfo::SetExifTagValues(const ExifTag &tag, const std::string &value) gpsLongitudeRef_ = value; } else if (tag == EXIF_TAG_DATE_TIME_ORIGINAL) { dateTimeOriginal_ = value; + } else if (tag == EXIF_TAG_EXPOSURE_TIME) { + exposureTime_ = value; + } else if (tag == EXIF_TAG_FNUMBER) { + fNumber_ = value; + } else if (tag == EXIF_TAG_ISO_SPEED_RATINGS) { + isoSpeedRatings_ = value; + } else if (tag == EXIF_TAG_SCENE_TYPE) { + sceneType_ = value; } else { HiLog::Error(LABEL, "No match tag name!"); } diff --git a/plugins/common/libs/image/libjpegplugin/src/jpeg_decoder.cpp b/plugins/common/libs/image/libjpegplugin/src/jpeg_decoder.cpp index 155728a5a..ae6db401a 100644 --- a/plugins/common/libs/image/libjpegplugin/src/jpeg_decoder.cpp +++ b/plugins/common/libs/image/libjpegplugin/src/jpeg_decoder.cpp @@ -58,6 +58,10 @@ const std::string GPS_LONGITUDE = "GPSLongitude"; const std::string GPS_LATITUDE_REF = "GPSLatitudeRef"; const std::string GPS_LONGITUDE_REF = "GPSLongitudeRef"; const std::string DATE_TIME_ORIGINAL = "DateTimeOriginal"; +const std::string EXPOSURE_TIME = "ExposureTime"; +const std::string F_NUMBER = "FNumber"; +const std::string ISO_SPEED_RATINGS = "ISOSpeedRatings"; +const std::string SCENE_TYPE = "SceneType"; } // namespace PluginServer &JpegDecoder::pluginServer_ = DelayedRefSingleton::GetInstance(); @@ -593,6 +597,14 @@ uint32_t JpegDecoder::GetImagePropertyString(uint32_t index, const std::string & value = exifInfo_.gpsLongitudeRef_; } else if (IsSameTextStr(key, DATE_TIME_ORIGINAL)) { value = exifInfo_.dateTimeOriginal_; + } else if (IsSameTextStr(key, EXPOSURE_TIME)) { + value = exifInfo_.exposureTime_; + } else if (IsSameTextStr(key, F_NUMBER)) { + value = exifInfo_.fNumber_; + } else if (IsSameTextStr(key, ISO_SPEED_RATINGS)) { + value = exifInfo_.isoSpeedRatings_; + } else if (IsSameTextStr(key, SCENE_TYPE)) { + value = exifInfo_.sceneType_; } else { return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT; } @@ -620,6 +632,14 @@ ExifTag JpegDecoder::getExifTagFromKey(const std::string &key) return EXIF_TAG_GPS_LONGITUDE_REF; } else if (IsSameTextStr(key, DATE_TIME_ORIGINAL)) { return EXIF_TAG_DATE_TIME_ORIGINAL; + } else if (IsSameTextStr(key, EXPOSURE_TIME)) { + return EXIF_TAG_EXPOSURE_TIME; + } else if (IsSameTextStr(key, F_NUMBER)) { + return EXIF_TAG_FNUMBER; + } else if (IsSameTextStr(key, ISO_SPEED_RATINGS)) { + return EXIF_TAG_ISO_SPEED_RATINGS; + } else if (IsSameTextStr(key, SCENE_TYPE)) { + return EXIF_TAG_SCENE_TYPE; } else { return EXIF_TAG_PRINT_IMAGE_MATCHING; } diff --git a/plugins/common/libs/image/libwebpplugin/BUILD.gn b/plugins/common/libs/image/libwebpplugin/BUILD.gn index 7b45dedd1..4baec83b5 100644 --- a/plugins/common/libs/image/libwebpplugin/BUILD.gn +++ b/plugins/common/libs/image/libwebpplugin/BUILD.gn @@ -17,11 +17,13 @@ import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") ohos_shared_library("webpplugin") { sources = [ "//foundation/multimedia/image_standard/plugins/common/libs/image/libwebpplugin/src/plugin_export.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/libwebpplugin/src/webp_encoder.cpp", "//foundation/multimedia/image_standard/plugins/common/libs/image/libwebpplugin/src/webp_decoder.cpp", ] include_dirs = [ "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/pixelconverter/include", "//foundation/multimedia/utils/include", "//foundation/multimedia/image_standard/plugins/manager/include", "//foundation/multimedia/image_standard/plugins/manager/include/image", @@ -56,6 +58,8 @@ ohos_shared_library("webpplugin") { deps = [ "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", "//third_party/flutter/build/skia:ace_skia_ohos", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/pixelconverter:pixelconvertadapter", + "//foundation/multimedia/image_standard/interfaces/innerkits:image_native", "//utils/native/base:utils", ] diff --git a/plugins/common/libs/image/libwebpplugin/include/webp_encoder.h b/plugins/common/libs/image/libwebpplugin/include/webp_encoder.h new file mode 100644 index 000000000..fec05a9af --- /dev/null +++ b/plugins/common/libs/image/libwebpplugin/include/webp_encoder.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef WEBP_ENCODER_H +#define WEBP_ENCODER_H +#include +#include "abs_image_encoder.h" +#include "plugin_class_base.h" +#include "webp/encode.h" +#include "src/images/SkImageEncoderFns.h" +#include "SkImageEncoderFns.h" +#include "SkStream.h" +namespace OHOS { +namespace ImagePlugin { +class WebpEncoder : public AbsImageEncoder, public OHOS::MultimediaPlugin::PluginClassBase { +public: + WebpEncoder(); + ~WebpEncoder() override; + uint32_t StartEncode(OutputDataStream &outputStream, PlEncodeOptions &option) override; + uint32_t AddImage(Media::PixelMap &pixelMap) override; + uint32_t FinalizeEncode() override; + bool Write(const uint8_t* data, size_t data_size); + +private: + DISALLOW_COPY_AND_MOVE(WebpEncoder); + bool CheckEncodeFormat(Media::PixelMap &pixelMap); + uint32_t SetEncodeConfig(Media::PixelMap &pixelMap, WebPConfig &webpConfig, WebPPicture &webpPicture); + uint32_t DoEncode(Media::PixelMap &pixelMap, WebPConfig &webpConfig, WebPPicture &webpPicture); + uint32_t DoEncodeForICC(Media::PixelMap &pixelMap); + bool DoTransform(Media::PixelMap &pixelMap, char* dst, int componentsNum); + +private: + Media::ColorSpace GetColorSpace(Media::PixelMap &pixelMap); + Media::PixelFormat GetPixelFormat(Media::PixelMap &pixelMap); + Media::AlphaType GetAlphaType(Media::PixelMap &pixelMap); + bool GetIcc(Media::PixelMap &pixelMap); + bool IsOpaque(Media::PixelMap &pixelMap); + +private: + static bool DoTransformMemcpy(Media::PixelMap &pixelMap, char* dst, int componentsNum); + static bool DoTransformRGBX(Media::PixelMap &pixelMap, char* dst, int componentsNum); + static bool DoTransformRgbA(Media::PixelMap &pixelMap, char* dst, int componentsNum); + static bool DoTransformBGRX(Media::PixelMap &pixelMap, char* dst, int componentsNum); + static bool DoTransformBGRA(Media::PixelMap &pixelMap, char* dst, int componentsNum); + static bool DoTransformBgrA(Media::PixelMap &pixelMap, char* dst, int componentsNum); + static bool DoTransformF16To8888(Media::PixelMap &pixelMap, char* dst, int componentsNum); + static bool DoTransformF16pTo8888(Media::PixelMap &pixelMap, char* dst, int componentsNum); + static bool DoTransformRGB565(Media::PixelMap &pixelMap, char* dst, int componentsNum); + static bool DoTransformGray(Media::PixelMap &pixelMap, char* dst, int componentsNum); + static Media::ImageInfo MakeImageInfo(int width, int height, Media::PixelFormat pf, Media::AlphaType at, + Media::ColorSpace cs = Media::ColorSpace::SRGB); + static void ShowTransformParam(const Media::ImageInfo &srcInfo, const uint32_t &srcRowBytes, + const Media::ImageInfo &dstInfo, const uint32_t &dstRowBytes, const int &componentsNum); + +private: + OutputDataStream *outputStream_ {nullptr}; + SkDynamicMemoryWStream memoryStream_; + std::vector pixelMaps_; + PlEncodeOptions encodeOpts_; + + int32_t componentsNum_ {0}; + + // ICC data + bool iccValid_ {false}; + uint8_t* iccBytes_ {nullptr}; + size_t iccSize_ {0}; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // WEBP_ENCODER_H \ No newline at end of file diff --git a/plugins/common/libs/image/libwebpplugin/src/plugin_export.cpp b/plugins/common/libs/image/libwebpplugin/src/plugin_export.cpp index 92950d6e2..d4620ea75 100644 --- a/plugins/common/libs/image/libwebpplugin/src/plugin_export.cpp +++ b/plugins/common/libs/image/libwebpplugin/src/plugin_export.cpp @@ -18,6 +18,7 @@ #include "log_tags.h" #include "plugin_utils.h" #include "webp_decoder.h" +#include "webp_encoder.h" // plugin package name same as metadata. namespace { @@ -27,6 +28,7 @@ namespace { // register implement classes of this plugin. PLUGIN_EXPORT_REGISTER_CLASS_BEGIN PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::WebpDecoder) +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::WebpEncoder) PLUGIN_EXPORT_REGISTER_CLASS_END using std::string; diff --git a/plugins/common/libs/image/libwebpplugin/src/webp_encoder.cpp b/plugins/common/libs/image/libwebpplugin/src/webp_encoder.cpp new file mode 100644 index 000000000..1a4379364 --- /dev/null +++ b/plugins/common/libs/image/libwebpplugin/src/webp_encoder.cpp @@ -0,0 +1,721 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "webp_encoder.h" +#include "webp/mux.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "media_errors.h" +#include "pixel_convert_adapter.h" +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace MultimediaPlugin; +using namespace Media; +namespace { +constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "WebpEncoder" }; +constexpr uint32_t WEBP_IMAGE_NUM = 1; +constexpr uint32_t COMPONENT_NUM_3 = 3; +constexpr uint32_t COMPONENT_NUM_4 = 4; +} // namespace + +static int StreamWriter(const uint8_t* data, size_t data_size, const WebPPicture* const picture) +{ + HiLog::Debug(LABEL, "StreamWriter data_size=%{public}u", data_size); + + auto webpEncoder = static_cast(picture->custom_ptr); + return webpEncoder->Write(data, data_size) ? 1 : 0; +} + +WebpEncoder::WebpEncoder() +{ + HiLog::Debug(LABEL, "create IN"); + + HiLog::Debug(LABEL, "create OUT"); +} + +WebpEncoder::~WebpEncoder() +{ + HiLog::Debug(LABEL, "release IN"); + + pixelMaps_.clear(); + + HiLog::Debug(LABEL, "release OUT"); +} + +uint32_t WebpEncoder::StartEncode(OutputDataStream &outputStream, PlEncodeOptions &option) +{ + HiLog::Debug(LABEL, "StartEncode IN, quality=%{public}u, numberHint=%{public}u", + option.quality, option.numberHint); + + pixelMaps_.clear(); + + outputStream_ = &outputStream; + encodeOpts_ = option; + + HiLog::Debug(LABEL, "StartEncode OUT"); + return SUCCESS; +} + +uint32_t WebpEncoder::AddImage(Media::PixelMap &pixelMap) +{ + HiLog::Debug(LABEL, "AddImage IN"); + + if (pixelMaps_.size() >= WEBP_IMAGE_NUM) { + HiLog::Error(LABEL, "AddImage, add pixel map out of range=%{public}u.", WEBP_IMAGE_NUM); + return ERR_IMAGE_ADD_PIXEL_MAP_FAILED; + } + + pixelMaps_.push_back(&pixelMap); + + HiLog::Debug(LABEL, "AddImage OUT"); + return SUCCESS; +} + +uint32_t WebpEncoder::FinalizeEncode() +{ + HiLog::Debug(LABEL, "FinalizeEncode IN"); + + if (pixelMaps_.empty()) { + HiLog::Error(LABEL, "FinalizeEncode, no pixel map input."); + return ERR_IMAGE_INVALID_PARAMETER; + } + + HiLog::Debug(LABEL, "FinalizeEncode, quality=%{public}u, numberHint=%{public}u", + encodeOpts_.quality, encodeOpts_.numberHint); + + uint32_t errorCode = ERROR; + + Media::PixelMap &pixelMap = *(pixelMaps_[0]); + WebPConfig webpConfig; + WebPPicture webpPicture; + WebPPictureInit(&webpPicture); + + errorCode = SetEncodeConfig(pixelMap, webpConfig, webpPicture); + HiLog::Debug(LABEL, "FinalizeEncode, config, %{public}u.", errorCode); + + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "FinalizeEncode, config failed=%{public}u.", errorCode); + WebPPictureFree(&webpPicture); + return errorCode; + } + + errorCode = DoEncode(pixelMap, webpConfig, webpPicture); + HiLog::Debug(LABEL, "FinalizeEncode, encode,%{public}u.", errorCode); + WebPPictureFree(&webpPicture); + + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "FinalizeEncode, encode failed=%{public}u.", errorCode); + } + + HiLog::Debug(LABEL, "FinalizeEncode OUT"); + return errorCode; +} + +bool WebpEncoder::Write(const uint8_t* data, size_t data_size) +{ + HiLog::Debug(LABEL, "Write data_size=%{public}u, iccValid=%{public}d", data_size, iccValid_); + + if (iccValid_) { + return memoryStream_.write(data, data_size); + } + + return outputStream_->Write(data, data_size); +} + +bool WebpEncoder::CheckEncodeFormat(Media::PixelMap &pixelMap) +{ + PixelFormat pixelFormat = GetPixelFormat(pixelMap); + HiLog::Debug(LABEL, "CheckEncodeFormat, pixelFormat=%{public}u", pixelFormat); + + switch (pixelFormat) { + case PixelFormat::RGBA_8888: { + HiLog::Debug(LABEL, "CheckEncodeFormat, RGBA_8888"); + return true; + } + case PixelFormat::BGRA_8888: { + HiLog::Debug(LABEL, "CheckEncodeFormat, BGRA_8888"); + return true; + } + case PixelFormat::RGBA_F16: { + HiLog::Debug(LABEL, "CheckEncodeFormat, RGBA_F16"); + return true; + } + case PixelFormat::RGB_565: { + bool isOpaque = IsOpaque(pixelMap); + HiLog::Debug(LABEL, "CheckEncodeFormat, RGB_565, isOpaque=%{public}d", isOpaque); + return isOpaque; + } + case PixelFormat::ALPHA_8: { + HiLog::Debug(LABEL, "CheckEncodeFormat, ALPHA_8"); + return true; + } + default: { + HiLog::Error(LABEL, "CheckEncodeFormat, pixelFormat=%{public}u", pixelFormat); + return false; + } + } +} + +bool WebpEncoder::DoTransform(Media::PixelMap &pixelMap, char* dst, int componentsNum) +{ + HiLog::Debug(LABEL, "DoTransform IN"); + + PixelFormat pixelFormat = GetPixelFormat(pixelMap); + AlphaType alphaType = GetAlphaType(pixelMap); + HiLog::Debug(LABEL, "DoTransform, pixelFormat=%{public}u, alphaType=%{public}d, componentsNum=%{public}d", + pixelFormat, alphaType, componentsNum); + + if ((pixelFormat == PixelFormat::RGBA_8888) && (alphaType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE)) { + HiLog::Debug(LABEL, "DoTransform, RGBA_8888, OPAQUE"); + return DoTransformRGBX(pixelMap, dst, componentsNum); + } else if ((pixelFormat == PixelFormat::RGBA_8888) && (alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL)) { + HiLog::Debug(LABEL, "DoTransform, RGBA_8888, UNPREMUL"); + return DoTransformMemcpy(pixelMap, dst, componentsNum); + } else if ((pixelFormat == PixelFormat::RGBA_8888) && (alphaType == AlphaType::IMAGE_ALPHA_TYPE_PREMUL)) { + HiLog::Debug(LABEL, "DoTransform, RGBA_8888, PREMUL"); + return DoTransformRgbA(pixelMap, dst, componentsNum); + } else if ((pixelFormat == PixelFormat::BGRA_8888) && (alphaType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE)) { + HiLog::Debug(LABEL, "DoTransform, BGRA_8888, OPAQUE"); + return DoTransformBGRX(pixelMap, dst, componentsNum); + } else if ((pixelFormat == PixelFormat::BGRA_8888) && (alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL)) { + HiLog::Debug(LABEL, "DoTransform, BGRA_8888, UNPREMUL"); + return DoTransformBGRA(pixelMap, dst, componentsNum); + } else if ((pixelFormat == PixelFormat::BGRA_8888) && (alphaType == AlphaType::IMAGE_ALPHA_TYPE_PREMUL)) { + HiLog::Debug(LABEL, "DoTransform, BGRA_8888, PREMUL"); + return DoTransformBgrA(pixelMap, dst, componentsNum); + } else if ((pixelFormat == PixelFormat::RGBA_F16) && (alphaType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE)) { + HiLog::Debug(LABEL, "DoTransform, RGBA_F16, OPAQUE"); + return DoTransformF16To8888(pixelMap, dst, componentsNum); + } else if ((pixelFormat == PixelFormat::RGBA_F16) && (alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL)) { + HiLog::Debug(LABEL, "DoTransform, RGBA_F16, UNPREMUL"); + return DoTransformF16To8888(pixelMap, dst, componentsNum); + } else if ((pixelFormat == PixelFormat::RGBA_F16) && (alphaType == AlphaType::IMAGE_ALPHA_TYPE_PREMUL)) { + HiLog::Debug(LABEL, "DoTransform, RGBA_F16, PREMUL"); + return DoTransformF16pTo8888(pixelMap, dst, componentsNum); + } else if ((pixelFormat == PixelFormat::RGB_565) && IsOpaque(pixelMap)) { + HiLog::Debug(LABEL, "DoTransform, RGB_565, Opaque"); + return DoTransformRGB565(pixelMap, dst, componentsNum); + } else if (pixelFormat == PixelFormat::ALPHA_8) { + HiLog::Debug(LABEL, "DoTransform, ALPHA_8"); + return DoTransformGray(pixelMap, dst, componentsNum); + } + + HiLog::Debug(LABEL, "DoTransform OUT"); + return false; +} + +uint32_t WebpEncoder::SetEncodeConfig(Media::PixelMap &pixelMap, WebPConfig &webpConfig, WebPPicture &webpPicture) +{ + HiLog::Debug(LABEL, "SetEncodeConfig IN"); + + if (pixelMap.GetPixels() == nullptr) { + HiLog::Error(LABEL, "SetEncodeConfig, pixels invalid."); + return ERROR; + } + + if (!CheckEncodeFormat(pixelMap)) { + HiLog::Error(LABEL, "SetEncodeConfig, check invalid."); + return ERR_IMAGE_UNKNOWN_FORMAT; + } + + if (GetPixelFormat(pixelMap) == PixelFormat::RGBA_F16) { + componentsNum_ = COMPONENT_NUM_4; + } else { + componentsNum_ = IsOpaque(pixelMap) ? COMPONENT_NUM_3 : COMPONENT_NUM_4; + } + HiLog::Debug(LABEL, "SetEncodeConfig, componentsNum_=%{public}u", componentsNum_); + + if (!WebPConfigPreset(&webpConfig, WEBP_PRESET_DEFAULT, encodeOpts_.quality)) { + HiLog::Error(LABEL, "SetEncodeConfig, config preset issue."); + return ERROR; + } + + GetIcc(pixelMap); + + webpConfig.lossless = 1; // Lossless encoding (0=lossy(default), 1=lossless). + webpConfig.method = 0; // quality/speed trade-off (0=fast, 6=slower-better) + webpPicture.use_argb = 1; // Main flag for encoder selecting between ARGB or YUV input. + + webpPicture.width = pixelMap.GetWidth(); // dimensions (less or equal to WEBP_MAX_DIMENSION) + webpPicture.height = pixelMap.GetHeight(); // dimensions (less or equal to WEBP_MAX_DIMENSION) + webpPicture.writer = StreamWriter; + webpPicture.custom_ptr = static_cast(this); + + auto colorSpace = GetColorSpace(pixelMap); + HiLog::Debug(LABEL, "SetEncodeConfig, " + "width=%{public}u, height=%{public}u, colorspace=%{public}d, componentsNum_=%{public}d.", + webpPicture.width, webpPicture.height, colorSpace, componentsNum_); + + HiLog::Debug(LABEL, "SetEncodeConfig OUT"); + return SUCCESS; +} + +uint32_t WebpEncoder::DoEncode(Media::PixelMap &pixelMap, WebPConfig &webpConfig, WebPPicture &webpPicture) +{ + HiLog::Debug(LABEL, "DoEncode IN"); + + const int width = pixelMap.GetWidth(); + const int height = webpPicture.height; + const int rgbStride = width * componentsNum_; + const int rgbSize = rgbStride * height; + HiLog::Debug(LABEL, "DoEncode, width=%{public}d, height=%{public}d, componentsNum=%{public}d," + " rgbStride=%{public}d, rgbSize=%{public}d", width, height, componentsNum_, rgbStride, rgbSize); + + std::unique_ptr rgb = std::make_unique(rgbSize); + if (!DoTransform(pixelMap, reinterpret_cast(&rgb[0]), componentsNum_)) { + HiLog::Error(LABEL, "DoEncode, transform issue."); + return ERROR; + } + + auto importProc = WebPPictureImportRGB; + if (componentsNum_ != COMPONENT_NUM_3) { + importProc = (IsOpaque(pixelMap)) ? WebPPictureImportRGBX : WebPPictureImportRGBA; + } + + HiLog::Debug(LABEL, "DoEncode, importProc"); + if (!importProc(&webpPicture, &rgb[0], rgbStride)) { + HiLog::Error(LABEL, "DoEncode, import issue."); + return ERROR; + } + + HiLog::Debug(LABEL, "DoEncode, WebPEncode"); + if (!WebPEncode(&webpConfig, &webpPicture)) { + HiLog::Error(LABEL, "DoEncode, encode issue."); + return ERROR; + } + + HiLog::Debug(LABEL, "DoEncode, iccValid=%{public}d", iccValid_); + if (iccValid_) { + auto res = DoEncodeForICC(pixelMap); + if (res != SUCCESS) { + HiLog::Error(LABEL, "DoEncode, encode for icc issue."); + return res; + } + } + + HiLog::Debug(LABEL, "DoEncode OUT"); + return SUCCESS; +} + +uint32_t WebpEncoder::DoEncodeForICC(Media::PixelMap &pixelMap) +{ + HiLog::Debug(LABEL, "DoEncodeForICC IN"); + + auto encodedData = memoryStream_.detachAsData(); + WebPData webpEncode = { encodedData->bytes(), encodedData->size() }; + WebPData webpIcc = { iccBytes_, iccSize_ }; + + auto mux = WebPMuxNew(); + if (WebPMuxSetImage(mux, &webpEncode, 0) != WEBP_MUX_OK) { + HiLog::Error(LABEL, "DoEncodeForICC, image issue."); + WebPMuxDelete(mux); + return ERROR; + } + + if (WebPMuxSetChunk(mux, "ICCP", &webpIcc, 0) != WEBP_MUX_OK) { + HiLog::Error(LABEL, "DoEncodeForICC, icc issue."); + WebPMuxDelete(mux); + return ERROR; + } + + WebPData webpAssembled; + if (WebPMuxAssemble(mux, &webpAssembled) != WEBP_MUX_OK) { + HiLog::Error(LABEL, "DoEncodeForICC, assemble issue."); + WebPMuxDelete(mux); + return ERROR; + } + + outputStream_->Write(webpAssembled.bytes, webpAssembled.size); + WebPDataClear(&webpAssembled); + WebPMuxDelete(mux); + + HiLog::Debug(LABEL, "DoEncodeForICC OUT"); + return SUCCESS; +} + +ColorSpace WebpEncoder::GetColorSpace(Media::PixelMap &pixelMap) +{ + return pixelMap.GetColorSpace(); +} + +PixelFormat WebpEncoder::GetPixelFormat(Media::PixelMap &pixelMap) +{ + return pixelMap.GetPixelFormat(); +} + +AlphaType WebpEncoder::GetAlphaType(Media::PixelMap &pixelMap) +{ + return pixelMap.GetAlphaType(); +} + +bool WebpEncoder::GetIcc(Media::PixelMap &pixelMap) +{ + return iccValid_; +} + +bool WebpEncoder::IsOpaque(Media::PixelMap &pixelMap) +{ + return (GetAlphaType(pixelMap) == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); +} + +bool WebpEncoder::DoTransformMemcpy(Media::PixelMap &pixelMap, char* dst, int componentsNum) +{ + HiLog::Debug(LABEL, "DoTransformMemcpy IN"); + + auto src = pixelMap.GetPixels(); + if ((src == nullptr) || (dst == nullptr)) { + HiLog::Error(LABEL, "DoTransformMemcpy, address issue."); + return false; + } + + const int32_t width = pixelMap.GetWidth(); + const int32_t height = pixelMap.GetHeight(); + const uint32_t rowBytes = pixelMap.GetRowBytes(); + const int stride = pixelMap.GetWidth() * componentsNum; + + HiLog::Debug(LABEL, + "width=%{public}u, height=%{public}u, rowBytes=%{public}u, stride=%{public}d, componentsNum=%{public}d", + width, height, rowBytes, stride, componentsNum); + + for (int32_t h = 0; h < height; h++) { + transform_scanline_memcpy(reinterpret_cast(&dst[h * stride]), + reinterpret_cast(&src[h * rowBytes]), + width, componentsNum); + } + + HiLog::Debug(LABEL, "DoTransformMemcpy OUT"); + return false; +} + +bool WebpEncoder::DoTransformRGBX(Media::PixelMap &pixelMap, char* dst, int componentsNum) +{ + HiLog::Debug(LABEL, "DoTransformRGBX IN"); + + const void *srcPixels = pixelMap.GetPixels(); + uint32_t srcRowBytes = pixelMap.GetRowBytes(); + const ImageInfo srcInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::RGBA_8888, AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); + + void *dstPixels = dst; + uint32_t dstRowBytes = pixelMap.GetWidth() * componentsNum; + const ImageInfo dstInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::RGB_888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + + ShowTransformParam(srcInfo, srcRowBytes, dstInfo, dstRowBytes, componentsNum); + + if ((srcPixels == nullptr) || (dstPixels == nullptr)) { + HiLog::Error(LABEL, "DoTransformRGBX, address issue."); + return false; + } + + const Position dstPos; + if (!PixelConvertAdapter::WritePixelsConvert(srcPixels, srcRowBytes, srcInfo, + dstPixels, dstPos, dstRowBytes, dstInfo)) { + HiLog::Error(LABEL, "DoTransformRGBX, pixel convert in adapter failed."); + return false; + } + + HiLog::Debug(LABEL, "DoTransformRGBX OUT"); + return true; +} + +bool WebpEncoder::DoTransformRgbA(Media::PixelMap &pixelMap, char* dst, int componentsNum) +{ + HiLog::Debug(LABEL, "DoTransformRgbA IN"); + + const void *srcPixels = pixelMap.GetPixels(); + uint32_t srcRowBytes = pixelMap.GetRowBytes(); + const ImageInfo srcInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::RGBA_8888, AlphaType::IMAGE_ALPHA_TYPE_PREMUL); + + void *dstPixels = dst; + uint32_t dstRowBytes = pixelMap.GetWidth() * componentsNum; + const ImageInfo dstInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::RGBA_8888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + + ShowTransformParam(srcInfo, srcRowBytes, dstInfo, dstRowBytes, componentsNum); + + if ((srcPixels == nullptr) || (dstPixels == nullptr)) { + HiLog::Error(LABEL, "DoTransformRgbA, address issue."); + return false; + } + + const Position dstPos; + if (!PixelConvertAdapter::WritePixelsConvert(srcPixels, srcRowBytes, srcInfo, + dstPixels, dstPos, dstRowBytes, dstInfo)) { + HiLog::Error(LABEL, "DoTransformRgbA, pixel convert in adapter failed."); + return false; + } + + HiLog::Debug(LABEL, "DoTransformRgbA OUT"); + return true; +} + +bool WebpEncoder::DoTransformBGRX(Media::PixelMap &pixelMap, char* dst, int componentsNum) +{ + HiLog::Debug(LABEL, "DoTransformBGRX IN"); + + const void *srcPixels = pixelMap.GetPixels(); + uint32_t srcRowBytes = pixelMap.GetRowBytes(); + const ImageInfo srcInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::BGRA_8888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + + void *dstPixels = dst; + uint32_t dstRowBytes = pixelMap.GetWidth() * componentsNum; + const ImageInfo dstInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::RGB_888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + + ShowTransformParam(srcInfo, srcRowBytes, dstInfo, dstRowBytes, componentsNum); + + if ((srcPixels == nullptr) || (dstPixels == nullptr)) { + HiLog::Error(LABEL, "DoTransformBGRX, address issue."); + return false; + } + + const Position dstPos; + if (!PixelConvertAdapter::WritePixelsConvert(srcPixels, srcRowBytes, srcInfo, + dstPixels, dstPos, dstRowBytes, dstInfo)) { + HiLog::Error(LABEL, "DoTransformBGRX, pixel convert in adapter failed."); + return false; + } + + HiLog::Debug(LABEL, "DoTransformBGRX OUT"); + return true; +} + +bool WebpEncoder::DoTransformBGRA(Media::PixelMap &pixelMap, char* dst, int componentsNum) +{ + HiLog::Debug(LABEL, "DoTransformBGRA IN"); + + const void *srcPixels = pixelMap.GetPixels(); + uint32_t srcRowBytes = pixelMap.GetRowBytes(); + const ImageInfo srcInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::BGRA_8888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + + void *dstPixels = dst; + uint32_t dstRowBytes = pixelMap.GetWidth() * componentsNum; + const ImageInfo dstInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::RGBA_8888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + + ShowTransformParam(srcInfo, srcRowBytes, dstInfo, dstRowBytes, componentsNum); + + if ((srcPixels == nullptr) || (dstPixels == nullptr)) { + HiLog::Error(LABEL, "DoTransformBGRA, address issue."); + return false; + } + + const Position dstPos; + if (!PixelConvertAdapter::WritePixelsConvert(srcPixels, srcRowBytes, srcInfo, + dstPixels, dstPos, dstRowBytes, dstInfo)) { + HiLog::Error(LABEL, "DoTransformBGRA, pixel convert in adapter failed."); + return false; + } + + HiLog::Debug(LABEL, "DoTransformBGRA OUT"); + return true; +} + +bool WebpEncoder::DoTransformBgrA(Media::PixelMap &pixelMap, char* dst, int componentsNum) +{ + HiLog::Debug(LABEL, "DoTransformBgrA IN"); + + const void *srcPixels = pixelMap.GetPixels(); + uint32_t srcRowBytes = pixelMap.GetRowBytes(); + const ImageInfo srcInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::BGRA_8888, AlphaType::IMAGE_ALPHA_TYPE_PREMUL); + + void *dstPixels = dst; + uint32_t dstRowBytes = pixelMap.GetWidth() * componentsNum; + const ImageInfo dstInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::RGBA_8888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + + ShowTransformParam(srcInfo, srcRowBytes, dstInfo, dstRowBytes, componentsNum); + + if ((srcPixels == nullptr) || (dstPixels == nullptr)) { + HiLog::Error(LABEL, "DoTransformBgrA, address issue."); + return false; + } + + const Position dstPos; + if (!PixelConvertAdapter::WritePixelsConvert(srcPixels, srcRowBytes, srcInfo, + dstPixels, dstPos, dstRowBytes, dstInfo)) { + HiLog::Error(LABEL, "DoTransformBgrA, pixel convert in adapter failed."); + return false; + } + + HiLog::Debug(LABEL, "DoTransformBgrA OUT"); + return true; +} + +bool WebpEncoder::DoTransformF16To8888(Media::PixelMap &pixelMap, char* dst, int componentsNum) +{ + HiLog::Debug(LABEL, "DoTransformF16To8888 IN"); + + const void *srcPixels = pixelMap.GetPixels(); + uint32_t srcRowBytes = pixelMap.GetRowBytes(); + const ImageInfo srcInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::RGBA_F16, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + + void *dstPixels = dst; + uint32_t dstRowBytes = pixelMap.GetWidth() * componentsNum; + const ImageInfo dstInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::RGBA_8888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + + ShowTransformParam(srcInfo, srcRowBytes, dstInfo, dstRowBytes, componentsNum); + + if ((srcPixels == nullptr) || (dstPixels == nullptr)) { + HiLog::Error(LABEL, "DoTransformF16To8888, address issue."); + return false; + } + + const Position dstPos; + if (!PixelConvertAdapter::WritePixelsConvert(srcPixels, srcRowBytes, srcInfo, + dstPixels, dstPos, dstRowBytes, dstInfo)) { + HiLog::Error(LABEL, "DoTransformF16To8888, pixel convert in adapter failed."); + return false; + } + + HiLog::Debug(LABEL, "DoTransformF16To8888 OUT"); + return true; +} + +bool WebpEncoder::DoTransformF16pTo8888(Media::PixelMap &pixelMap, char* dst, int componentsNum) +{ + HiLog::Debug(LABEL, "DoTransformF16pTo8888 IN"); + + const void *srcPixels = pixelMap.GetPixels(); + uint32_t srcRowBytes = pixelMap.GetRowBytes(); + const ImageInfo srcInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::RGBA_F16, AlphaType::IMAGE_ALPHA_TYPE_PREMUL); + + void *dstPixels = dst; + uint32_t dstRowBytes = pixelMap.GetWidth() * componentsNum; + const ImageInfo dstInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::RGBA_8888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + + ShowTransformParam(srcInfo, srcRowBytes, dstInfo, dstRowBytes, componentsNum); + + if ((srcPixels == nullptr) || (dstPixels == nullptr)) { + HiLog::Error(LABEL, "DoTransformF16pTo8888, address issue."); + return false; + } + + const Position dstPos; + if (!PixelConvertAdapter::WritePixelsConvert(srcPixels, srcRowBytes, srcInfo, + dstPixels, dstPos, dstRowBytes, dstInfo)) { + HiLog::Error(LABEL, "DoTransformF16pTo8888, pixel convert in adapter failed."); + return false; + } + + HiLog::Debug(LABEL, "DoTransformF16pTo8888 OUT"); + return true; +} + +bool WebpEncoder::DoTransformRGB565(Media::PixelMap &pixelMap, char* dst, int componentsNum) +{ + HiLog::Debug(LABEL, "DoTransformRGB565 IN"); + + const void *srcPixels = pixelMap.GetPixels(); + uint32_t srcRowBytes = pixelMap.GetRowBytes(); + const ImageInfo srcInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::RGB_565, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + + void *dstPixels = dst; + uint32_t dstRowBytes = pixelMap.GetWidth() * componentsNum; + const ImageInfo dstInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::RGB_888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + + ShowTransformParam(srcInfo, srcRowBytes, dstInfo, dstRowBytes, componentsNum); + + if ((srcPixels == nullptr) || (dstPixels == nullptr)) { + HiLog::Error(LABEL, "DoTransformRGB565, address issue."); + return false; + } + + const Position dstPos; + if (!PixelConvertAdapter::WritePixelsConvert(srcPixels, srcRowBytes, srcInfo, + dstPixels, dstPos, dstRowBytes, dstInfo)) { + HiLog::Error(LABEL, "DoTransformRGB565, pixel convert in adapter failed."); + return false; + } + + HiLog::Debug(LABEL, "DoTransformRGB565 OUT"); + return true; +} + +bool WebpEncoder::DoTransformGray(Media::PixelMap &pixelMap, char* dst, int componentsNum) +{ + HiLog::Debug(LABEL, "DoTransformGray IN"); + + const void *srcPixels = pixelMap.GetPixels(); + uint32_t srcRowBytes = pixelMap.GetRowBytes(); + const ImageInfo srcInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::ALPHA_8, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + + void *dstPixels = dst; + uint32_t dstRowBytes = pixelMap.GetWidth() * componentsNum; + const ImageInfo dstInfo = MakeImageInfo(pixelMap.GetWidth(), pixelMap.GetHeight(), + PixelFormat::RGB_888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + + ShowTransformParam(srcInfo, srcRowBytes, dstInfo, dstRowBytes, componentsNum); + + if ((srcPixels == nullptr) || (dstPixels == nullptr)) { + HiLog::Error(LABEL, "DoTransformGray, address issue."); + return false; + } + + const Position dstPos; + if (!PixelConvertAdapter::WritePixelsConvert(srcPixels, srcRowBytes, srcInfo, + dstPixels, dstPos, dstRowBytes, dstInfo)) { + HiLog::Error(LABEL, "DoTransformGray, pixel convert in adapter failed."); + return false; + } + + HiLog::Debug(LABEL, "DoTransformGray OUT"); + return true; +} + +ImageInfo WebpEncoder::MakeImageInfo(int width, int height, PixelFormat pf, AlphaType at, ColorSpace cs) +{ + ImageInfo info = { + .size = { + .width = width, + .height = height + }, + .pixelFormat = pf, + .colorSpace = cs, + .alphaType = at + }; + + return info; +} + +void WebpEncoder::ShowTransformParam(const ImageInfo &srcInfo, const uint32_t &srcRowBytes, + const ImageInfo &dstInfo, const uint32_t &dstRowBytes, const int &componentsNum) +{ + HiLog::Debug(LABEL, + "src(width=%{public}u, height=%{public}u, rowBytes=%{public}u," + " pixelFormat=%{public}u, colorspace=%{public}d, alphaType=%{public}d, baseDensity=%{public}d), " + "dst(width=%{public}u, height=%{public}u, rowBytes=%{public}u," + " pixelFormat=%{public}u, colorspace=%{public}d, alphaType=%{public}d, baseDensity=%{public}d), " + "componentsNum=%{public}d", + srcInfo.size.width, srcInfo.size.height, srcRowBytes, + srcInfo.pixelFormat, srcInfo.colorSpace, srcInfo.alphaType, srcInfo.baseDensity, + dstInfo.size.width, dstInfo.size.height, dstRowBytes, + dstInfo.pixelFormat, dstInfo.colorSpace, dstInfo.alphaType, dstInfo.baseDensity, + componentsNum); +} +} // namespace ImagePlugin +} // namespace OHOS \ No newline at end of file diff --git a/plugins/common/libs/image/libwebpplugin/webpplugin.pluginmeta b/plugins/common/libs/image/libwebpplugin/webpplugin.pluginmeta index 9a2fa9087..d30f3b469 100644 --- a/plugins/common/libs/image/libwebpplugin/webpplugin.pluginmeta +++ b/plugins/common/libs/image/libwebpplugin/webpplugin.pluginmeta @@ -20,6 +20,23 @@ "value": "image/webp" } ] + }, + { + "className":"OHOS::ImagePlugin::WebpEncoder", + "services": [ + { + "interfaceID":3, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/webp" + } + ] } ] } -- Gitee From 49a077aeed3cf28ad1ce4a3c1cd6ab64161a105d Mon Sep 17 00:00:00 2001 From: zewu-feng Date: Fri, 27 May 2022 16:35:51 +0800 Subject: [PATCH 3/8] fix debug Signed-off-by: zewu-feng --- plugins/common/libs/image/libwebpplugin/src/webp_encoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/common/libs/image/libwebpplugin/src/webp_encoder.cpp b/plugins/common/libs/image/libwebpplugin/src/webp_encoder.cpp index 1a4379364..9d52ab957 100644 --- a/plugins/common/libs/image/libwebpplugin/src/webp_encoder.cpp +++ b/plugins/common/libs/image/libwebpplugin/src/webp_encoder.cpp @@ -32,7 +32,7 @@ constexpr uint32_t COMPONENT_NUM_4 = 4; static int StreamWriter(const uint8_t* data, size_t data_size, const WebPPicture* const picture) { - HiLog::Debug(LABEL, "StreamWriter data_size=%{public}u", data_size); + HiLog::Debug(LABEL, "StreamWriter data_size=%{public}zu", data_size); auto webpEncoder = static_cast(picture->custom_ptr); return webpEncoder->Write(data, data_size) ? 1 : 0; @@ -125,7 +125,7 @@ uint32_t WebpEncoder::FinalizeEncode() bool WebpEncoder::Write(const uint8_t* data, size_t data_size) { - HiLog::Debug(LABEL, "Write data_size=%{public}u, iccValid=%{public}d", data_size, iccValid_); + HiLog::Debug(LABEL, "Write data_size=%{public}zu, iccValid=%{public}d", data_size, iccValid_); if (iccValid_) { return memoryStream_.write(data, data_size); -- Gitee From 05431a6d10f7d38417b138af5bc0b4c772147ef8 Mon Sep 17 00:00:00 2001 From: zewu-feng Date: Fri, 27 May 2022 18:28:49 +0800 Subject: [PATCH 4/8] Framework extension feature adding Signed-off-by: zewu-feng --- .../innerkitsimpl/codec/src/image_source.cpp | 58 +- .../innerkitsimpl/common/src/pixel_map.cpp | 54 ++ .../converter/include/post_proc.h | 3 +- .../converter/src/basic_transformer.cpp | 27 +- .../innerkitsimpl/converter/src/post_proc.cpp | 11 + .../kits/js/common/image_source_napi.cpp | 100 +-- frameworks/kits/js/common/pixel_map_napi.cpp | 644 +++++++++++++++++- interfaces/innerkits/BUILD.gn | 1 + interfaces/innerkits/include/image_source.h | 2 + interfaces/innerkits/include/pixel_map.h | 5 + .../kits/js/@ohos.multimedia.image.d.ts | 18 +- .../kits/js/common/include/pixel_map_napi.h | 12 +- 12 files changed, 853 insertions(+), 82 deletions(-) diff --git a/frameworks/innerkitsimpl/codec/src/image_source.cpp b/frameworks/innerkitsimpl/codec/src/image_source.cpp index 47b4e5be2..37da1f566 100644 --- a/frameworks/innerkitsimpl/codec/src/image_source.cpp +++ b/frameworks/innerkitsimpl/codec/src/image_source.cpp @@ -34,6 +34,7 @@ #include "plugin_server.h" #include "post_proc.h" #include "source_stream.h" +#include "include/utils/SkBase64.h" namespace OHOS { namespace Media { @@ -87,6 +88,11 @@ namespace InnerFormat { "image/x-samsung-srw", }; } // namespace InnerFormat +// BASE64 image prefix type data:image/;base64, +static const std::string IMAGE_URL_PREFIX = "data:image/"; +static const std::string BASE64_URL_PREFIX = ";base64,"; +static const int INT_2 = 2; +static const int INT_8 = 8; PluginServer &ImageSource::pluginServer_ = ImageUtils::GetPluginServer(); ImageSource::FormatAgentMap ImageSource::formatAgentMap_ = InitClass(); @@ -169,7 +175,11 @@ unique_ptr ImageSource::CreateImageSource(const uint8_t *data, uint return nullptr; } - unique_ptr streamPtr = BufferSourceStream::CreateSourceStream(data, size); + unique_ptr streamPtr = DecodeBase64(data, size); + if (streamPtr == nullptr) { + streamPtr = BufferSourceStream::CreateSourceStream(data, size); + } + if (streamPtr == nullptr) { IMAGE_LOGE("[ImageSource]failed to create buffer source stream."); errorCode = ERR_IMAGE_SOURCE_DATA; @@ -197,7 +207,11 @@ unique_ptr ImageSource::CreateImageSource(const std::string &pathNa #endif IMAGE_LOGD("[ImageSource]create Imagesource with pathName."); - unique_ptr streamPtr = FileSourceStream::CreateSourceStream(pathName); + unique_ptr streamPtr = DecodeBase64(pathName); + if (streamPtr == nullptr) { + streamPtr = FileSourceStream::CreateSourceStream(pathName); + } + if (streamPtr == nullptr) { IMAGE_LOGE("[ImageSource]failed to create file source stream."); errorCode = ERR_IMAGE_SOURCE_DATA; @@ -1257,5 +1271,45 @@ bool ImageSource::ImageConverChange(const Rect &cropRect, ImageInfo &dstImageInf } return true; } +unique_ptr ImageSource::DecodeBase64(const uint8_t *data, uint32_t size) +{ + string data1(reinterpret_cast(data), size); + return DecodeBase64(data1); +} + +unique_ptr ImageSource::DecodeBase64(const string &data) +{ + if (data.size() < IMAGE_URL_PREFIX.size() || + (data.compare(0, IMAGE_URL_PREFIX.size(), IMAGE_URL_PREFIX) != 0)) { + IMAGE_LOGD("[ImageSource]Base64 image header mismatch."); + return nullptr; + } + + size_t encoding = data.find(BASE64_URL_PREFIX, IMAGE_URL_PREFIX.size()); + if (encoding == data.npos) { + IMAGE_LOGE("[ImageSource]Base64 mismatch."); + return nullptr; + } + string b64Data = data.substr(encoding + BASE64_URL_PREFIX.size()); + size_t rawDataLen = b64Data.size() - count(b64Data.begin(), b64Data.end(), '='); + rawDataLen -= (rawDataLen / INT_8) * INT_2; + + SkBase64 base64Decoder; + if (base64Decoder.decode(b64Data.data(), b64Data.size()) != SkBase64::kNoError) { + IMAGE_LOGE("[ImageSource]base64 image decode failed!"); + return nullptr; + } + + auto base64Data = base64Decoder.getData(); + const uint8_t* imageData = reinterpret_cast(base64Data); + IMAGE_LOGD("[ImageSource]Create BufferSource from decoded base64 string."); + auto result = BufferSourceStream::CreateSourceStream(imageData, rawDataLen); + + if (base64Data != nullptr) { + delete[] base64Data; + base64Data = nullptr; + } + return result; +} } // namespace Media } // namespace OHOS diff --git a/frameworks/innerkitsimpl/common/src/pixel_map.cpp b/frameworks/innerkitsimpl/common/src/pixel_map.cpp index 48efc1353..109815dda 100644 --- a/frameworks/innerkitsimpl/common/src/pixel_map.cpp +++ b/frameworks/innerkitsimpl/common/src/pixel_map.cpp @@ -1378,5 +1378,59 @@ PixelMap *PixelMap::Unmarshalling(Parcel &parcel) pixelMap->SetPixelsAddr(base, context, bufferSize, allocType, nullptr); return pixelMap; } + +void PixelMap::scale(float xAxis, float yAxis) +{ + PostProc postProc; + if (!postProc.ScalePixelMap(xAxis, yAxis, *this)) { + HiLog::Error(LABEL, "scale fail"); + } +} +void PixelMap::translate(float xAxis, float yAxis) +{ + PostProc postProc; + if (!postProc.TranslatePixelMap(xAxis, yAxis, *this)) { + HiLog::Error(LABEL, "translate fail"); + } +} +void PixelMap::rotate(float degrees) +{ + PostProc postProc; + if (!postProc.RotatePixelMap(degrees, *this)) { + HiLog::Error(LABEL, "rotate fail"); + } +} +void PixelMap::flip(bool xAxis, bool yAxis) +{ + if (xAxis == false && yAxis == false) { + return; + } + scale(xAxis?-1:1, yAxis?-1:1); +} +uint32_t PixelMap::crop(const Rect &rect) +{ + PostProc postProc; + auto cropValue = PostProc::GetCropValue(rect, imageInfo_.size); + if (cropValue == CropValue::NOCROP) { + return SUCCESS; + } + + if (cropValue == CropValue::INVALID) { + HiLog::Error(LABEL, "Invalid crop rect"); + return ERR_IMAGE_CROP; + } + + ImageInfo dstImageInfo = { + .size = { + .width = rect.width, + .height = rect.height, + }, + .pixelFormat = imageInfo_.pixelFormat, + .colorSpace = imageInfo_.colorSpace, + .alphaType = imageInfo_.alphaType, + .baseDensity = imageInfo_.baseDensity, + }; + return postProc.ConvertProc(rect, dstImageInfo, *this, imageInfo_); +} } // namespace Media } // namespace OHOS diff --git a/frameworks/innerkitsimpl/converter/include/post_proc.h b/frameworks/innerkitsimpl/converter/include/post_proc.h index ec3ca58d4..787842cd0 100644 --- a/frameworks/innerkitsimpl/converter/include/post_proc.h +++ b/frameworks/innerkitsimpl/converter/include/post_proc.h @@ -36,6 +36,7 @@ public: bool RotatePixelMap(float rotateDegrees, PixelMap &pixelMap); bool ScalePixelMap(const Size &size, PixelMap &pixelMap); bool ScalePixelMap(float scaleX, float scaleY, PixelMap &pixelMap); + bool TranslatePixelMap(float tX, float tY, PixelMap &pixelMap); bool CenterScale(const Size &size, PixelMap &pixelMap); static CropValue GetCropValue(const Rect &rect, const Size &size); @@ -61,4 +62,4 @@ private: } // namespace Media } // namespace OHOS -#endif // POST_PROC_H +#endif // POST_PROC_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/converter/src/basic_transformer.cpp b/frameworks/innerkitsimpl/converter/src/basic_transformer.cpp index f6f79d371..465c6b504 100644 --- a/frameworks/innerkitsimpl/converter/src/basic_transformer.cpp +++ b/frameworks/innerkitsimpl/converter/src/basic_transformer.cpp @@ -66,14 +66,23 @@ void BasicTransformer::GetDstDimension(const Size &srcSize, Size &dstSize) { Matrix::OperType operType = matrix_.GetOperType(); if ((static_cast(operType) & Matrix::SCALE) == Matrix::SCALE) { - dstSize.width = static_cast(srcSize.width * matrix_.GetScaleX() + FHALF); - dstSize.height = static_cast(srcSize.height * matrix_.GetScaleY() + FHALF); + dstSize.width = static_cast(srcSize.width * fabs(matrix_.GetScaleX()) + FHALF); + dstSize.height = static_cast(srcSize.height * fabs(matrix_.GetScaleY()) + FHALF); } if ((static_cast(operType) & Matrix::ROTATEORSKEW) == Matrix::ROTATEORSKEW) { Matrix::CalcXYProc fInvProc = Matrix::GetXYProc(operType); GetRotateDimension(fInvProc, srcSize, dstSize); } + + if ((static_cast(operType) & Matrix::TRANSLATE) == Matrix::TRANSLATE) { + if (matrix_.GetTransX() > 0) { + dstSize.width = static_cast(srcSize.width + matrix_.GetTransX() + FHALF); + } + if (matrix_.GetTranY() > 0) { + dstSize.height = static_cast(srcSize.height + matrix_.GetTranY() + FHALF); + } + } } bool BasicTransformer::CheckAllocateBuffer(PixmapInfo &outPixmap, AllocateMem allocate, @@ -170,6 +179,16 @@ uint32_t BasicTransformer::TransformPixmap(const PixmapInfo &inPixmap, PixmapInf return IMAGE_SUCCESS; } +static inline void pointLoop(Point &pt, const Size &size) +{ + if (pt.x < 0) { + pt.x = size.width + pt.x; + } + if (pt.y < 0) { + pt.y = size.height + pt.y; + } +} + bool BasicTransformer::DrawPixelmap(const PixmapInfo &pixmapInfo, const int32_t pixelBytes, const Size &size, uint8_t *data) { @@ -188,6 +207,9 @@ bool BasicTransformer::DrawPixelmap(const PixmapInfo &pixmapInfo, const int32_t // Center coordinate alignment, need to add 0.5, so the boundary can also be considered fInvProc(invertMatrix, static_cast(x) + minX_ + FHALF, static_cast(y) + minY_ + FHALF, srcPoint); + if ((static_cast(operType) & Matrix::OperType::SCALE) == Matrix::OperType::SCALE) { + pointLoop(srcPoint, pixmapInfo.imageInfo.size); + } if (CheckOutOfRange(srcPoint, pixmapInfo.imageInfo.size)) { continue; } @@ -242,6 +264,7 @@ void BasicTransformer::BilinearProc(const Point &pt, const PixmapInfo &pixmapInf uint32_t suby = GetSubValue(srcY); AroundPixels aroundPixels; + switch (pixmapInfo.imageInfo.pixelFormat) { case PixelFormat::RGBA_8888: case PixelFormat::ARGB_8888: diff --git a/frameworks/innerkitsimpl/converter/src/post_proc.cpp b/frameworks/innerkitsimpl/converter/src/post_proc.cpp index dff5d38a4..6a3da5a95 100644 --- a/frameworks/innerkitsimpl/converter/src/post_proc.cpp +++ b/frameworks/innerkitsimpl/converter/src/post_proc.cpp @@ -84,6 +84,8 @@ uint32_t PostProc::DecodePostProc(const DecodeOptions &opts, PixelMap &pixelMap, IMAGE_LOGE("[PostProc]density scale:transform pixel map failed"); return ERR_IMAGE_TRANSFORM; } + info.baseDensity = opts.fitDensity; + pixelMap.SetImageInfo(info); } } return SUCCESS; @@ -474,6 +476,15 @@ bool PostProc::ScalePixelMap(float scaleX, float scaleY, PixelMap &pixelMap) trans.SetScaleParam(scaleX, scaleY); return Transform(trans, input, pixelMap); } +bool PostProc::TranslatePixelMap(float tX, float tY, PixelMap &pixelMap) +{ + BasicTransformer trans; + PixmapInfo input(false); + ConvertPixelMapToPixmapInfo(pixelMap, input); + + trans.SetTranslateParam(tX, tY); + return Transform(trans, input, pixelMap); +} bool PostProc::Transform(BasicTransformer &trans, const PixmapInfo &input, PixelMap &pixelMap) { diff --git a/frameworks/kits/js/common/image_source_napi.cpp b/frameworks/kits/js/common/image_source_napi.cpp index 99ace31b3..a3a0ccd33 100644 --- a/frameworks/kits/js/common/image_source_napi.cpp +++ b/frameworks/kits/js/common/image_source_napi.cpp @@ -397,9 +397,29 @@ static PixelFormat ParsePixlForamt(int32_t val) return PixelFormat::UNKNOWN; } -static bool ParseDecodeOptions(napi_env env, napi_value root, DecodeOptions* opts, uint32_t* pIndex, napi_value* error) +static bool ParseDecodeOptions2(napi_env env, napi_value root, DecodeOptions* opts, napi_value* error) { uint32_t tmpNumber = 0; + if (!GET_UINT32_BY_NAME(root, "desiredPixelFormat", tmpNumber)) { + HiLog::Debug(LABEL, "no desiredPixelFormat"); + } else { + if (IsSupportPixelFormat(tmpNumber)) { + opts->desiredPixelFormat = ParsePixlForamt(tmpNumber); + } else { + HiLog::Debug(LABEL, "Invalid desiredPixelFormat %{public}d", tmpNumber); + napi_create_string_utf8(env, "DecodeOptions mismatch", NAPI_AUTO_LENGTH, error); + return false; + } + } + + if (!GET_INT32_BY_NAME(root, "fitDensity", opts->fitDensity)) { + HiLog::Debug(LABEL, "no fitDensity"); + } + return true; +} + +static bool ParseDecodeOptions(napi_env env, napi_value root, DecodeOptions* opts, uint32_t* pIndex, napi_value* error) +{ napi_value tmpValue = nullptr; if (!ImageNapiUtils::GetUint32ByName(env, root, "index", pIndex)) { @@ -442,20 +462,7 @@ static bool ParseDecodeOptions(napi_env env, napi_value root, DecodeOptions* opt HiLog::Debug(LABEL, "ParseRegion error"); } } - - tmpNumber = 0; - if (!GET_UINT32_BY_NAME(root, "desiredPixelFormat", tmpNumber)) { - HiLog::Debug(LABEL, "no desiredPixelFormat"); - } else { - if (IsSupportPixelFormat(tmpNumber)) { - opts->desiredPixelFormat = ParsePixlForamt(tmpNumber); - } else { - HiLog::Debug(LABEL, "Invalid desiredPixelFormat %{public}d", tmpNumber); - napi_create_string_utf8(env, "DecodeOptions mismatch", NAPI_AUTO_LENGTH, error); - return false; - } - } - return true; + return ParseDecodeOptions2(env, root, opts, error); } static std::string FileUrlToRawPath(const std::string &path) @@ -467,6 +474,13 @@ static std::string FileUrlToRawPath(const std::string &path) return path; } +static void parseSourceOptions(napi_env env, napi_value root, SourceOptions* opts) +{ + if (!ImageNapiUtils::GetInt32ByName(env, root, "sourceDensity", &(opts->baseDensity))) { + HiLog::Debug(LABEL, "no sourceDensity"); + } +} + napi_value ImageSourceNapi::CreateImageSource(napi_env env, napi_callback_info info) { napi_value result = nullptr; @@ -488,46 +502,36 @@ napi_value ImageSourceNapi::CreateImageSource(napi_env env, napi_callback_info i uint32_t errorCode = ERR_MEDIA_INVALID_VALUE; SourceOptions opts; std::unique_ptr imageSource = nullptr; - if (argCount == NUM_1 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_string) { - size_t bufferSize = 0; - status = napi_get_value_string_utf8(env, argValue[NUM_0], nullptr, NUM_0, &bufferSize); - IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status) && bufferSize > (size_t)0, nullptr, - HiLog::Error(LABEL, "fail to get bufferSize")); - - char* buffer = new char[bufferSize + NUM_1] { 0 }; - status = napi_get_value_string_utf8(env, argValue[NUM_0], buffer, - bufferSize + NUM_1, &(asyncContext->pathNameLength)); - if (!IMG_IS_OK(status)) { - delete[] buffer; + + NAPI_ASSERT(env, argCount > 0, "No arg!"); + + if (argCount > NUM_1) { + parseSourceOptions(env, argValue[NUM_1], &opts); + } + + auto inputType = ImageNapiUtils::getType(env, argValue[NUM_0]); + if (napi_string == inputType) { // File Path + if (!ImageNapiUtils::GetUtf8String(env, argValue[NUM_0], asyncContext->pathName)) { HiLog::Error(LABEL, "fail to get pathName"); napi_get_undefined(env, &result); return result; } - - asyncContext->pathName = buffer; asyncContext->pathName = FileUrlToRawPath(asyncContext->pathName); - + asyncContext->pathNameLength = asyncContext->pathName.size(); HiLog::Debug(LABEL, "pathName is [%{public}s]", asyncContext->pathName.c_str()); filePath_ = asyncContext->pathName; imageSource = ImageSource::CreateImageSource(asyncContext->pathName, opts, errorCode); - } else if (argCount == NUM_1 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_number) { + } else if (napi_number == inputType) { // Fd napi_get_value_int32(env, argValue[NUM_0], &asyncContext->fdIndex); HiLog::Debug(LABEL, "CreateImageSource fdIndex is [%{public}d]", asyncContext->fdIndex); fileDescriptor_ = asyncContext->fdIndex; imageSource = ImageSource::CreateImageSource(asyncContext->fdIndex, opts, errorCode); - } else if (argCount == NUM_1) { - status = napi_get_arraybuffer_info(env, argValue[NUM_0], - &(asyncContext->sourceBuffer), &(asyncContext->sourceBufferSize)); - if (!IMG_IS_OK(status)) { - HiLog::Error(LABEL, "fail to getarraybuffer"); - napi_get_undefined(env, &result); - return result; - } - - fileBuffer_ = asyncContext->sourceBuffer; - fileBufferSize_ = asyncContext->sourceBufferSize; - imageSource = ImageSource::CreateImageSource(static_cast(asyncContext->sourceBuffer), - asyncContext->sourceBufferSize, opts, errorCode); + } else { // Input Buffer + status = napi_get_arraybuffer_info(env, argValue[NUM_0], &(fileBuffer_), &(fileBufferSize_)); + asyncContext->sourceBuffer = fileBuffer_; + asyncContext->sourceBufferSize = fileBufferSize_; + imageSource = ImageSource::CreateImageSource(static_cast(fileBuffer_), + fileBufferSize_, opts, errorCode); } if (errorCode != SUCCESS || imageSource == nullptr) { @@ -582,8 +586,18 @@ napi_value ImageSourceNapi::CreateIncrementalSource(napi_env env, napi_callback_ napi_status status; HiLog::Debug(LABEL, "CreateIncrementalSource IN"); + napi_value thisVar = nullptr; + napi_value argValue[NUM_2] = {0}; + size_t argCount = NUM_2; + IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar); + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + uint32_t errorCode = 0; IncrementalSourceOptions incOpts; + if (argCount == NUM_2) { + parseSourceOptions(env, argValue[NUM_1], &(incOpts.sourceOptions)); + } + incOpts.incrementalMode = IncrementalMode::INCREMENTAL_DATA; std::unique_ptr imageSource = ImageSource::CreateIncrementalImageSource(incOpts, errorCode); DecodeOptions decodeOpts; diff --git a/frameworks/kits/js/common/pixel_map_napi.cpp b/frameworks/kits/js/common/pixel_map_napi.cpp index a426eb4d3..2bf3d6f3c 100644 --- a/frameworks/kits/js/common/pixel_map_napi.cpp +++ b/frameworks/kits/js/common/pixel_map_napi.cpp @@ -56,8 +56,13 @@ struct PixelMapAsyncContext { InitializationOptions opts; PositionArea area; std::shared_ptr rPixelMap; + std::shared_ptr alphaMap; uint32_t resultUint32; ImageInfo imageInfo; + double xArg = 0; + double yArg = 0; + bool xBarg = false; + bool yBarg = false; }; static PixelFormat ParsePixlForamt(int32_t val) @@ -202,6 +207,8 @@ static void CommonCallbackRoutine(napi_env env, PixelMapAsyncContext* &asyncCont if (asyncContext->status == SUCCESS) { result[NUM_1] = valueParam; + } else { + napi_create_uint32(env, asyncContext->status, &result[NUM_0]); } if (asyncContext->deferred) { @@ -249,6 +256,35 @@ PixelMapNapi::~PixelMapNapi() } } +static napi_value DoInitAfter(napi_env env, + napi_value exports, + napi_value constructor, + size_t property_count, + const napi_property_descriptor* properties) +{ + napi_value global = nullptr; + IMG_NAPI_CHECK_RET_D(IMG_IS_OK( + napi_get_global(env, &global)), + nullptr, HiLog::Error(LABEL, "Init:get global fail") + ); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK( + napi_set_named_property(env, global, CLASS_NAME.c_str(), constructor)), + nullptr, HiLog::Error(LABEL, "Init:set global named property fail") + ); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK( + napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor)), + nullptr, HiLog::Error(LABEL, "set named property fail") + ); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK( + napi_define_properties(env, exports, property_count, properties)), + nullptr, HiLog::Error(LABEL, "define properties fail") + ); + return exports; +} + napi_value PixelMapNapi::Init(napi_env env, napi_value exports) { napi_property_descriptor props[] = { @@ -259,7 +295,17 @@ napi_value PixelMapNapi::Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("getImageInfo", GetImageInfo), DECLARE_NAPI_FUNCTION("getBytesNumberPerRow", GetBytesNumberPerRow), DECLARE_NAPI_FUNCTION("getPixelBytesNumber", GetPixelBytesNumber), + DECLARE_NAPI_FUNCTION("isSupportAlpha", IsSupportAlpha), + DECLARE_NAPI_FUNCTION("setAlphaAble", SetAlphaAble), + DECLARE_NAPI_FUNCTION("createAlphaPixelmap", CreateAlphaPixelmap), + DECLARE_NAPI_FUNCTION("getDensity", GetDensity), + DECLARE_NAPI_FUNCTION("setDensity", SetDensity), DECLARE_NAPI_FUNCTION("release", Release), + DECLARE_NAPI_FUNCTION("scale", Scale), + DECLARE_NAPI_FUNCTION("translate", Translate), + DECLARE_NAPI_FUNCTION("rotate", Rotate), + DECLARE_NAPI_FUNCTION("flip", Flip), + DECLARE_NAPI_FUNCTION("crop", Crop), DECLARE_NAPI_GETTER("isEditable", GetIsEditable), }; @@ -274,43 +320,19 @@ napi_value PixelMapNapi::Init(napi_env env, napi_value exports) napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr, IMG_ARRAY_SIZE(props), props, &constructor)), - nullptr, - HiLog::Error(LABEL, "define class fail") + nullptr, HiLog::Error(LABEL, "define class fail") ); IMG_NAPI_CHECK_RET_D(IMG_IS_OK( napi_create_reference(env, constructor, 1, &sConstructor_)), - nullptr, - HiLog::Error(LABEL, "create reference fail") - ); - - napi_value global = nullptr; - IMG_NAPI_CHECK_RET_D(IMG_IS_OK( - napi_get_global(env, &global)), - nullptr, - HiLog::Error(LABEL, "Init:get global fail") + nullptr, HiLog::Error(LABEL, "create reference fail") ); - IMG_NAPI_CHECK_RET_D(IMG_IS_OK( - napi_set_named_property(env, global, CLASS_NAME.c_str(), constructor)), - nullptr, - HiLog::Error(LABEL, "Init:set global named property fail") - ); - - IMG_NAPI_CHECK_RET_D(IMG_IS_OK( - napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor)), - nullptr, - HiLog::Error(LABEL, "set named property fail") - ); - - IMG_NAPI_CHECK_RET_D(IMG_IS_OK( - napi_define_properties(env, exports, IMG_ARRAY_SIZE(static_prop), static_prop)), - nullptr, - HiLog::Error(LABEL, "define properties fail") - ); + auto result = DoInitAfter(env, exports, constructor, + IMG_ARRAY_SIZE(static_prop), static_prop); HiLog::Debug(LABEL, "Init success"); - return exports; + return result; } std::shared_ptr PixelMapNapi::GetPixelMap(napi_env env, napi_value pixelmap) @@ -871,6 +893,9 @@ STATIC_COMPLETE_FUNC(GetImageInfo) napi_value alphaTypeValue = nullptr; napi_create_int32(env, static_cast(context->imageInfo.alphaType), &alphaTypeValue); napi_set_named_property(env, result, "alphaType", alphaTypeValue); + napi_value densityValue = nullptr; + napi_create_int32(env, static_cast(context->imageInfo.baseDensity), &densityValue); + napi_set_named_property(env, result, "density", densityValue); if (!IMG_IS_OK(status)) { context->status = ERROR; HiLog::Error(LABEL, "napi_create_int32 failed!"); @@ -982,6 +1007,202 @@ napi_value PixelMapNapi::GetPixelBytesNumber(napi_env env, napi_callback_info in return result; } +napi_value PixelMapNapi::IsSupportAlpha(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + napi_status status; + napi_value thisVar = nullptr; + size_t argCount = NUM_0; + + HiLog::Debug(LABEL, "IsSupportAlpha IN"); + IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + + std::unique_ptr pixelMapNapi = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&pixelMapNapi)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, pixelMapNapi), result, HiLog::Error(LABEL, "fail to unwrap context")); + if (pixelMapNapi->nativePixelMap_ != nullptr) { + AlphaType alphaType = pixelMapNapi->nativePixelMap_->GetAlphaType(); + bool isSupportAlpha = !(alphaType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); + status = napi_get_boolean(env, isSupportAlpha, &result); + if (!IMG_IS_OK(status)) { + HiLog::Error(LABEL, "napi_create_bool failed!"); + } + } else { + HiLog::Error(LABEL, "native pixelmap is nullptr!"); + } + pixelMapNapi.release(); + return result; +} + +napi_value PixelMapNapi::SetAlphaAble(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + napi_status status; + napi_value thisVar = nullptr; + napi_value argValue[NUM_1] = {0}; + size_t argCount = NUM_1; + bool isAlphaAble = false; + + HiLog::Debug(LABEL, "SetAlphaAble IN"); + IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + NAPI_ASSERT(env, argCount > NUM_0, "Invalid input"); + NAPI_ASSERT(env, ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_boolean, "Invalid input type"); + NAPI_ASSERT(env, napi_get_value_bool(env, argValue[NUM_0], &isAlphaAble) == napi_ok, "Parse input error"); + + std::unique_ptr pixelMapNapi = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&pixelMapNapi)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, pixelMapNapi), result, HiLog::Error(LABEL, "fail to unwrap context")); + + if (pixelMapNapi->nativePixelMap_ != nullptr) { + AlphaType alphaType = pixelMapNapi->nativePixelMap_->GetAlphaType(); + if (isAlphaAble && (alphaType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE)) { + pixelMapNapi->nativePixelMap_->SetAlphaType(AlphaType::IMAGE_ALPHA_TYPE_PREMUL); + } else if ((!isAlphaAble) && !(alphaType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE)) { + pixelMapNapi->nativePixelMap_->SetAlphaType(AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); + } + } else { + HiLog::Error(LABEL, "native pixelmap is nullptr!"); + } + pixelMapNapi.release(); + return result; +} + +static void CreateAlphaPixelmapComplete(napi_env env, napi_status status, void *data) +{ + HiLog::Debug(LABEL, "[PixelMap]CreateAlphaPixelmapComplete IN"); + napi_value result = nullptr; + napi_get_undefined(env, &result); + auto context = static_cast(data); + + if (context->alphaMap != nullptr) { + result = PixelMapNapi::CreatePixelMap(env, context->alphaMap); + context->status = SUCCESS; + } else { + context->status = ERROR; + } + HiLog::Debug(LABEL, "[PixelMap]CreateAlphaPixelmapComplete OUT"); + CommonCallbackRoutine(env, context, result); +} + +napi_value PixelMapNapi::CreateAlphaPixelmap(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + int32_t refCount = 1; + napi_status status; + napi_value thisVar = nullptr; + napi_value argValue[NUM_1] = {0}; + size_t argCount = 1; + HiLog::Debug(LABEL, "CreateAlphaPixelmap IN"); + IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar); + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + std::unique_ptr asyncContext = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->nConstructor)); + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor), + nullptr, HiLog::Error(LABEL, "fail to unwrap context")); + asyncContext->rPixelMap = asyncContext->nConstructor->nativePixelMap_; + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rPixelMap), + nullptr, HiLog::Error(LABEL, "empty native pixelmap")); + if (argCount == NUM_1 && ImageNapiUtils::getType(env, argValue[argCount - 1]) == napi_function) { + napi_create_reference(env, argValue[argCount - 1], refCount, &asyncContext->callbackRef); + } + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &(asyncContext->deferred), &result); + } else { + napi_get_undefined(env, &result); + } + IMG_CREATE_CREATE_ASYNC_WORK(env, status, "CreateAlphaPixelmap", + [](napi_env env, void *data) + { + auto context = static_cast(data); + InitializationOptions opts; + opts.pixelFormat = PixelFormat::ALPHA_8; + auto tmpPixelMap = PixelMap::Create(*(context->rPixelMap), opts); + context->alphaMap = std::move(tmpPixelMap); + context->status = SUCCESS; + }, CreateAlphaPixelmapComplete, asyncContext, asyncContext->work); + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), + nullptr, HiLog::Error(LABEL, "fail to create async work")); + return result; +} + +napi_value PixelMapNapi::GetDensity(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + napi_status status; + napi_value thisVar = nullptr; + size_t argCount = 0; + + HiLog::Debug(LABEL, "GetDensity IN"); + IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + + std::unique_ptr pixelMapNapi = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&pixelMapNapi)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, pixelMapNapi), result, HiLog::Error(LABEL, "fail to unwrap context")); + if (pixelMapNapi->nativePixelMap_ != nullptr) { + uint32_t baseDensity = pixelMapNapi->nativePixelMap_->GetBaseDensity(); + status = napi_create_int32(env, baseDensity, &result); + if (!IMG_IS_OK(status)) { + HiLog::Error(LABEL, "napi_create_int32 failed!"); + } + } else { + HiLog::Error(LABEL, "native pixelmap is nullptr!"); + } + pixelMapNapi.release(); + return result; +} + +napi_value PixelMapNapi::SetDensity(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + napi_status status; + napi_value thisVar = nullptr; + napi_value argValue[NUM_1] = {0}; + size_t argCount = NUM_1; + uint32_t density = 0; + + HiLog::Debug(LABEL, "SetDensity IN"); + IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar); + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + + NAPI_ASSERT(env, + (argCount == NUM_1 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_number), + "Density input mismatch"); + NAPI_ASSERT(env, napi_get_value_uint32(env, argValue[NUM_0], &density) == napi_ok, "Could not parse density"); + + std::unique_ptr pixelMapNapi = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&pixelMapNapi)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, pixelMapNapi), result, HiLog::Error(LABEL, "fail to unwrap context")); + if (pixelMapNapi->nativePixelMap_ != nullptr) { + ImageInfo imageinfo; + pixelMapNapi->nativePixelMap_->GetImageInfo(imageinfo); + imageinfo.baseDensity = density; + pixelMapNapi->nativePixelMap_->SetImageInfo(imageinfo, true); + } else { + HiLog::Error(LABEL, "native pixelmap is nullptr!"); + } + pixelMapNapi.release(); + return result; +} + napi_value PixelMapNapi::Release(napi_env env, napi_callback_info info) { napi_value result = nullptr; @@ -1031,5 +1252,370 @@ napi_value PixelMapNapi::Release(napi_env env, napi_callback_info info) nullptr, HiLog::Error(LABEL, "fail to create async work")); return result; } + +struct NapiValues { + napi_status status; + napi_value thisVar = nullptr; + napi_value result = nullptr; + napi_value* argv = nullptr; + size_t argc; + int32_t refCount = 1; + std::unique_ptr context; +}; + +static bool prepareNapiEnv(napi_env env, napi_callback_info info, struct NapiValues* nVal) +{ + napi_get_undefined(env, &(nVal->result)); + nVal->status = napi_get_cb_info(env, info, &(nVal->argc), nVal->argv, &(nVal->thisVar), nullptr); + if (nVal->status != napi_ok) { + HiLog::Error(LABEL, "fail to napi_get_cb_info"); + return false; + } + nVal->context = std::make_unique(); + nVal->status = napi_unwrap(env, nVal->thisVar, reinterpret_cast(&(nVal->context->nConstructor))); + if (nVal->status != napi_ok) { + HiLog::Error(LABEL, "fail to unwrap context"); + return false; + } + nVal->context->status = SUCCESS; + return true; +} + +static void ScaleExec(napi_env env, PixelMapAsyncContext* context) +{ + if (context == nullptr) { + HiLog::Error(LABEL, "Null context"); + return; + } + if (context->status == SUCCESS) { + if (context->rPixelMap != nullptr) { + + context->rPixelMap->scale(static_cast(context->xArg), static_cast(context->yArg)); + context->status = SUCCESS; + } else { + HiLog::Error(LABEL, "Null native ref"); + context->status = ERR_IMAGE_INIT_ABNORMAL; + } + } else { + HiLog::Debug(LABEL, "Scale has failed. do nothing"); + } +} + +napi_value PixelMapNapi::Scale(napi_env env, napi_callback_info info) +{ + NapiValues nVal; + nVal.argc = NUM_3; + napi_value argValue[NUM_3] = {0}; + nVal.argv = argValue; + HiLog::Debug(LABEL, "Scale IN"); + if (!prepareNapiEnv(env, info, &nVal)) { + return nVal.result; + } + nVal.context->rPixelMap = nVal.context->nConstructor->nativePixelMap_; + + if (nVal.argc != NUM_2 && nVal.argc != NUM_3) { + HiLog::Error(LABEL, "Invalid args count %{public}d", nVal.argc); + nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; + } else { + if (napi_ok != napi_get_value_double(env, nVal.argv[NUM_0], &(nVal.context->xArg))) { + HiLog::Error(LABEL, "Arg 0 type mismatch"); + nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; + } + if (napi_ok != napi_get_value_double(env, nVal.argv[NUM_1], &(nVal.context->yArg))) { + HiLog::Error(LABEL, "Arg 1 type mismatch"); + nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; + } + } + if (nVal.argc >= 1 && ImageNapiUtils::getType(env, nVal.argv[nVal.argc - 1]) == napi_function) { + napi_create_reference(env, nVal.argv[nVal.argc - 1], nVal.refCount, &(nVal.context->callbackRef)); + } + + if (nVal.context->callbackRef == nullptr) { + napi_create_promise(env, &(nVal.context->deferred), &(nVal.result)); + } + napi_value _resource = nullptr; + napi_create_string_utf8(env, "Scale", NAPI_AUTO_LENGTH, &_resource); + nVal.status = napi_create_async_work(env, nullptr, _resource, + [](napi_env env, void *data) + { + auto context = static_cast(data); + ScaleExec(env, context); + }, EmptyResultComplete, static_cast(nVal.context.get()), &(nVal.context->work)); + + if (nVal.status == napi_ok) { + nVal.status = napi_queue_async_work(env, nVal.context->work); + if (nVal.status == napi_ok) { + nVal.context.release(); + } + } + return nVal.result; +} + +static void TranslateExec(napi_env env, PixelMapAsyncContext* context) +{ + if (context == nullptr) { + HiLog::Error(LABEL, "Null context"); + return; + } + if (context->status == SUCCESS) { + if (context->rPixelMap != nullptr) { + context->rPixelMap->translate(static_cast(context->xArg), static_cast(context->yArg)); + context->status = SUCCESS; + } else { + HiLog::Error(LABEL, "Null native ref"); + context->status = ERR_IMAGE_INIT_ABNORMAL; + } + } else { + HiLog::Debug(LABEL, "Translate has failed. do nothing"); + } +} + +napi_value PixelMapNapi::Translate(napi_env env, napi_callback_info info) +{ + NapiValues nVal; + nVal.argc = NUM_3; + napi_value argValue[NUM_3] = {0}; + nVal.argv = argValue; + HiLog::Debug(LABEL, "Translate IN"); + if (!prepareNapiEnv(env, info, &nVal)) { + return nVal.result; + } + nVal.context->rPixelMap = nVal.context->nConstructor->nativePixelMap_; + + if (nVal.argc != NUM_2 && nVal.argc != NUM_3) { + HiLog::Error(LABEL, "Invalid args count"); + nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; + } else { + if (napi_ok != napi_get_value_double(env, nVal.argv[NUM_0], &(nVal.context->xArg))) { + HiLog::Error(LABEL, "Arg 0 type mismatch"); + nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; + } + if (napi_ok != napi_get_value_double(env, nVal.argv[NUM_1], &(nVal.context->yArg))) { + HiLog::Error(LABEL, "Arg 1 type mismatch"); + nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; + } + } + if (nVal.argc >= 1 && ImageNapiUtils::getType(env, nVal.argv[nVal.argc - 1]) == napi_function) { + napi_create_reference(env, nVal.argv[nVal.argc - 1], nVal.refCount, &(nVal.context->callbackRef)); + } + + if (nVal.context->callbackRef == nullptr) { + napi_create_promise(env, &(nVal.context->deferred), &(nVal.result)); + } + napi_value _resource = nullptr; + napi_create_string_utf8(env, "Translate", NAPI_AUTO_LENGTH, &_resource); + nVal.status = napi_create_async_work(env, nullptr, _resource, + [](napi_env env, void *data) + { + auto context = static_cast(data); + TranslateExec(env, context); + }, EmptyResultComplete, static_cast(nVal.context.get()), &(nVal.context->work)); + + if (nVal.status == napi_ok) { + nVal.status = napi_queue_async_work(env, nVal.context->work); + if (nVal.status == napi_ok) { + nVal.context.release(); + } + } + return nVal.result; +} + +static void RotateExec(napi_env env, PixelMapAsyncContext* context) +{ + if (context == nullptr) { + HiLog::Error(LABEL, "Null context"); + return; + } + if (context->status == SUCCESS) { + if (context->rPixelMap != nullptr) { + context->rPixelMap->rotate(context->xArg); + context->status = SUCCESS; + } else { + HiLog::Error(LABEL, "Null native ref"); + context->status = ERR_IMAGE_INIT_ABNORMAL; + } + } else { + HiLog::Debug(LABEL, "Rotate has failed. do nothing"); + } +} + +napi_value PixelMapNapi::Rotate(napi_env env, napi_callback_info info) +{ + NapiValues nVal; + nVal.argc = NUM_2; + napi_value argValue[NUM_2] = {0}; + nVal.argv = argValue; + HiLog::Debug(LABEL, "Rotate IN"); + if (!prepareNapiEnv(env, info, &nVal)) { + return nVal.result; + } + nVal.context->rPixelMap = nVal.context->nConstructor->nativePixelMap_; + + if (nVal.argc != NUM_1 && nVal.argc != NUM_2) { + HiLog::Error(LABEL, "Invalid args count"); + nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; + } else { + if (napi_ok != napi_get_value_double(env, nVal.argv[NUM_0], &(nVal.context->xArg))) { + HiLog::Error(LABEL, "Arg 0 type mismatch"); + nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; + } + } + if (nVal.argc >= 1 && ImageNapiUtils::getType(env, nVal.argv[nVal.argc - 1]) == napi_function) { + napi_create_reference(env, nVal.argv[nVal.argc - 1], nVal.refCount, &(nVal.context->callbackRef)); + } + + if (nVal.context->callbackRef == nullptr) { + napi_create_promise(env, &(nVal.context->deferred), &(nVal.result)); + } + napi_value _resource = nullptr; + napi_create_string_utf8(env, "Rotate", NAPI_AUTO_LENGTH, &_resource); + nVal.status = napi_create_async_work(env, nullptr, _resource, + [](napi_env env, void *data) + { + auto context = static_cast(data); + RotateExec(env, context); + }, EmptyResultComplete, static_cast(nVal.context.get()), &(nVal.context->work)); + + if (nVal.status == napi_ok) { + nVal.status = napi_queue_async_work(env, nVal.context->work); + if (nVal.status == napi_ok) { + nVal.context.release(); + } + } + return nVal.result; +} + +static void FlipExec(napi_env env, PixelMapAsyncContext* context) +{ + if (context == nullptr) { + HiLog::Error(LABEL, "Null context"); + return; + } + if (context->status == SUCCESS) { + if (context->rPixelMap != nullptr) { + context->rPixelMap->flip(context->xBarg, context->yBarg); + context->status = SUCCESS; + } else { + HiLog::Error(LABEL, "Null native ref"); + context->status = ERR_IMAGE_INIT_ABNORMAL; + } + } else { + HiLog::Debug(LABEL, "Flip has failed. do nothing"); + } +} + +napi_value PixelMapNapi::Flip(napi_env env, napi_callback_info info) +{ + NapiValues nVal; + nVal.argc = NUM_3; + napi_value argValue[NUM_3] = {0}; + nVal.argv = argValue; + HiLog::Debug(LABEL, "Flip IN"); + if (!prepareNapiEnv(env, info, &nVal)) { + return nVal.result; + } + nVal.context->rPixelMap = nVal.context->nConstructor->nativePixelMap_; + + if (nVal.argc != NUM_2 && nVal.argc != NUM_3) { + HiLog::Error(LABEL, "Invalid args count"); + nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; + } else { + if (napi_ok != napi_get_value_bool(env, nVal.argv[NUM_0], &(nVal.context->xBarg))) { + HiLog::Error(LABEL, "Arg 0 type mismatch"); + nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; + } + if (napi_ok != napi_get_value_bool(env, nVal.argv[NUM_1], &(nVal.context->yBarg))) { + HiLog::Error(LABEL, "Arg 1 type mismatch"); + nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; + } + } + if (nVal.argc >= 1 && ImageNapiUtils::getType(env, nVal.argv[nVal.argc - 1]) == napi_function) { + napi_create_reference(env, nVal.argv[nVal.argc - 1], nVal.refCount, &(nVal.context->callbackRef)); + } + + if (nVal.context->callbackRef == nullptr) { + napi_create_promise(env, &(nVal.context->deferred), &(nVal.result)); + } + napi_value _resource = nullptr; + napi_create_string_utf8(env, "Flip", NAPI_AUTO_LENGTH, &_resource); + nVal.status = napi_create_async_work(env, nullptr, _resource, + [](napi_env env, void *data) + { + auto context = static_cast(data); + FlipExec(env, context); + }, EmptyResultComplete, static_cast(nVal.context.get()), &(nVal.context->work)); + + if (nVal.status == napi_ok) { + nVal.status = napi_queue_async_work(env, nVal.context->work); + if (nVal.status == napi_ok) { + nVal.context.release(); + } + } + return nVal.result; +} + +static void CropExec(napi_env env, PixelMapAsyncContext* context) +{ + if (context == nullptr) { + HiLog::Error(LABEL, "Null context"); + return; + } + if (context->status == SUCCESS) { + if (context->rPixelMap != nullptr) { + context->status = context->rPixelMap->crop(context->area.region); + } else { + HiLog::Error(LABEL, "Null native ref"); + context->status = ERR_IMAGE_INIT_ABNORMAL; + } + } else { + HiLog::Debug(LABEL, "Crop has failed. do nothing"); + } +} + +napi_value PixelMapNapi::Crop(napi_env env, napi_callback_info info) +{ + NapiValues nVal; + nVal.argc = NUM_2; + napi_value argValue[NUM_2] = {0}; + nVal.argv = argValue; + HiLog::Debug(LABEL, "Crop IN"); + if (!prepareNapiEnv(env, info, &nVal)) { + return nVal.result; + } + nVal.context->rPixelMap = nVal.context->nConstructor->nativePixelMap_; + + if (nVal.argc != NUM_1 && nVal.argc != NUM_2) { + HiLog::Error(LABEL, "Invalid args count"); + nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; + } else { + if (!parseRegion(env, nVal.argv[NUM_0], &(nVal.context->area.region))) { + HiLog::Error(LABEL, "Region type mismatch"); + nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; + } + } + if (nVal.argc >= 1 && ImageNapiUtils::getType(env, nVal.argv[nVal.argc - 1]) == napi_function) { + napi_create_reference(env, nVal.argv[nVal.argc - 1], nVal.refCount, &(nVal.context->callbackRef)); + } + + if (nVal.context->callbackRef == nullptr) { + napi_create_promise(env, &(nVal.context->deferred), &(nVal.result)); + } + napi_value _resource = nullptr; + napi_create_string_utf8(env, "CropExec", NAPI_AUTO_LENGTH, &_resource); + nVal.status = napi_create_async_work(env, nullptr, _resource, + [](napi_env env, void *data) + { + auto context = static_cast(data); + CropExec(env, context); + }, EmptyResultComplete, static_cast(nVal.context.get()), &(nVal.context->work)); + + if (nVal.status == napi_ok) { + nVal.status = napi_queue_async_work(env, nVal.context->work); + if (nVal.status == napi_ok) { + nVal.context.release(); + } + } + return nVal.result; +} } // namespace Media } // namespace OHOS diff --git a/interfaces/innerkits/BUILD.gn b/interfaces/innerkits/BUILD.gn index 96a0d97a2..03c043f03 100644 --- a/interfaces/innerkits/BUILD.gn +++ b/interfaces/innerkits/BUILD.gn @@ -172,6 +172,7 @@ ohos_shared_library("image_native") { DUAL_ADAPTER = true deps = [ + "//third_party/flutter/build/skia:ace_skia_ohos", "//foundation/arkui/napi:ace_napi", "//foundation/graphic/graphic_2d:libsurface", "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/pixelconverter:pixelconvertadapter", diff --git a/interfaces/innerkits/include/image_source.h b/interfaces/innerkits/include/image_source.h index 3ec8b00f8..607e8e4ca 100644 --- a/interfaces/innerkits/include/image_source.h +++ b/interfaces/innerkits/include/image_source.h @@ -210,6 +210,8 @@ private: bool ImageSizeChange(int32_t width, int32_t height, int32_t desiredWidth, int32_t desiredHeight); bool ImageConverChange(const Rect &cropRect, ImageInfo &dstImageInfo, ImageInfo &srcImageInfo); void Reset(); + static std::unique_ptr DecodeBase64(const uint8_t *data, uint32_t size); + static std::unique_ptr DecodeBase64(const std::string &data); const std::string NINE_PATCH = "ninepatch"; const std::string SKIA_DECODER = "SKIA_DECODER"; diff --git a/interfaces/innerkits/include/pixel_map.h b/interfaces/innerkits/include/pixel_map.h index d7f356a53..a2639232e 100644 --- a/interfaces/innerkits/include/pixel_map.h +++ b/interfaces/innerkits/include/pixel_map.h @@ -70,6 +70,11 @@ public: NATIVEEXPORT int32_t GetWidth(); NATIVEEXPORT int32_t GetHeight(); NATIVEEXPORT int32_t GetBaseDensity(); + NATIVEEXPORT void scale(float xAxis, float yAxis); + NATIVEEXPORT void translate(float xAxis, float yAxis); + NATIVEEXPORT void rotate(float degrees); + NATIVEEXPORT void flip(bool xAxis, bool yAxis); + NATIVEEXPORT uint32_t crop(const Rect &rect); NATIVEEXPORT void GetImageInfo(ImageInfo &imageInfo); NATIVEEXPORT PixelFormat GetPixelFormat(); NATIVEEXPORT ColorSpace GetColorSpace(); diff --git a/interfaces/kits/js/@ohos.multimedia.image.d.ts b/interfaces/kits/js/@ohos.multimedia.image.d.ts index 17ec79142..d7c65cf08 100644 --- a/interfaces/kits/js/@ohos.multimedia.image.d.ts +++ b/interfaces/kits/js/@ohos.multimedia.image.d.ts @@ -324,6 +324,7 @@ declare namespace image { * @syscap SystemCapability.Multimedia.Image.Core */ size: Size; + density: number; } /** @@ -424,6 +425,8 @@ declare namespace image { * @syscap SystemCapability.Multimedia.Image.ImageSource */ desiredPixelFormat?: PixelMapFormat; + + fitDensity?: number; } /** @@ -503,6 +506,9 @@ declare namespace image { scaleMode?: ScaleMode; } + interface SourceOptions { + sourceDensity: number; + } /** * Create pixelmap by data buffer. * @since 8 @@ -524,7 +530,7 @@ declare namespace image { * @param uri Image source URI. * @return Returns the ImageSource instance if the operation is successful; returns null otherwise. */ - function createImageSource(uri: string): ImageSource; + function createImageSource(uri: string, options?: SourceOptions): ImageSource; /** * Creates an ImageSource instance based on the file descriptor. @@ -533,7 +539,7 @@ declare namespace image { * @param fd ID of a file descriptor. * @return Returns the ImageSource instance if the operation is successful; returns null otherwise. */ - function createImageSource(fd: number): ImageSource; + function createImageSource(fd: number, options?: SourceOptions): ImageSource; /** * Creates an ImageSource instance based on the buffer. @@ -542,7 +548,7 @@ declare namespace image { * @param buf The buffer of the iamge. * @return Returns the ImageSource instance if the operation is successful; returns null otherwise. */ - function createImageSource(buf: ArrayBuffer): ImageSource; + function createImageSource(buf: ArrayBuffer, options?: SourceOptions): ImageSource; /** * Creates an ImageSource instance based on the buffer in incremental. @@ -551,7 +557,7 @@ declare namespace image { * @param buf The buffer of the iamge. * @return Returns the ImageSource instance if the operation is successful; returns null otherwise. */ - function CreateIncrementalSource(buf: ArrayBuffer): ImageSource; + function CreateIncrementalSource(buf: ArrayBuffer, options?: SourceOptions): ImageSource; /** * Creates an ImagePacker instance. @@ -697,6 +703,10 @@ declare namespace image { */ getPixelBytesNumber(): number; + + getDensity():number; + setDensity(density: number); + /** * Releases this PixelMap object. This method uses a callback to return the result. * @since 7 diff --git a/interfaces/kits/js/common/include/pixel_map_napi.h b/interfaces/kits/js/common/include/pixel_map_napi.h index d670d3aba..9c95358ef 100644 --- a/interfaces/kits/js/common/include/pixel_map_napi.h +++ b/interfaces/kits/js/common/include/pixel_map_napi.h @@ -58,8 +58,19 @@ private: static napi_value GetBytesNumberPerRow(napi_env env, napi_callback_info info); static napi_value GetPixelBytesNumber(napi_env env, napi_callback_info info); static napi_value getPixelBytesCount(napi_env env, napi_callback_info info); + static napi_value IsSupportAlpha(napi_env env, napi_callback_info info); + static napi_value SetAlphaAble(napi_env env, napi_callback_info info); + static napi_value CreateAlphaPixelmap(napi_env env, napi_callback_info info); + static napi_value GetDensity(napi_env env, napi_callback_info info); + static napi_value SetDensity(napi_env env, napi_callback_info info); static napi_value Release(napi_env env, napi_callback_info info); + static napi_value Scale(napi_env env, napi_callback_info info); + static napi_value Translate(napi_env env, napi_callback_info info); + static napi_value Rotate(napi_env env, napi_callback_info info); + static napi_value Flip(napi_env env, napi_callback_info info); + static napi_value Crop(napi_env env, napi_callback_info info); + static thread_local napi_ref sConstructor_; static std::shared_ptr sPixelMap_; @@ -67,7 +78,6 @@ private: napi_ref wrapper_ = nullptr; std::shared_ptr nativePixelMap_; int32_t lockCount = 0; - bool isRelease = false; }; } // namespace Media } // namespace OHOS -- Gitee From 435bbede32da227087c9a542f73185d97d8ded56 Mon Sep 17 00:00:00 2001 From: zewu-feng Date: Fri, 27 May 2022 18:56:01 +0800 Subject: [PATCH 5/8] fix debug in pixel_map_napi.cpp Signed-off-by: zewu-feng --- frameworks/kits/js/common/pixel_map_napi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/kits/js/common/pixel_map_napi.cpp b/frameworks/kits/js/common/pixel_map_napi.cpp index 2bf3d6f3c..c57075d02 100644 --- a/frameworks/kits/js/common/pixel_map_napi.cpp +++ b/frameworks/kits/js/common/pixel_map_napi.cpp @@ -1314,7 +1314,7 @@ napi_value PixelMapNapi::Scale(napi_env env, napi_callback_info info) nVal.context->rPixelMap = nVal.context->nConstructor->nativePixelMap_; if (nVal.argc != NUM_2 && nVal.argc != NUM_3) { - HiLog::Error(LABEL, "Invalid args count %{public}d", nVal.argc); + HiLog::Error(LABEL, "Invalid args count %{public}zu", nVal.argc); nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; } else { if (napi_ok != napi_get_value_double(env, nVal.argv[NUM_0], &(nVal.context->xArg))) { -- Gitee From ebc0b4defedda8e03ae38f56eb1ad8d4ab7b46f3 Mon Sep 17 00:00:00 2001 From: zewu-feng Date: Sat, 28 May 2022 11:05:22 +0800 Subject: [PATCH 6/8] format check Signed-off-by: zewu-feng --- interfaces/innerkits/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interfaces/innerkits/BUILD.gn b/interfaces/innerkits/BUILD.gn index 03c043f03..94056401c 100644 --- a/interfaces/innerkits/BUILD.gn +++ b/interfaces/innerkits/BUILD.gn @@ -172,12 +172,12 @@ ohos_shared_library("image_native") { DUAL_ADAPTER = true deps = [ - "//third_party/flutter/build/skia:ace_skia_ohos", "//foundation/arkui/napi:ace_napi", "//foundation/graphic/graphic_2d:libsurface", "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/pixelconverter:pixelconvertadapter", "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils", "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//third_party/flutter/build/skia:ace_skia_ohos", "//utils/native/base:utils", ] -- Gitee From 85ef2f2bac59a9ee90e82ce5a5027aa1968637e6 Mon Sep 17 00:00:00 2001 From: zewu-feng Date: Sat, 28 May 2022 11:16:58 +0800 Subject: [PATCH 7/8] format check Signed-off-by: zewu-feng --- plugins/common/libs/image/libwebpplugin/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/common/libs/image/libwebpplugin/BUILD.gn b/plugins/common/libs/image/libwebpplugin/BUILD.gn index 4baec83b5..9abd3acc3 100644 --- a/plugins/common/libs/image/libwebpplugin/BUILD.gn +++ b/plugins/common/libs/image/libwebpplugin/BUILD.gn @@ -57,9 +57,9 @@ ohos_shared_library("webpplugin") { deps = [ "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", - "//third_party/flutter/build/skia:ace_skia_ohos", "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/pixelconverter:pixelconvertadapter", "//foundation/multimedia/image_standard/interfaces/innerkits:image_native", + "//third_party/flutter/build/skia:ace_skia_ohos", "//utils/native/base:utils", ] -- Gitee From 5b12517750e67582a8bbb17c708943edb2afb646 Mon Sep 17 00:00:00 2001 From: zewu-feng Date: Sat, 28 May 2022 17:01:37 +0800 Subject: [PATCH 8/8] delete pr of Add support for color space and Add setAlpha feature Signed-off-by: zewu-feng --- .../innerkitsimpl/common/src/pixel_map.cpp | 197 ++++++++++++++++++ frameworks/kits/js/common/pixel_map_napi.cpp | 68 ++++++ interfaces/innerkits/include/pixel_map.h | 1 + .../kits/js/common/include/pixel_map_napi.h | 1 + 4 files changed, 267 insertions(+) diff --git a/frameworks/innerkitsimpl/common/src/pixel_map.cpp b/frameworks/innerkitsimpl/common/src/pixel_map.cpp index 109815dda..324c50ae9 100644 --- a/frameworks/innerkitsimpl/common/src/pixel_map.cpp +++ b/frameworks/innerkitsimpl/common/src/pixel_map.cpp @@ -43,8 +43,12 @@ using namespace std; constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "PixelMap" }; constexpr int32_t MAX_DIMENSION = INT32_MAX >> 2; constexpr uint8_t FOUR_BYTE_SHIFT = 2; +constexpr int8_t INVALID_ALPHA_INDEX = -1; +constexpr uint8_t ARGB_ALPHA_INDEX = 0; constexpr uint8_t BGRA_ALPHA_INDEX = 3; +constexpr uint8_t ALPHA_BYTES = 1; constexpr uint8_t BGRA_BYTES = 4; +constexpr uint8_t RGBA_F16_BYTES = 8; constexpr uint8_t PER_PIXEL_LEN = 1; constexpr uint8_t FILL_NUMBER = 3; @@ -1379,6 +1383,199 @@ PixelMap *PixelMap::Unmarshalling(Parcel &parcel) return pixelMap; } +static const string GetNamedAlphaType(const AlphaType alphaType) +{ + switch (alphaType) { + case AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN: + return "Alpha Type Unknown"; + case AlphaType::IMAGE_ALPHA_TYPE_OPAQUE: + return "Alpha Type Opaque"; + case AlphaType::IMAGE_ALPHA_TYPE_PREMUL: + return "Alpha Type Premul"; + case AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL: + return "Alpha Type Unpremul"; + } + return "Alpha Type Unknown"; +} + +static const string GetNamedPixelFormat(const PixelFormat pixelFormat) +{ + switch (pixelFormat) { + case PixelFormat::UNKNOWN: + return "Pixel Format UNKNOWN"; + case PixelFormat::RGB_565: + return "Pixel Format RGB_565"; + case PixelFormat::RGB_888: + return "Pixel Format RGB_888"; + case PixelFormat::NV21: + return "Pixel Format NV21"; + case PixelFormat::NV12: + return "Pixel Format NV12"; + case PixelFormat::CMYK: + return "Pixel Format CMYK"; + case PixelFormat::ARGB_8888: + return "Pixel Format ARGB_8888"; + case PixelFormat::ALPHA_8: + return "Pixel Format ALPHA_8"; + case PixelFormat::RGBA_8888: + return "Pixel Format RGBA_8888"; + case PixelFormat::BGRA_8888: + return "Pixel Format BGRA_8888"; + case PixelFormat::RGBA_F16: + return "Pixel Format RGBA_F16"; + } + return "Pixel Format UNKNOWN"; +} + +constexpr uint8_t HALF_LOW_BYTE = 0; +constexpr uint8_t HALF_HIGH_BYTE = 1; + +static float HalfTranslate(const uint8_t* ui) +{ + return HalfToFloat(U8ToU16(ui[HALF_HIGH_BYTE], ui[HALF_LOW_BYTE])); +} + +static void HalfTranslate(const float pixel, uint8_t* ui) +{ + uint16_t val = FloatToHalf(pixel); + ui[HALF_LOW_BYTE] = static_cast((val >> SHIFT_8_BIT) & UINT8_MAX); + ui[HALF_HIGH_BYTE] = static_cast(val & UINT8_MAX); +} +constexpr uint8_t RGBA_F16_R_OFFSET = 0; +constexpr uint8_t RGBA_F16_G_OFFSET = 2; +constexpr uint8_t RGBA_F16_B_OFFSET = 4; +constexpr uint8_t RGBA_F16_A_OFFSET = 6; + +static constexpr float FLOAT_ZERO = 0.0f; +static float ProcessPremulF16Pixel(float mulPixel, float alpha, const float percent) +{ + if (alpha == 0) { + return FLOAT_ZERO; + } + float res = mulPixel * percent / alpha; + return res > MAX_HALF? MAX_HALF: res; +} + +static void SetF16PixelAlpha(uint8_t *pixel, const float percent, bool isPixelPremul) +{ + float A = HalfTranslate(pixel + RGBA_F16_A_OFFSET); + if (isPixelPremul) { + float R = HalfTranslate(pixel + RGBA_F16_R_OFFSET); + float G = HalfTranslate(pixel + RGBA_F16_G_OFFSET); + float B = HalfTranslate(pixel + RGBA_F16_B_OFFSET); + R = ProcessPremulF16Pixel(R, A, percent); + G = ProcessPremulF16Pixel(G, A, percent); + B = ProcessPremulF16Pixel(B, A, percent); + HalfTranslate(R, pixel + RGBA_F16_R_OFFSET); + HalfTranslate(G, pixel + RGBA_F16_G_OFFSET); + HalfTranslate(B, pixel + RGBA_F16_B_OFFSET); + } + A = percent * MAX_HALF; + HalfTranslate(A, pixel + RGBA_F16_A_OFFSET); +} + +static constexpr uint8_t U_ZERO = 0; +static uint8_t ProcessPremulPixel(uint8_t mulPixel, uint8_t alpha, const float percent) +{ + // mP = oP * oAlpha / UINT8_MAX + // => oP = mP * UINT8_MAX / oAlpha + // nP = oP * percent + // => nP = mP * UINT8_MAX * percent / oAlpha + if (alpha == 0) { + return U_ZERO; + } + float nPixel = mulPixel * percent * UINT8_MAX / alpha; + if ((nPixel + HALF_ONE) >= UINT8_MAX) { + return UINT8_MAX; + } + return static_cast(nPixel + HALF_ONE); +} + +static void SetUintPixelAlpha(uint8_t *pixel, const float percent, + uint8_t pixelByte, int8_t alphaIndex, bool isPixelPremul) +{ + if (isPixelPremul) { + for (int32_t pixelIndex = 0; pixelIndex < pixelByte; pixelIndex++) { + if (pixelIndex != alphaIndex) { + pixel[pixelIndex] = ProcessPremulPixel(pixel[pixelIndex], + pixel[alphaIndex], percent); + } + } + } + pixel[alphaIndex] = static_cast(UINT8_MAX * percent + HALF_ONE); +} + +static uint32_t DoSetAlpha(const PixelFormat pixelFormat, uint8_t *pixels, + uint32_t pixelsSize, uint8_t pixelByte, int8_t alphaIndex, + const float percent, bool isPixelPremul) +{ + if (alphaIndex == INVALID_ALPHA_INDEX) { + HiLog::Error(LABEL, "Invaild alpha index"); + return ERR_IMAGE_INVALID_PARAMETER; + } + + if ((pixelFormat == PixelFormat::ALPHA_8 && pixelByte != ALPHA_BYTES) || + (pixelFormat == PixelFormat::RGBA_F16 && pixelByte != RGBA_F16_BYTES)) { + HiLog::Error(LABEL, "Pixel format %{public}s mismatch pixelByte %{public}d", + GetNamedPixelFormat(pixelFormat).c_str(), pixelByte); + return ERR_IMAGE_INVALID_PARAMETER; + } + for (uint32_t i = 0; i < pixelsSize;) { + uint8_t* pixel = pixels + i; + if (pixelFormat == PixelFormat::RGBA_F16) { + SetF16PixelAlpha(pixel, percent, isPixelPremul); + } else { + SetUintPixelAlpha(pixel, percent, pixelByte, alphaIndex, isPixelPremul); + } + i += pixelByte; + } + return SUCCESS; +} + +uint32_t PixelMap::SetAlpha(const float percent) +{ + auto alphaType = GetAlphaType(); + if (AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN == alphaType || + AlphaType::IMAGE_ALPHA_TYPE_OPAQUE == alphaType) { + HiLog::Error(LABEL, + "Could not set alpha on %{public}s", + GetNamedAlphaType(alphaType).c_str()); + return ERR_IMAGE_DATA_UNSUPPORT; + } + + if (percent <= 0 || percent > 1) { + HiLog::Error(LABEL, + "Set alpha input should (0 < input <= 1). Current input %{public}f", + percent); + return ERR_IMAGE_INVALID_PARAMETER; + } + + bool pixelPremul = alphaType == AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + int8_t alphaIndex = INVALID_ALPHA_INDEX; + auto pixelFormat = GetPixelFormat(); + switch (pixelFormat) { + case PixelFormat::ARGB_8888: + case PixelFormat::ALPHA_8: { + alphaIndex = ARGB_ALPHA_INDEX; + break; + } + case PixelFormat::RGBA_8888: + case PixelFormat::BGRA_8888: + case PixelFormat::RGBA_F16: { + alphaIndex = BGRA_ALPHA_INDEX; + break; + } + default: { + HiLog::Error(LABEL, + "Could not set alpha on %{public}s", + GetNamedPixelFormat(pixelFormat).c_str()); + return ERR_IMAGE_DATA_UNSUPPORT; + } + } + return DoSetAlpha(pixelFormat, data_, + GetByteCount(), pixelBytes_, + alphaIndex, percent, pixelPremul); +} void PixelMap::scale(float xAxis, float yAxis) { PostProc postProc; diff --git a/frameworks/kits/js/common/pixel_map_napi.cpp b/frameworks/kits/js/common/pixel_map_napi.cpp index c57075d02..6a74b7edf 100644 --- a/frameworks/kits/js/common/pixel_map_napi.cpp +++ b/frameworks/kits/js/common/pixel_map_napi.cpp @@ -57,6 +57,7 @@ struct PixelMapAsyncContext { PositionArea area; std::shared_ptr rPixelMap; std::shared_ptr alphaMap; + double alpha = -1; uint32_t resultUint32; ImageInfo imageInfo; double xArg = 0; @@ -295,6 +296,7 @@ napi_value PixelMapNapi::Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("getImageInfo", GetImageInfo), DECLARE_NAPI_FUNCTION("getBytesNumberPerRow", GetBytesNumberPerRow), DECLARE_NAPI_FUNCTION("getPixelBytesNumber", GetPixelBytesNumber), + DECLARE_NAPI_FUNCTION("setAlpha", SetAlpha), DECLARE_NAPI_FUNCTION("isSupportAlpha", IsSupportAlpha), DECLARE_NAPI_FUNCTION("setAlphaAble", SetAlphaAble), DECLARE_NAPI_FUNCTION("createAlphaPixelmap", CreateAlphaPixelmap), @@ -1281,6 +1283,72 @@ static bool prepareNapiEnv(napi_env env, napi_callback_info info, struct NapiVal return true; } +static void SetAlphaExec(napi_env env, PixelMapAsyncContext* context) +{ + if (context == nullptr) { + HiLog::Error(LABEL, "Null context"); + return; + } + if (context->status == SUCCESS) { + if (context->rPixelMap != nullptr) { + context->status = context->rPixelMap->SetAlpha( + static_cast(context->alpha)); + } else { + HiLog::Error(LABEL, "Null native ref"); + context->status = ERR_IMAGE_INIT_ABNORMAL; + } + } else { + HiLog::Debug(LABEL, "Scale has failed. do nothing"); + } +} + +napi_value PixelMapNapi::SetAlpha(napi_env env, napi_callback_info info) +{ + NapiValues nVal; + nVal.argc = NUM_2; + napi_value argValue[NUM_2] = {0}; + nVal.argv = argValue; + + HiLog::Debug(LABEL, "SetAlpha IN"); + if (!prepareNapiEnv(env, info, &nVal)) { + return nVal.result; + } + nVal.context->rPixelMap = nVal.context->nConstructor->nativePixelMap_; + + if (nVal.argc != NUM_1 && nVal.argc != NUM_2) { + HiLog::Error(LABEL, "Invalid args count %{public}zu", nVal.argc); + nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; + } else { + if (napi_ok != + napi_get_value_double(env, nVal.argv[NUM_0], &(nVal.context->alpha))) { + HiLog::Error(LABEL, "Arg 0 type mismatch"); + nVal.context->status = ERR_IMAGE_INVALID_PARAMETER; + } + } + if (nVal.argc >= 1 && ImageNapiUtils::getType(env, nVal.argv[nVal.argc - 1]) == napi_function) { + napi_create_reference(env, nVal.argv[nVal.argc - 1], nVal.refCount, &(nVal.context->callbackRef)); + } + + if (nVal.context->callbackRef == nullptr) { + napi_create_promise(env, &(nVal.context->deferred), &(nVal.result)); + } + napi_value _resource = nullptr; + napi_create_string_utf8(env, "SetAlpha", NAPI_AUTO_LENGTH, &_resource); + nVal.status = napi_create_async_work(env, nullptr, _resource, + [](napi_env env, void *data) + { + auto context = static_cast(data); + SetAlphaExec(env, context); + }, EmptyResultComplete, static_cast(nVal.context.get()), &(nVal.context->work)); + + if (nVal.status == napi_ok) { + nVal.status = napi_queue_async_work(env, nVal.context->work); + if (nVal.status == napi_ok) { + nVal.context.release(); + } + } + return nVal.result; +} static void ScaleExec(napi_env env, PixelMapAsyncContext* context) { if (context == nullptr) { diff --git a/interfaces/innerkits/include/pixel_map.h b/interfaces/innerkits/include/pixel_map.h index a2639232e..86fd161a7 100644 --- a/interfaces/innerkits/include/pixel_map.h +++ b/interfaces/innerkits/include/pixel_map.h @@ -79,6 +79,7 @@ public: NATIVEEXPORT PixelFormat GetPixelFormat(); NATIVEEXPORT ColorSpace GetColorSpace(); NATIVEEXPORT AlphaType GetAlphaType(); + NATIVEEXPORT uint32_t SetAlpha(const float percent); NATIVEEXPORT const uint8_t *GetPixels(); NATIVEEXPORT uint8_t GetARGB32ColorA(uint32_t color); NATIVEEXPORT uint8_t GetARGB32ColorR(uint32_t color); diff --git a/interfaces/kits/js/common/include/pixel_map_napi.h b/interfaces/kits/js/common/include/pixel_map_napi.h index 9c95358ef..eac2769bb 100644 --- a/interfaces/kits/js/common/include/pixel_map_napi.h +++ b/interfaces/kits/js/common/include/pixel_map_napi.h @@ -64,6 +64,7 @@ private: static napi_value GetDensity(napi_env env, napi_callback_info info); static napi_value SetDensity(napi_env env, napi_callback_info info); static napi_value Release(napi_env env, napi_callback_info info); + static napi_value SetAlpha(napi_env env, napi_callback_info info); static napi_value Scale(napi_env env, napi_callback_info info); static napi_value Translate(napi_env env, napi_callback_info info); -- Gitee