From 589b91113434fae8436f1912d0566abd485fba33 Mon Sep 17 00:00:00 2001 From: Cao Chuan Date: Fri, 15 Dec 2023 15:19:06 +0800 Subject: [PATCH] Add color space name on decoding options Signed-off-by: Cao Chuan --- .../innerkitsimpl/codec/src/image_source.cpp | 18 +- .../innerkitsimpl/pixelconverter/BUILD.gn | 5 +- frameworks/innerkitsimpl/test/BUILD.gn | 11 +- frameworks/innerkitsimpl/utils/BUILD.gn | 1 + .../kits/js/common/image_source_napi.cpp | 35 +--- interfaces/innerkits/include/image_type.h | 11 +- .../libs/image/formatagentplugin/BUILD.gn | 1 + .../image/libextplugin/include/ext_decoder.h | 4 + .../image/libextplugin/src/ext_decoder.cpp | 161 +++++++++++++++--- plugins/manager/BUILD.gn | 2 + .../manager/include/image/abs_image_decoder.h | 2 +- .../manager/include/image/image_plugin_type.h | 8 - 12 files changed, 166 insertions(+), 93 deletions(-) diff --git a/frameworks/innerkitsimpl/codec/src/image_source.cpp b/frameworks/innerkitsimpl/codec/src/image_source.cpp index 046cc0440..a26747ec7 100644 --- a/frameworks/innerkitsimpl/codec/src/image_source.cpp +++ b/frameworks/innerkitsimpl/codec/src/image_source.cpp @@ -1556,19 +1556,6 @@ uint32_t ImageSource::UpdatePixelMapInfo(const DecodeOptions &opts, ImagePlugin: return pixelMap.SetImageInfo(info, isReUsed); } -static void CopyColorSpaceToPlugin(const ColorSpaceInfo &src, PlColorSpaceInfo &dst) -{ - dst.isValidColorSpace = src.isValidColorSpace; - for (int i = NUM_0; i < ColorSpaceInfo::XYZ_SIZE; i++) { - for (int j = NUM_0; j < ColorSpaceInfo::XYZ_SIZE; j++) { - dst.xyz[i][j] = src.xyz[i][j]; - } - } - for (int k = NUM_0; k < ColorSpaceInfo::XYZ_SIZE; k++) { - dst.transferFn[k] = src.transferFn[k]; - } -} - void ImageSource::CopyOptionsToPlugin(const DecodeOptions &opts, PixelDecodeOptions &plOpts) { plOpts.CropRect.left = opts.CropRect.left; @@ -1594,10 +1581,7 @@ void ImageSource::CopyOptionsToPlugin(const DecodeOptions &opts, PixelDecodeOpti plOpts.plSVGResize.isValidPercentage = opts.SVGOpts.SVGResize.isValidPercentage; plOpts.plSVGResize.resizePercentage = opts.SVGOpts.SVGResize.resizePercentage; } - - if (opts.desiredColorSpaceInfo.isValidColorSpace) { - CopyColorSpaceToPlugin(opts.desiredColorSpaceInfo, plOpts.plDesiredColorSpace); - } + plOpts.plDesiredColorSpace = opts.desiredColorSpaceInfo; } void ImageSource::CopyOptionsToProcOpts(const DecodeOptions &opts, DecodeOptions &procOpts, PixelMap &pixelMap) diff --git a/frameworks/innerkitsimpl/pixelconverter/BUILD.gn b/frameworks/innerkitsimpl/pixelconverter/BUILD.gn index 136b37c7b..9d0015b94 100644 --- a/frameworks/innerkitsimpl/pixelconverter/BUILD.gn +++ b/frameworks/innerkitsimpl/pixelconverter/BUILD.gn @@ -169,7 +169,10 @@ if (use_clang_ios) { "//foundation/multimedia/image_framework/mock/native:log_mock_static", ] deps += skia_platform - external_deps = [ "c_utils:utils" ] + external_deps = [ + "c_utils:utils", + "graphic_2d:color_manager", + ] } #relative_install_dir = "module/multimedia" diff --git a/frameworks/innerkitsimpl/test/BUILD.gn b/frameworks/innerkitsimpl/test/BUILD.gn index 71330b6ef..7438abf2d 100644 --- a/frameworks/innerkitsimpl/test/BUILD.gn +++ b/frameworks/innerkitsimpl/test/BUILD.gn @@ -312,6 +312,7 @@ ohos_unittest("imageutilstest") { external_deps = [ "c_utils:utils", + "graphic_2d:color_manager", #"hilog:libhilog", "hitrace:hitrace_meter", @@ -500,7 +501,10 @@ ohos_unittest("attrdatatest") { "//third_party/googletest:gtest_main", ] resource_config_file = "$image_subsystem/test/resource/image/ohos_test.xml" - external_deps = [ "c_utils:utils" ] + external_deps = [ + "c_utils:utils", + "graphic_2d:color_manager", + ] } ohos_unittest("convertertest") { @@ -620,7 +624,10 @@ ohos_unittest("pluginsmanagersrcframeworktest") { "//third_party/googletest:gtest_main", ] resource_config_file = "$image_subsystem/test/resource/image/ohos_test.xml" - external_deps = [ "c_utils:utils" ] + external_deps = [ + "c_utils:utils", + "graphic_2d:color_manager", + ] } ohos_unittest("pngtest") { diff --git a/frameworks/innerkitsimpl/utils/BUILD.gn b/frameworks/innerkitsimpl/utils/BUILD.gn index 024b5f1b8..efccdf153 100644 --- a/frameworks/innerkitsimpl/utils/BUILD.gn +++ b/frameworks/innerkitsimpl/utils/BUILD.gn @@ -112,6 +112,7 @@ if (use_clang_ios) { external_deps = [ "c_utils:utils", + "graphic_2d:color_manager", "graphic_2d:surface", "hilog:libhilog", "hitrace:hitrace_meter", diff --git a/frameworks/kits/js/common/image_source_napi.cpp b/frameworks/kits/js/common/image_source_napi.cpp index 379685d62..1de485bf5 100644 --- a/frameworks/kits/js/common/image_source_napi.cpp +++ b/frameworks/kits/js/common/image_source_napi.cpp @@ -639,33 +639,6 @@ static PixelFormat ParsePixlForamt(int32_t val) return PixelFormat::UNKNOWN; } -static bool ParseColorSpaceInfo(napi_env env, napi_value colorSpace, ColorSpaceInfo &colorSpaceInfo) -{ - if (env == nullptr || colorSpace == nullptr) { - HiLog::Error(LABEL, "Invalid args"); - return false; - } - auto grColorSpacePtr = OHOS::ColorManager::GetColorSpaceByJSObject(env, colorSpace); - if (grColorSpacePtr == nullptr) { - HiLog::Error(LABEL, "Get colorspace by JS object failed"); - return false; - } - auto skColorSpace = grColorSpacePtr->ToSkColorSpace(); - if (skColorSpace == nullptr) { - HiLog::Error(LABEL, "To skcolorspace failed"); - return false; - } - skcms_Matrix3x3 skMatrix; - skColorSpace->toXYZD50(&skMatrix); - for (int i = 0; i < ColorSpaceInfo::XYZ_SIZE; ++i) { - for (int j = 0; j < ColorSpaceInfo::XYZ_SIZE; ++j) { - colorSpaceInfo.xyz[i][j] = skMatrix.vals[i][j]; - } - } - skColorSpace->transferFn(colorSpaceInfo.transferFn); - return true; -} - static bool ParseDecodeOptions2(napi_env env, napi_value root, DecodeOptions* opts, std::string &error) { uint32_t tmpNumber = 0; @@ -699,11 +672,11 @@ static bool ParseDecodeOptions2(napi_env env, napi_value root, DecodeOptions* op HiLog::Debug(LABEL, "no SVGResize percentage"); } napi_value nDesiredColorSpace = nullptr; - if (napi_get_named_property(env, root, "desiredColorSpace", &nDesiredColorSpace) == napi_ok && - ParseColorSpaceInfo(env, nDesiredColorSpace, opts->desiredColorSpaceInfo)) { - opts->desiredColorSpaceInfo.isValidColorSpace = true; + if (napi_get_named_property(env, root, "desiredColorSpace", &nDesiredColorSpace) == napi_ok) { + opts->desiredColorSpaceInfo = OHOS::ColorManager::GetColorSpaceByJSObject(env, nDesiredColorSpace); HiLog::Debug(LABEL, "desiredColorSpace parse finished"); - } else { + } + if (opts->desiredColorSpaceInfo == nullptr) { HiLog::Debug(LABEL, "no desiredColorSpace"); } return true; diff --git a/interfaces/innerkits/include/image_type.h b/interfaces/innerkits/include/image_type.h index 7a7b7060a..38a97e10d 100644 --- a/interfaces/innerkits/include/image_type.h +++ b/interfaces/innerkits/include/image_type.h @@ -17,6 +17,7 @@ #define INTERFACES_INNERKITS_INCLUDE_IMAGE_TYPE_H_ #include +#include "color_space.h" namespace OHOS { namespace Media { @@ -174,14 +175,6 @@ struct SVGDecodeOptions { SVGResize SVGResize; }; -struct ColorSpaceInfo { - static constexpr uint8_t XYZ_SIZE = 3; - static constexpr uint8_t TRANSFER_FN_SIZE = 7; - bool isValidColorSpace = false; - float xyz[XYZ_SIZE][XYZ_SIZE] = {{0}}; - float transferFn[TRANSFER_FN_SIZE] = {0}; -}; - struct DecodeOptions { int32_t fitDensity = 0; Rect CropRect; @@ -202,7 +195,7 @@ struct DecodeOptions { bool editable = false; MemoryUsagePreference preference = MemoryUsagePreference::DEFAULT; SVGDecodeOptions SVGOpts; - ColorSpaceInfo desiredColorSpaceInfo; + std::shared_ptr desiredColorSpaceInfo = nullptr; }; enum class ScaleMode : int32_t { diff --git a/plugins/common/libs/image/formatagentplugin/BUILD.gn b/plugins/common/libs/image/formatagentplugin/BUILD.gn index 98f45d41c..670138f82 100644 --- a/plugins/common/libs/image/formatagentplugin/BUILD.gn +++ b/plugins/common/libs/image/formatagentplugin/BUILD.gn @@ -70,6 +70,7 @@ ohos_shared_library("imageformatagent") { # external_deps = [ "hilog:libhilog" ] external_deps = [ "c_utils:utils", + "graphic_2d:color_manager", "hilog:libhilog", ] } diff --git a/plugins/common/libs/image/libextplugin/include/ext_decoder.h b/plugins/common/libs/image/libextplugin/include/ext_decoder.h index 2b5b46960..087ef8746 100644 --- a/plugins/common/libs/image/libextplugin/include/ext_decoder.h +++ b/plugins/common/libs/image/libextplugin/include/ext_decoder.h @@ -84,6 +84,7 @@ private: SkColorType ConvertToColorType(PlPixelFormat format, PlPixelFormat &outputFormat); uint32_t SetContextPixelsBuffer(uint64_t byteCount, DecodeContext &context); uint32_t GetMakerImagePropertyString(const std::string &key, std::string &value); + uint32_t CheckDecodeOptions(uint32_t index, const PixelDecodeOptions &opts); void ReportImageType(SkEncodedImageFormat skEncodeFormat); ImagePlugin::InputDataStream *stream_ = nullptr; uint32_t streamOff_ = 0; @@ -96,6 +97,9 @@ private: EXIFInfo exifInfo_; uint8_t *gifCache_ = nullptr; uint32_t gifCacheIndex_ = 0; +#ifdef IMAGE_COLORSPACE_FLAG + std::shared_ptr dstColorSpace_ = nullptr; +#endif // hardware OHOS::HDI::Codec::Image::V1_0::CodecImageBuffer outputBuffer_; diff --git a/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp b/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp index 43e1dd24a..a7f471691 100644 --- a/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp +++ b/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp @@ -16,6 +16,7 @@ #include "ext_decoder.h" #include +#include #include "ext_pixel_convert.h" #include "hilog/log.h" @@ -39,11 +40,23 @@ namespace { constexpr static size_t SIZE_ZERO = 0; constexpr static uint32_t DEFAULT_SAMPLE_SIZE = 1; constexpr static uint32_t NO_EXIF_TAG = 1; + constexpr static uint32_t OFFSET_0 = 0; + constexpr static uint32_t OFFSET_1 = 1; + constexpr static uint32_t OFFSET_2 = 2; + constexpr static uint32_t OFFSET_3 = 3; + constexpr static uint32_t OFFSET_5 = 5; + constexpr static uint32_t SHIFT_BITS_8 = 8; + constexpr static uint32_t SHIFT_BITS_16 = 16; + constexpr static uint32_t SHIFT_BITS_24 = 24; + constexpr static uint32_t DESC_SIGNATURE = 0x64657363; + constexpr static size_t SIZE_1 = 1; + constexpr static size_t SIZE_4 = 4; constexpr static int HARDWARE_MIN_DIM = 512; constexpr static int HARDWARE_MAX_DIM = 8192; constexpr static float HALF = 0.5; constexpr static float QUARTER = 0.25; constexpr static float ONE_EIGHTH = 0.125; + constexpr static uint64_t ICC_HEADER_SIZE = 132; } namespace OHOS { @@ -397,16 +410,34 @@ static inline bool IsValidCrop(const PlRect &crop, SkImageInfo &info, SkIRect &o static sk_sp getDesiredColorSpace(SkImageInfo &srcInfo, const PixelDecodeOptions &opts) { - if (!opts.plDesiredColorSpace.isValidColorSpace) { + if (opts.plDesiredColorSpace == nullptr) { return srcInfo.refColorSpace(); } - auto xyzSize = PlColorSpaceInfo::XYZ_SIZE * PlColorSpaceInfo::XYZ_SIZE * sizeof(float); - skcms_Matrix3x3 skXYZ; - memcpy_s(&skXYZ, xyzSize, opts.plDesiredColorSpace.xyz, xyzSize); - auto transferFnSize = PlColorSpaceInfo::TRANSFER_FN_SIZE * sizeof(float); - skcms_TransferFunction skTransferFun; - memcpy_s(&skTransferFun, transferFnSize, opts.plDesiredColorSpace.transferFn, transferFnSize); - return SkColorSpace::MakeRGB(skTransferFun, skXYZ); + return opts.plDesiredColorSpace->ToSkColorSpace(); +} + +uint32_t ExtDecoder::CheckDecodeOptions(uint32_t index, const PixelDecodeOptions &opts) +{ + if (ImageUtils::CheckMulOverflow(dstInfo_.width(), dstInfo_.height(), dstInfo_.bytesPerPixel())) { + HiLog::Error(LABEL, "SetDecodeOptions failed, width:%{public}d, height:%{public}d is too large", + dstInfo_.width(), dstInfo_.height()); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (!IsValidCrop(opts.CropRect, info_, dstSubset_)) { + HiLog::Error(LABEL, + "Invalid crop rect xy [%{public}d x %{public}d], wh [%{public}d x %{public}d]", + dstSubset_.left(), dstSubset_.top(), dstSubset_.width(), dstSubset_.height()); + return ERR_IMAGE_INVALID_PARAMETER; + } + + dstOptions_.fFrameIndex = index; +#ifdef IMAGE_COLORSPACE_FLAG + dstColorSpace_ = opts.plDesiredColorSpace; +#endif + if (IsSupportCropOnDecode(dstSubset_)) { + dstOptions_.fSubset = &dstSubset_; + } + return SUCCESS; } uint32_t ExtDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) @@ -444,21 +475,9 @@ uint32_t ExtDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions & dstInfo_ = SkImageInfo::Make(info_.width(), info_.height(), desireColor, desireAlpha, getDesiredColorSpace(info_, opts)); } - if (ImageUtils::CheckMulOverflow(dstInfo_.width(), dstInfo_.height(), dstInfo_.bytesPerPixel())) { - HiLog::Error(LABEL, "SetDecodeOptions failed, width:%{public}d, height:%{public}d is too large", - dstInfo_.width(), dstInfo_.height()); - return ERR_IMAGE_INVALID_PARAMETER; - } - dstOptions_.fFrameIndex = index; - - if (!IsValidCrop(opts.CropRect, info_, dstSubset_)) { - HiLog::Error(LABEL, - "Invalid crop rect xy [%{public}d x %{public}d], wh [%{public}d x %{public}d]", - dstSubset_.left(), dstSubset_.top(), dstSubset_.width(), dstSubset_.height()); - return ERR_IMAGE_INVALID_PARAMETER; - } - if (IsSupportCropOnDecode(dstSubset_)) { - dstOptions_.fSubset = &dstSubset_; + auto resCode = CheckDecodeOptions(index, opts); + if (resCode != SUCCESS) { + return resCode; } info.size.width = dstInfo_.width(); @@ -902,14 +921,108 @@ SkColorType ExtDecoder::ConvertToColorType(PlPixelFormat format, PlPixelFormat & } #ifdef IMAGE_COLORSPACE_FLAG +static uint32_t u8ToU32(const uint8_t* p) +{ + return (p[OFFSET_0] << SHIFT_BITS_24) | (p[OFFSET_1] << SHIFT_BITS_16) | + (p[OFFSET_2] << SHIFT_BITS_8) | p[OFFSET_3]; +} + +struct ICCTag { + uint8_t signature[SIZE_4]; + uint8_t offset[SIZE_4]; + uint8_t size[SIZE_4]; +}; + +struct ColorSpaceNameEnum { + std::string desc; + OHOS::ColorManager::ColorSpaceName name; +}; + +static std::vector sColorSpaceNamedMap = { + {"Display P3", OHOS::ColorManager::ColorSpaceName::DISPLAY_P3}, + {"sRGB EOTF with DCI-P3 Color Gamut", OHOS::ColorManager::ColorSpaceName::DISPLAY_P3}, + {"DCI-P3 D65 Gamut with sRGB Transfer", OHOS::ColorManager::ColorSpaceName::DISPLAY_P3}, + {"Adobe RGB (1998)", OHOS::ColorManager::ColorSpaceName::ADOBE_RGB}, + {"DCI P3", OHOS::ColorManager::ColorSpaceName::DCI_P3}, + {"sRGB", OHOS::ColorManager::ColorSpaceName::SRGB} + /*{"BT.2020", OHOS::ColorManager::ColorSpaceName::BT2020}*/ +}; + +static bool MatchColorSpaceName(const uint8_t* buf, uint32_t size, OHOS::ColorManager::ColorSpaceName &name) +{ + if (buf == nullptr || size <= OFFSET_5) { + return false; + } + std::vector desc; + // We need skip desc type + for (uint32_t i = OFFSET_5; i < size; i++) { + if (buf[i] != '\0') { + desc.push_back(buf[i]); + } + } + if (desc.size() <= SIZE_1) { + HiLog::Info(LABEL, "empty buffer"); + return false; + } + std::string descText(desc.begin() + OFFSET_1, desc.end()); + for (auto nameEnum : sColorSpaceNamedMap) { + if (descText.find(nameEnum.desc) == std::string::npos) { + continue; + } + name = nameEnum.name; + return true; + } + HiLog::Error(LABEL, "Failed to match desc [%{public}s]", descText.c_str()); + return false; +} + +static bool GetColorSpaceName(const skcms_ICCProfile* profile, OHOS::ColorManager::ColorSpaceName &name) +{ + if (profile == nullptr || profile->buffer == nullptr) { + HiLog::Info(LABEL, "profile is nullptr"); + return false; + } + auto tags = reinterpret_cast(profile->buffer + ICC_HEADER_SIZE); + for (uint32_t i = SIZE_ZERO; i < profile->tag_count; i++) { + auto signature = u8ToU32(tags[i].signature); + if (signature != DESC_SIGNATURE) { + continue; + } + auto size = u8ToU32(tags[i].size); + auto offset = u8ToU32(tags[i].offset); + if (size <= SIZE_ZERO || offset >= profile->size) { + continue; + } + auto buffer = u8ToU32(tags[i].offset) + profile->buffer; + if (MatchColorSpaceName(buffer, size, name)) { + return true; + } + } + return false; +} + OHOS::ColorManager::ColorSpace ExtDecoder::getGrColorSpace() { + if (dstColorSpace_ != nullptr) { + return *dstColorSpace_; + } auto skColorSpace = dstInfo_.isEmpty() ? info_.refColorSpace() : dstInfo_.refColorSpace(); - return OHOS::ColorManager::ColorSpace(skColorSpace); + OHOS::ColorManager::ColorSpaceName name = OHOS::ColorManager::ColorSpaceName::CUSTOM; + if (codec_ != nullptr) { + auto profile = codec_->getICCProfile(); + if (profile != nullptr) { + HiLog::Info(LABEL, "profile got !!!!"); + GetColorSpaceName(profile, name); + } + } + return OHOS::ColorManager::ColorSpace(skColorSpace, name); } bool ExtDecoder::IsSupportICCProfile() { + if (dstColorSpace_ != nullptr) { + return true; + } if (info_.isEmpty()) { return false; } diff --git a/plugins/manager/BUILD.gn b/plugins/manager/BUILD.gn index fd3028f54..d8dc54f17 100644 --- a/plugins/manager/BUILD.gn +++ b/plugins/manager/BUILD.gn @@ -143,6 +143,7 @@ if (use_clang_ios) { external_deps = [ "c_utils:utils", + "graphic_2d:color_manager", "hilog:libhilog", ] } @@ -225,6 +226,7 @@ ohos_static_library("pluginmanager_static") { external_deps = [ "c_utils:utils", + "graphic_2d:color_manager", "hilog:libhilog", ] } diff --git a/plugins/manager/include/image/abs_image_decoder.h b/plugins/manager/include/image/abs_image_decoder.h index 728980c02..9e2c401ee 100644 --- a/plugins/manager/include/image/abs_image_decoder.h +++ b/plugins/manager/include/image/abs_image_decoder.h @@ -100,7 +100,7 @@ struct PixelDecodeOptions { bool editable = false; PlFillColor plFillColor; PlSVGResize plSVGResize; - PlColorSpaceInfo plDesiredColorSpace; + std::shared_ptr plDesiredColorSpace = nullptr; }; class AbsImageDecoder { diff --git a/plugins/manager/include/image/image_plugin_type.h b/plugins/manager/include/image/image_plugin_type.h index 0a9f914ba..3e75b2fc5 100644 --- a/plugins/manager/include/image/image_plugin_type.h +++ b/plugins/manager/include/image/image_plugin_type.h @@ -132,14 +132,6 @@ struct PlSVGResize { uint32_t resizePercentage = 100; }; -struct PlColorSpaceInfo { - static constexpr uint8_t XYZ_SIZE = 3; - static constexpr uint8_t TRANSFER_FN_SIZE = 7; - bool isValidColorSpace = false; - float xyz[XYZ_SIZE][XYZ_SIZE] = {{0}}; - float transferFn[TRANSFER_FN_SIZE] = {0}; -}; - struct PlImageInfo { PlSize size; PlPixelFormat pixelFormat = PlPixelFormat::UNKNOWN;