/* * Copyright (c) 2021-2023 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 "frameworks/bridge/declarative_frontend/jsview/js_image.h" #include #include #include "base/utils/utils.h" #if !defined(PREVIEW) #include #endif #include "base/geometry/ng/vector.h" #include "base/image/pixel_map.h" #include "base/log/ace_scoring_log.h" #include "base/log/ace_trace.h" #include "bridge/declarative_frontend/engine/functions/js_drag_function.h" #include "bridge/declarative_frontend/engine/js_ref_ptr.h" #include "bridge/declarative_frontend/engine/js_types.h" #include "bridge/declarative_frontend/jsview/models/image_model_impl.h" #include "core/common/container.h" #include "core/components/image/image_event.h" #include "core/components/image/image_theme.h" #include "core/components_ng/base/view_stack_processor.h" #include "core/components_ng/event/gesture_event_hub.h" #include "core/components_ng/pattern/image/image_model.h" #include "core/components_ng/pattern/image/image_model_ng.h" #include "core/image/image_source_info.h" #include "interfaces/inner_api/ace/ai/image_analyzer.h" namespace { const std::vector DEFAULT_COLORFILTER_MATRIX = { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 }; constexpr float CEIL_SMOOTHEDGE_VALUE = 1.333f; constexpr float FLOOR_SMOOTHEDGE_VALUE = 0.334f; constexpr float DEFAULT_SMOOTHEDGE_VALUE = 0.0f; } namespace OHOS::Ace { std::unique_ptr ImageModel::instance_ = nullptr; std::mutex ImageModel::mutex_; ImageModel* ImageModel::GetInstance() { if (!instance_) { std::lock_guard lock(mutex_); if (!instance_) { #ifdef NG_BUILD instance_.reset(new NG::ImageModelNG()); #else if (Container::IsCurrentUseNewPipeline()) { instance_.reset(new NG::ImageModelNG()); } else { instance_.reset(new Framework::ImageModelImpl()); } #endif } } return instance_.get(); } } // namespace OHOS::Ace namespace OHOS::Ace::Framework { JSRef LoadImageSuccEventToJSValue(const LoadImageSuccessEvent& eventInfo) { JSRef obj = JSRef::New(); obj->SetProperty("width", eventInfo.GetWidth()); obj->SetProperty("height", eventInfo.GetHeight()); obj->SetProperty("componentWidth", eventInfo.GetComponentWidth()); obj->SetProperty("componentHeight", eventInfo.GetComponentHeight()); obj->SetProperty("loadingStatus", eventInfo.GetLoadingStatus()); obj->SetProperty("contentWidth", eventInfo.GetContentWidth()); obj->SetProperty("contentHeight", eventInfo.GetContentHeight()); obj->SetProperty("contentOffsetX", eventInfo.GetContentOffsetX()); obj->SetProperty("contentOffsetY", eventInfo.GetContentOffsetY()); return JSRef::Cast(obj); } JSRef LoadImageFailEventToJSValue(const LoadImageFailEvent& eventInfo) { JSRef obj = JSRef::New(); obj->SetProperty("componentWidth", eventInfo.GetComponentWidth()); obj->SetProperty("componentHeight", eventInfo.GetComponentHeight()); obj->SetProperty("message", eventInfo.GetErrorMessage()); return JSRef::Cast(obj); } void JSImage::SetAlt(const JSCallbackInfo& args) { if (args.Length() < 1) { return; } std::string src; if (args[0]->IsString()) { src = args[0]->ToString(); } else if (!ParseJsMedia(args[0], src)) { return; } int32_t resId = 0; if (args[0]->IsObject()) { JSRef jsObj = JSRef::Cast(args[0]); JSRef tmp = jsObj->GetProperty("id"); if (!tmp->IsNull() && tmp->IsNumber()) { resId = tmp->ToNumber(); } } if (ImageSourceInfo::ResolveURIType(src) == SrcType::NETWORK) { return; } std::string bundleName; std::string moduleName; GetJsMediaBundleInfo(args[0], bundleName, moduleName); ImageSourceInfo srcInfo = ImageSourceInfo { src, bundleName, moduleName }; srcInfo.SetIsUriPureNumber((resId == -1)); ImageModel::GetInstance()->SetAlt(srcInfo); } void JSImage::SetObjectFit(const JSCallbackInfo& args) { if (args.Length() < 1) { ImageModel::GetInstance()->SetImageFit(ImageFit::COVER); return; } int32_t parseRes = 2; ParseJsInteger(args[0], parseRes); if (parseRes < static_cast(ImageFit::FILL) || parseRes > static_cast(ImageFit::SCALE_DOWN)) { parseRes = 2; } auto fit = static_cast(parseRes); ImageModel::GetInstance()->SetImageFit(fit); } void JSImage::SetMatchTextDirection(bool value) { ImageModel::GetInstance()->SetMatchTextDirection(value); } void JSImage::SetFitOriginalSize(bool value) { ImageModel::GetInstance()->SetFitOriginSize(value); } void JSImage::SetBorder(const Border& border) { ImageModel::GetInstance()->SetBorder(border); } void JSImage::OnComplete(const JSCallbackInfo& args) { if (args[0]->IsFunction()) { auto jsLoadSuccFunc = AceType::MakeRefPtr>( JSRef::Cast(args[0]), LoadImageSuccEventToJSValue); auto onComplete = [execCtx = args.GetExecutionContext(), func = std::move(jsLoadSuccFunc)]( const LoadImageSuccessEvent& info) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("Image.onComplete"); func->Execute(info); }; ImageModel::GetInstance()->SetOnComplete(std::move(onComplete)); } } void JSImage::OnError(const JSCallbackInfo& args) { if (args[0]->IsFunction()) { auto jsLoadFailFunc = AceType::MakeRefPtr>( JSRef::Cast(args[0]), LoadImageFailEventToJSValue); auto onError = [execCtx = args.GetExecutionContext(), func = std::move(jsLoadFailFunc)]( const LoadImageFailEvent& info) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("Image.onError"); func->Execute(info); }; ImageModel::GetInstance()->SetOnError(onError); } } void JSImage::OnFinish(const JSCallbackInfo& info) { auto tmpInfo = info[0]; if (!tmpInfo->IsFunction()) { return; } RefPtr jsFunc = AceType::MakeRefPtr(JSRef(), JSRef::Cast(tmpInfo)); WeakPtr targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode(); auto onFinish = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("Image.onFinish"); PipelineContext::SetCallBackNode(node); func->Execute(); }; ImageModel::GetInstance()->SetSvgAnimatorFinishEvent(onFinish); } void JSImage::Create(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto container = Container::Current(); CHECK_NULL_VOID(container); auto context = PipelineBase::GetCurrentContext(); CHECK_NULL_VOID(context); bool isCard = context->IsFormRender() && !container->IsDynamicRender(); // Interim programme std::string bundleName; std::string moduleName; std::string src; bool srcValid = ParseJsMedia(info[0], src); int32_t resId = 0; if (info[0]->IsObject()) { JSRef jsObj = JSRef::Cast(info[0]); JSRef tmp = jsObj->GetProperty("id"); if (!tmp->IsNull() && tmp->IsNumber()) { resId = tmp->ToNumber(); } } if (isCard && info[0]->IsString()) { SrcType srcType = ImageSourceInfo::ResolveURIType(src); bool notSupport = (srcType == SrcType::NETWORK || srcType == SrcType::FILE || srcType == SrcType::DATA_ABILITY); if (notSupport) { src.clear(); } } GetJsMediaBundleInfo(info[0], bundleName, moduleName); RefPtr pixmap = nullptr; // input is PixelMap / Drawable if (!srcValid) { #if defined(PIXEL_MAP_SUPPORTED) if (!isCard) { if (IsDrawable(info[0])) { pixmap = GetDrawablePixmap(info[0]); } else { pixmap = CreatePixelMapFromNapiValue(info[0]); } } #endif } ImageModel::GetInstance()->Create(src, pixmap, bundleName, moduleName, (resId == -1)); } bool JSImage::IsDrawable(const JSRef& jsValue) { if (!jsValue->IsObject()) { return false; } JSRef jsObj = JSRef::Cast(jsValue); if (jsObj->IsUndefined()) { return false; } // if jsObject has function getPixelMap, it's a DrawableDescriptor object JSRef func = jsObj->GetProperty("getPixelMap"); return (!func->IsNull() && func->IsFunction()); } void JSImage::JsBorder(const JSCallbackInfo& info) { JSViewAbstract::JsBorder(info); ImageModel::GetInstance()->SetBackBorder(); } void JSImage::JsImageResizable(const JSCallbackInfo& info) { auto infoObj = info[0]; ImageResizableSlice sliceResult; if (!infoObj->IsObject()) { ImageModel::GetInstance()->SetResizableSlice(sliceResult); return; } JSRef resizableObject = JSRef::Cast(infoObj); if (resizableObject->IsEmpty()) { ImageModel::GetInstance()->SetResizableSlice(sliceResult); return; } auto sliceValue = resizableObject->GetProperty("slice"); JSRef sliceObj = JSRef::Cast(sliceValue); if (sliceObj->IsEmpty()) { ImageModel::GetInstance()->SetResizableSlice(sliceResult); return; } static std::array keys = { "left", "right", "top", "bottom" }; for (uint32_t i = 0; i < keys.size(); i++) { auto sliceSize = sliceObj->GetProperty(keys.at(i).c_str()); CalcDimension sliceDimension; if (!ParseJsDimensionVp(sliceSize, sliceDimension)) { continue; } if (!sliceDimension.IsValid()) { continue; } switch (static_cast(i)) { case BorderImageDirection::LEFT: sliceResult.left = sliceDimension; break; case BorderImageDirection::RIGHT: sliceResult.right = sliceDimension; break; case BorderImageDirection::TOP: sliceResult.top = sliceDimension; break; case BorderImageDirection::BOTTOM: sliceResult.bottom = sliceDimension; break; default: break; } } ImageModel::GetInstance()->SetResizableSlice(sliceResult); } void JSImage::JsBorderRadius(const JSCallbackInfo& info) { JSViewAbstract::JsBorderRadius(info); ImageModel::GetInstance()->SetBackBorder(); } void JSImage::SetSourceSize(const JSCallbackInfo& info) { ImageModel::GetInstance()->SetImageSourceSize(JSViewAbstract::ParseSize(info)); } void JSImage::SetImageFill(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } Color color; if (!ParseJsColor(info[0], color)) { if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) { return; } auto pipelineContext = PipelineBase::GetCurrentContext(); CHECK_NULL_VOID(pipelineContext); auto theme = pipelineContext->GetTheme(); CHECK_NULL_VOID(theme); color = theme->GetFillColor(); } ImageModel::GetInstance()->SetImageFill(color); } void JSImage::SetImageRenderMode(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsImageRenderMode = info[0]; if (jsImageRenderMode->IsNumber()) { auto renderMode = static_cast(jsImageRenderMode->ToNumber()); if (renderMode < ImageRenderMode::ORIGINAL || renderMode > ImageRenderMode::TEMPLATE) { renderMode = ImageRenderMode::ORIGINAL; } ImageModel::GetInstance()->SetImageRenderMode(renderMode); } } void JSImage::SetImageInterpolation(int32_t imageInterpolation) { auto interpolation = static_cast(imageInterpolation); if (interpolation < ImageInterpolation::NONE || interpolation > ImageInterpolation::HIGH) { interpolation = ImageInterpolation::NONE; } ImageModel::GetInstance()->SetImageInterpolation(interpolation); } void JSImage::SetImageRepeat(int32_t imageRepeat) { auto repeat = static_cast(imageRepeat); if (repeat < ImageRepeat::NO_REPEAT || repeat > ImageRepeat::REPEAT) { repeat = ImageRepeat::NO_REPEAT; } ImageModel::GetInstance()->SetImageRepeat(repeat); } void JSImage::JsTransition(const JSCallbackInfo& info) { if (ImageModel::GetInstance()->IsSrcSvgImage()) { JSViewAbstract::JsTransition(info); } else { JSViewAbstract::JsTransitionPassThrough(info); } } void JSImage::JsOpacity(const JSCallbackInfo& info) { if (ImageModel::GetInstance()->IsSrcSvgImage()) { JSViewAbstract::JsOpacity(info); } else { JSViewAbstract::JsOpacityPassThrough(info); } } void JSImage::JsBlur(const JSCallbackInfo& info) { // only flutter runs special image blur #ifdef ENABLE_ROSEN_BACKEND JSViewAbstract::JsBlur(info); #else if (info.Length() < 1) { return; } double blur = 0.0; if (ParseJsDouble(info[0], blur)) { ImageModel::GetInstance()->SetBlur(blur); } #endif } void JSImage::SetAutoResize(bool autoResize) { ImageModel::GetInstance()->SetAutoResize(autoResize); } void JSImage::SetSyncLoad(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto tmpInfo = info[0]; if (!tmpInfo->IsBoolean()) { return; } ImageModel::GetInstance()->SetSyncMode(tmpInfo->ToBoolean()); } void JSColorFilter::ConstructorCallback(const JSCallbackInfo& args) { if (args.Length() < 1) { return; } auto tmpInfo = args[0]; if (!tmpInfo->IsArray()) { return; } JSRef array = JSRef::Cast(tmpInfo); if (array->Length() != COLOR_FILTER_MATRIX_SIZE) { return; } auto jscolorfilter = Referenced::MakeRefPtr(); if (jscolorfilter == nullptr) { return; } std::vector colorfilter; for (size_t i = 0; i < array->Length(); i++) { JSRef value = array->GetValueAt(i); if (value->IsNumber()) { colorfilter.emplace_back(value->ToNumber()); } } if (colorfilter.size() != COLOR_FILTER_MATRIX_SIZE) { return; } jscolorfilter->SetColorFilterMatrix(std::move(colorfilter)); jscolorfilter->IncRefCount(); args.SetReturnValue(Referenced::RawPtr(jscolorfilter)); } void JSColorFilter::DestructorCallback(JSColorFilter* obj) { if (obj != nullptr) { obj->DecRefCount(); } } void JSImage::SetColorFilter(const JSCallbackInfo& info) { if (info.Length() != 1) { ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX); return; } auto tmpInfo = info[0]; if (!tmpInfo->IsArray() && !tmpInfo->IsObject()) { ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX); return; } if (tmpInfo->IsObject() && !tmpInfo->IsArray()) { JSColorFilter* colorFilter; if (!tmpInfo->IsUndefined() && !tmpInfo->IsNull()) { colorFilter = JSRef::Cast(tmpInfo)->Unwrap(); } else { ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX); return; } if (colorFilter && colorFilter->GetColorFilterMatrix().size() == COLOR_FILTER_MATRIX_SIZE) { ImageModel::GetInstance()->SetColorFilterMatrix(colorFilter->GetColorFilterMatrix()); return; } ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX); return; } JSRef array = JSRef::Cast(tmpInfo); if (array->Length() != COLOR_FILTER_MATRIX_SIZE) { ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX); return; } std::vector colorfilter; for (size_t i = 0; i < array->Length(); i++) { JSRef value = array->GetValueAt(i); if (value->IsNumber()) { colorfilter.emplace_back(value->ToNumber()); } else { ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX); return; } } ImageModel::GetInstance()->SetColorFilterMatrix(colorfilter); } void JSImage::SetSmoothEdge(const JSCallbackInfo& info) { if (info.Length() != 1) { ImageModel::GetInstance()->SetSmoothEdge(DEFAULT_SMOOTHEDGE_VALUE); return; } double parseRes = DEFAULT_SMOOTHEDGE_VALUE; ParseJsDouble(info[0], parseRes); // Effective range : (FLOOR_SMOOTHEDGE_VALUE, CEIL_SMOOTHEDGE_VALUE] // otherwise: DEFAULT_SMOOTHEDGE_VALUE if (GreatNotEqual(parseRes, CEIL_SMOOTHEDGE_VALUE) || LessNotEqual(parseRes, FLOOR_SMOOTHEDGE_VALUE)) { parseRes = DEFAULT_SMOOTHEDGE_VALUE; } ImageModel::GetInstance()->SetSmoothEdge(static_cast(parseRes)); } void JSImage::JSBind(BindingTarget globalObj) { JSClass::Declare("Image"); MethodOptions opt = MethodOptions::NONE; JSClass::StaticMethod("create", &JSImage::Create, opt); JSClass::StaticMethod("alt", &JSImage::SetAlt, opt); JSClass::StaticMethod("objectFit", &JSImage::SetObjectFit, opt); JSClass::StaticMethod("matchTextDirection", &JSImage::SetMatchTextDirection, opt); JSClass::StaticMethod("fitOriginalSize", &JSImage::SetFitOriginalSize, opt); JSClass::StaticMethod("sourceSize", &JSImage::SetSourceSize, opt); JSClass::StaticMethod("fillColor", &JSImage::SetImageFill, opt); JSClass::StaticMethod("renderMode", &JSImage::SetImageRenderMode, opt); JSClass::StaticMethod("objectRepeat", &JSImage::SetImageRepeat, opt); JSClass::StaticMethod("interpolation", &JSImage::SetImageInterpolation, opt); JSClass::StaticMethod("colorFilter", &JSImage::SetColorFilter, opt); JSClass::StaticMethod("edgeAntialiasing", &JSImage::SetSmoothEdge, opt); JSClass::StaticMethod("border", &JSImage::JsBorder); JSClass::StaticMethod("borderRadius", &JSImage::JsBorderRadius); JSClass::StaticMethod("onAppear", &JSInteractableView::JsOnAppear); JSClass::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear); JSClass::StaticMethod("autoResize", &JSImage::SetAutoResize); JSClass::StaticMethod("resizable", &JSImage::JsImageResizable); JSClass::StaticMethod("onTouch", &JSInteractableView::JsOnTouch); JSClass::StaticMethod("onHover", &JSInteractableView::JsOnHover); JSClass::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey); JSClass::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete); JSClass::StaticMethod("onClick", &JSInteractableView::JsOnClick); JSClass::StaticMethod("onComplete", &JSImage::OnComplete); JSClass::StaticMethod("onError", &JSImage::OnError); JSClass::StaticMethod("onFinish", &JSImage::OnFinish); JSClass::StaticMethod("syncLoad", &JSImage::SetSyncLoad); JSClass::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage); JSClass::StaticMethod("draggable", &JSImage::JsSetDraggable); JSClass::StaticMethod("onDragStart", &JSImage::JsOnDragStart); JSClass::StaticMethod("copyOption", &JSImage::SetCopyOption); JSClass::StaticMethod("enableAnalyzer", &JSImage::EnableAnalyzer); JSClass::StaticMethod("analyzerConfig", &JSImage::AnalyzerConfig); // override method JSClass::StaticMethod("opacity", &JSImage::JsOpacity); JSClass::StaticMethod("blur", &JSImage::JsBlur); JSClass::StaticMethod("transition", &JSImage::JsTransition); JSClass::StaticMethod("pointLight", &JSViewAbstract::JsPointLight, opt); JSClass::InheritAndBind(globalObj); JSClass::Declare("ColorFilter"); JSClass::Bind(globalObj, JSColorFilter::ConstructorCallback, JSColorFilter::DestructorCallback); } void JSImage::JsSetDraggable(bool draggable) { ImageModel::GetInstance()->SetDraggable(draggable); } void JSImage::JsOnDragStart(const JSCallbackInfo& info) { if (info.Length() != 1 || !info[0]->IsFunction()) { return; } RefPtr jsOnDragStartFunc = AceType::MakeRefPtr(JSRef::Cast(info[0])); WeakPtr frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode(); auto onDragStartId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragStartFunc), node = frameNode]( const RefPtr& info, const std::string& extraParams) -> NG::DragDropBaseInfo { NG::DragDropBaseInfo itemInfo; JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, itemInfo); PipelineContext::SetCallBackNode(node); auto ret = func->Execute(info, extraParams); if (!ret->IsObject()) { return itemInfo; } if (ParseAndUpdateDragItemInfo(ret, itemInfo)) { return itemInfo; } auto builderObj = JSRef::Cast(ret); #if defined(PIXEL_MAP_SUPPORTED) auto pixmap = builderObj->GetProperty("pixelMap"); itemInfo.pixelMap = CreatePixelMapFromNapiValue(pixmap); #endif auto extraInfo = builderObj->GetProperty("extraInfo"); ParseJsString(extraInfo, itemInfo.extraInfo); ParseAndUpdateDragItemInfo(builderObj->GetProperty("builder"), itemInfo); return itemInfo; }; ImageModel::GetInstance()->SetOnDragStart(std::move(onDragStartId)); } void JSImage::SetCopyOption(const JSCallbackInfo& info) { auto copyOptions = CopyOptions::None; if (info[0]->IsNumber()) { auto enumNumber = info[0]->ToNumber(); copyOptions = static_cast(enumNumber); if (copyOptions < CopyOptions::None || copyOptions > CopyOptions::Distributed) { copyOptions = CopyOptions::None; } } ImageModel::GetInstance()->SetCopyOption(copyOptions); } void JSImage::EnableAnalyzer(bool isEnableAnalyzer) { ImageModel::GetInstance()->EnableAnalyzer(isEnableAnalyzer); } void JSImage::AnalyzerConfig(const JSCallbackInfo &info) { auto configParams = info[0]; if (configParams->IsNull() || !configParams->IsObject()) { return; } auto paramObject = JSRef::Cast(configParams); JSRef typeVal = paramObject->GetProperty("types"); JSRef showButtonVal = paramObject->GetProperty("showAIButton"); JSRef marginVal = paramObject->GetProperty("aiButtonOffset"); JSRef textOpVal = paramObject->GetProperty("textOptions"); JSRef subjectOpVal = paramObject->GetProperty("subjectOptions"); JSRef tagVal = paramObject->GetProperty("tag"); ImageAnalyzerConfig analyzerConfig; if (typeVal->IsArray()) { auto array = JSRef::Cast(typeVal); std::set types; for (size_t i = 0; i < array->Length(); ++i) { if (!array->GetValueAt(i)->IsNumber()) { continue; } int value = array->GetValueAt(i)->ToNumber(); ImageAnalyzerType type = static_cast(value); if (type != ImageAnalyzerType::SUBJECT && type != ImageAnalyzerType::TEXT) { continue; } types.insert(type); } analyzerConfig.types = std::move(types); } if (showButtonVal->IsBoolean()) { analyzerConfig.isShowAIButton = showButtonVal->ToBoolean(); } if (!marginVal->IsNull() && marginVal->IsObject()) { auto marginValue = JSRef::Cast(marginVal); std::optional top; std::optional bottom; std::optional left; std::optional right; ParseMarginOrPaddingCorner(marginValue, top, bottom, left, right); analyzerConfig.aiButtonMargin = NG::ConvertToCalcPaddingProperty(top, bottom, left, right); } if (subjectOpVal->IsObject()) { ParseImageAnalyzerSubjectOptions(subjectOpVal, analyzerConfig); } if (textOpVal->IsObject()) { ParseImageAnalyzerTextOptions(textOpVal, analyzerConfig); } if (tagVal->IsString()) { analyzerConfig.tag = tagVal->ToString(); } ImageModel::GetInstance()->SetImageAnalyzerConfig(analyzerConfig); } } // namespace OHOS::Ace::Framework