From f87537cb317b73dae922cf6a01a05f59d9dceedd Mon Sep 17 00:00:00 2001 From: zhang-xiaobo1997 Date: Sat, 12 Mar 2022 15:38:17 +0800 Subject: [PATCH] Modify for exif Signed-off-by: zhang-xiaobo1997 --- .../innerkitsimpl/codec/src/image_source.cpp | 18 + .../innerkitsimpl/pixelconverter/BUILD.gn | 2 + .../kits/js/common/image_packer_napi.cpp | 69 ++- .../kits/js/common/image_source_napi.cpp | 178 ++++++- interfaces/innerkits/include/image_source.h | 2 + .../js/common/include/image_source_napi.h | 10 + .../common/libs/image/libjpegplugin/BUILD.gn | 10 +- .../image/libjpegplugin/include/exif_info.h | 66 +++ .../libjpegplugin/include/jpeg_decoder.h | 5 + .../image/libjpegplugin/src/exif_info.cpp | 466 ++++++++++++++++++ .../image/libjpegplugin/src/jpeg_decoder.cpp | 99 +++- plugins/manager/BUILD.gn | 2 + .../manager/include/image/abs_image_decoder.h | 7 + 13 files changed, 913 insertions(+), 21 deletions(-) create mode 100644 plugins/common/libs/image/libjpegplugin/include/exif_info.h create mode 100644 plugins/common/libs/image/libjpegplugin/src/exif_info.cpp diff --git a/frameworks/innerkitsimpl/codec/src/image_source.cpp b/frameworks/innerkitsimpl/codec/src/image_source.cpp index 25af2eaad..7a876381a 100644 --- a/frameworks/innerkitsimpl/codec/src/image_source.cpp +++ b/frameworks/innerkitsimpl/codec/src/image_source.cpp @@ -532,6 +532,24 @@ uint32_t ImageSource::GetImageInfo(uint32_t index, ImageInfo &imageInfo) return SUCCESS; } +uint32_t ImageSource::ModifyImageProperty(uint32_t index, const std::string &key, + const std::string &value, const std::string &path) +{ + std::unique_lock guard(decodingMutex_); + uint32_t ret; + auto iter = GetValidImageStatus(0, ret); + if (iter == imageStatusMap_.end()) { + IMAGE_LOGE("[ImageSource]get valid image status fail on modify image property, ret:%{public}u.", ret); + return ret; + } + ret = mainDecoder_->ModifyImageProperty(index, key, value, path); + if (ret != SUCCESS) { + IMAGE_LOGE("[ImageSource] GetImagePropertyInt fail, ret:%{public}u", ret); + return ret; + } + return SUCCESS; +} + uint32_t ImageSource::GetImagePropertyInt(uint32_t index, const std::string &key, int32_t &value) { std::unique_lock guard(decodingMutex_); diff --git a/frameworks/innerkitsimpl/pixelconverter/BUILD.gn b/frameworks/innerkitsimpl/pixelconverter/BUILD.gn index 9e511d040..bf2342c26 100644 --- a/frameworks/innerkitsimpl/pixelconverter/BUILD.gn +++ b/frameworks/innerkitsimpl/pixelconverter/BUILD.gn @@ -143,4 +143,6 @@ ohos_static_library("pixelconvertadapter_static") { external_deps = [ "hiviewdfx_hilog_native:libhilog" ] } + subsystem_name = "multimedia" + part_name = "multimedia_image_standard" } diff --git a/frameworks/kits/js/common/image_packer_napi.cpp b/frameworks/kits/js/common/image_packer_napi.cpp index 0f114c1cd..b1f555b87 100644 --- a/frameworks/kits/js/common/image_packer_napi.cpp +++ b/frameworks/kits/js/common/image_packer_napi.cpp @@ -42,6 +42,8 @@ const int PARAM0 = 0; const int PARAM1 = 1; const int PARAM2 = 2; const int32_t SIZE = 100; +const int32_t TYPE_IMAGE_SOURCE = 1; +const int32_t TYPE_PIXEL_MAP = 2; struct ImagePackerAsyncContext { napi_env env; @@ -341,6 +343,41 @@ static bool parsePackOptions(napi_env env, napi_value root, PackOption* opts) return true; } +static int32_t ParserPackingArguments(napi_env env, napi_value argv) +{ + napi_value constructor = nullptr; + napi_value global = nullptr; + bool isInstance = false; + napi_status ret = napi_invalid_arg; + + napi_get_global(env, &global); + + ret = napi_get_named_property(env, global, "ImageSourceNapi", &constructor); + if (ret != napi_ok) { + HiLog::Error(LABEL, "Get ImageSourceNapi property failed!"); + } + + ret = napi_instanceof(env, argv, constructor, &isInstance); + if (ret == napi_ok && isInstance) { + HiLog::Debug(LABEL, "This is ImageSourceNapi type!"); + return TYPE_IMAGE_SOURCE; + } + + ret = napi_get_named_property(env, global, "PixelMapNapi", &constructor); + if (ret != napi_ok) { + HiLog::Error(LABEL, "Get PixelMapNapi property failed!"); + } + + ret = napi_instanceof(env, argv, constructor, &isInstance); + if (ret == napi_ok && isInstance) { + HiLog::Debug(LABEL, "This is PixelMapNapi type!"); + return TYPE_PIXEL_MAP; + } + + HiLog::Error(LABEL, "Inalued type!"); + return TYPE_IMAGE_SOURCE; +} + napi_value ImagePackerNapi::Packing(napi_env env, napi_callback_info info) { napi_status status; @@ -349,6 +386,7 @@ napi_value ImagePackerNapi::Packing(napi_env env, napi_callback_info info) napi_value argv[ARGS_THREE] = {0}; napi_value thisVar = nullptr; int32_t refCount = 1; + int32_t packType = TYPE_IMAGE_SOURCE; std::shared_ptr imagesourceObj = nullptr; std::unique_ptr pixelMap = nullptr; @@ -366,13 +404,20 @@ napi_value ImagePackerNapi::Packing(napi_env env, napi_callback_info info) for (size_t i = PARAM0; i < argc; i++) { napi_valuetype argvType = ImageNapiUtils::getType(env, argv[i]); if (i == PARAM0 && argvType == napi_object) { - std::shared_ptr imageSourceNapi = std::make_unique(); - status = napi_unwrap(env, argv[i], reinterpret_cast(&imageSourceNapi)); - IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, imageSourceNapi), nullptr, - HiLog::Error(LABEL, "fail to unwrap ImageSourceNapi")); - asyncContext->rImageSource = imageSourceNapi->nativeImgSrc; - IMG_NAPI_CHECK_RET_D(IMG_IS_OK(asyncContext->rImageSource == nullptr), nullptr, - HiLog::Error(LABEL, "fail to napi_get rImageSource")); + packType = ParserPackingArguments(env, argv[0]); + if (packType == TYPE_IMAGE_SOURCE) { + std::shared_ptr imageSourceNapi = std::make_unique(); + status = napi_unwrap(env, argv[i], reinterpret_cast(&imageSourceNapi)); + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, imageSourceNapi), nullptr, + HiLog::Error(LABEL, "fail to unwrap ImageSourceNapi")); + asyncContext->rImageSource = imageSourceNapi->nativeImgSrc; + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(asyncContext->rImageSource == nullptr), nullptr, + HiLog::Error(LABEL, "fail to napi_get rImageSource")); + } else { + asyncContext->rPixelMap = PixelMapNapi::GetPixelMap(env, argv[i]); + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(asyncContext->rPixelMap == nullptr), nullptr, + HiLog::Error(LABEL, "fail to napi_get rPixelMap")); + } } else if (i == PARAM1 && ImageNapiUtils::getType(env, argv[i]) == napi_object) { IMG_NAPI_CHECK_RET_D(parsePackOptions(env, argv[i], &(asyncContext->packOption)), nullptr, HiLog::Error(LABEL, "PackOptions mismatch")); @@ -389,8 +434,14 @@ napi_value ImagePackerNapi::Packing(napi_env env, napi_callback_info info) } ImageNapiUtils::HicheckerReport(); - IMG_CREATE_CREATE_ASYNC_WORK(env, status, "Packing", - PackingExec, PackingComplete, asyncContext, asyncContext->work); + + if (packType == TYPE_IMAGE_SOURCE) { + IMG_CREATE_CREATE_ASYNC_WORK(env, status, "Packing", + PackingExec, PackingComplete, asyncContext, asyncContext->work); + } else { + IMG_CREATE_CREATE_ASYNC_WORK(env, status, "PackingFromPixelMap", + PackingFromPixelMapExec, PackingComplete, asyncContext, asyncContext->work); + } IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to create async work")); diff --git a/frameworks/kits/js/common/image_source_napi.cpp b/frameworks/kits/js/common/image_source_napi.cpp index 0100147c2..1b62e57b5 100644 --- a/frameworks/kits/js/common/image_source_napi.cpp +++ b/frameworks/kits/js/common/image_source_napi.cpp @@ -34,7 +34,9 @@ namespace OHOS { namespace Media { napi_ref ImageSourceNapi::sConstructor_ = nullptr; std::shared_ptr ImageSourceNapi::sImgSrc_ = nullptr; +std::shared_ptr ImageSourceNapi::sIncPixelMap_ = nullptr; static const std::string CLASS_NAME = "ImageSource"; +std::string ImageSourceNapi::filePath_ = ""; struct ImageSourceAsyncContext { napi_env env; @@ -143,6 +145,7 @@ napi_value ImageSourceNapi::Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_FUNCTION("getImageInfo", GetImageInfo), + DECLARE_NAPI_FUNCTION("modifyImageProperty", ModifyImageProperty), DECLARE_NAPI_FUNCTION("getImageProperty", GetImageProperty), DECLARE_NAPI_FUNCTION("createPixelMap", CreatePixelMap), DECLARE_NAPI_FUNCTION("updateData", UpdateData), @@ -200,6 +203,8 @@ napi_value ImageSourceNapi::Constructor(napi_env env, napi_callback_info info) if (pImgSrcNapi != nullptr) { pImgSrcNapi->env_ = env; pImgSrcNapi->nativeImgSrc = sImgSrc_; + pImgSrcNapi->navIncPixelMap_ = sIncPixelMap_; + sIncPixelMap_ = nullptr; status = napi_wrap(env, thisVar, reinterpret_cast(pImgSrcNapi.get()), ImageSourceNapi::Destructor, nullptr, &(pImgSrcNapi->wrapper_)); @@ -430,6 +435,7 @@ napi_value ImageSourceNapi::CreateImageSource(napi_env env, napi_callback_info i asyncContext->pathName = buffer; 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) { napi_get_value_int32(env, argValue[NUM_0], &asyncContext->fdIndex); @@ -495,6 +501,8 @@ napi_value ImageSourceNapi::CreateIncrementalSource(napi_env env, napi_callback_ IncrementalSourceOptions incOpts; incOpts.incrementalMode = IncrementalMode::INCREMENTAL_DATA; std::unique_ptr imageSource = ImageSource::CreateIncrementalImageSource(incOpts, errorCode); + DecodeOptions decodeOpts; + std::unique_ptr incPixelMap = imageSource->CreateIncrementalPixelMap(0, decodeOpts, errorCode); HiLog::Debug(LABEL, "CreateIncrementalImageSource end"); if (errorCode != SUCCESS || imageSource == nullptr) { HiLog::Error(LABEL, "CreateIncrementalImageSource error"); @@ -505,6 +513,7 @@ napi_value ImageSourceNapi::CreateIncrementalSource(napi_env env, napi_callback_ status = napi_get_reference_value(env, sConstructor_, &constructor); if (IMG_IS_OK(status)) { sImgSrc_ = std::move(imageSource); + sIncPixelMap_ = std::move(incPixelMap); status = napi_new_instance(env, constructor, NUM_0, nullptr, &result); } if (!IMG_IS_OK(status)) { @@ -587,8 +596,18 @@ static void CreatePixelMapExecute(napi_env env, void *data) HiLog::Error(LABEL, "empty context rImageSource"); } - context->rPixelMap = context->rImageSource->CreatePixelMap(context->decodeOpts, errorCode); - + if (context->constructor_ != nullptr) { + auto incPixelMap = context->constructor_->GetIncrementalPixelMap(); + if (incPixelMap != nullptr) { + HiLog::Info(LABEL, "Get Incremental PixelMap!!!"); + context->rPixelMap = incPixelMap; + } + } else { + HiLog::Info(LABEL, "Get Incremental PixelMap!!!"); + } + if (context->rPixelMap == nullptr) { + context->rPixelMap = context->rImageSource->CreatePixelMap(context->decodeOpts, errorCode); + } if (context->rPixelMap == nullptr) { HiLog::Error(LABEL, "empty context rPixelMap"); } @@ -636,7 +655,7 @@ napi_value ImageSourceNapi::CreatePixelMap(napi_env env, napi_callback_info info nullptr, HiLog::Error(LABEL, "fail to unwrap context")); IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, imageSourceNapi->nativeImgSrc), nullptr, HiLog::Error(LABEL, "fail to unwrap nativeImgSrc")); - + asyncContext->constructor_ = imageSourceNapi.get(); asyncContext->rImageSource = imageSourceNapi->nativeImgSrc; IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rImageSource), nullptr, HiLog::Error(LABEL, "empty native rImageSource")); @@ -689,6 +708,21 @@ static bool ParsePropertyOptions(napi_env env, napi_value root, ImageSourceAsync return true; } +static void ModifyImagePropertyComplete(napi_env env, napi_status status, ImageSourceAsyncContext *context) +{ + HiLog::Debug(LABEL, "ModifyPropertyComplete IN"); + + if (context == nullptr) { + HiLog::Error(LABEL, "context is nullptr"); + return; + } + napi_value result = nullptr; + napi_get_undefined(env, &result); + + HiLog::Debug(LABEL, "ModifyPropertyComplete OUT"); + ImageSourceCallbackRoutine(env, context, result); +} + static void GetImagePropertyComplete(napi_env env, napi_status status, ImageSourceAsyncContext *context) { HiLog::Debug(LABEL, "GetImagePropertyComplete IN"); @@ -756,6 +790,93 @@ static std::unique_ptr UnwrapContext(napi_env env, napi return context; } +static std::unique_ptr UnwrapContextForModify(napi_env env, + napi_callback_info info) +{ + int32_t refCount = 1; + napi_status status; + napi_value thisVar = nullptr; + napi_value argValue[NUM_4] = {0}; + size_t argCount = NUM_4; + IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar); + HiLog::Debug(LABEL, "UnwrapContextForModify argCount is [%{public}zu]", argCount); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + + std::unique_ptr context = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&context->constructor_)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->constructor_), + nullptr, HiLog::Error(LABEL, "fail to unwrap context")); + + context->rImageSource = context->constructor_->nativeImgSrc; + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->rImageSource), + nullptr, HiLog::Error(LABEL, "empty native rImageSource")); + if (argCount < NUM_1 || argCount > NUM_4) { + HiLog::Error(LABEL, "argCount missmatch"); + return nullptr; + } + if (ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_string) { + context->keyStr = GetStringArgument(env, argValue[NUM_0]); + } else { + HiLog::Error(LABEL, "arg 0 type missmatch"); + return nullptr; + } + if (ImageNapiUtils::getType(env, argValue[NUM_1]) == napi_string) { + context->valueStr = GetStringArgument(env, argValue[NUM_1]); + } else { + HiLog::Error(LABEL, "arg 1 type missmatch"); + return nullptr; + } + if (argCount == NUM_3 || argCount == NUM_4) { + if (ImageNapiUtils::getType(env, argValue[NUM_2]) == napi_object) { + IMG_NAPI_CHECK_RET_D(ParsePropertyOptions(env, argValue[NUM_2], context.get()), + nullptr, HiLog::Error(LABEL, "PropertyOptions mismatch")); + } + if (ImageNapiUtils::getType(env, argValue[argCount - 1]) == napi_function) { + napi_create_reference(env, argValue[argCount - 1], refCount, &context->callbackRef); + } + } + context->pathName = ImageSourceNapi::filePath_; + return context; +} + +napi_value ImageSourceNapi::ModifyImageProperty(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + napi_status status; + HiLog::Debug(LABEL, "ModifyImageProperty IN"); + std::unique_ptr asyncContext = UnwrapContextForModify(env, info); + if (asyncContext == nullptr) { + HiLog::Error(LABEL, "async context unwrap failed"); + return result; + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &(asyncContext->deferred), &result); + } else { + napi_get_undefined(env, &result); + } + + IMG_CREATE_CREATE_ASYNC_WORK(env, status, "ModifyImageProperty", + [](napi_env env, void *data) + { + auto context = static_cast(data); + context->status = context->rImageSource->ModifyImageProperty(context->index, + context->keyStr, context->valueStr, context->pathName); + }, + reinterpret_cast(ModifyImagePropertyComplete), + 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 ImageSourceNapi::GetImageProperty(napi_env env, napi_callback_info info) { napi_value result = nullptr; @@ -795,8 +916,31 @@ napi_value ImageSourceNapi::GetImageProperty(napi_env env, napi_callback_info in static void UpdateDataExecute(napi_env env, void *data) { auto context = static_cast(data); - context->isSuccess = context->rImageSource->UpdateData(static_cast(context->updataBuffer), - context->updataBufferSize, context->isCompleted); + uint8_t *buffer = static_cast(context->updataBuffer); + if (context->updataBufferOffset < context->updataBufferSize) { + buffer = buffer + context->updataBufferOffset; + } + + uint32_t lastSize = context->updataBufferSize - context->updataBufferOffset; + uint32_t size = context->updataLength < lastSize ? context->updataLength : lastSize; + + uint32_t res = context->rImageSource->UpdateData(buffer, size, + context->isCompleted); + context->isSuccess = res == 0; + if (context->isSuccess && context->constructor_ != nullptr) { + auto incPixelMap = context->constructor_->GetIncrementalPixelMap(); + if (incPixelMap != nullptr) { + uint8_t decodeProgress = 0; + uint32_t err = incPixelMap->PromoteDecoding(decodeProgress); + if (!(err == SUCCESS || (err == ERR_IMAGE_SOURCE_DATA_INCOMPLETE && !context->isCompleted))) { + HiLog::Error(LABEL, "UpdateData PromoteDecoding error"); + context->isSuccess = false; + } + if (context->isCompleted) { + incPixelMap->DetachFromDecoding(); + } + } + } } static void UpdateDataComplete(napi_env env, napi_status status, void *data) @@ -812,6 +956,14 @@ static void UpdateDataComplete(napi_env env, napi_status status, void *data) ImageSourceCallbackRoutine(env, context, result); } +static bool isNapiTypedArray(napi_env env, napi_value val) +{ + bool res = false; + napi_is_typedarray(env, val, &res); + HiLog::Debug(LABEL, "isNapiTypedArray %{public}d", res); + return res; +} + napi_value ImageSourceNapi::UpdateData(napi_env env, napi_callback_info info) { napi_value result = nullptr; @@ -838,11 +990,15 @@ napi_value ImageSourceNapi::UpdateData(napi_env env, napi_callback_info info) IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rImageSource), nullptr, HiLog::Error(LABEL, "empty native rImageSource")); - - if (argCount > NUM_0 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_string) { - size_t bufferSize = static_cast(asyncContext->updataBufferSize); - status = napi_get_arraybuffer_info(env, argValue[NUM_0], - &(asyncContext->updataBuffer), &bufferSize); + HiLog::Error(LABEL, "UpdateData argCount %{public}d ", argCount); + if (argCount > NUM_0 && isNapiTypedArray(env, argValue[NUM_0])) { + HiLog::Error(LABEL, "UpdateData napi_get_arraybuffer_info "); + napi_typedarray_type type; + napi_value arraybuffer; + size_t offset; + status = napi_get_typedarray_info(env, argValue[NUM_0], &type, + &(asyncContext->updataBufferSize), &(asyncContext->updataBuffer), + &arraybuffer, &offset); } if (argCount >= NUM_2 && ImageNapiUtils::getType(env, argValue[NUM_1]) == napi_boolean) { @@ -850,11 +1006,13 @@ napi_value ImageSourceNapi::UpdateData(napi_env env, napi_callback_info info) } if (argCount >= NUM_3 && ImageNapiUtils::getType(env, argValue[NUM_2]) == napi_number) { + asyncContext->updataBufferOffset = 0; status = napi_get_value_uint32(env, argValue[NUM_2], &(asyncContext->updataBufferOffset)); HiLog::Debug(LABEL, "asyncContext->updataBufferOffset is [%{public}u]", asyncContext->updataBufferOffset); } if (argCount >= NUM_4 && ImageNapiUtils::getType(env, argValue[NUM_3]) == napi_number) { + asyncContext->updataLength = 0; status = napi_get_value_uint32(env, argValue[NUM_3], &(asyncContext->updataLength)); HiLog::Debug(LABEL, "asyncContext->updataLength is [%{public}u]", asyncContext->updataLength); } diff --git a/interfaces/innerkits/include/image_source.h b/interfaces/innerkits/include/image_source.h index 04021861a..1c33bbe01 100644 --- a/interfaces/innerkits/include/image_source.h +++ b/interfaces/innerkits/include/image_source.h @@ -162,6 +162,8 @@ public: NATIVEEXPORT bool IsIncrementalSource(); NATIVEEXPORT uint32_t GetImagePropertyInt(uint32_t index, const std::string &key, int32_t &value); NATIVEEXPORT uint32_t GetImagePropertyString(uint32_t index, const std::string &key, std::string &value); + NATIVEEXPORT uint32_t ModifyImageProperty(uint32_t index, const std::string &key, const std::string &value, + const std::string &path); NATIVEEXPORT const NinePatchInfo &GetNinePatchInfo() const; NATIVEEXPORT void SetMemoryUsagePreference(const MemoryUsagePreference preference); NATIVEEXPORT MemoryUsagePreference GetMemoryUsagePreference(); diff --git a/interfaces/kits/js/common/include/image_source_napi.h b/interfaces/kits/js/common/include/image_source_napi.h index e63fdb217..7c02fe4a4 100644 --- a/interfaces/kits/js/common/include/image_source_napi.h +++ b/interfaces/kits/js/common/include/image_source_napi.h @@ -22,6 +22,7 @@ #include "napi/native_api.h" #include "napi/native_node_api.h" #include "pixel_map_napi.h" +#include "incremental_pixel_map.h" namespace OHOS { namespace Media { @@ -32,6 +33,12 @@ public: static napi_value Init(napi_env env, napi_value exports); std::shared_ptr nativeImgSrc = nullptr; + std::shared_ptr GetIncrementalPixelMap() + { + return navIncPixelMap_; + } + + static std::string filePath_; private: static napi_value Constructor(napi_env env, napi_callback_info info); static void Destructor(napi_env env, void *nativeObject, void *finalize); @@ -47,12 +54,15 @@ private: // methods static napi_value GetImageInfo(napi_env env, napi_callback_info info); static napi_value CreatePixelMap(napi_env env, napi_callback_info info); + static napi_value ModifyImageProperty(napi_env env, napi_callback_info info); static napi_value GetImageProperty(napi_env env, napi_callback_info info); static napi_value UpdateData(napi_env env, napi_callback_info info); static napi_value Release(napi_env env, napi_callback_info info); static napi_ref sConstructor_; static std::shared_ptr sImgSrc_; + static std::shared_ptr sIncPixelMap_; + std::shared_ptr navIncPixelMap_ = nullptr; napi_env env_ = nullptr; napi_ref wrapper_ = nullptr; diff --git a/plugins/common/libs/image/libjpegplugin/BUILD.gn b/plugins/common/libs/image/libjpegplugin/BUILD.gn index 7403c06de..520cdab29 100644 --- a/plugins/common/libs/image/libjpegplugin/BUILD.gn +++ b/plugins/common/libs/image/libjpegplugin/BUILD.gn @@ -16,6 +16,7 @@ import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") ohos_shared_library("jpegplugin") { sources = [ + "//foundation/multimedia/image_standard/plugins/common/libs/image/libjpegplugin/src/exif_info.cpp", "//foundation/multimedia/image_standard/plugins/common/libs/image/libjpegplugin/src/jpeg_decoder.cpp", "//foundation/multimedia/image_standard/plugins/common/libs/image/libjpegplugin/src/jpeg_utils.cpp", "//foundation/multimedia/image_standard/plugins/common/libs/image/libjpegplugin/src/plugin_export.cpp", @@ -34,6 +35,7 @@ ohos_shared_library("jpegplugin") { "//third_party/flutter/skia", "//third_party/flutter/skia/include/core", "//third_party/flutter/skia/third_party/libjpeg-turbo", + "//third_party/libexif", ] if (use_mingw_win) { @@ -48,6 +50,7 @@ ohos_shared_library("jpegplugin") { "//foundation/multimedia/image_standard/interfaces/innerkits:image_static", "//foundation/multimedia/image_standard/mock/native:utils_mock_static", "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//third_party/libexif:libexif", ] } else if (use_clang_mac) { defines = image_decode_mac_defines @@ -60,6 +63,7 @@ ohos_shared_library("jpegplugin") { "//foundation/multimedia/image_standard/interfaces/innerkits:image_static", "//foundation/multimedia/image_standard/mock/native:utils_mock_static", "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//third_party/libexif:libexif", ] } else { defines = [ "DUAL_ADAPTER" ] @@ -71,12 +75,16 @@ ohos_shared_library("jpegplugin") { "//foundation/ace/ace_engine/build/external_config/flutter/libjpeg:ace_libjpeg", "//foundation/multimedia/image_standard/interfaces/innerkits:image_native", "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//third_party/libexif:libexif", "//utils/native/base:utils", ] if (DUAL_ADAPTER) { } else { - deps += [ "//foundation/ace/ace_engine/build/external_config/flutter/libjpeg:ace_libjpeg" ] + deps += [ + "//foundation/ace/ace_engine/build/external_config/flutter/libjpeg:ace_libjpeg", + "//third_party/libexif:libexif", + ] include_dirs += [ "//third_party/flutter/skia/third_party/libjpeg-turbo" ] } diff --git a/plugins/common/libs/image/libjpegplugin/include/exif_info.h b/plugins/common/libs/image/libjpegplugin/include/exif_info.h new file mode 100644 index 000000000..8ca9cca35 --- /dev/null +++ b/plugins/common/libs/image/libjpegplugin/include/exif_info.h @@ -0,0 +1,66 @@ +/* + * 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 EXIF_INFO_H +#define EXIF_INFO_H +#include +#include +#include "hilog/log.h" +#include "log_tags.h" +namespace OHOS { +namespace ImagePlugin { +/* + * Class responsible for storing and parsing EXIF information from a JPEG blob + */ +class EXIFInfo { +public: + EXIFInfo(); + ~EXIFInfo(); + /* + * Parsing function for an entire JPEG image buffer. + * PARAM 'data': A pointer to a JPEG image. + * PARAM 'length': The length of the JPEG image. + * RETURN: PARSE_EXIF_SUCCESS (0) on succes with 'result' filled out + * error code otherwise, as defined by the PARSE_EXIF_ERROR_* macros + */ + int ParseExifData(const unsigned char *buf, unsigned len); + int ParseExifData(const std::string &data); + bool ModifyExifData(const ExifTag &tag, const std::string &value, const std::string &path); + +public: + std::string bitsPerSample_; // Number of bits in each pixel of an image. + std::string orientation_; + std::string imageLength_; // Image length. + std::string imageWidth_; // mage width. + std::string gpsLatitude_; + std::string gpsLongitude_; + std::string gpsLatitudeRef_; + std::string gpsLongitudeRef_; + std::string dateTimeOriginal_; // Original date and time. + +private: + void SetExifTagValues(const ExifTag &tag, const std::string &value); + ExifIfd GetImageFileDirectory(const ExifTag &tag); + ExifEntry* InitExifTag(ExifData *exif, ExifIfd ifd, ExifTag tag); + ExifEntry* CreateExifTag(ExifData *exif, ExifIfd ifd, ExifTag tag, size_t len, ExifFormat format); + long GetFileSize(FILE *fp); + void ReleaseSource(unsigned char *buf, FILE *file); + +private: + ExifIfd imageFileDirectory_; + ExifData* exifData_; +}; +} // namespace ImagePlugin +} // namespace OHOS +#endif // EXIF_INFO_H diff --git a/plugins/common/libs/image/libjpegplugin/include/jpeg_decoder.h b/plugins/common/libs/image/libjpegplugin/include/jpeg_decoder.h index 588f4ecaf..cd1c56a60 100644 --- a/plugins/common/libs/image/libjpegplugin/include/jpeg_decoder.h +++ b/plugins/common/libs/image/libjpegplugin/include/jpeg_decoder.h @@ -26,6 +26,7 @@ #include "log_tags.h" #include "plugin_class_base.h" #include "plugin_server.h" +#include "exif_info.h" namespace OHOS { namespace ImagePlugin { @@ -52,6 +53,8 @@ public: uint32_t PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) override; uint32_t GetImagePropertyInt(uint32_t index, const std::string &key, int32_t &value) override; uint32_t GetImagePropertyString(uint32_t index, const std::string &key, std::string &value) override; + uint32_t ModifyImageProperty(uint32_t index, const std::string &key, const std::string &value, + const std::string &path) override; private: DISALLOW_COPY_AND_MOVE(JpegDecoder); int ExifPrintMethod(); @@ -65,6 +68,7 @@ private: void CreateDecoder(); bool IsMarker(uint8_t rawPrefix, uint8_t rawMarkderCode, uint8_t markerCode); bool FindMarker(InputDataStream &stream, uint8_t marker); + ExifTag getExifTagFromKey(const std::string &key, const std::string &value); static MultimediaPlugin::PluginServer &pluginServer_; jpeg_decompress_struct decodeInfo_; @@ -75,6 +79,7 @@ private: uint32_t streamPosition_ = 0; // may be changed by other decoders, record it and restore if needed. PlPixelFormat outputFormat_ = PlPixelFormat::UNKNOWN; PixelDecodeOptions opts_; + EXIFInfo exifInfo_; }; } // namespace ImagePlugin } // namespace OHOS diff --git a/plugins/common/libs/image/libjpegplugin/src/exif_info.cpp b/plugins/common/libs/image/libjpegplugin/src/exif_info.cpp new file mode 100644 index 000000000..49f254002 --- /dev/null +++ b/plugins/common/libs/image/libjpegplugin/src/exif_info.cpp @@ -0,0 +1,466 @@ +/* + * 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 "exif_info.h" +#include +#include +#include "string_ex.h" +#include "securec.h" + +namespace OHOS { +namespace ImagePlugin { +namespace { + using namespace OHOS::HiviewDFX; + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "Exif" }; + static const int PARSE_EXIF_SUCCESS = 0; + static const int PARSE_EXIF_DATA_ERROR = 10001; + static const int PARSE_EXIF_IFD_ERROR = 10002; + static const int BUFFER_POSITION_4 = 4; + static const int BUFFER_POSITION_5 = 5; + static const int BUFFER_POSITION_6 = 6; + static const int BUFFER_POSITION_7 = 7; + static const int BUFFER_POSITION_8 = 8; + static const int BUFFER_POSITION_9 = 9; + static const int BUFFER_POSITION_12 = 12; + static const int BUFFER_POSITION_13 = 13; + static const int LENGTH_OFFSET_2 = 2; + static const int MOVE_OFFSET_8 = 8; + static const int LENGTH_ARRAY_SIZE = 2; + static const int CONSTANT_2 = 2; + + /* raw EXIF header data */ + static const unsigned char exifHeader[] = { + 0xff, 0xd8, 0xff, 0xe1 + }; +} + +EXIFInfo::EXIFInfo() : imageFileDirectory_(EXIF_IFD_COUNT), exifData_(nullptr) +{ +} + +EXIFInfo::~EXIFInfo() +{ + if (exifData_ != nullptr) { + exif_data_unref(exifData_); + exifData_ = nullptr; + } +} + +int EXIFInfo::ParseExifData(const unsigned char *buf, unsigned len) +{ + HiLog::Debug(LABEL, "ParseExifData ENTER"); + exifData_ = exif_data_new_from_data(buf, len); + if (!exifData_) { + return PARSE_EXIF_DATA_ERROR; + } + exif_data_foreach_content(exifData_, + [](ExifContent *ec, void *userData) { + ExifIfd ifd = exif_content_get_ifd(ec); + ((EXIFInfo*)userData)->imageFileDirectory_ = ifd; + if (ifd == EXIF_IFD_COUNT) { + HiLog::Debug(LABEL, "GetIfd ERROR"); + return; + } + exif_content_foreach_entry(ec, + [](ExifEntry *ee, void* userData) { + char tagValueChar[1024]; + exif_entry_get_value(ee, tagValueChar, sizeof(tagValueChar)); + std::string tagValueStr(&tagValueChar[0], &tagValueChar[strlen(tagValueChar)]); + ((EXIFInfo*)userData)->SetExifTagValues(ee->tag, tagValueStr); + }, userData); + }, this); + + if (imageFileDirectory_ == EXIF_IFD_COUNT) { + return PARSE_EXIF_IFD_ERROR; + } + return PARSE_EXIF_SUCCESS; +} + +int EXIFInfo::ParseExifData(const std::string &data) +{ + return ParseExifData((const unsigned char *)data.data(), data.length()); +} + +void EXIFInfo::SetExifTagValues(const ExifTag &tag, const std::string &value) +{ + if (tag == EXIF_TAG_BITS_PER_SAMPLE) { + bitsPerSample_ = value; + } else if (tag == EXIF_TAG_ORIENTATION) { + orientation_ = value; + } else if (tag == EXIF_TAG_IMAGE_LENGTH) { + imageLength_ = value; + } else if (tag == EXIF_TAG_IMAGE_WIDTH) { + imageWidth_ = value; + } else if (tag == EXIF_TAG_GPS_LATITUDE) { + gpsLatitude_ = value; + } else if (tag == EXIF_TAG_GPS_LONGITUDE) { + gpsLongitude_ = value; + } else if (tag == EXIF_TAG_GPS_LATITUDE_REF) { + gpsLatitudeRef_ = value; + } else if (tag == EXIF_TAG_GPS_LONGITUDE_REF) { + gpsLongitudeRef_ = value; + } else if (tag == EXIF_TAG_DATE_TIME_ORIGINAL) { + dateTimeOriginal_ = value; + } else { + HiLog::Error(LABEL, "No match tag name!"); + } +} + +bool EXIFInfo::ModifyExifData(const ExifTag &tag, const std::string &value, const std::string &path) +{ + FILE *file = fopen(path.c_str(), "rb"); + if (file == nullptr) { + HiLog::Error(LABEL, "Error creating file %{public}s", path.c_str()); + return false; + } + + // read jpeg file to buff + unsigned long fileLength = GetFileSize(file); + if (fileLength == 0) { + HiLog::Error(LABEL, "Get file size failed."); + fclose(file); + return false; + } + unsigned char *fileBuf = (unsigned char *)malloc(fileLength); + if (fileBuf == nullptr) { + HiLog::Error(LABEL, "Allocate buf for %{public}s failed.", path.c_str()); + fclose(file); + return false; + } + + if (fread(fileBuf, fileLength, 1, file) != 1) { + HiLog::Error(LABEL, "Read %{public}s failed.", path.c_str()); + ReleaseSource(fileBuf, file); + return false; + } + + if (!(fileBuf[0] == 0xFF && fileBuf[1] == 0xD8)) { + HiLog::Error(LABEL, "%{public}s is not jpeg file.", path.c_str()); + ReleaseSource(fileBuf, file); + return false; + } + + unsigned char lenthArray[LENGTH_ARRAY_SIZE] = { + fileBuf[BUFFER_POSITION_5], fileBuf[BUFFER_POSITION_4] + }; + unsigned int orginExifDataLength = *(unsigned int*)lenthArray; + + ExifData *ptrExifData = nullptr; + if ((fileBuf[BUFFER_POSITION_6] == 'E' && fileBuf[BUFFER_POSITION_7] == 'x' && + fileBuf[BUFFER_POSITION_8] == 'i' && fileBuf[BUFFER_POSITION_9] == 'f')) { + ptrExifData = exif_data_new_from_file(path.c_str()); + if (!ptrExifData) { + HiLog::Error(LABEL, "Create exif data from file failed."); + ReleaseSource(fileBuf, file); + return false; + } + } else { + ptrExifData = exif_data_new(); + if (!ptrExifData) { + HiLog::Error(LABEL, "Create exif data failed."); + ReleaseSource(fileBuf, file); + return false; + } + /* Set the image options */ + exif_data_set_option(ptrExifData, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); + exif_data_set_data_type(ptrExifData, EXIF_DATA_TYPE_COMPRESSED); + exif_data_set_byte_order(ptrExifData, EXIF_BYTE_ORDER_INTEL); + + /* Create the mandatory EXIF fields with default data */ + exif_data_fix(ptrExifData); + } + (void)fclose(file); + file = nullptr; + + ExifByteOrder order = EXIF_BYTE_ORDER_MOTOROLA; + if (fileBuf[BUFFER_POSITION_12] == 'M' && fileBuf[BUFFER_POSITION_13] == 'M') { + order = EXIF_BYTE_ORDER_MOTOROLA; + } else { + order = EXIF_BYTE_ORDER_INTEL; + } + + FILE *newFile = fopen(path.c_str(), "wb"); + if (newFile == nullptr) { + HiLog::Error(LABEL, "Error create new file %{public}s", path.c_str()); + ReleaseSource(fileBuf, newFile); + return false; + } + + ExifEntry *entry = nullptr; + switch (tag) { + case EXIF_TAG_BITS_PER_SAMPLE: { + entry = InitExifTag(ptrExifData, EXIF_IFD_1, EXIF_TAG_BITS_PER_SAMPLE); + std::vector bitsVec; + SplitStr(value, ",", bitsVec); + if (bitsVec.size() > CONSTANT_2) { + HiLog::Error(LABEL, "BITS_PER_SAMPLE Invalid value %{public}s", value.c_str()); + ReleaseSource(fileBuf, newFile); + return false; + } + if (bitsVec.size() != 0) { + for (size_t i = 0; i < bitsVec.size(); i++) { + exif_set_short(entry->data + i * CONSTANT_2, order, (ExifShort)atoi(bitsVec[i].c_str())); + } + } + break; + } + case EXIF_TAG_ORIENTATION: { + entry = InitExifTag(ptrExifData, EXIF_IFD_0, EXIF_TAG_ORIENTATION); + exif_set_short(entry->data, order, (ExifShort)atoi(value.c_str())); + break; + } + case EXIF_TAG_IMAGE_LENGTH: { + entry = InitExifTag(ptrExifData, EXIF_IFD_1, EXIF_TAG_IMAGE_LENGTH); + exif_set_short(entry->data, order, (ExifShort)atoi(value.c_str())); + break; + } + case EXIF_TAG_IMAGE_WIDTH: { + entry = InitExifTag(ptrExifData, EXIF_IFD_1, EXIF_TAG_IMAGE_WIDTH); + exif_set_short(entry->data, order, (ExifShort)atoi(value.c_str())); + break; + } + case EXIF_TAG_GPS_LATITUDE: { + std::vector latVec; + SplitStr(value, ",", latVec); + if (latVec.size() != CONSTANT_2) { + HiLog::Error(LABEL, "GPS_LATITUDE Invalid value %{public}s", value.c_str()); + ReleaseSource(fileBuf, newFile); + return false; + } + + ExifRational latRational; + latRational.numerator = atoi(latVec[0].c_str()); + latRational.denominator = atoi(latVec[1].c_str()); + entry = CreateExifTag(ptrExifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE, + sizeof(latRational), EXIF_FORMAT_RATIONAL); + exif_set_rational(entry->data, order, latRational); + break; + } + case EXIF_TAG_GPS_LONGITUDE: { + std::vector longVec; + SplitStr(value, ",", longVec); + if (longVec.size() != CONSTANT_2) { + HiLog::Error(LABEL, "GPS_LONGITUDE Invalid value %{public}s", value.c_str()); + ReleaseSource(fileBuf, newFile); + return false; + } + + ExifRational longRational; + longRational.numerator = atoi(longVec[0].c_str()); + longRational.denominator = atoi(longVec[1].c_str()); + entry = CreateExifTag(ptrExifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE, + sizeof(longRational), EXIF_FORMAT_RATIONAL); + exif_set_rational(entry->data, order, longRational); + break; + } + case EXIF_TAG_GPS_LATITUDE_REF: { + entry = CreateExifTag(ptrExifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE_REF, + value.length(), EXIF_FORMAT_ASCII); + if (memcpy_s(entry->data, value.length(), value.c_str(), value.length()) != 0) { + HiLog::Error(LABEL, "LATITUDE ref memcpy error"); + } + break; + } + case EXIF_TAG_GPS_LONGITUDE_REF: { + entry = CreateExifTag(ptrExifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE_REF, + value.length(), EXIF_FORMAT_ASCII); + if (memcpy_s(entry->data, value.length(), value.c_str(), value.length()) != 0) { + HiLog::Error(LABEL, "LONGITUDE ref memcpy error"); + } + break; + } + default: + break; + } + + unsigned char* exifDataBuf = nullptr; + unsigned int exifDataBufLength = 0; + exif_data_save_data(ptrExifData, &exifDataBuf, &exifDataBufLength); + if (exifDataBuf == nullptr) { + HiLog::Error(LABEL, "Get Exif Data Buf failed!"); + return false; + } + + /* Write EXIF header */ + if (fwrite(exifHeader, sizeof(exifHeader), 1, newFile) != 1) { + HiLog::Error(LABEL, "Error writing EXIF header to file!"); + ReleaseSource(fileBuf, newFile); + return false; + } + + /* Write EXIF block length in big-endian order */ + if (fputc((exifDataBufLength + LENGTH_OFFSET_2) >> MOVE_OFFSET_8, newFile) < 0) { + HiLog::Error(LABEL, "Error writing EXIF block length to file!"); + ReleaseSource(fileBuf, newFile); + return false; + } + if (fputc((exifDataBufLength + LENGTH_OFFSET_2) & 0xff, newFile) < 0) { + HiLog::Error(LABEL, "Error writing EXIF block length to file!"); + ReleaseSource(fileBuf, newFile); + return false; + } + + /* Write EXIF data block */ + if (fwrite(exifDataBuf, exifDataBufLength, 1, newFile) != 1) { + HiLog::Error(LABEL, "Error writing EXIF data block to file!"); + ReleaseSource(fileBuf, newFile); + return false; + } + /* Write JPEG image data, skipping the non-EXIF header */ + unsigned int dataOffset = orginExifDataLength + sizeof(exifHeader); + if (fwrite(fileBuf + dataOffset, fileLength - dataOffset, 1, newFile) != 1) { + HiLog::Error(LABEL, "Error writing JPEG image data to file!"); + ReleaseSource(fileBuf, newFile); + return false; + } + + ReleaseSource(fileBuf, newFile); + return true; +} + +ExifIfd EXIFInfo::GetImageFileDirectory(const ExifTag &tag) +{ + switch (tag) { + case EXIF_TAG_BITS_PER_SAMPLE: + case EXIF_TAG_ORIENTATION: + case EXIF_TAG_IMAGE_LENGTH: + case EXIF_TAG_IMAGE_WIDTH: { + return EXIF_IFD_0; + } + case EXIF_TAG_DATE_TIME_ORIGINAL: { + return EXIF_IFD_EXIF; + } + case EXIF_TAG_GPS_LATITUDE: + case EXIF_TAG_GPS_LONGITUDE: + case EXIF_TAG_GPS_LATITUDE_REF: + case EXIF_TAG_GPS_LONGITUDE_REF: { + return EXIF_IFD_GPS; + } + default: + break; + } + return EXIF_IFD_COUNT; +} + +ExifEntry* EXIFInfo::InitExifTag(ExifData *exif, ExifIfd ifd, ExifTag tag) +{ + ExifEntry *entry; + /* Return an existing tag if one exists */ + if (!(entry = exif_content_get_entry(exif->ifd[ifd], tag))) { + /* Allocate a new entry */ + entry = exif_entry_new(); + if (entry == nullptr) { + HiLog::Error(LABEL, "Create new entry failed!"); + return nullptr; + } + entry->tag = tag; // tag must be set before calling exif_content_add_entry + /* Attach the ExifEntry to an IFD */ + exif_content_add_entry (exif->ifd[ifd], entry); + + /* Allocate memory for the entry and fill with default data */ + exif_entry_initialize (entry, tag); + + /* Ownership of the ExifEntry has now been passed to the IFD. + * One must be very careful in accessing a structure after + * unref'ing it; in this case, we know "entry" won't be freed + * because the reference count was bumped when it was added to + * the IFD. + */ + exif_entry_unref(entry); + } + return entry; +} + +ExifEntry* EXIFInfo::CreateExifTag(ExifData *exif, ExifIfd ifd, ExifTag tag, + size_t len, ExifFormat format) +{ + void *buf; + ExifEntry *entry; + + if ((entry = exif_content_get_entry(exif->ifd[ifd], tag)) != nullptr) { + return entry; + } + + /* Create a memory allocator to manage this ExifEntry */ + ExifMem *mem = exif_mem_new_default(); + if (mem == nullptr) { + HiLog::Error(LABEL, "Create mem failed!"); + return nullptr; + } + + /* Create a new ExifEntry using our allocator */ + entry = exif_entry_new_mem (mem); + if (entry == nullptr) { + HiLog::Error(LABEL, "Create entry by mem failed!"); + return nullptr; + } + + /* Allocate memory to use for holding the tag data */ + buf = exif_mem_alloc(mem, len); + if (buf == nullptr) { + HiLog::Error(LABEL, "Allocate memory failed!"); + return nullptr; + } + + /* Fill in the entry */ + entry->data = static_cast(buf); + entry->size = len; + entry->tag = tag; + entry->components = len; + entry->format = format; + + /* Attach the ExifEntry to an IFD */ + exif_content_add_entry (exif->ifd[ifd], entry); + + /* The ExifMem and ExifEntry are now owned elsewhere */ + exif_mem_unref(mem); + exif_entry_unref(entry); + + return entry; +} + +long EXIFInfo::GetFileSize(FILE *fp) +{ + long int position; + long size; + + /* Save the current position. */ + position = ftell(fp); + + /* Jump to the end of the file. */ + fseek(fp, 0L, SEEK_END); + + /* Get the end position. */ + size = ftell(fp); + + /* Jump back to the original position. */ + fseek(fp, position, SEEK_SET); + + return size; +} + +void EXIFInfo::ReleaseSource(unsigned char *buf, FILE *file) +{ + if (buf) { + free(buf); + buf = nullptr; + } + + if (file != nullptr) { + fclose(file); + file = nullptr; + } +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/libjpegplugin/src/jpeg_decoder.cpp b/plugins/common/libs/image/libjpegplugin/src/jpeg_decoder.cpp index 977f8d20b..59ffe5f09 100644 --- a/plugins/common/libs/image/libjpegplugin/src/jpeg_decoder.cpp +++ b/plugins/common/libs/image/libjpegplugin/src/jpeg_decoder.cpp @@ -16,6 +16,7 @@ #include "jerror.h" #include "media_errors.h" +#include "string_ex.h" #ifndef _WIN32 #include "securec.h" #else @@ -49,12 +50,13 @@ constexpr uint8_t JPG_MARKER_APP0 = 0XE0; constexpr uint8_t JPG_MARKER_APPN = 0XEF; const std::string BITS_PER_SAMPLE = "BitsPerSample"; const std::string ORIENTATION = "Orientation"; -const std::string IMAGE_HEIGHT = "ImageHeight"; +const std::string IMAGE_LENGTH = "ImageLength"; const std::string IMAGE_WIDTH = "ImageWidth"; const std::string GPS_LATITUDE = "GPSLatitude"; 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"; } // namespace PluginServer &JpegDecoder::pluginServer_ = DelayedRefSingleton::GetInstance(); @@ -104,6 +106,30 @@ void JpegDecoder::SetSource(InputDataStream &sourceStream) { srcMgr_.inputStream = &sourceStream; state_ = JpegDecodingState::SOURCE_INITED; + HiLog::Error(LABEL, "SetSource ExifPrintMethod"); + ExifPrintMethod(); +} + +int JpegDecoder::ExifPrintMethod() +{ + HiLog::Debug(LABEL, "ExifPrintMethod enter"); + srcMgr_.inputStream->Seek(0); + unsigned long fsize = 0; + fsize = static_cast(srcMgr_.inputStream->GetStreamSize()); + unsigned char *buf = new unsigned char[fsize]; + uint32_t readSize = 0; + srcMgr_.inputStream->Read(fsize, buf, fsize, readSize); + HiLog::Debug(LABEL, "parsing EXIF: fsize %{public}lu", fsize); + HiLog::Debug(LABEL, "parsing EXIF: readSize %{public}u", readSize); + + int code = exifInfo_.ParseExifData(buf, fsize); + delete[] buf; + if (code) { + HiLog::Error(LABEL, "Error parsing EXIF: code %{public}d", code); + return ERR_MEDIA_VALUE_INVALID; + } + + return Media::SUCCESS; } uint32_t JpegDecoder::GetImageSize(uint32_t index, PlSize &size) @@ -548,7 +574,78 @@ uint32_t JpegDecoder::GetImagePropertyInt(uint32_t index, const std::string &key uint32_t JpegDecoder::GetImagePropertyString(uint32_t index, const std::string &key, std::string &value) { HiLog::Error(LABEL, "[GetImagePropertyString] enter jped plugin, key:%{public}s", key.c_str()); + if (IsSameTextStr(key, BITS_PER_SAMPLE)) { + value = exifInfo_.bitsPerSample_; + } else if (IsSameTextStr(key, ORIENTATION)) { + value = exifInfo_.orientation_; + } else if (IsSameTextStr(key, IMAGE_LENGTH)) { + value = exifInfo_.imageLength_; + } else if (IsSameTextStr(key, IMAGE_WIDTH)) { + value = exifInfo_.imageWidth_; + } else if (IsSameTextStr(key, GPS_LATITUDE)) { + value = exifInfo_.gpsLatitude_; + } else if (IsSameTextStr(key, GPS_LONGITUDE)) { + value = exifInfo_.gpsLongitude_; + } else if (IsSameTextStr(key, GPS_LATITUDE_REF)) { + value = exifInfo_.gpsLatitudeRef_; + } else if (IsSameTextStr(key, GPS_LONGITUDE_REF)) { + value = exifInfo_.gpsLongitudeRef_; + } else if (IsSameTextStr(key, DATE_TIME_ORIGINAL)) { + value = exifInfo_.dateTimeOriginal_; + } else { + return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT; + } + HiLog::Error(LABEL, "[GetImagePropertyString] enter jped plugin, value:%{public}s", value.c_str()); + return Media::SUCCESS; +} + +ExifTag JpegDecoder::getExifTagFromKey(const std::string &key, const std::string &value) +{ + if (IsSameTextStr(key, BITS_PER_SAMPLE)) { + exifInfo_.bitsPerSample_ = value; + return EXIF_TAG_BITS_PER_SAMPLE; + } else if (IsSameTextStr(key, ORIENTATION)) { + exifInfo_.orientation_ = value; + return EXIF_TAG_ORIENTATION; + } else if (IsSameTextStr(key, IMAGE_LENGTH)) { + exifInfo_.imageLength_ = value; + return EXIF_TAG_IMAGE_LENGTH; + } else if (IsSameTextStr(key, IMAGE_WIDTH)) { + exifInfo_.imageWidth_ = value; + return EXIF_TAG_IMAGE_WIDTH; + } else if (IsSameTextStr(key, GPS_LATITUDE)) { + exifInfo_.gpsLatitude_ = value; + return EXIF_TAG_GPS_LATITUDE; + } else if (IsSameTextStr(key, GPS_LONGITUDE)) { + exifInfo_.gpsLongitude_ = value; + return EXIF_TAG_GPS_LONGITUDE; + } else if (IsSameTextStr(key, GPS_LATITUDE_REF)) { + exifInfo_.gpsLatitudeRef_ = value; + return EXIF_TAG_GPS_LATITUDE_REF; + } else if (IsSameTextStr(key, GPS_LONGITUDE_REF)) { + exifInfo_.gpsLongitudeRef_ = value; + return EXIF_TAG_GPS_LONGITUDE_REF; + } else if (IsSameTextStr(key, DATE_TIME_ORIGINAL)) { + exifInfo_.dateTimeOriginal_ = value; + return EXIF_TAG_DATE_TIME_ORIGINAL; + } else { + return EXIF_TAG_PRINT_IMAGE_MATCHING; + } +} +uint32_t JpegDecoder::ModifyImageProperty(uint32_t index, const std::string &key, + const std::string &value, const std::string &path) +{ + HiLog::Error(LABEL, "[ModifyImageProperty] enter jped plugin, key:%{public}s, value:%{public}s", + key.c_str(), value.c_str()); + ExifTag tag = getExifTagFromKey(key, value); + if (tag == EXIF_TAG_PRINT_IMAGE_MATCHING) { + return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT; + } + + if (!exifInfo_.ModifyExifData(tag, value, path)) { + return ERR_IMAGE_DECODE_EXIF_UNSUPPORT; + } return Media::SUCCESS; } } // namespace ImagePlugin diff --git a/plugins/manager/BUILD.gn b/plugins/manager/BUILD.gn index 11223d876..fe42893f2 100644 --- a/plugins/manager/BUILD.gn +++ b/plugins/manager/BUILD.gn @@ -144,4 +144,6 @@ ohos_static_library("pluginmanager_static") { external_deps = [ "hiviewdfx_hilog_native:libhilog" ] } + subsystem_name = "multimedia" + part_name = "multimedia_image_standard" } diff --git a/plugins/manager/include/image/abs_image_decoder.h b/plugins/manager/include/image/abs_image_decoder.h index 801719b8b..7dffb2e56 100644 --- a/plugins/manager/include/image/abs_image_decoder.h +++ b/plugins/manager/include/image/abs_image_decoder.h @@ -147,6 +147,13 @@ public: return Media::ERR_MEDIA_INVALID_OPERATION; } + // modify image property. + virtual uint32_t ModifyImageProperty(uint32_t index, const std::string &key, + const std::string &value, const std::string &path) + { + return Media::ERR_MEDIA_INVALID_OPERATION; + } + // define multiple subservices for this interface static constexpr uint16_t SERVICE_DEFAULT = 0; }; -- Gitee