diff --git a/frameworks/innerkitsimpl/codec/src/image_source.cpp b/frameworks/innerkitsimpl/codec/src/image_source.cpp index 262df7358ac5efd410c045d21b3fbe5fcf79e5c4..d95f0f7b6954f1b53bc80e1b2860305e3f8a2dca 100644 --- a/frameworks/innerkitsimpl/codec/src/image_source.cpp +++ b/frameworks/innerkitsimpl/codec/src/image_source.cpp @@ -2325,6 +2325,31 @@ unique_ptr> ImageSource::GetDelayTime(uint32_t &errorCode) return delayTimes; } +unique_ptr> ImageSource::GetDisposalType(uint32_t &errorCode) +{ + auto frameCount = GetFrameCount(errorCode); + if (errorCode != SUCCESS) { + IMAGE_LOGE("[ImageSource]GetDisposalType get frame sum error."); + return nullptr; + } + + auto disposalTypes = std::make_unique>(); + const string IMAGE_DISPOSAL_TYPE = "DisposalType"; + for (uint32_t index = 0; index < frameCount; index++) { + int disposalType = 0; + errorCode = mainDecoder_->GetImagePropertyInt(index, IMAGE_DISPOSAL_TYPE, disposalType); + if (errorCode != SUCCESS) { + IMAGE_LOGE("[ImageSource]GetDisposalType get delay time issue. index=%{public}u", index); + return nullptr; + } + disposalTypes->push_back(disposalType); + } + + errorCode = SUCCESS; + + return disposalTypes; +} + uint32_t ImageSource::GetFrameCount(uint32_t &errorCode) { uint32_t frameCount = GetSourceInfo(errorCode).topLevelImageNum; diff --git a/frameworks/innerkitsimpl/test/unittest/image_source_test/image_source_gif_ex_test.cpp b/frameworks/innerkitsimpl/test/unittest/image_source_test/image_source_gif_ex_test.cpp index 7ab8c01a325379942ebea6c4d89801168f89edd6..eb7324cadb930f91e2d24838485c175972ad2af8 100644 --- a/frameworks/innerkitsimpl/test/unittest/image_source_test/image_source_gif_ex_test.cpp +++ b/frameworks/innerkitsimpl/test/unittest/image_source_test/image_source_gif_ex_test.cpp @@ -229,6 +229,85 @@ HWTEST_F(ImageSourceGifExTest, GetDelayTime003, TestSize.Level3) GTEST_LOG_(INFO) << "ImageSourceGifExTest: GetDelayTime003 end"; } +/** + * @tc.name: GetDisposalType001 + * @tc.desc: test GetDisposalType + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceGifExTest, GetDisposalType001, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImageSourceGifExTest: GetDisposalType001 start"; + + const std::string testName = TEST_FILE_SINGLE_FRAME_GIF; + + uint32_t errorCode = 0; + const SourceOptions opts; + const std::string inputName = INPUT_PATH + testName; + auto imageSource = ImageSource::CreateImageSource(inputName, opts, errorCode); + + auto delayTimes = imageSource->GetDisposalType(errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(delayTimes, nullptr); + ASSERT_EQ(delayTimes->size(), TEST_FILE_SINGLE_FRAME_GIF_FRAME_COUNT); + + for (auto delayTime : *delayTimes) { + IMAGE_LOGD("delay time is %{public}u.", delayTime); + } + + GTEST_LOG_(INFO) << "ImageSourceGifExTest: GetDisposalType001 end"; +} + +/** + * @tc.name: GetDisposalType002 + * @tc.desc: test GetDisposalType + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceGifExTest, GetDisposalType002, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImageSourceGifExTest: GetDisposalType002 start"; + + const std::string testName = TEST_FILE_MULTI_FRAME_GIF; + + uint32_t errorCode = 0; + const SourceOptions opts; + const std::string inputName = INPUT_PATH + testName; + auto imageSource = ImageSource::CreateImageSource(inputName, opts, errorCode); + + auto delayTimes = imageSource->GetDisposalType(errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(delayTimes, nullptr); + ASSERT_EQ(delayTimes->size(), TEST_FILE_MULTI_FRAME_GIF_FRAME_COUNT); + + for (auto delayTime : *delayTimes) { + IMAGE_LOGD("delay time is %{public}u.", delayTime); + } + + GTEST_LOG_(INFO) << "ImageSourceGifExTest: GetDisposalType002 end"; +} + +/** + * @tc.name: GetDisposalType003 + * @tc.desc: test GetDisposalType + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceGifExTest, GetDisposalType003, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImageSourceGifExTest: GetDisposalType003 start"; + + const std::string testName = TEST_FILE_JPG; + + uint32_t errorCode = 0; + const SourceOptions opts; + const std::string inputName = INPUT_PATH + testName; + auto imageSource = ImageSource::CreateImageSource(inputName, opts, errorCode); + + auto delayTimes = imageSource->GetDisposalType(errorCode); + ASSERT_NE(errorCode, SUCCESS); + ASSERT_EQ(delayTimes, nullptr); + + GTEST_LOG_(INFO) << "ImageSourceGifExTest: GetDisposalType003 end"; +} + /** * @tc.name: GetFrameCount001 * @tc.desc: test GetFrameCount diff --git a/frameworks/innerkitsimpl/test/unittest/image_source_test/image_source_test.cpp b/frameworks/innerkitsimpl/test/unittest/image_source_test/image_source_test.cpp index 1d2557a21387791528e364cb8ba3509f7e09887f..0708cafa0320c3c3bf3b83aff4d4753da3c68791 100644 --- a/frameworks/innerkitsimpl/test/unittest/image_source_test/image_source_test.cpp +++ b/frameworks/innerkitsimpl/test/unittest/image_source_test/image_source_test.cpp @@ -1578,6 +1578,22 @@ HWTEST_F(ImageSourceTest, GetDelayTimeTest001, TestSize.Level3) GTEST_LOG_(INFO) << "ImageSourceTest: GetDelayTimeTest001 end"; } +/** + * @tc.name: GetDisposalTypeTest001 + * @tc.desc: test GetDisposalType + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceTest, GetDisposalTypeTest001, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImageSourceTest: GetDisposalTypeTest001 start"; + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_JPEG_PATH, opts, errorCode); + auto ret = imageSource->GetDisposalType(errorCode); + ASSERT_EQ(ret, nullptr); + GTEST_LOG_(INFO) << "ImageSourceTest: GetDisposalTypeTest001 end"; +} + /** * @tc.name: DecodeSourceInfoTest001 * @tc.desc: test DecodeSourceInfo diff --git a/frameworks/kits/js/common/image_source_napi.cpp b/frameworks/kits/js/common/image_source_napi.cpp index 015808b21a3e2f56635dd797c2495eef2b7ac03d..6014ae95733b51a6278bad7cc0cdd8fff7ed2143 100644 --- a/frameworks/kits/js/common/image_source_napi.cpp +++ b/frameworks/kits/js/common/image_source_napi.cpp @@ -99,6 +99,7 @@ struct ImageSourceAsyncContext { std::string errMsg; std::unique_ptr>> pixelMaps; std::unique_ptr> delayTimes; + std::unique_ptr> disposalType; uint32_t frameCount = 0; struct RawFileDescriptorInfo rawFileInfo; }; @@ -423,6 +424,7 @@ napi_value ImageSourceNapi::Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("modifyImageProperty", ModifyImageProperty), DECLARE_NAPI_FUNCTION("getImageProperty", GetImageProperty), DECLARE_NAPI_FUNCTION("getDelayTimeList", GetDelayTime), + DECLARE_NAPI_FUNCTION("getDisposalTypeList", GetDisposalType), DECLARE_NAPI_FUNCTION("getFrameCount", GetFrameCount), DECLARE_NAPI_FUNCTION("createPixelMapList", CreatePixelMapList), DECLARE_NAPI_FUNCTION("createPixelMap", CreatePixelMap), @@ -2104,6 +2106,90 @@ napi_value ImageSourceNapi::GetDelayTime(napi_env env, napi_callback_info info) return result; } +STATIC_EXEC_FUNC(GetDisposalType) +{ + if (data == nullptr) { + IMAGE_LOGE("data is nullptr"); + return; + } + + auto context = CheckAsyncContext(static_cast(data), true); + if (context == nullptr) { + IMAGE_LOGE("check async context fail"); + return; + } + + uint32_t errorCode = 0; + context->disposalType = context->rImageSource->GetDisposalType(errorCode); + if ((errorCode == SUCCESS) && IMG_NOT_NULL(context->disposalType)) { + context->status = SUCCESS; + } else { + IMAGE_LOGE("Get DisposalType error, error=%{public}u", errorCode); + context->errMsg = "Get DisposalType error"; + context->status = (errorCode != SUCCESS) ? errorCode : ERROR; + } +} + +STATIC_COMPLETE_FUNC(GetDisposalType) +{ + if (data == nullptr) { + IMAGE_LOGE("data is nullptr"); + return; + } + + auto context = CheckAsyncContext(static_cast(data), false); + if (context == nullptr) { + IMAGE_LOGE("check async context fail"); + return; + } + + napi_value result = nullptr; + if (context->status == SUCCESS && IMG_NOT_NULL(context->disposalType)) { + IMAGE_LOGD("GetDisposalTypeComplete array"); + napi_create_array(env, &result); + size_t i = 0; + for (auto disposalType : *context->disposalType) { + napi_value napiDisposalType = nullptr; + napi_create_uint32(env, disposalType, &napiDisposalType); + napi_set_element(env, result, i, napiDisposalType); + i++; + } + } else { + IMAGE_LOGD("GetDisposalTypeComplete undefined"); + napi_get_undefined(env, &result); + } + + IMAGE_LOGD("GetDisposalTypeComplete set to nullptr"); + context->disposalType = nullptr; + ImageSourceCallbackWithErrorObj(env, context, result); +} + +napi_value ImageSourceNapi::GetDisposalType(napi_env env, napi_callback_info info) +{ + ImageTrace imageTrace("ImageSourceNapi::GetDisposalType"); + + auto asyncContext = UnwrapContextForList(env, info); + if (asyncContext == nullptr) { + return ImageNapiUtils::ThrowExceptionError(env, ERR_IMAGE_DATA_ABNORMAL, + "async context unwrap failed"); + } + + napi_value result = nullptr; + napi_get_undefined(env, &result); + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &(asyncContext->deferred), &result); + } else { + napi_get_undefined(env, &result); + } + + napi_status status; + IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetDisposalType", GetDisposalTypeExec, + GetDisposalTypeComplete, asyncContext, asyncContext->work); + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("fail to create async work")); + + return result; +} + STATIC_EXEC_FUNC(GetFrameCount) { if (data == nullptr) { diff --git a/interfaces/innerkits/include/image_source.h b/interfaces/innerkits/include/image_source.h index 39614f9a81dad2d4236ab31f34d9cec2954eea17..2ee7b5b1fb231c78bf3fb2ee37e42defadf93904 100644 --- a/interfaces/innerkits/include/image_source.h +++ b/interfaces/innerkits/include/image_source.h @@ -201,6 +201,7 @@ public: NATIVEEXPORT std::unique_ptr>> CreatePixelMapList(const DecodeOptions &opts, uint32_t &errorCode); NATIVEEXPORT std::unique_ptr> GetDelayTime(uint32_t &errorCode); + NATIVEEXPORT std::unique_ptr> GetDisposalType(uint32_t &errorCode); NATIVEEXPORT uint32_t GetFrameCount(uint32_t &errorCode); #ifdef IMAGE_PURGEABLE_PIXELMAP NATIVEEXPORT size_t GetSourceSize() const; diff --git a/interfaces/kits/js/common/include/image_source_napi.h b/interfaces/kits/js/common/include/image_source_napi.h index 43cdf9ff1f2ae0760fa72d2b172ae5c467d165c1..da7c07d1b02166e91a37c260e7d130850722c205 100644 --- a/interfaces/kits/js/common/include/image_source_napi.h +++ b/interfaces/kits/js/common/include/image_source_napi.h @@ -72,6 +72,7 @@ private: static napi_value Release(napi_env env, napi_callback_info info); static napi_value CreatePixelMapList(napi_env env, napi_callback_info info); static napi_value GetDelayTime(napi_env env, napi_callback_info info); + static napi_value GetDisposalType(napi_env env, napi_callback_info info); static napi_value GetFrameCount(napi_env env, napi_callback_info info); void release(); diff --git a/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp b/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp index c42e8b835fdb4f89e21b5bfd4e893e9010133487..2c6d0f0f6e07aeefce5d391263f3e586b591c078 100644 --- a/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp +++ b/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp @@ -81,6 +81,7 @@ const static string EXT_SHAREMEM_NAME = "EXT RawData"; const static string TAG_ORIENTATION_STRING = "Orientation"; const static string TAG_ORIENTATION_INT = "OrientationInt"; const static string IMAGE_DELAY_TIME = "DelayTime"; +const static string IMAGE_DISPOSAL_TYPE = "DisposalType"; const static std::string HW_MNOTE_TAG_HEADER = "HwMnote"; const static std::string HW_MNOTE_CAPTURE_MODE = "HwMnoteCaptureMode"; const static std::string HW_MNOTE_PHYSICAL_APERTURE = "HwMnotePhysicalAperture"; @@ -1281,6 +1282,22 @@ static uint32_t GetDelayTime(SkCodec * codec, uint32_t index, int32_t &value) return SUCCESS; } +static uint32_t GetDisposalType(SkCodec * codec, uint32_t index, int32_t &value) +{ + if (codec->getEncodedFormat() != SkEncodedImageFormat::kGIF) { + IMAGE_LOGE("[GetDisposalType] Should not get disposal type in %{public}d", codec->getEncodedFormat()); + return ERR_MEDIA_INVALID_PARAM; + } + auto frameInfos = codec->getFrameInfo(); + if (index > frameInfos.size() - 1) { + IMAGE_LOGE("[GetDisposalType] frame size %{public}zu, index:%{public}d", frameInfos.size(), index); + return ERR_MEDIA_INVALID_PARAM; + } + value = static_cast(frameInfos[index].fDisposalMethod); + IMAGE_LOGD("[GetDisposalType] index[%{public}d]:%{public}d", index, value); + return SUCCESS; +} + uint32_t ExtDecoder::GetImagePropertyInt(uint32_t index, const std::string &key, int32_t &value) { IMAGE_LOGD("[GetImagePropertyInt] enter ExtDecoder plugin, key:%{public}s", key.c_str()); @@ -1291,6 +1308,9 @@ uint32_t ExtDecoder::GetImagePropertyInt(uint32_t index, const std::string &key, if (IMAGE_DELAY_TIME.compare(key) == ZERO) { return GetDelayTime(codec_.get(), index, value); } + if (IMAGE_DISPOSAL_TYPE.compare(key) == ZERO) { + return GetDisposalType(codec_.get(), index, value); + } // There can add some not need exif property if (res == Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT) { return res; @@ -1325,6 +1345,11 @@ uint32_t ExtDecoder::GetImagePropertyString(uint32_t index, const std::string &k res = GetDelayTime(codec_.get(), index, delayTime); value = std::to_string(delayTime); return res; + } else if (IMAGE_DISPOSAL_TYPE.compare(key) == ZERO) { + int disposalType = ZERO; + res = GetDisposalType(codec_.get(), index, disposalType); + value = std::to_string(disposalType); + return res; } if (res == Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT) { return res;