diff --git a/OAT.xml b/OAT.xml
index a859db12f89c5a9c27affe4176ee471b5ac41b19..15f8f74c9447036a7605d31acd60e2019de66e17 100644
--- a/OAT.xml
+++ b/OAT.xml
@@ -424,7 +424,14 @@ Note:If the text contains special characters, please escape them according to th
-
+
+
+
+
+
+
+
+
@@ -843,6 +850,12 @@ Note:If the text contains special characters, please escape them according to th
+
+
+
+
+
+
diff --git a/code/DocsSample/Media/Image/ImageEffect/.gitignore b/code/DocsSample/Media/Image/ImageEffect/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..b8017deb0acccd6154f5770a667148c7a495787c
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/.gitignore
@@ -0,0 +1,13 @@
+/node_modules
+/oh_modules
+/local.properties
+/.idea
+**/build
+/.hvigor
+.cxx
+/.clangd
+/.clang-format
+/.clang-tidy
+**/.test
+/oh-package-lock.json5
+/entry/oh-package-lock.json5
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/AppScope/app.json5 b/code/DocsSample/Media/Image/ImageEffect/AppScope/app.json5
new file mode 100644
index 0000000000000000000000000000000000000000..f54b2635e34a955355ee0523b717a62c4528661f
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/AppScope/app.json5
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+{
+ "app": {
+ "bundleName": "com.samples.ImageEffect",
+ "vendor": "example",
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "icon": "$media:app_icon",
+ "label": "$string:app_name"
+ }
+}
diff --git a/code/DocsSample/Media/Image/ImageEffect/AppScope/resources/base/element/string.json b/code/DocsSample/Media/Image/ImageEffect/AppScope/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..da03b5b8382de77f478084eaa2e0d0f13e682e80
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/AppScope/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "ImageEffect"
+ }
+ ]
+}
diff --git a/code/DocsSample/Media/Image/ImageEffect/AppScope/resources/base/media/app_icon.png b/code/DocsSample/Media/Image/ImageEffect/AppScope/resources/base/media/app_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..cd45accb1dfd2fd0da16c732c72faa6e46b26521
Binary files /dev/null and b/code/DocsSample/Media/Image/ImageEffect/AppScope/resources/base/media/app_icon.png differ
diff --git a/code/DocsSample/Media/Image/ImageEffect/README.md b/code/DocsSample/Media/Image/ImageEffect/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..36618eae529d165a706da9672a602ceaf93929b2
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/README.md
@@ -0,0 +1,95 @@
+# ImageEffect
+
+## 介绍
+
+本示例依照指南 媒体->Image Kit(图片处理服务)->图片开发指导(C/C++)->[使用ImageEffect编辑图片](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/media/image/image-effect-guidelines.md)进行编写。
+
+本示例主要功能如下:
+- 通过ImageEffect提供的Native API接口添加滤镜或滤镜链,对输入图像应用滤镜效果。
+- 注册实现了自定义亮度滤镜与自定义裁剪滤镜。
+- 通过ImageEffect提供的Native API接口快速实现单个滤镜的处理效果。
+- 通过ImageEffect提供的Native API接口查询滤镜能力信息。
+
+## 效果预览
+
+| 主界面 | 设置滤镜 | 选择输入类型 | 查询滤镜信息 |
+|------------------------------------------------------------------|--------------------------------------------------------------------------|--------------------------------------------------------------------------------|----------------------------------------------------------------------|
+|  |  |  |  |
+
+
+使用说明:
+1. 输入类型选择:在参数设置页面中,选择输入类型,显示区域将切换为对应的输入类型。
+2. 调整滤镜参数:在参数设置页面中,选择所需的滤镜选项,并通过拖动滑动条来调节各个滤镜算子的参数。
+3. 滤镜算子选择:可以选择裁剪、缩放、旋转等内置的算子,或选择自定义亮度、自定义剪裁滤镜。本示例允许同时选择多个滤镜以形成滤镜链。
+4. 确认与保存设置:调整完毕后,点击确认按钮以保存所设置的滤镜参数。
+5. 应用滤镜效果:返回图片展示页面后,点击Apply按钮,系统将展现经过滤镜处理后的图片效果。
+6. 重置图片效果:如需撤销所做改动,点击Reset按钮,图片将恢复至调整前状态。
+7. 查看滤镜详细信息:在参数设置页面,点击滑块旁的搜索图标,系统将展示一个详细信息页面,提供所选滤镜相关信息。
+8. 查询滤镜信息:点击查询按钮并选择查询参数来获取滤镜信息页面,该页面将显示所应用的滤镜个数和名称信息。
+
+## 工程目录
+
+```
+ImageEffect
+entry/src/main/cpp/
+├── CMakeLists.txt(CMake构建配置文件)
+├── backend
+│ ├── image_edit.cpp(图片编辑)
+│ └── image_edit.h
+├── logging.h(Log相关定义声明)
+├── napi_init.cpp(图片处理功能注册)
+└── utils
+ ├── common_utils.cpp(字符处理工具函数)
+ ├── common_utils.h
+ ├── json_utils.cpp(json格式处理工具函数)
+ ├── json_utils.h
+ ├── pixelmap_helper.cpp(图片解码)
+ └── pixelmap_helper.h
+entry/src/main/ets/
+├── pages
+│ └── ImageEditPage.ets(图片显示、设置页面)
+└── utils
+ └── ImageUtils.ets(图片资源获取处理)
+entry/src/ohosTest/ets/
+└── test
+ ├── Ability.test.ets (UI测试代码)
+ └── List.test.ets (测试套件列表)
+```
+
+## 具体实现
+
++ 图片编辑功能在ImageEditPage中实现,源码参考ImageEditPage.ets:
+ + 输入类型选择:在图片展示页面点击设置按钮弹出设置页面,选择输入类型。
+ + 滤镜选择:在图片展示页面点击设置按钮弹出设置页面,选择滤镜并设置参数,点击确认按钮保存滤镜参数选择。
+ + 滤镜生效:点击Apply按钮,展示经过滤镜处理后的图片效果,点击Reset按钮,图片恢复至调整前状态。
+ + 滤镜查询:点击滑动条后面的查询图标可查询单个滤镜信息,点击下方查询按钮可查询对应条件的滤镜信息。
+
++ native接口在image_edit中实现,源码参考image_edit.cpp:
+ - 应用滤镜:应用滤镜处理需要加载libimage_effect.so,对传入的输入类型进行处理,使用Brightness对图像进行亮度处理使用Contrast对图像进行对比度处理,使用Crop对图像进行裁剪处理,也可以自定义滤镜对图像进行处理。
+ - 滤镜查询:接口实现对滤镜的查询功能,通过OH_EffectFilter_LookupFilterInfo接口方法查询单个滤镜的详细信息,通过OH_EffectFilter_LookupFilters接口方法查询指定条件下的滤镜数量以及信息。
+
+## 相关权限
+
+[ohos.permission.CAMERA](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/AccessToken/permissions-for-all-user.md#ohospermissioncamera)
+
+## 依赖
+
+不涉及。
+
+## 约束和限制
+
+1. 本示例支持标准系统上运行,支持设备:RK3568;
+2. 本示例支持API12版本SDK,版本号:5.0.0.71;
+3. 本示例已支持使DevEco Studio 5.0.1 Release (构建版本:5.0.5.306,构建 2024年12月6日)编译运行
+
+## 下载
+
+如需单独下载本工程,执行如下命令:
+
+```
+git init
+git config core.sparsecheckout true
+echo code/DocsSample/Media/Image/ImageEffect/ > .git/info/sparse-checkout
+git remote add origin OpenHarmony/applications_app_samples
+git pull origin master
+```
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/build-profile.json5 b/code/DocsSample/Media/Image/ImageEffect/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..e6d9cfeb040286c33ab736dc93b6c5d8ba4034bd
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/build-profile.json5
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+{
+ "app": {
+ "products": [
+ {
+ "name": "default",
+ "signingConfig": "default",
+ "compileSdkVersion": 12,
+ "compatibleSdkVersion": 12,
+ "targetSdkVersion": 12,
+ "runtimeOS": "OpenHarmony"
+ }
+ ],
+ "buildModeSet": [
+ {
+ "name": "debug"
+ },
+ {
+ "name": "release"
+ }
+ ]
+ },
+ "modules": [
+ {
+ "name": "entry",
+ "srcPath": "./entry",
+ "targets": [
+ {
+ "name": "default",
+ "applyToProducts": [
+ "default"
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/.gitignore b/code/DocsSample/Media/Image/ImageEffect/entry/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/.gitignore
@@ -0,0 +1,6 @@
+/node_modules
+/oh_modules
+/.preview
+/build
+/.cxx
+/.test
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/build-profile.json5 b/code/DocsSample/Media/Image/ImageEffect/entry/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..eef3f858b97a349c18ff7fce6b39d369041ff4ef
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/build-profile.json5
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+{
+ "apiType": "stageMode",
+ "buildOption": {
+ "externalNativeOptions": {
+ "path": "./src/main/cpp/CMakeLists.txt",
+ "arguments": "",
+ "cppFlags": "",
+ "abiFilters": ["armeabi-v7a","arm64-v8a"]
+ }
+ },
+ "buildOptionSet": [
+ {
+ "name": "release",
+ "arkOptions": {
+ "obfuscation": {
+ "ruleOptions": {
+ "enable": true,
+ "files": [
+ "./obfuscation-rules.txt"
+ ]
+ }
+ }
+ },
+ "nativeLib": {
+ "debugSymbol": {
+ "strip": true,
+ "exclude": []
+ }
+ }
+ },
+ ],
+ "targets": [
+ {
+ "name": "default"
+ },
+ {
+ "name": "ohosTest",
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/hvigorfile.ts b/code/DocsSample/Media/Image/ImageEffect/entry/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8774588471ede4c1563f09d9a1d22f764bb1fd9e
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/hvigorfile.ts
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+import { hapTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/obfuscation-rules.txt b/code/DocsSample/Media/Image/ImageEffect/entry/obfuscation-rules.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a1dfa0bd175984dc49e641436aa67b1de1b8abeb
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/obfuscation-rules.txt
@@ -0,0 +1,22 @@
+# Define project specific obfuscation rules here.
+# You can include the obfuscation configuration files in the current module's build-profile.json5.
+#
+# For more details, see
+# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md
+
+# Obfuscation options:
+# -disable-obfuscation: disable all obfuscations
+# -enable-property-obfuscation: obfuscate the property names
+# -enable-toplevel-obfuscation: obfuscate the names in the global scope
+# -compact: remove unnecessary blank spaces and all line feeds
+# -remove-log: remove all console.* statements
+# -print-namecache: print the name cache that contains the mapping from the old names to new names
+# -apply-namecache: reuse the given cache file
+
+# Keep options:
+# -keep-property-name: specifies property names that you want to keep
+# -keep-global-name: specifies names that you want to keep in the global scope
+-enable-property-obfuscation
+-enable-toplevel-obfuscation
+-enable-filename-obfuscation
+-enable-export-obfuscation
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/oh-package.json5 b/code/DocsSample/Media/Image/ImageEffect/entry/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..5b21e253af246edab8b6ef4f10938f4417e8bc25
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/oh-package.json5
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+{
+ "name": "entry",
+ "version": "1.0.0",
+ "description": "Please describe the basic information.",
+ "main": "",
+ "author": "",
+ "license": "",
+ "dependencies": {
+ "libentry.so": "file:./src/main/cpp/types/libentry"
+ }
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/CMakeLists.txt b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c8672e7c40f5069317db457233f11a07962da4da
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,30 @@
+# the minimum version of CMake.
+cmake_minimum_required(VERSION 3.5.0)
+project(ImageEffect)
+
+set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
+
+include_directories(${NATIVERENDER_ROOT_PATH}
+ ${NATIVERENDER_ROOT_PATH}/include
+ ${NATIVERENDER_ROOT_PATH}/backend
+ ${NATIVERENDER_ROOT_PATH}/utils
+)
+
+add_library(entry SHARED
+ napi_init.cpp
+ utils/common_utils.cpp
+ utils/json_utils.cpp
+ utils/pixelmap_helper.cpp
+ backend/image_edit.cpp
+)
+target_link_libraries(entry PUBLIC
+ libace_napi.z.so
+ libpixelmap_ndk.z.so
+ libimage_packer.so
+ libimage_source.so
+ libhilog_ndk.z.so
+ libimage_effect.so
+ libpixelmap.so
+ libnative_window.so
+ libnative_buffer.so
+)
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/backend/image_edit.cpp b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/backend/image_edit.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..73bfd8b5f71447a67fc5a9c9ec6852f056e05f8f
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/backend/image_edit.cpp
@@ -0,0 +1,878 @@
+/*
+ * Copyright (c) 2025 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include "logging.h"
+#include "image_edit.h"
+#include "utils/common_utils.h"
+#include "utils/pixelmap_helper.h"
+#include "utils/json_utils.h"
+
+struct FilterArrayData {
+ std::string name;
+ int value;
+};
+
+struct PixelmapInfo {
+ uint32_t width = 0;
+ uint32_t height = 0;
+ int32_t format = PIXEL_FORMAT::PIXEL_FORMAT_UNKNOWN;
+ uint32_t rowStride = 0;
+};
+
+static ImageEffect_FilterDelegate delegateBrightness;
+static ImageEffect_FilterDelegate delegateCrop;
+
+std::vector> GetFilters(napi_env env, napi_value arg);
+
+OH_EffectFilter *AddFilter(OH_ImageEffect *imageEffect, const char *filterName);
+napi_value SetFilterValue(OH_EffectFilter *filter, const char *filterName, float filterValue,
+ OH_PixelmapNative *pixelmap);
+void AddFilterSingle(const char *filterName, float filterValue, OH_PixelmapNative *inputPixelmap,
+ OH_PixelmapNative *outputPixelmap);
+PixelmapInfo GetPixelmapInfo(OH_PixelmapNative *pixelmap);
+napi_value SetCropFilterValue(OH_EffectFilter *filter, float filterValue);
+
+const double PI = 3.14159265;
+
+// 滤镜数据范围
+const float_t DATA_VALUE_MIN = -100.0;
+const float_t DATA_VALUE_MAX = 100.0;
+
+// 预期参数数量
+constexpr int EXPECTED_ARGS_ZERO = 0;
+constexpr int EXPECTED_ARGS_ONE = 1;
+constexpr int EXPECTED_ARGS_TWO = 2;
+
+// AREA信息索引下标
+constexpr int AREA_INFO_ZERO = 0;
+constexpr int AREA_INFO_ONE = 1;
+constexpr int AREA_INFO_TWO = 2;
+constexpr int AREA_INFO_THREE = 3;
+
+// RBGA8888格式,一个像素点由四个字节组成
+constexpr int RGB_IDX_ZERO = 0;
+constexpr int RGB_IDX_THREE = 3;
+
+// RGB颜色范围
+constexpr int RBG_MIN = 0;
+constexpr int RBG_MAX = 255;
+
+OH_ImageEffect* ImageEdit::imageEffect_ = nullptr;
+
+ImageEdit::~ImageEdit()
+{
+ if (imageEffect_ != nullptr) {
+ OH_ImageEffect_Release(imageEffect_);
+ imageEffect_ = nullptr;
+ }
+}
+
+napi_value ImageEdit::PixelMapFilterStart(napi_env env, napi_callback_info info)
+{
+ napi_value result = nullptr;
+ napi_get_boolean(env, false, &result);
+
+ size_t argc = EXPECTED_ARGS_TWO;
+ napi_value args[EXPECTED_ARGS_TWO] = {nullptr};
+ napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
+ CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_get_cb_info fail! status = %{public}d", status);
+
+ std::string path = CommonUtils::GetStringArgument(env, args[EXPECTED_ARGS_ZERO]);
+ std::vector> filters = GetFilters(env, args[EXPECTED_ARGS_ONE]);
+
+ OH_ImageEffect *imageEffect = OH_ImageEffect_Create("imageEdit");
+ CHECK_AND_RETURN_RET_LOG(imageEffect != nullptr, result, "OH_ImageEffect_Create fail!");
+ std::shared_ptr imageEffectPtr(
+ imageEffect, [](OH_ImageEffect *imageEffect) { OH_ImageEffect_Release(imageEffect); });
+
+ std::shared_ptr pixelmapNativePtr = PixelMapHelper::Decode(path);
+ CHECK_AND_RETURN_RET_LOG(pixelmapNativePtr != nullptr, result, "Decode path fail! path=%{public}s", path.c_str());
+
+ if (filters.size() == 1 && (strcmp(filters[0][0].name.c_str(), OH_EFFECT_BRIGHTNESS_FILTER) == 0 ||
+ strcmp(filters[0][0].name.c_str(), OH_EFFECT_CONTRAST_FILTER) == 0)) {
+ std::shared_ptr outputpixelmapNativePtr = PixelMapHelper::Decode(path);
+ CHECK_AND_RETURN_RET_LOG(outputpixelmapNativePtr != nullptr, result, "Decode path fail! path=%{public}s",
+ path.c_str());
+
+ AddFilterSingle(filters[0][0].name.c_str(), filters[0][0].value, pixelmapNativePtr.get(),
+ outputpixelmapNativePtr.get());
+
+ bool encodeRes = PixelMapHelper::Encode(outputpixelmapNativePtr.get(), path);
+ CHECK_AND_RETURN_RET_LOG(encodeRes, result, "Encode path fail! path=%{public}s", path.c_str());
+
+ napi_get_boolean(env, true, &result);
+ return result;
+ }
+
+ for (int i = 0; i < filters.size(); i++) {
+ OH_EffectFilter *filter = AddFilter(imageEffectPtr.get(), filters[i][0].name.c_str());
+ CHECK_AND_RETURN_RET_LOG(filter != nullptr, result, "OH_ImageEffect_AddFilter fail!");
+ LOG_I("%{public}s : %{public}d", filters[i][0].name.c_str(), filters[i][0].value);
+ SetFilterValue(filter, filters[i][0].name.c_str(), filters[i][0].value, pixelmapNativePtr.get());
+ }
+
+ ImageEffect_ErrorCode errorCode = OH_ImageEffect_SetInputPixelmap(imageEffectPtr.get(), pixelmapNativePtr.get());
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_ImageEffect_SetInputPixelMap fail! errorCode = %{public}d", errorCode);
+
+ // 设置输出的Pixelmap(可选),不调用该接口时会在输入Pixelmap上直接生效滤镜效果。
+ errorCode = OH_ImageEffect_SetOutputPixelmap(imageEffectPtr.get(), pixelmapNativePtr.get());
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_ImageEffect_SetOutputPixelmap fail!");
+
+ errorCode = OH_ImageEffect_Start(imageEffectPtr.get());
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_ImageEffect_Start fail! errorCode = %{public}d", errorCode);
+
+ // (可选 序列化效果器)
+ char *imageinfo = nullptr;
+ errorCode = OH_ImageEffect_Save(imageEffect, &imageinfo);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result, "OH_ImageEffect_Save fail!");
+
+ bool encodeRes = PixelMapHelper::Encode(pixelmapNativePtr.get(), path);
+ CHECK_AND_RETURN_RET_LOG(encodeRes, result, "Encode path fail! path=%{public}s", path.c_str());
+
+ napi_get_boolean(env, true, &result);
+ return result;
+}
+
+napi_value ImageEdit::NativeBufferFilterStart(napi_env env, napi_callback_info info)
+{
+ napi_value result = nullptr;
+ napi_get_boolean(env, false, &result);
+
+ size_t argc = EXPECTED_ARGS_ONE;
+ napi_value args[EXPECTED_ARGS_ONE] = {nullptr};
+ napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
+ CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_get_cb_info fail! status = %{public}d", status);
+
+ std::vector> filters = GetFilters(env, args[EXPECTED_ARGS_ZERO]);
+
+ OH_ImageEffect *imageEffect = OH_ImageEffect_Create("imageEdit");
+ CHECK_AND_RETURN_RET_LOG(imageEffect != nullptr, result, "OH_ImageEffect_Create fail!");
+ std::shared_ptr imageEffectPtr(imageEffect, [](OH_ImageEffect *imageEffect) {
+ ImageEffect_ErrorCode errorCode = OH_ImageEffect_Release(imageEffect);
+ CHECK_AND_RETURN_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, "OH_ImageEffect_Release fail!");
+ });
+
+ OH_NativeBuffer_Config config{
+ .width = 0x100,
+ .height = 0x100,
+ .format = NATIVEBUFFER_PIXEL_FMT_RGBA_8888,
+ .usage = NATIVEBUFFER_USAGE_ALIGNMENT_512,
+ };
+
+ for (int i = 0; i < filters.size(); i++) {
+ OH_EffectFilter *filter = AddFilter(imageEffectPtr.get(), filters[i][0].name.c_str());
+ CHECK_AND_RETURN_RET_LOG(filter != nullptr, result, "OH_ImageEffect_AddFilter fail!");
+ SetFilterValue(filter, filters[i][0].name.c_str(), filters[i][0].value, nullptr);
+ }
+
+ OH_NativeBuffer *inputNativeBuffer = OH_NativeBuffer_Alloc(&config);
+ CHECK_AND_RETURN_RET_LOG(inputNativeBuffer != nullptr, result, "OH_NativeBuffer_Alloc Failed!");
+
+ OH_NativeBuffer *outputNativeBuffer = inputNativeBuffer;
+
+ // 设置输入的NativeBuffer。
+ ImageEffect_ErrorCode errorCode = OH_ImageEffect_SetInputNativeBuffer(imageEffect, inputNativeBuffer);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_ImageEffect_SetInputNativeBuffer fail!");
+
+ // 设置输出的NativeBuffer(可选),不调用该接口时会在输入NativeBuffer上直接生效滤镜效果。
+ errorCode = OH_ImageEffect_SetOutputNativeBuffer(imageEffect, outputNativeBuffer);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_ImageEffect_SetOutputNativeBuffer fail!");
+
+ errorCode = OH_ImageEffect_Start(imageEffectPtr.get());
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_ImageEffect_Start fail! errorCode = %{public}d", errorCode);
+
+ // (可选 序列化效果器)
+ char *imageinfo = nullptr;
+ errorCode = OH_ImageEffect_Save(imageEffect, &imageinfo);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result, "OH_ImageEffect_Save fail!");
+
+ napi_get_boolean(env, true, &result);
+ return result;
+}
+
+napi_value ImageEdit::URIFilterStart(napi_env env, napi_callback_info info)
+{
+ napi_value result = nullptr;
+ napi_get_boolean(env, false, &result);
+
+ size_t argc = EXPECTED_ARGS_TWO;
+ napi_value args[EXPECTED_ARGS_TWO] = {nullptr};
+ napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
+ CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_get_cb_info fail! status = %{public}d", status);
+
+ std::string path = CommonUtils::GetStringArgument(env, args[EXPECTED_ARGS_ZERO]);
+ std::vector> filters = GetFilters(env, args[EXPECTED_ARGS_ONE]);
+
+ OH_ImageEffect *imageEffect = OH_ImageEffect_Create("imageEdit");
+ CHECK_AND_RETURN_RET_LOG(imageEffect != nullptr, result, "OH_ImageEffect_Create fail!");
+ std::shared_ptr imageEffectPtr(imageEffect, [](OH_ImageEffect *imageEffect) {
+ ImageEffect_ErrorCode errorCode = OH_ImageEffect_Release(imageEffect);
+ CHECK_AND_RETURN_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, "OH_ImageEffect_Release fail!");
+ });
+
+ std::shared_ptr pixelmapNativePtr = PixelMapHelper::Decode(path);
+ CHECK_AND_RETURN_RET_LOG(pixelmapNativePtr != nullptr, result, "Decode path fail! path=%{public}s", path.c_str());
+
+ for (int i = 0; i < filters.size(); i++) {
+ OH_EffectFilter *filter = AddFilter(imageEffectPtr.get(), filters[i][0].name.c_str());
+ CHECK_AND_RETURN_RET_LOG(filter != nullptr, result, "OH_ImageEffect_AddFilter fail!");
+ SetFilterValue(filter, filters[i][0].name.c_str(), filters[i][0].value, pixelmapNativePtr.get());
+ }
+
+ // 设置输入的URI。
+ ImageEffect_ErrorCode errorCode = OH_ImageEffect_SetInputUri(imageEffectPtr.get(), path.c_str());
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_ImageEffect_SetInputPixelMap fail! errorCode = %{public}d", errorCode);
+
+ // 设置输出的URI(可选),不调用该接口时会在输入URI上直接生效滤镜效果。
+ errorCode = OH_ImageEffect_SetOutputUri(imageEffect, path.c_str());
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_ImageEffect_SetOutputUri fail!");
+
+ errorCode = OH_ImageEffect_Start(imageEffectPtr.get());
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_ImageEffect_Start fail! errorCode = %{public}d", errorCode);
+
+ // (可选 序列化效果器)
+ char *imageinfo = nullptr;
+ errorCode = OH_ImageEffect_Save(imageEffect, &imageinfo);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result, "OH_ImageEffect_Save fail!");
+
+ napi_get_boolean(env, true, &result);
+ return result;
+}
+
+napi_value ImageEdit::SurfaceFilterStart(napi_env env, napi_callback_info info)
+{
+ napi_value result = nullptr;
+ napi_get_boolean(env, false, &result);
+
+ size_t argc = EXPECTED_ARGS_ONE;
+ napi_value args[EXPECTED_ARGS_ONE] = {nullptr};
+ napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
+ CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_get_cb_info fail! status = %{public}d", status);
+
+ std::vector> filters = GetFilters(env, args[EXPECTED_ARGS_ZERO]);
+
+ OH_ImageEffect *imageEffect = ImageEdit::imageEffect_;
+ CHECK_AND_RETURN_RET_LOG(imageEffect != nullptr, result, "imageEffect is nullptr!");
+
+ for (int i = 0; i < filters.size(); i++) {
+ OH_EffectFilter *filter = AddFilter(imageEffect, filters[i][0].name.c_str());
+ CHECK_AND_RETURN_RET_LOG(filter != nullptr, result, "OH_ImageEffect_AddFilter fail!");
+ SetFilterValue(filter, filters[i][0].name.c_str(), filters[i][0].value, nullptr);
+ }
+
+ // 执行生效滤镜效果。
+ ImageEffect_ErrorCode errorCode = OH_ImageEffect_Start(imageEffect);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_ImageEffect_Start fail! %{public}d", errorCode);
+ napi_get_boolean(env, true, &result);
+ return result;
+}
+
+napi_value ImageEdit::SurfaceFilterStop(napi_env env, napi_callback_info info)
+{
+ napi_value result = nullptr;
+ napi_get_boolean(env, false, &result);
+
+ OH_ImageEffect *imageEffect = ImageEdit::imageEffect_;
+ CHECK_AND_RETURN_RET_LOG(imageEffect != nullptr, result, "imageEffect is nullptr!");
+
+ // 停止生效滤镜效果。
+ ImageEffect_ErrorCode errorCode = OH_ImageEffect_Stop(imageEffect);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result, "OH_ImageEffect_Stop fail!");
+
+ napi_get_boolean(env, true, &result);
+ return result;
+}
+
+OH_EffectFilter *AddFilter(OH_ImageEffect *imageEffect, const char *filterName)
+{
+ OH_EffectFilter *filter = OH_ImageEffect_AddFilter(imageEffect, filterName);
+ CHECK_AND_RETURN_RET_LOG(filter != nullptr, filter, "OH_ImageEffect_AddFilter fail!");
+ return filter;
+}
+
+void AddFilterSingle(const char *filterName, float filterValue, OH_PixelmapNative *inputPixelmap,
+ OH_PixelmapNative *outputPixelmap)
+{
+ // 创建滤镜。比如:创建对比度效果器。
+ OH_EffectFilter *filter = OH_EffectFilter_Create(filterName);
+
+ // 设置滤镜参数, 滤镜强度设置为50。
+ ImageEffect_Any value = {.dataType = ImageEffect_DataType::EFFECT_DATA_TYPE_FLOAT,
+ .dataValue.floatValue = filterValue};
+ ImageEffect_ErrorCode errorCode = OH_EffectFilter_SetValue(filter, OH_EFFECT_FILTER_INTENSITY_KEY, &value);
+ CHECK_AND_RETURN_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, "OH_EffectFilter_SetValue fail!");
+
+ // 生效滤镜效果。
+ errorCode = OH_EffectFilter_Render(filter, inputPixelmap, outputPixelmap);
+
+ // 销毁滤镜实例。
+ errorCode = OH_EffectFilter_Release(filter);
+}
+
+PixelmapInfo GetPixelmapInfo(OH_PixelmapNative *pixelmap)
+{
+ OH_Pixelmap_ImageInfo *imageInfo = nullptr;
+ OH_PixelmapImageInfo_Create(&imageInfo);
+ OH_PixelmapNative_GetImageInfo(pixelmap, imageInfo);
+ PixelmapInfo info;
+ OH_PixelmapImageInfo_GetWidth(imageInfo, &info.width);
+ OH_PixelmapImageInfo_GetHeight(imageInfo, &info.height);
+ OH_PixelmapImageInfo_GetPixelFormat(imageInfo, &info.format);
+ OH_PixelmapImageInfo_GetRowStride(imageInfo, &info.rowStride);
+ OH_PixelmapImageInfo_Release(imageInfo);
+
+ return info;
+}
+
+napi_value SetFilterValue(OH_EffectFilter *filter, const char *filterName, float filterValue,
+ OH_PixelmapNative *pixelmap)
+{
+ napi_value result;
+ ImageEffect_Any value;
+ std::string key;
+
+ if (strcmp(filterName, OH_EFFECT_CROP_FILTER) == 0) {
+ CHECK_AND_RETURN_RET_LOG(pixelmap != nullptr, result, "pixelmap nullptr!");
+ PixelmapInfo pixelMapInfo = GetPixelmapInfo(pixelmap);
+ uint32_t *areaInfo = new uint32_t[4];
+ CHECK_AND_RETURN_RET_LOG(areaInfo, result, "areaInfo fail!");
+ areaInfo[AREA_INFO_ZERO] = pixelMapInfo.width / 100.f * (100.f - static_cast(filterValue));
+ areaInfo[AREA_INFO_ONE] = pixelMapInfo.height / 100.f * (100.f - static_cast(filterValue));
+ areaInfo[AREA_INFO_TWO] = pixelMapInfo.width;
+ areaInfo[AREA_INFO_THREE] = pixelMapInfo.height;
+ value.dataType = ImageEffect_DataType::EFFECT_DATA_TYPE_PTR;
+ value.dataValue.ptrValue = areaInfo;
+ key = OH_EFFECT_FILTER_REGION_KEY;
+ } else if (strcmp(filterName, "CustomBrightness") == 0) {
+ value.dataType = ImageEffect_DataType::EFFECT_DATA_TYPE_FLOAT;
+ value.dataValue.floatValue = filterValue;
+ key = "brightness";
+ } else if (strcmp(filterName, "CustomCrop") == 0) {
+ value.dataType = ImageEffect_DataType::EFFECT_DATA_TYPE_FLOAT;
+ value.dataValue.floatValue = filterValue;
+ key = "crop";
+ } else {
+ value.dataType = ImageEffect_DataType::EFFECT_DATA_TYPE_FLOAT;
+ value.dataValue.floatValue = filterValue;
+ key = OH_EFFECT_FILTER_INTENSITY_KEY;
+ }
+ ImageEffect_ErrorCode errorCode = OH_EffectFilter_SetValue(filter, key.c_str(), &value);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, nullptr,
+ "OH_EffectFilter_SetValue fail! errorCode = %{public}d", errorCode);
+ return result;
+}
+
+std::pair GetNapiArrayLength(napi_env env, napi_value element)
+{
+ uint32_t length = 0;
+ napi_status status = napi_get_array_length(env, element, &length);
+ return std::make_pair(status, length);
+}
+
+std::string HandleStringType(napi_env env, napi_value childElement, napi_status &status)
+{
+ std::string name;
+
+ size_t bufferLength = 0;
+ status = napi_get_value_string_utf8(env, childElement, nullptr, 0, &bufferLength);
+ CHECK_AND_RETURN_RET_LOG(status == napi_ok && bufferLength > 0, name,
+ "GetFilters napi_get_value_string_utf8 fail! status = %{public}d", status);
+ char *buffer = nullptr;
+ buffer = reinterpret_cast(malloc((bufferLength + 1) * sizeof(char)));
+ status = napi_get_value_string_utf8(env, childElement, buffer, bufferLength + 1, &bufferLength);
+ if (status == napi_ok) {
+ name = buffer;
+ }
+ free(buffer);
+ return name;
+}
+
+int HandleNumberType(napi_env env, napi_value childElement, napi_status &status)
+{
+ int32_t result = 0;
+ status = napi_get_value_int32(env, childElement, &result);
+ CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "GetFilters napi_get_value_int32 fail! status = %{public}d",
+ status);
+ return result;
+}
+
+std::vector> GetFilters(napi_env env, napi_value arg)
+{
+ std::vector> data;
+ napi_status status;
+
+ bool is_array;
+ status = napi_is_array(env, arg, &is_array);
+ CHECK_AND_RETURN_RET_LOG(is_array == true, data, "GetFilters napi_is_array fail! status=%{public}d", status);
+
+ auto array_length = GetNapiArrayLength(env, arg);
+ CHECK_AND_RETURN_RET_LOG(array_length.first == napi_ok, data,
+ "GetFilters napi_get_array_length fail! status=%{public}d", array_length.first);
+
+ for (uint32_t i = 0; i < array_length.second; i++) {
+ napi_value element;
+ status = napi_get_element(env, arg, i, &element);
+ CHECK_AND_RETURN_RET_LOG(status == napi_ok, data, "GetFilters napi_get_element fail! status=%{public}d",
+ status);
+
+ auto child_length = GetNapiArrayLength(env, element);
+ CHECK_AND_RETURN_RET_LOG(child_length.first == napi_ok, data,
+ "GetFilters child napi_get_array_length fail! status=%{public}d", child_length.first);
+
+ std::vector row;
+ FilterArrayData filterArrayData;
+ for (uint32_t j = 0; j < child_length.second; j++) {
+ napi_value childElement;
+ status = napi_get_element(env, element, j, &childElement);
+
+ napi_valuetype valueType;
+ status = napi_typeof(env, childElement, &valueType);
+ CHECK_AND_RETURN_RET_LOG(status == napi_ok, data,
+ "GetFilters child napi_typeof fail! status=%{public}d, value=%{public}d", status,
+ valueType);
+
+ if (valueType == napi_string) {
+ filterArrayData.name = HandleStringType(env, childElement, status);
+ } else if (valueType == napi_number) {
+ filterArrayData.value = HandleNumberType(env, childElement, status);
+ }
+ }
+ row.push_back(filterArrayData);
+ data.push_back(row);
+ }
+
+ return data;
+}
+
+napi_value ImageEdit::LookupFilterInfo(napi_env env, napi_callback_info info)
+{
+ napi_value result = nullptr;
+ napi_get_undefined(env, &result);
+ size_t argc = EXPECTED_ARGS_ONE;
+ napi_value args[EXPECTED_ARGS_ONE] = {nullptr};
+ napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
+ CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_get_cb_info fail! status = %{public}d", status);
+ std::string filterName = CommonUtils::GetStringArgument(env, args[EXPECTED_ARGS_ZERO]);
+
+ OH_EffectFilterInfo *effectInfo = OH_EffectFilterInfo_Create();
+ // 示例代码: 传入nullptr的format, 获取OH_Formats的size
+ ImageEffect_ErrorCode errorCode = OH_EffectFilter_LookupFilterInfo(filterName.c_str(), effectInfo);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_EffectFilter_LookupFilterInfo fail! errorCode = %{public}d", errorCode);
+
+ char *name = nullptr;
+ OH_EffectFilterInfo_GetFilterName(effectInfo, &name);
+
+ uint32_t supportedBufferTypesCount = 0;
+ ImageEffect_BufferType *bufferTypeArray = nullptr;
+ OH_EffectFilterInfo_GetSupportedBufferTypes(effectInfo, &supportedBufferTypesCount, &bufferTypeArray);
+
+ uint32_t supportedFormatsCount = 0;
+ ImageEffect_Format *formatArray = nullptr;
+ OH_EffectFilterInfo_GetSupportedFormats(effectInfo, &supportedFormatsCount, &formatArray);
+
+ LOG_I("LookupFilterInfo: name=%{public}s, bufferTypesCount=%{public}d, formatsCount=%{public}d", name,
+ supportedBufferTypesCount, supportedFormatsCount);
+
+ std::string infoStr = CommonUtils::EffectInfoToString(effectInfo);
+ LOG_I("LookupFilterInfo:%{public}s", infoStr.c_str());
+ status = napi_create_string_utf8(env, infoStr.c_str(), strlen(infoStr.c_str()), &result);
+ CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_create_string_utf8 fail!");
+
+ OH_EffectFilterInfo_Release(effectInfo);
+ return result;
+}
+
+// 图像信息结构体。
+struct EffectBufferInfo {
+ void *addr = nullptr;
+ int32_t width = 0;
+ int32_t height = 0;
+ int32_t rowSize = 0;
+ ImageEffect_Format format = ImageEffect_Format::EFFECT_PIXEL_FORMAT_UNKNOWN;
+};
+
+void ApplyCustomBrightnessAlgo(OH_EffectFilter *filter, EffectBufferInfo inputBufferInfo)
+{
+ ImageEffect_Any value;
+ ImageEffect_ErrorCode errorCode = OH_EffectFilter_GetValue(filter, "brightness", &value);
+ CHECK_AND_RETURN_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS,
+ "OH_EffectFilter_GetValue fail! 11 %{public}d", errorCode);
+
+ float brightnessIncrement = value.dataValue.floatValue;
+
+ // 获取图像的宽度和高度
+ int32_t width = inputBufferInfo.width;
+ int32_t height = inputBufferInfo.height;
+ int32_t rowSize = inputBufferInfo.rowSize;
+ ImageEffect_Format format = inputBufferInfo.format;
+
+ // 检查图片格式是否为RGBA8888
+ CHECK_AND_RETURN_LOG(format == ImageEffect_Format::EFFECT_PIXEL_FORMAT_RGBA8888,
+ "Unsupported image format: %{public}d", format);
+
+ // 获取图像数据指针
+ uint8_t *pixelData = static_cast(inputBufferInfo.addr);
+ // 遍历每个像素
+ for (int y = 0; y < height; ++y) {
+ for (int x = 0; x < width; ++x) {
+ // 计算当前像素的起始地址
+ uint8_t *pixel = pixelData + y * rowSize + x * 4;
+ // 增加亮度值,最小值为0,最大值为255
+ for (int i = RGB_IDX_ZERO; i < RGB_IDX_THREE; ++i) {
+ int tempPixel = static_cast(pixel[i]) + static_cast(brightnessIncrement);
+ pixel[i] = std::max(RBG_MIN, std::min(RBG_MAX, tempPixel));
+ }
+ }
+ }
+}
+
+bool RenderBrightness(OH_EffectFilter *filter, OH_EffectBufferInfo *info, OH_EffectFilterDelegate_PushData pushData)
+{
+ // 获取图像信息具体参数。
+ EffectBufferInfo inputBufferInfo;
+ OH_EffectBufferInfo_GetAddr(info, &inputBufferInfo.addr);
+ OH_EffectBufferInfo_GetWidth(info, &inputBufferInfo.width);
+ OH_EffectBufferInfo_GetHeight(info, &inputBufferInfo.height);
+ OH_EffectBufferInfo_GetRowSize(info, &inputBufferInfo.rowSize);
+ OH_EffectBufferInfo_GetEffectFormat(info, &inputBufferInfo.format);
+
+ // 调用自定义滤镜算法。
+ ApplyCustomBrightnessAlgo(filter, inputBufferInfo);
+
+ // 编辑完成后调用pushData直接传递原图。
+ pushData(filter, info);
+ return true;
+}
+
+void ApplyCustomCropAlgo(OH_EffectFilter *filter, EffectBufferInfo inputBufferInfo,
+ EffectBufferInfo &outputBufferInfo)
+{
+ ImageEffect_Any value;
+ ImageEffect_ErrorCode errorCode = OH_EffectFilter_GetValue(filter, "crop", &value);
+ CHECK_AND_RETURN_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS,
+ "OH_EffectFilter_GetValue fail! 22 %{public}d", errorCode);
+
+ float cropIncrement = value.dataValue.floatValue;
+
+ // 计算新的高度
+ int32_t newHeight = static_cast(inputBufferInfo.height * cropIncrement / 100);
+
+ // 分配新的内存来存储裁剪后的图像数据
+ uint8_t *croppedData = new uint8_t[newHeight * inputBufferInfo.rowSize];
+
+ // 复制裁剪后的图像数据
+ for (int y = 0; y < newHeight; ++y) {
+ uint8_t *src = static_cast(inputBufferInfo.addr) + y * inputBufferInfo.rowSize;
+ uint8_t *dst = croppedData + y * inputBufferInfo.rowSize;
+ for (int x = 0; x < inputBufferInfo.rowSize; ++x) {
+ dst[x] = src[x];
+ }
+ }
+
+ // 设置输出缓冲区的信息
+ outputBufferInfo.addr = croppedData;
+ outputBufferInfo.width = inputBufferInfo.width;
+ outputBufferInfo.height = newHeight;
+ outputBufferInfo.rowSize = inputBufferInfo.rowSize;
+ outputBufferInfo.format = inputBufferInfo.format;
+}
+
+bool RenderCrop(OH_EffectFilter *filter, OH_EffectBufferInfo *info, OH_EffectFilterDelegate_PushData pushData)
+{
+ // 获取图像信息具体参数。
+ EffectBufferInfo inputBufferInfo;
+ OH_EffectBufferInfo_GetAddr(info, &inputBufferInfo.addr);
+ OH_EffectBufferInfo_GetWidth(info, &inputBufferInfo.width);
+ OH_EffectBufferInfo_GetHeight(info, &inputBufferInfo.height);
+ OH_EffectBufferInfo_GetRowSize(info, &inputBufferInfo.rowSize);
+ OH_EffectBufferInfo_GetEffectFormat(info, &inputBufferInfo.format);
+
+ // 创建输出像素信息。
+ EffectBufferInfo outputBufferInfo;
+
+ // 调用自定义滤镜算法。
+ ApplyCustomCropAlgo(filter, inputBufferInfo, outputBufferInfo);
+
+ // 生成outputOhInfo。
+ OH_EffectBufferInfo *outputOhInfo = OH_EffectBufferInfo_Create();
+ OH_EffectBufferInfo_SetAddr(outputOhInfo, outputBufferInfo.addr);
+ OH_EffectBufferInfo_SetWidth(outputOhInfo, outputBufferInfo.width);
+ OH_EffectBufferInfo_SetHeight(outputOhInfo, outputBufferInfo.height);
+ OH_EffectBufferInfo_SetRowSize(outputOhInfo, outputBufferInfo.rowSize);
+ OH_EffectBufferInfo_SetEffectFormat(outputOhInfo, outputBufferInfo.format);
+
+ // 编辑完成后调用pushData传递outputOhInfo。
+ pushData(filter, outputOhInfo);
+
+ // 释放资源。
+ OH_EffectBufferInfo_Release(outputOhInfo);
+
+ return true;
+}
+
+bool SaveFilterBrightness(OH_EffectFilter *filter, char **info)
+{
+ // 获取自定义所设置的滤镜参数,其中"brightness"为自定义滤镜的Key,由开发者自己任意指定。
+ ImageEffect_Any value;
+ ImageEffect_ErrorCode errorCode = OH_EffectFilter_GetValue(filter, "brightness", &value);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, false,
+ "OH_EffectFilter_GetValue fail! 33 %{public}d", errorCode);
+
+ // 生成键值对信息。
+ Json values;
+ values["brightness"] = value.dataValue.floatValue;
+ Json root;
+ root["name"] = "CustomBrightness";
+ root["values"] = values;
+
+ // 将json对象转成字符串infoStr
+ std::string infoStr = root.Dump();
+
+ // 对*info赋值序列化字符串地址。
+ *info = strdup(infoStr.data());
+
+ return true;
+}
+
+bool SaveFilterCrop(OH_EffectFilter *filter, char **info)
+{
+ // 获取自定义所设置的滤镜参数,其中"crop"为自定义滤镜的Key,由开发者自己任意指定。
+ ImageEffect_Any value;
+ ImageEffect_ErrorCode errorCode = OH_EffectFilter_GetValue(filter, "crop", &value);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, false,
+ "OH_EffectFilter_GetValue fail! 44 %{public}d", errorCode);
+
+ // 生成键值对信息。
+ Json values;
+ values["crop"] = value.dataValue.floatValue;
+ Json root;
+ root["name"] = "CustomCrop";
+ root["values"] = values;
+
+ // 将json对象转成字符串infoStr
+ std::string infoStr = root.Dump();
+
+ // 对*info赋值序列化字符串地址。
+ *info = strdup(infoStr.data());
+
+ return true;
+}
+
+napi_value ImageEdit::RegisterCustomBrightness()
+{
+ napi_value result = nullptr;
+ // 自定义算子能力信息
+ OH_EffectFilterInfo *effectInfo = OH_EffectFilterInfo_Create();
+ OH_EffectFilterInfo_SetFilterName(effectInfo, "CustomBrightness");
+ ImageEffect_BufferType bufferType = ImageEffect_BufferType::EFFECT_BUFFER_TYPE_PIXEL;
+ OH_EffectFilterInfo_SetSupportedBufferTypes(effectInfo, 1, &bufferType);
+ ImageEffect_Format format = ImageEffect_Format::EFFECT_PIXEL_FORMAT_RGBA8888;
+ OH_EffectFilterInfo_SetSupportedFormats(effectInfo, 1, &format);
+ // 自定义算子实现接口
+ delegateBrightness = {
+ .setValue =
+ [](OH_EffectFilter *filter, const char *key, const ImageEffect_Any *value) {
+ // 参数校验,校验成功时返回true,否则返回false。
+ if (value->dataValue.floatValue >= DATA_VALUE_MIN && value->dataValue.floatValue <= DATA_VALUE_MAX) {
+ return true;
+ } else {
+ return false;
+ }
+ },
+ .render = [](OH_EffectFilter *filter, OH_EffectBufferInfo *info,
+ OH_EffectFilterDelegate_PushData pushData) { return RenderBrightness(filter, info, pushData); },
+ .save = SaveFilterBrightness,
+ .restore = [](const char *info) -> OH_EffectFilter * {
+ // 创建 OH_EffectFilter 实例,其中"CustomBrightness"为自定义滤镜的滤镜名。
+ OH_EffectFilter *filter = OH_EffectFilter_Create("CustomBrightness");
+ // 解析json字符串info获取key和value。
+ std::map parsedJson = Json::Parse(info);
+ if (parsedJson.find("values") != parsedJson.end()) {
+ std::string valuesStr = parsedJson["values"];
+ std::map valuesJson = Json::Parse(valuesStr);
+ if (valuesJson.find("brightness") != valuesJson.end()) {
+ float brightness =
+ std::stof(valuesJson["brightness"].substr(1, valuesJson["brightness"].size() - 2));
+ ImageEffect_Any value;
+ value.dataType = ImageEffect_DataType::EFFECT_DATA_TYPE_FLOAT;
+ value.dataValue.floatValue = brightness;
+ // 设置滤镜参数, value为info中按json解析出来的参数。
+ LOG_E("brightness value: %{public}f ", value.dataValue.floatValue);
+ ImageEffect_ErrorCode errorCode = OH_EffectFilter_SetValue(filter, "brightness", &value);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, nullptr,
+ "OH_EffectFilter_SetValue fail!");
+ }
+ }
+ return filter;
+ }};
+
+ ImageEffect_ErrorCode errorCode = OH_EffectFilter_Register(effectInfo, &delegateBrightness);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_EffectFilter_Register fail! errorCode = %{public}d", errorCode);
+ return result;
+}
+
+napi_value ImageEdit::RegisterCustomCrop()
+{
+ napi_value result = nullptr;
+ // 自定义算子能力信息
+ OH_EffectFilterInfo *effectInfo = OH_EffectFilterInfo_Create();
+ OH_EffectFilterInfo_SetFilterName(effectInfo, "CustomCrop");
+ ImageEffect_BufferType bufferType = ImageEffect_BufferType::EFFECT_BUFFER_TYPE_PIXEL;
+ OH_EffectFilterInfo_SetSupportedBufferTypes(effectInfo, 1, &bufferType);
+ ImageEffect_Format format = ImageEffect_Format::EFFECT_PIXEL_FORMAT_RGBA8888;
+ OH_EffectFilterInfo_SetSupportedFormats(effectInfo, 1, &format);
+ // 自定义算子实现接口
+ delegateCrop = {
+ .setValue =
+ [](OH_EffectFilter *filter, const char *key, const ImageEffect_Any *value) {
+ // 参数校验,校验成功时返回true,否则返回false。
+ if (value->dataValue.floatValue >= DATA_VALUE_MIN && value->dataValue.floatValue <= DATA_VALUE_MAX) {
+ return true;
+ } else {
+ return false;
+ }
+ },
+ .render = [](OH_EffectFilter *filter, OH_EffectBufferInfo *info,
+ OH_EffectFilterDelegate_PushData pushData) { return RenderCrop(filter, info, pushData); },
+ .save = SaveFilterCrop,
+ .restore = [](const char *info) -> OH_EffectFilter * {
+ // 创建 OH_EffectFilter 实例,其中"CustomBrightness"为自定义滤镜的滤镜名。
+ OH_EffectFilter *filter = OH_EffectFilter_Create("CustomCrop");
+ // 解析json字符串info获取key和value。
+ std::map parsedJson = Json::Parse(info);
+ if (parsedJson.find("values") != parsedJson.end()) {
+ std::string valuesStr = parsedJson["values"];
+ std::map valuesJson = Json::Parse(valuesStr);
+ if (valuesJson.find("crop") != valuesJson.end()) {
+ float crop = std::stof(valuesJson["crop"].substr(1, valuesJson["crop"].size() - 2));
+ ImageEffect_Any value;
+ value.dataType = ImageEffect_DataType::EFFECT_DATA_TYPE_FLOAT;
+ value.dataValue.floatValue = crop;
+ // 设置滤镜参数, value为info中按json解析出来的参数。
+ LOG_E("crop value: %{public}f ", value.dataValue.floatValue);
+ ImageEffect_ErrorCode errorCode = OH_EffectFilter_SetValue(filter, "crop", &value);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, nullptr,
+ "OH_EffectFilter_SetValue fail!");
+ }
+ }
+ return filter;
+ }};
+
+ ImageEffect_ErrorCode errorCode = OH_EffectFilter_Register(effectInfo, &delegateCrop);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_EffectFilter_Register fail! errorCode = %{public}d", errorCode);
+ return result;
+}
+
+napi_value ImageEdit::LookupFilters(napi_env env, napi_callback_info info)
+{
+ napi_value result = nullptr;
+ napi_get_undefined(env, &result);
+ size_t argc = EXPECTED_ARGS_ONE;
+ napi_value args[EXPECTED_ARGS_ONE] = {nullptr};
+ napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
+ CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_get_cb_info fail! status = %{public}d", status);
+ const char *key = CommonUtils::GetStringArgument(env, args[EXPECTED_ARGS_ZERO]);
+
+ ImageEffect_FilterNames *filterNames = OH_EffectFilter_LookupFilters(key);
+ CHECK_AND_RETURN_RET_LOG(filterNames != nullptr, result, "OH_EffectFilter_LookupFilters fail!");
+
+ std::string res = "size: " + std::to_string(filterNames->size) + std::string(", name: ");
+ for (int i = 0; i < filterNames->size; i++) {
+ res += filterNames->nameList[i];
+ if (i < filterNames->size - 1) {
+ res += " | ";
+ }
+ }
+ status = napi_create_string_utf8(env, res.c_str(), res.size(), &result);
+ // 释放FilterNames虚拟内存资源。
+ OH_EffectFilter_ReleaseFilterNames();
+ return result;
+}
+
+napi_value ImageEdit::getSurfaceId(napi_env env, napi_callback_info info)
+{
+ napi_value result = nullptr;
+ napi_get_undefined(env, &result);
+
+ size_t argc = EXPECTED_ARGS_ONE;
+ napi_value args[EXPECTED_ARGS_ONE] = {nullptr};
+ napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
+ CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_get_cb_info fail! status = %{public}d", status);
+
+ std::string surfaceId = CommonUtils::GetStringArgument(env, args[EXPECTED_ARGS_ZERO]);
+ // 根据SurfaceId创建NativeWindow,注意创建出来的NativeWindow在使用结束后需要主动调用OH_NativeWindow_DestoryNativeWindow进行释放。
+ uint64_t iSurfaceId;
+ std::istrstream iss(surfaceId.c_str());
+ iss >> iSurfaceId;
+ LOG_I("iSurfaceId %{public}llu", iSurfaceId);
+ OHNativeWindow *outputNativeWindow = nullptr;
+ int32_t res = OH_NativeWindow_CreateNativeWindowFromSurfaceId(iSurfaceId, &outputNativeWindow);
+ CHECK_AND_RETURN_RET_LOG(res == 0, result, "OH_NativeWindow_CreateNativeWindowFromSurfaceId fail!");
+
+ OH_ImageEffect *imageEffect = OH_ImageEffect_Create("imageEdit");
+ CHECK_AND_RETURN_RET_LOG(imageEffect != nullptr, result, "OH_ImageEffect_Create fail!");
+
+ ImageEffect_Any runningType{.dataType = ImageEffect_DataType::EFFECT_DATA_TYPE_INT32, .dataValue.int32Value = 1};
+ ImageEffect_ErrorCode errorCode = OH_ImageEffect_Configure(imageEffect, "runningType", &runningType);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_ImageEffect_Configure fail!");
+
+ // 设置输出显示的Surface。
+ errorCode = OH_ImageEffect_SetOutputSurface(imageEffect, outputNativeWindow);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_ImageEffect_SetOutputSurface fail!");
+
+ // 获取输入的Surface。注意获取的inputNativeWindow在使用结束后需要主动调用OH_NativeWindow_DestoryNativeWindow进行释放。
+ OHNativeWindow *inputNativeWindow = nullptr;
+ errorCode = OH_ImageEffect_GetInputSurface(imageEffect, &inputNativeWindow);
+ CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
+ "OH_ImageEffect_GetInputSurface fail!");
+
+ ImageEdit::imageEffect_ = imageEffect;
+
+ // 从获取到输入的NativeWindow中获取SurfaceId。
+ uint64_t inputSurfaceId = 0;
+ res = OH_NativeWindow_GetSurfaceId(inputNativeWindow, &inputSurfaceId);
+ CHECK_AND_RETURN_RET_LOG(res == 0, result, "OH_NativeWindow_GetSurfaceId fail!");
+
+ OH_NativeWindow_DestroyNativeWindow(outputNativeWindow);
+ OH_NativeWindow_DestroyNativeWindow(inputNativeWindow);
+
+ std::string inputSurfaceIdStr = std::to_string(inputSurfaceId);
+
+ status = napi_create_string_utf8(env, inputSurfaceIdStr.c_str(), inputSurfaceIdStr.length(), &result);
+ CHECK_AND_RETURN_RET_LOG(status == napi_status::napi_ok, result, "napi_create_string_utf8 fail!");
+ return result;
+}
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/backend/image_edit.h b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/backend/image_edit.h
new file mode 100644
index 0000000000000000000000000000000000000000..ac307b69480cc92b21c1e286b0b2d1710073f1d2
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/backend/image_edit.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2025 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 IMAGE_EDIT_H
+#define IMAGE_EDIT_H
+
+#include "napi/native_api.h"
+#include
+
+class ImageEdit {
+public:
+ ~ImageEdit();
+
+ static napi_value PixelMapFilterStart(napi_env env, napi_callback_info info);
+
+ static napi_value NativeBufferFilterStart(napi_env env, napi_callback_info info);
+
+ static napi_value URIFilterStart(napi_env env, napi_callback_info info);
+
+ static napi_value SurfaceFilterStart(napi_env env, napi_callback_info info);
+
+ static napi_value SurfaceFilterStop(napi_env env, napi_callback_info info);
+
+ static napi_value LookupFilterInfo(napi_env env, napi_callback_info info);
+
+ static napi_value LookupFilters(napi_env env, napi_callback_info info);
+
+ static napi_value RegisterCustomBrightness();
+
+ static napi_value RegisterCustomCrop();
+
+ static napi_value getSurfaceId(napi_env env, napi_callback_info info);
+
+private:
+ static OH_ImageEffect *imageEffect_;
+};
+
+#endif //IMAGE_EDIT_H
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/logging.h b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/logging.h
new file mode 100644
index 0000000000000000000000000000000000000000..7f4d83dbf144033a5ac84a58339835a01e24a39c
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/logging.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2024 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 IMAGE_EFFECT_LOGGING_H
+#define IMAGE_EFFECT_LOGGING_H
+
+#include
+
+#define EFFECT_LOG_TAG "ImageEffectSample"
+
+#define LOG_I(...) OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, EFFECT_LOG_TAG, __VA_ARGS__)
+#define LOG_W(...) OH_LOG_Print(LOG_APP, LOG_WARN, 0xFF00, EFFECT_LOG_TAG, __VA_ARGS__)
+#define LOG_E(...) OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, EFFECT_LOG_TAG, __VA_ARGS__)
+
+#endif // IMAGE_EFFECT_LOGGING_H
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/napi_init.cpp b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/napi_init.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d71a307d809aae8c92a78df3b6de87dd24f30729
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/napi_init.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2025 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 "napi/native_api.h"
+#include "image_edit.h"
+
+EXTERN_C_START
+void RegisterCustomBrightness() { ImageEdit::RegisterCustomBrightness(); }
+void RegisterCustomCrop() { ImageEdit::RegisterCustomCrop(); }
+
+static napi_value Init(napi_env env, napi_value exports)
+{
+ RegisterCustomBrightness();
+ RegisterCustomCrop();
+
+ napi_property_descriptor desc[] = {
+ {"PixelMapFilterStart", nullptr, ImageEdit::PixelMapFilterStart, nullptr, nullptr, nullptr,
+ napi_default, nullptr},
+ {"NativeBufferFilterStart", nullptr, ImageEdit::NativeBufferFilterStart, nullptr, nullptr, nullptr,
+ napi_default, nullptr},
+ {"URIFilterStart", nullptr, ImageEdit::URIFilterStart, nullptr, nullptr, nullptr, napi_default, nullptr},
+ {"SurfaceFilterStart", nullptr, ImageEdit::SurfaceFilterStart, nullptr, nullptr, nullptr,
+ napi_default, nullptr},
+ {"SurfaceFilterStop", nullptr, ImageEdit::SurfaceFilterStop, nullptr, nullptr, nullptr, napi_default, nullptr},
+ {"lookupFilterInfo", nullptr, ImageEdit::LookupFilterInfo, nullptr, nullptr, nullptr, napi_default, nullptr},
+ {"lookupFilters", nullptr, ImageEdit::LookupFilters, nullptr, nullptr, nullptr, napi_default, nullptr},
+ {"getSurfaceId", nullptr, ImageEdit::getSurfaceId, nullptr, nullptr, nullptr, napi_default, nullptr},
+ };
+ napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
+ return exports;
+}
+EXTERN_C_END
+
+static napi_module demoModule = {
+ .nm_version = 1,
+ .nm_flags = 0,
+ .nm_filename = nullptr,
+ .nm_register_func = Init,
+ .nm_modname = "entry",
+ .nm_priv = ((void *)0),
+ .reserved = {0},
+};
+
+extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/types/libentry/index.d.ts b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/types/libentry/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1ed00cddb9aeab2c5ff6b481bf244e2e9af61846
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/types/libentry/index.d.ts
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+
+declare namespace ImageEffect {
+ const PixelMapFilterStart: (path: string, filterOptions: Array>) => boolean;
+
+ const NativeBufferFilterStart: (filterOptions: Array>) => boolean;
+
+ const URIFilterStart: (path: string, filterOptions: Array>) => boolean;
+
+ const SurfaceFilterStart: (filterOptions: Array>) => boolean;
+
+ const SurfaceFilterStop: () => boolean;
+
+ const lookupFilterInfo: (name: String) => string;
+
+ const lookupFilters: (key: String) => string;
+
+ const getSurfaceId: (surfaceId: string) => string;
+}
+
+export default ImageEffect;
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/types/libentry/oh-package.json5 b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/types/libentry/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..4b632d9ae4da85dcccb452b7ed9db62023c89901
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/types/libentry/oh-package.json5
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+{
+ "name": "libentry.so",
+ "types": "./index.d.ts",
+ "version": " ",
+ "description": "Please describe the basic information."
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/common_utils.cpp b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/common_utils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b6c26226a7989dd29a3c9d2dc7454f8674b19084
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/common_utils.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2025 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 "common_utils.h"
+#include
+#include "logging.h"
+
+const std::map formatToStr_ = {
+ {ImageEffect_Format::EFFECT_PIXEL_FORMAT_RGBA8888, "RGBA8888"},
+ {ImageEffect_Format::EFFECT_PIXEL_FORMAT_NV12, "YUVNV12"},
+ {ImageEffect_Format::EFFECT_PIXEL_FORMAT_NV21, "YUVNV21"},
+};
+
+const std::map bufferTypeToStr_ = {
+ {ImageEffect_BufferType::EFFECT_BUFFER_TYPE_PIXEL, "Pixel"},
+ {ImageEffect_BufferType::EFFECT_BUFFER_TYPE_TEXTURE, "Texture"},
+};
+
+const char *CommonUtils::GetStringArgument(napi_env env, napi_value value)
+{
+ char *buffer = nullptr;
+ size_t bufferLength = 0;
+ napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &bufferLength);
+ if (status == napi_ok && bufferLength > 0) {
+ buffer = reinterpret_cast(malloc((bufferLength + 1) * sizeof(char)));
+ if (buffer == nullptr) {
+ LOG_E("No memory");
+ return nullptr;
+ }
+
+ status = napi_get_value_string_utf8(env, value, buffer, bufferLength + 1, &bufferLength);
+ if (status != napi_ok) {
+ LOG_E("napi_get_value_string_utf8 fail");
+ free(buffer);
+ buffer = nullptr;
+ }
+ }
+ return buffer;
+}
+
+const char *GetBufferType(ImageEffect_BufferType &bufferType)
+{
+ auto it = bufferTypeToStr_.find(bufferType);
+ if (it == bufferTypeToStr_.end()) {
+ return "unknown";
+ }
+
+ return it->second;
+}
+
+const char *GetFormat(ImageEffect_Format &ohFormat)
+{
+ auto it = formatToStr_.find(ohFormat);
+ if (it == formatToStr_.end()) {
+ return "unknown";
+ }
+
+ return it->second;
+}
+
+std::string CommonUtils::EffectInfoToString(OH_EffectFilterInfo *info)
+{
+ std::string result = "";
+
+ char *name = nullptr;
+ OH_EffectFilterInfo_GetFilterName(info, &name);
+ result += "name:" + std::string(name) + ", ";
+
+ uint32_t supportedBufferTypesSize = 0;
+ ImageEffect_BufferType *bufferTypeArray = nullptr;
+ OH_EffectFilterInfo_GetSupportedBufferTypes(info, &supportedBufferTypesSize, &bufferTypeArray);
+ result += "supportedBufferType: {";
+ for (uint32_t i = 0;i < supportedBufferTypesSize; ++i) {
+ ImageEffect_BufferType bufferType = bufferTypeArray[i];
+ result += GetBufferType(bufferType) + std::string(" ");
+ }
+ result += "}";
+
+ uint32_t supportedFormatsSize = 0;
+ ImageEffect_Format *formatArray = nullptr;
+ OH_EffectFilterInfo_GetSupportedFormats(info, &supportedFormatsSize, &formatArray);
+ result += "supportedFormat: {";
+ for (uint32_t i = 0;i < supportedFormatsSize; ++i) {
+ ImageEffect_Format ohFormat = formatArray[i];
+ result += GetFormat(ohFormat) + std::string(" ");
+ }
+ result += "}";
+
+ return result;
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/common_utils.h b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/common_utils.h
new file mode 100644
index 0000000000000000000000000000000000000000..daa477206e3d2f8c4cecc9cbdd6d596e84012171
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/common_utils.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025 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 COMMON_UTILS_H
+#define COMMON_UTILS_H
+
+#include
+#include "napi/native_api.h"
+
+#include "logging.h"
+#include
+
+#define CHECK_AND_RETURN_RET_LOG(cond, ret, fmt, ...) \
+ do { \
+ if (!(cond)) { \
+ LOG_E(fmt, ##__VA_ARGS__); \
+ return ret; \
+ } \
+ } while (0)
+
+#define CHECK_AND_RETURN_LOG(cond, fmt, ...) \
+ do { \
+ if (!(cond)) { \
+ LOG_E(fmt, ##__VA_ARGS__); \
+ return; \
+ } \
+ } while (0)
+
+#define CHECK_AND_NO_RETURN_LOG(cond, fmt, ...) \
+ do { \
+ if (!(cond)) { \
+ LOG_E(fmt, ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+#define CHECK_AND_RETURN_NO_RET(cond, fmt, ...) \
+ do { \
+ if (!(cond)) { \
+ LOG_E(fmt, ##__VA_ARGS__); \
+ return; \
+ } \
+ } while (0)
+
+class CommonUtils {
+public:
+ static const char *GetStringArgument(napi_env env, napi_value value);
+
+ static std::string EffectInfoToString(OH_EffectFilterInfo *info);
+};
+
+#endif // COMMON_UTILS_H
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/json_utils.cpp b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/json_utils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c4e125e0cbdec0e42d9222776387e79f5c818896
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/json_utils.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2025 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 "json_utils.h"
+#include
+#include
+#include
+
+// 表示小数点后保留的位数
+constexpr int PRECISION = 2;
+// 构造函数
+Json::JsonValueProxy::JsonValueProxy(Json& parent, const std::string& key) : parent_(parent), key_(key) {}
+
+// 设置浮点值
+void Json::JsonValueProxy::operator=(const float value)
+{
+ parent_.Set(key_, value);
+}
+
+// 设置const char*值
+void Json::JsonValueProxy::operator=(const char* value)
+{
+ parent_.Set(key_, value);
+}
+
+// 设置字符串值
+void Json::JsonValueProxy::operator=(const std::string& value)
+{
+ parent_.Set(key_, value);
+}
+
+// 设置json值
+void Json::JsonValueProxy::operator=(const Json& value)
+{
+ parent_.Set(key_, value);
+}
+
+// 重载operator[]以返回代理对象
+Json::JsonValueProxy Json::operator[](const std::string& key)
+{
+ return JsonValueProxy(*this, key);
+}
+
+// 设置浮点值
+void Json::Set(const std::string& key, float value)
+{
+ std::ostringstream oss;
+ // 将浮点数 value 转换为字符串时,保留小数点后两位
+ oss << std::fixed << std::setprecision(PRECISION) << value;
+ values_[key] = oss.str();
+}
+
+// 设置字符串值
+void Json::Set(const std::string& key, const std::string& value)
+{
+ values_[key] = "\"" + value + "\"";
+}
+
+// 设置const char*值
+void Json::Set(const std::string& key, const char* value)
+{
+ values_[key] = "\"" + std::string(value) + "\"";
+}
+
+// 设置json值
+void Json::Set(const std::string& key, const Json& value)
+{
+ values_[key] = value.Dump();
+}
+
+// 将json对象转成字符串
+std::string Json::Dump() const
+{
+ std::ostringstream oss;
+ oss << "{";
+ bool first = true;
+ for (const auto& pair : values_) {
+ if (!first) {
+ oss << ", ";
+ }
+ oss << "\"" << pair.first << "\": " << pair.second;
+ first = false;
+ }
+ oss << "}";
+ return oss.str();
+}
+
+// 解析json字符串获取json格式的key和value
+std::map Json::Parse(const std::string& jsonStr)
+{
+ std::map result;
+ std::string key;
+ std::string value;
+ bool inKey = false;
+ bool inValue = false;
+ for (size_t i = 0; i < jsonStr.size(); ++i) {
+ char c = jsonStr[i];
+ if (c == '"') {
+ if (inKey) {
+ inKey = false;
+ } else if (inValue) {
+ inValue = false;
+ result[key] = value;
+ key.clear();
+ value.clear();
+ } else {
+ inKey = true;
+ }
+ } else if (c == ':') {
+ inKey = false;
+ inValue = true;
+ } else if (c == ',') {
+ inValue = false;
+ } else if (inKey) {
+ key += c;
+ } else if (inValue) {
+ value += c;
+ }
+ }
+ return result;
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/json_utils.h b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/json_utils.h
new file mode 100644
index 0000000000000000000000000000000000000000..0b981ebc14bf433229bfe41c2a8761dd9ff00e92
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/json_utils.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2025 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 JSON_UTILS_H
+#define JSON_UTILS_H
+
+#include
+#include
+
+class Json {
+public:
+ // 代理类,用于设置值
+ class JsonValueProxy {
+ public:
+ JsonValueProxy(Json& parent, const std::string& key);
+ void operator=(const float value);
+ void operator=(const char* value);
+ void operator=(const std::string& value);
+ void operator=(const Json& value);
+
+ private:
+ Json& parent_;
+ std::string key_;
+ };
+
+ // 重载operator[]以返回代理对象
+ JsonValueProxy operator[](const std::string& key);
+
+ // 设置浮点值
+ void Set(const std::string& key, float value);
+ // 设置字符串值
+ void Set(const std::string& key, const std::string& value);
+ // 设置const char*值
+ void Set(const std::string& key, const char* value);
+ // 设置json值
+ void Set(const std::string& key, const Json& value);
+
+ // 将json对象转成字符串
+ std::string Dump() const;
+
+ // 解析json字符串获取json格式的key和value
+ static std::map Parse(const std::string& jsonStr);
+
+private:
+ std::map values_;
+};
+
+#endif // JSON_UTILS_H
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/pixelmap_helper.cpp b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/pixelmap_helper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9457ef85c625a2d05ead7b938694ced07fe3f80f
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/pixelmap_helper.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2025 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 "pixelmap_helper.h"
+#include "common_utils.h"
+#include
+#include
+#include
+#include
+
+constexpr int EXPECTED_ONE_HUNDRED = 100;
+
+std::shared_ptr CreateDecodingOptions()
+{
+ OH_DecodingOptions *options = nullptr;
+ Image_ErrorCode errorCode = OH_DecodingOptions_Create(&options);
+ CHECK_AND_RETURN_RET_LOG(errorCode == Image_ErrorCode::IMAGE_SUCCESS, nullptr,
+ "OH_DecodingOptions_Create fail! errorCode=%{public}d", errorCode);
+
+ std::shared_ptr optionsPtr(options, [](OH_DecodingOptions *options) {
+ OH_DecodingOptions_Release(options);
+ });
+
+ return optionsPtr;
+}
+
+std::shared_ptr PixelMapHelper::Decode(std::string &pathName)
+{
+ int fd = open(pathName.c_str(), O_RDWR);
+ CHECK_AND_RETURN_RET_LOG(fd != -1, nullptr, "Open path fail! pathName=%{public}s", pathName.c_str());
+
+ std::shared_ptr fdPtr(&fd, [](int *fd) { close(*fd); });
+ OH_ImageSourceNative *imageSource = nullptr;
+ Image_ErrorCode errorCode = OH_ImageSourceNative_CreateFromFd(*fdPtr.get(), &imageSource);
+ CHECK_AND_RETURN_RET_LOG(errorCode == Image_ErrorCode::IMAGE_SUCCESS, nullptr,
+ "OH_ImageSourceNative_CreateFromFd fail! errorCode=%{public}d", errorCode);
+
+ std::shared_ptr imageSourcePtr(imageSource, [](OH_ImageSourceNative *imageSource) {
+ OH_ImageSourceNative_Release(imageSource);
+ });
+
+ std::shared_ptr optionsPtr = CreateDecodingOptions();
+ CHECK_AND_RETURN_RET_LOG(optionsPtr != nullptr, nullptr, "CreateDecodingOptions fail!");
+
+ OH_PixelmapNative *pixelmap = nullptr;
+ errorCode = OH_ImageSourceNative_CreatePixelmap(imageSourcePtr.get(), optionsPtr.get(), &pixelmap);
+ CHECK_AND_RETURN_RET_LOG(errorCode == Image_ErrorCode::IMAGE_SUCCESS, nullptr,
+ "OH_ImageSourceNative_CreatePixelmap fail! errorCode=%{public}d", errorCode);
+
+ std::shared_ptr pixelmapPtr(pixelmap, [](OH_PixelmapNative *pixelmap) {
+ OH_PixelmapNative_Release(pixelmap);
+ });
+
+ return pixelmapPtr;
+}
+
+std::shared_ptr CreatePackingOptions()
+{
+ OH_PackingOptions *options = nullptr;
+ Image_ErrorCode errorCode = OH_PackingOptions_Create(&options);
+ CHECK_AND_RETURN_RET_LOG(errorCode == Image_ErrorCode::IMAGE_SUCCESS, nullptr,
+ "OH_PackingOptions_Create fail! errorCode=%{public}d", errorCode);
+
+ std::shared_ptr optionsPtr(options, [](OH_PackingOptions *options) {
+ OH_PackingOptions_Release(options);
+ });
+
+ OH_PackingOptions_SetQuality(optionsPtr.get(), EXPECTED_ONE_HUNDRED);
+ Image_MimeType format = { .data = const_cast(MIME_TYPE_JPEG), .size = strlen(MIME_TYPE_JPEG) };
+ OH_PackingOptions_SetMimeType(optionsPtr.get(), &format);
+ return optionsPtr;
+}
+
+bool PixelMapHelper::Encode(OH_PixelmapNative *pixelmap, std::string &path)
+{
+ OH_ImagePackerNative *imagePacker = nullptr;
+ Image_ErrorCode errorCode = OH_ImagePackerNative_Create(&imagePacker);
+ CHECK_AND_RETURN_RET_LOG(errorCode == Image_ErrorCode::IMAGE_SUCCESS, false,
+ "OH_ImagePackerNative_Create fail! errorCode=%{public}d", errorCode);
+
+ std::shared_ptr imagePackerPtr(imagePacker, [](OH_ImagePackerNative *imagePacker) {
+ OH_ImagePackerNative_Release(imagePacker);
+ });
+
+ std::shared_ptr optionsPtr = CreatePackingOptions();
+ CHECK_AND_RETURN_RET_LOG(optionsPtr != nullptr, false, "CreatePackingOptions fail!");
+
+ int fd = open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+ CHECK_AND_RETURN_RET_LOG(fd != -1, false, "Open path fail! path=%{public}s", path.c_str());
+ errorCode = OH_ImagePackerNative_PackToFileFromPixelmap(imagePackerPtr.get(), optionsPtr.get(), pixelmap, fd);
+ close(fd);
+ CHECK_AND_RETURN_RET_LOG(errorCode == Image_ErrorCode::IMAGE_SUCCESS, false,
+ "OH_ImagePackerNative_PackToFileFromPixelmap fail! errorCode=%{public}d", errorCode);
+
+ return true;
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/pixelmap_helper.h b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/pixelmap_helper.h
new file mode 100644
index 0000000000000000000000000000000000000000..e5b74ab27b629dfabfc93742a15da48d183de3d4
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/cpp/utils/pixelmap_helper.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2025 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 IMAGEEFFECT_PIXELMAP_HELPER_H
+#define IMAGEEFFECT_PIXELMAP_HELPER_H
+
+#include
+#include
+#include
+
+#include "napi/native_api.h"
+
+class PixelMapHelper {
+public:
+ static std::shared_ptr Decode(std::string &pathName);
+ static bool Encode(OH_PixelmapNative *pixelmap, std::string &pathName);
+
+ static std::shared_ptr ConvertPixelmap(NativePixelMap *nativePixelMap);
+ static napi_value ConvertPixelmap(OH_PixelmapNative *pixelmapNative, napi_env env);
+};
+
+#endif // IMAGEEFFECT_PIXELMAP_HELPER_H
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/ets/entryability/EntryAbility.ets b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/ets/entryability/EntryAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..462b5f8efe4bca6f2b64b04d9b14491818d7083c
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/ets/entryability/EntryAbility.ets
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+
+import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { window } from '@kit.ArkUI';
+import { checkAndRequestPermissions, permissions } from '../utils/PermissionUtils';
+
+export default class EntryAbility extends UIAbility {
+ onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
+ }
+
+ onDestroy(): void {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
+ }
+
+ onWindowStageCreate(windowStage: window.WindowStage): void {
+ // Main window is created, set main page for this ability
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
+
+ windowStage.loadContent('pages/ImageEditPage', (err, data) => {
+ checkAndRequestPermissions(permissions, this.context);
+ if (err.code) {
+ hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
+ return;
+ }
+ hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
+ });
+ }
+
+ onWindowStageDestroy(): void {
+ // Main window is destroyed, release UI related resources
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
+ }
+
+ onForeground(): void {
+ // Ability has brought to foreground
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
+ }
+
+ onBackground(): void {
+ // Ability has back to background
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
+ }
+};
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/ets/pages/ImageEditPage.ets b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/ets/pages/ImageEditPage.ets
new file mode 100644
index 0000000000000000000000000000000000000000..9fc7adca86193321119a465ce3e90f89354ad67c
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/ets/pages/ImageEditPage.ets
@@ -0,0 +1,788 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+
+import imageEffect from 'libentry.so';
+import image from '@ohos.multimedia.image';
+import { ImageUtils } from '../utils/ImageUtils';
+import { fileUri } from '@kit.CoreFileKit';
+import fs from '@ohos.file.fs';
+import { camera } from '@kit.CameraKit';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { promptAction } from '@kit.ArkUI';
+
+const VALUE_MIN_MINUS = -100;
+const VALUE_MIN = 1;
+const VALUE_MAX = 100;
+
+@Entry
+@Component
+struct ImageEditPage {
+ settingBtn: Resource = $r('app.media.ic_public_settings');
+ @Provide displayPixelMap: image.PixelMap | undefined = undefined;
+ @Provide displayPixelMapUri: image.PixelMap | undefined = undefined;
+ @State brightnessSetValue: number = 100;
+ @State brightnessSelect: boolean = false;
+ @State contrastSetValue: number = 0;
+ @State contrastSelect: boolean = false;
+ @State cropSetValue: number = 100;
+ @State cropSelect: boolean = false;
+ @State customBrightnessSetValue: number = 0;
+ @State customBrightnessSelect: boolean = false;
+ @State customCropSetValue: number = 50;
+ @State customCropSelect: boolean = false;
+ @State filterOptions: Array> = [];
+ @State filterInfo: string = '';
+ mXComponentController: XComponentController = new XComponentController();
+ @State mSurfaceId: string = '';
+ @State inputType: 'PixelmapNative' | 'NativeBuffer' | 'URI' | 'NativeWindow' = 'PixelmapNative';
+ @State index: number = 0;
+ cameraMgr: camera.CameraManager | undefined = undefined;
+ dialogController: CustomDialogController = new CustomDialogController({
+ builder: CustomDialogExample({
+ cancel: this.onCancel,
+ confirm: this.onAccept,
+ filterOptions: $filterOptions,
+ brightnessSetValue: $brightnessSetValue,
+ brightnessSelect: $brightnessSelect,
+ contrastSetValue: $contrastSetValue,
+ contrastSelect: $contrastSelect,
+ cropSetValue: $cropSetValue,
+ cropSelect: $cropSelect,
+ customBrightnessSetValue: $customBrightnessSetValue,
+ customBrightnessSelect: $customBrightnessSelect,
+ customCropSetValue: $customCropSetValue,
+ customCropSelect: $customCropSelect,
+ filterInfo: $filterInfo,
+ inputType: $inputType,
+ index: $index,
+ }),
+ cancel: this.existApp,
+ autoCancel: true,
+ });
+ private tag: string = '[Sample_ImageEdit]';
+
+ aboutToAppear(): void {
+ console.info(`${this.tag} aboutToAppear called`);
+ ImageUtils.getInstance().getPixelMap($r('app.media.ic_1080x1920')).then(pixelMap => {
+ this.displayPixelMap = pixelMap;
+ })
+ ImageUtils.getInstance().getPixelMap($r('app.media.ic_700x700')).then(pixelMap => {
+ this.displayPixelMapUri = pixelMap;
+ })
+ console.info(`${this.tag} aboutToAppear done`);
+ }
+
+ aboutToDisappear(): void {
+ console.info(`${this.tag} aboutToDisappear called`);
+ console.info(`${this.tag} aboutToDisappear done`);
+ }
+
+ build() {
+ Column() {
+ Row() {
+ Row() {
+ Text($r('app.string.image_edit'))
+ .fontColor(Color.White)
+ .fontSize('app.float.title_font_size')
+ .margin({ left: $r('app.float.home_page_title_margin') })
+ }
+
+ Blank()
+
+ Row() {
+ Button() {
+ Image(this.settingBtn)
+ .width($r('app.float.title_image_width'))
+ .height($r('app.float.title_image_height'))
+ .id('btn_setting')
+ }
+ .height('100%')
+ .type(ButtonType.Normal)
+ .backgroundColor(Color.Transparent)
+ .onClick(() => {
+ if (this.dialogController != undefined) {
+ console.info(`${this.tag} to open setting dialog`);
+ this.dialogController.open();
+ }
+ })
+ }
+ }
+ .width('100%')
+ .height($r('app.float.home_page_title_height'))
+ .margin({
+ top: $r('app.float.home_page_title_margin'),
+ left: $r('app.float.home_page_title_margin'),
+ right: $r('app.float.home_page_title_margin')
+ })
+
+ Column() {
+ if (this.inputType == 'PixelmapNative') {
+ Image(this.displayPixelMap)
+ .objectFit(ImageFit.None)
+ }
+ if (this.inputType == 'NativeBuffer') {
+ Column() {
+ Text($r('app.string.native_buffer_description'))
+ .fontSize($r('app.float.title_size'))
+ }
+ .backgroundColor(Color.White)
+ }
+ if (this.inputType == 'URI') {
+ Image(this.displayPixelMapUri)
+ .objectFit(ImageFit.None)
+ }
+ if (this.inputType == 'NativeWindow') {
+ XComponent({
+ id: 'xcomponentId',
+ type: XComponentType.SURFACE,
+ controller: this.mXComponentController,
+ libraryname: 'entry'
+ })
+ .onLoad(async () => {
+ // 获取XComponent的SurfaceId。
+ this.mSurfaceId = this.mXComponentController.getXComponentSurfaceId();
+ // 调用native接口获取输入SurfaceId。
+ this.mSurfaceId = imageEffect.getSurfaceId(this.mSurfaceId);
+ // 调用相机接口启动预览,将获取到的输入SurfaceId传递给相机框架
+ this.startPreview(this.mSurfaceId);
+ })
+ .width('100%')
+ .height('100%')
+ }
+ }
+ .clip(true)
+ .justifyContent(FlexAlign.Center)
+ .width('100%')
+ .height('85%')
+
+ Row() {
+ Button('Reset')
+ .id('btn_reset')
+ .onClick(() => {
+ this.pixelInit();
+ })
+ .width($r('app.float.button_width'))
+
+ Button('Apply')
+ .id('btn_apply')
+ .onClick(() => {
+ this.doApply();
+ })
+ .width($r('app.float.button_width'))
+ }
+ .justifyContent(FlexAlign.SpaceEvenly)
+ .width('100%')
+ .height('6%')
+ .margin({ top: $r('app.float.home_page_title_margin') })
+ }
+ .width('100%')
+ .height('100%')
+ .backgroundColor(Color.Grey)
+ }
+
+ onCancel() {
+ console.info(`Callback when the cancel button is clicked`);
+ }
+
+ onAccept() {
+ console.info(`Callback when the confirm button is clicked`);
+ }
+
+ existApp() {
+ console.info(`click the callback in the blank area`);
+ }
+
+ private async startPreview(surfaceId: string) {
+ let cameraManager = camera.getCameraManager(getContext(this));
+ let cameras = this.getSupportedCameras(cameraManager);
+ let modes = this.getSupportedSceneModes(cameraManager, cameras[0]);
+ let cameraOutputCapability = cameraManager.getSupportedOutputCapability(cameras[0], modes[0]);
+ let previewOutput = this.getPreviewOutput(cameraManager, cameraOutputCapability, surfaceId);
+ if (previewOutput != undefined) {
+ await this.startPreviewOutput(cameraManager, previewOutput);
+ }
+ }
+
+ private getSupportedCameras(cameraManager: camera.CameraManager): camera.CameraDevice[] {
+ let cameras: camera.CameraDevice[] = [];
+ try {
+ cameras = cameraManager.getSupportedCameras();
+ } catch (error) {
+ let err = error as BusinessError;
+ console.error(`The getSupportedCameras call failed. error code: ${err.code}`);
+ }
+ return cameras;
+ }
+
+ private getSupportedSceneModes(cameraManager: camera.CameraManager,
+ camera: camera.CameraDevice): camera.SceneMode[] {
+ let modes: camera.SceneMode[] = [];
+ try {
+ modes = cameraManager.getSupportedSceneModes(camera);
+ } catch (error) {
+ let err = error as BusinessError;
+ console.error(`The getSupportedSceneModes call failed. error code: ${err.code}`);
+ }
+ return modes;
+ }
+
+ private getPreviewOutput(cameraManager: camera.CameraManager, cameraOutputCapability: camera.CameraOutputCapability,
+ surfaceId: string): camera.PreviewOutput | undefined {
+ let previewProfilesArray: camera.Profile[] = cameraOutputCapability.previewProfiles;
+ let previewOutput: camera.PreviewOutput | undefined = undefined;
+ try {
+ previewOutput = cameraManager.createPreviewOutput(previewProfilesArray[0], surfaceId);
+ } catch (error) {
+ let err = error as BusinessError;
+ console.error('Failed to create the PreviewOutput instance. error code: ' + err.code);
+ }
+ return previewOutput;
+ }
+
+ private async startPreviewOutput(cameraManager: camera.CameraManager,
+ previewOutput: camera.PreviewOutput): Promise {
+ let cameraArray: camera.CameraDevice[] = [];
+ cameraArray = cameraManager.getSupportedCameras();
+ if (cameraArray.length == 0) {
+ console.error('no camera.');
+ return;
+ }
+ // 获取支持的模式类型
+ let sceneModes: camera.SceneMode[] = cameraManager.getSupportedSceneModes(cameraArray[0]);
+ let isSupportPhotoMode: boolean = sceneModes.indexOf(camera.SceneMode.NORMAL_PHOTO) >= 0;
+ if (!isSupportPhotoMode) {
+ console.error('photo mode not support');
+ return;
+ }
+ let cameraInput: camera.CameraInput | undefined = undefined;
+ cameraInput = cameraManager.createCameraInput(cameraArray[0]);
+ if (cameraInput === undefined) {
+ console.error('cameraInput is undefined');
+ return;
+ }
+ // 打开相机
+ await cameraInput.open();
+ let session: camera.PhotoSession =
+ cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO) as camera.PhotoSession;
+ session.beginConfig();
+ session.addInput(cameraInput);
+ session.addOutput(previewOutput);
+ await session.commitConfig();
+ await session.start();
+ }
+
+ private async doSavePixel(): Promise {
+ let pixelMap: image.PixelMap | undefined = undefined;
+ if (this.inputType == 'PixelmapNative') {
+ pixelMap = await ImageUtils.getInstance().getPixelMap($r('app.media.ic_1080x1920'));
+ } else {
+ pixelMap = await ImageUtils.getInstance().getPixelMap($r('app.media.ic_700x700'));
+ }
+ const imagePackerApi = image.createImagePacker();
+ const packOption: image.PackingOption = {
+ format: 'image/jpeg',
+ quality: 100
+ };
+ let filePath = '';
+ if (this.inputType == 'PixelmapNative') {
+ filePath = getContext().filesDir + '/ic_1080x1920.jpg';
+ } else {
+ filePath = getContext().filesDir + '/ic_700x700.jpg';
+ }
+ console.info(`savePixel to ${filePath}`);
+ let uri = fileUri.getUriFromPath(filePath);
+ let imageData = await imagePackerApi.packing(pixelMap, packOption);
+ let file = fs.openSync(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
+ let writeLen = fs.writeSync(file.fd, imageData);
+ fs.closeSync(file);
+ console.info(`write data to file succeed and size is ${writeLen}`);
+ }
+
+ private confirmInfo() {
+ this.filterOptions = [];
+ if (this.brightnessSelect) {
+ let brightnessArray: (string | number)[] = [];
+ brightnessArray.push('Brightness', this.brightnessSetValue);
+ this.filterOptions.push(brightnessArray);
+ }
+ if (this.contrastSelect) {
+ let contrastArray: (string | number)[] = [];
+ contrastArray.push('Contrast', this.contrastSetValue);
+ this.filterOptions.push(contrastArray);
+ }
+ if (this.cropSelect && this.inputType != 'NativeBuffer' && this.inputType != 'NativeWindow') {
+ let cropArray: (string | number)[] = [];
+ cropArray.push('Crop', this.cropSetValue);
+ this.filterOptions.push(cropArray);
+ }
+ if (this.customBrightnessSelect) {
+ let customBrightnessArray: (string | number)[] = [];
+ customBrightnessArray.push('CustomBrightness', this.customBrightnessSetValue);
+ this.filterOptions.push(customBrightnessArray);
+ }
+ if (this.customCropSelect && this.inputType != 'NativeWindow') {
+ let customCropArray: (string | number)[] = [];
+ customCropArray.push('CustomCrop', this.customCropSetValue);
+ this.filterOptions.push(customCropArray);
+ }
+ }
+
+ private async doApply(): Promise {
+ this.confirmInfo();
+ if (this.filterOptions.toString() != '') {
+ let filePath: string = '';
+ let result: boolean = true;
+ switch (this.inputType) {
+ case 'PixelmapNative':
+ await this.doSavePixel();
+ filePath = getContext().filesDir + '/ic_1080x1920.jpg';
+ result = imageEffect.PixelMapFilterStart(filePath, [...this.filterOptions]);
+ this.displayPixelMap = await ImageUtils.getInstance().getPixelMapByFilePath(filePath);
+ promptAction.showToast({ message: `apply PixelMapNative ${result == true ? 'succeed' : 'fail'}!` });
+ break;
+ case 'NativeBuffer':
+ result = imageEffect.NativeBufferFilterStart([...this.filterOptions]);
+ promptAction.showToast({ message: `apply NativeBuffer ${result == true ? 'succeed' : 'fail'}!` });
+ break;
+ case 'URI':
+ await this.doSavePixel();
+ filePath = getContext().filesDir + '/ic_700x700.jpg';
+ result = imageEffect.URIFilterStart(filePath, [...this.filterOptions]);
+ this.displayPixelMapUri = await ImageUtils.getInstance().getPixelMapByFilePath(filePath);
+ promptAction.showToast({ message: `apply URI ${result == true ? 'succeed' : 'fail'}!` });
+ break;
+ case 'NativeWindow':
+ result = imageEffect.SurfaceFilterStart([...this.filterOptions]);
+ promptAction.showToast({ message: `apply NativeWindow ${result == true ? 'succeed' : 'fail'}!` });
+ break;
+ }
+ }
+ }
+
+ private async pixelInit(): Promise {
+ if (this.inputType == 'NativeWindow') {
+ imageEffect.SurfaceFilterStop();
+ this.mSurfaceId = imageEffect.getSurfaceId(this.mSurfaceId);
+ this.startPreview(this.mSurfaceId);
+ console.info(`initCamera succeed`);
+ }
+ this.displayPixelMap?.release();
+ this.displayPixelMap = await ImageUtils.getInstance().getPixelMap($r('app.media.ic_1080x1920'));
+ this.displayPixelMapUri?.release();
+ this.displayPixelMapUri = await ImageUtils.getInstance().getPixelMap($r('app.media.ic_700x700'));
+ }
+}
+
+@CustomDialog
+struct CustomDialogExample {
+ @Link brightnessSetValue: number;
+ @Link brightnessSelect: boolean;
+ @Link contrastSetValue: number;
+ @Link contrastSelect: boolean;
+ @Link cropSetValue: number;
+ @Link cropSelect: boolean;
+ @Link customBrightnessSetValue: number;
+ @Link customBrightnessSelect: boolean;
+ @Link customCropSetValue: number;
+ @Link customCropSelect: boolean;
+ @Link filterOptions: Array>;
+ @Link filterInfo: string;
+ @Link inputType: string;
+ @Link index: number;
+ inputList: SelectOption[] = [{ value: 'PixelmapNative' }, { value: 'NativeBuffer' },
+ { value: 'URI' }, { value: 'NativeWindow' }];
+ controller: CustomDialogController;
+ @State formatList: String[] = ['Format:rgba_8888', 'Format:nv21', 'Format:nv12'];
+ @State handlePopup: boolean = false;
+ cancel: () => void = () => {
+ }
+ confirm: () => void = () => {
+ }
+
+ @Builder
+ filterInfoMenu() {
+ Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Center }) {
+ Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Start }) {
+ Text(this.filterInfo).fontSize($r('app.float.filter_info_size'))
+ }
+ }
+ .width('60%').height('15%')
+ .opacity($r('app.float.filter_info_opacity'))
+ .id('filter_info_menu')
+ }
+
+ build() {
+ Column() {
+ Select(this.inputList)
+ .value($r('app.string.select_description'))
+ .selected(this.index)
+ .onSelect((index: number) => {
+ this.index = index;
+ this.inputType = this.inputList[index].value.toString();
+ })
+ .id('select_input')
+ Divider().height($r('app.float.divider_height')).color(0xCCCCCC)
+
+ Column() {
+ Column() {
+ Text('Filter')
+ .width('100%')
+ .fontSize($r('app.float.dialog_title_size'))
+ .margin({ bottom: $r('app.float.bottom_size') })
+
+ Row() {
+ Column() {
+ Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
+ Checkbox({ name: 'brightnessCheckbox', group: 'filterCheckboxGroup' })
+ .selectedColor(0x39a2db)
+ .select(this.brightnessSelect)
+ .onChange((value: boolean) => {
+ this.brightnessSelect = value;
+ })
+ .width($r('app.float.check_box_width'))
+ .height($r('app.float.check_box_height'))
+ .id('checkbox_brightness')
+ Text('Brightness').fontSize($r('app.float.filter_text_size')).width('18%')
+ Slider({
+ value: this.brightnessSetValue,
+ min: VALUE_MIN_MINUS,
+ max: VALUE_MAX,
+ style: SliderStyle.OutSet
+ })
+ .showTips(true, this.brightnessSetValue.toFixed())
+ .onChange((value: number, mode: SliderChangeMode) => {
+ this.brightnessSetValue = value;
+ console.info('value:' + value + 'mode:' + mode.toString());
+ })
+ .width('60%')
+ .id('slider_brightness')
+ // toFixed()将滑动条返回值处理为整数精度
+ Column() {
+ Text(this.brightnessSetValue.toFixed()).fontSize($r('app.float.filter_number_size'))
+ }.width('8%')
+
+ Column() {
+ Image($r('app.media.ic_public_search'))
+ .width('5%')
+ .height('3.7%')
+ }.bindMenu(this.filterInfoMenu, {
+ onAppear: () => {
+ this.doLookFilterInfo('Brightness');
+ },
+ onDisappear: () => {
+ this.filterInfo = '';
+ }
+ })
+ .margin({ left: $r('app.float.margin_left') })
+ .id('btn_search_brightness')
+ }
+
+ Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
+ Checkbox({ name: 'contrastCheckbox', group: 'filterCheckboxGroup' })
+ .selectedColor(0x39a2db)
+ .select(this.contrastSelect)
+ .onChange((value: boolean) => {
+ this.contrastSelect = value;
+ })
+ .width($r('app.float.check_box_width'))
+ .height($r('app.float.check_box_height'))
+ .id('checkbox_contrast')
+ Text('Contrast').fontSize($r('app.float.filter_text_size')).width('18%')
+ Slider({
+ value: this.contrastSetValue,
+ min: VALUE_MIN_MINUS,
+ max: VALUE_MAX,
+ style: SliderStyle.OutSet
+ })
+ .showTips(true, this.contrastSetValue.toFixed())
+ .onChange((value: number, mode: SliderChangeMode) => {
+ this.contrastSetValue = value;
+ console.info('value:' + value + 'mode:' + mode.toString());
+ })
+ .width('60%')
+ .id('slider_contrast')
+ // toFixed()将滑动条返回值处理为整数精度
+ Column() {
+ Text(this.contrastSetValue.toFixed()).fontSize($r('app.float.filter_number_size'))
+ }.width('8%')
+
+ Column() {
+ Image($r('app.media.ic_public_search'))
+ .width('5%')
+ .height('3.7%')
+ }.bindMenu(this.filterInfoMenu, {
+ onAppear: () => {
+ this.doLookFilterInfo('Contrast');
+ },
+ onDisappear: () => {
+ this.filterInfo = '';
+ }
+ })
+ .margin({ left: $r('app.float.margin_left') })
+ .id('btn_search_contrast')
+ }
+
+ if (this.inputType != 'NativeBuffer' && this.inputType != 'NativeWindow') {
+ Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
+ Checkbox({ name: 'cropCheckbox', group: 'filterCheckboxGroup' })
+ .selectedColor(0x39a2db)
+ .select(this.cropSelect)
+ .onChange((value: boolean) => {
+ this.cropSelect = value;
+ })
+ .width($r('app.float.check_box_width'))
+ .height($r('app.float.check_box_height'))
+ .id('checkbox_crop')
+ Text('Crop').fontSize($r('app.float.filter_text_size')).width('18%')
+ Slider({
+ value: this.cropSetValue,
+ min: VALUE_MIN,
+ max: VALUE_MAX,
+ style: SliderStyle.OutSet
+ })
+ .showTips(true, this.cropSetValue.toFixed())
+ .onChange((value: number, mode: SliderChangeMode) => {
+ this.cropSetValue = value;
+ console.info('value:' + value + 'mode:' + mode.toString());
+ })
+ .width('60%')
+ .id('slider_crop')
+ // toFixed()将滑动条返回值处理为整数精度
+ Column() {
+ Text(this.cropSetValue.toFixed()).fontSize($r('app.float.filter_number_size'))
+ }.width('8%')
+
+ Column() {
+ Image($r('app.media.ic_public_search'))
+ .width('5%')
+ .height('3.7%')
+ }.bindMenu(this.filterInfoMenu, {
+ onAppear: () => {
+ this.doLookFilterInfo('Crop');
+ },
+ onDisappear: () => {
+ this.filterInfo = '';
+ }
+ })
+ .margin({ left: $r('app.float.margin_left') })
+ .id('btn_search_crop')
+ }
+ }
+
+ Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
+ Checkbox({ name: 'customBrightnessCheckbox', group: 'filterCheckboxGroup' })
+ .selectedColor(0x39a2db)
+ .select(this.customBrightnessSelect)
+ .onChange((value: boolean) => {
+ this.customBrightnessSelect = value;
+ })
+ .width($r('app.float.check_box_width'))
+ .height($r('app.float.check_box_height'))
+ .id('checkbox_custom_brightness')
+ Text('CustomBrightness').fontSize($r('app.float.filter_text_size')).width('18%')
+ Slider({
+ value: this.customBrightnessSetValue,
+ min: VALUE_MIN_MINUS,
+ max: VALUE_MAX,
+ style: SliderStyle.OutSet
+ })
+ .showTips(true, this.customBrightnessSetValue.toFixed())
+ .onChange((value: number, mode: SliderChangeMode) => {
+ this.customBrightnessSetValue = value;
+ console.info('value:' + value + 'mode:' + mode.toString());
+ })
+ .width('60%')
+ .id('slider_custom_brightness')
+ // toFixed()将滑动条返回值处理为整数精度
+ Column() {
+ Text(this.customBrightnessSetValue.toFixed()).fontSize($r('app.float.filter_number_size'))
+ }.width('8%')
+
+ Column() {
+ Image($r('app.media.ic_public_search'))
+ .width('5%')
+ .height('3.7%')
+ }.bindMenu(this.filterInfoMenu, {
+ onAppear: () => {
+ this.doLookFilterInfo('CustomBrightness');
+ },
+ onDisappear: () => {
+ this.filterInfo = '';
+ }
+ })
+ .margin({ left: $r('app.float.margin_left') })
+ .id('btn_search_custom_brightness')
+ }
+
+ if (this.inputType != 'NativeWindow') {
+ Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
+ Checkbox({ name: 'customCropCheckbox', group: 'filterCheckboxGroup' })
+ .selectedColor(0x39a2db)
+ .select(this.customCropSelect)
+ .onChange((value: boolean) => {
+ this.customCropSelect = value;
+ })
+ .width($r('app.float.check_box_width'))
+ .height($r('app.float.check_box_height'))
+ .id('checkbox_custom_crop')
+ Text('CustomCrop').fontSize($r('app.float.filter_text_size')).width('18%')
+ Slider({
+ value: this.customCropSetValue,
+ min: VALUE_MIN,
+ max: VALUE_MAX,
+ style: SliderStyle.OutSet
+ })
+ .showTips(true, this.customCropSetValue.toFixed())
+ .onChange((value: number, mode: SliderChangeMode) => {
+ this.customCropSetValue = value;
+ console.info('value:' + value + 'mode:' + mode.toString());
+ })
+ .width('60%')
+ .id('slider_custom_crop')
+ // toFixed()将滑动条返回值处理为整数精度
+ Column() {
+ Text(this.customCropSetValue.toFixed()).fontSize($r('app.float.filter_number_size'))
+ }.width('8%')
+
+ Column() {
+ Image($r('app.media.ic_public_search'))
+ .width('5%')
+ .height('3.7%')
+ }.bindMenu(this.filterInfoMenu, {
+ onAppear: () => {
+ this.doLookFilterInfo('CustomCrop');
+ },
+ onDisappear: () => {
+ this.filterInfo = '';
+ }
+ })
+ .margin({ left: $r('app.float.margin_left') })
+ .id('btn_search_custom_crop')
+ }
+ }
+ }
+ .width('100%')
+ }
+ }
+ }.margin({ bottom: $r('app.float.bottom_size') })
+
+ Column() {
+ Divider().height($r('app.float.divider_height')).color(0xCCCCCC);
+ Column() {
+ Text($r('app.string.look_up'))
+ .width('100%')
+ .fontSize($r('app.float.dialog_title_size'))
+ .margin({ bottom: $r('app.float.bottom_size') })
+ Row() {
+ Column() {
+ Text($r('app.string.btn_search'))
+ .width('15%')
+ .fontSize($r('app.float.search_size'))
+ .margin({ left: '35%' })
+ }
+
+ Column() {
+ Image($r('app.media.ic_public_arrow_right'))
+ .fillColor(Color.Black)
+ .width('10%')
+ .height('4%')
+ }
+ }
+ .id('btn_search')
+ .width('100%')
+ .justifyContent(FlexAlign.Start)
+ .bindMenu(this.lookupCategoryMenuBuilder)
+ }
+ }.margin({ bottom: $r('app.float.bottom_size') })
+
+ Divider().height($r('app.float.divider_height')).color(0xCCCCCC)
+
+ Flex({ justifyContent: FlexAlign.SpaceAround }) {
+ Button($r('app.string.btn_cancel'))
+ .onClick(() => {
+ this.controller.close();
+ this.cancel();
+ }).backgroundColor(0xffffff)
+ .fontColor(Color.Black)
+ .id('btn_dialog_cancel')
+ Button($r('app.string.btn_confirm'))
+ .onClick(() => {
+ this.controller.close();
+ this.confirm();
+ }).backgroundColor(0xffffff)
+ .fontColor(Color.Red)
+ .id('btn_dialog_confirm')
+ }
+ }.margin($r('app.float.margin'))
+ }
+
+ @Builder
+ lookupCategoryMenuBuilder() {
+ Menu() {
+ MenuItem({
+ content: 'Format',
+ builder: (): void => this.formatMenuBuilder()
+ });
+ }.id('menu_category')
+ }
+
+ @Builder
+ formatMenuBuilder() {
+ Menu() {
+ ForEach(this.formatList, (item: string) => {
+ LookupFilterMenuItem({ item: item })
+ .id('menu_format')
+ });
+ }
+ }
+
+ private async doLookFilterInfo(name: String): Promise {
+ this.filterInfo = imageEffect.lookupFilterInfo(name);
+ }
+}
+
+@Component
+struct LookupFilterMenuItem {
+ @State item: string = '';
+ dialogController: CustomDialogController = new CustomDialogController({
+ builder: CustomDialogDetails({
+ item: $item
+ }),
+ offset: { dx: $r('app.float.offset_x'), dy: $r('app.float.offset_y') },
+ autoCancel: true,
+ });
+
+ build() {
+ MenuItem({ content: this.item })
+ .onClick(() => {
+ if (this.dialogController != null) {
+ this.dialogController.open();
+ }
+ })
+ }
+}
+
+@CustomDialog
+struct CustomDialogDetails {
+ @Link item: string
+ controller?: CustomDialogController
+
+ build() {
+ Column() {
+ Text('Filters:\n' + imageEffect.lookupFilters(this.item))
+ .fontSize($r('app.float.filter_info_size'))
+ }
+ }
+}
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/ets/utils/ImageUtils.ets b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/ets/utils/ImageUtils.ets
new file mode 100644
index 0000000000000000000000000000000000000000..0f690a1c37b8f98d1a3aedaa178ff7f5f41e446c
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/ets/utils/ImageUtils.ets
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+
+import image from '@ohos.multimedia.image';
+
+export class ImageUtils {
+ private static instance: ImageUtils;
+
+ public static getInstance(): ImageUtils {
+ if (!ImageUtils.instance) {
+ ImageUtils.instance = new ImageUtils();
+ }
+ return ImageUtils.instance;
+ }
+
+ async getPixelMap(resource: Resource): Promise {
+ const resourceStr = getContext(this).resourceManager;
+ let imageBuffer = await resourceStr.getMediaContent(resource);
+ const pixelMap = await image.createImageSource(imageBuffer.buffer as object as ArrayBuffer).createPixelMap();
+ return pixelMap;
+ }
+
+ async getPixelMapByFilePath(filePath: string): Promise {
+ const imageSource: image.ImageSource = image.createImageSource(filePath);
+ const pixelMap = await imageSource.createPixelMap();
+ return pixelMap;
+ }
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/ets/utils/PermissionUtils.ets b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/ets/utils/PermissionUtils.ets
new file mode 100644
index 0000000000000000000000000000000000000000..73d8b7d303f3e5d0a7ff8821227267238c473870
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/ets/utils/PermissionUtils.ets
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+
+import { abilityAccessCtrl, bundleManager, common, Permissions } from '@kit.AbilityKit';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { promptAction } from '@kit.ArkUI';
+
+export const permissions: Permissions[] = ['ohos.permission.CAMERA'];
+
+async function checkPermissionGrant(permission: Permissions): Promise {
+ // 1. 创建应用权限管理器
+ let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
+ let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;
+
+ // 2. 获取应用程序的accessTokenID
+ let tokenId: number = 0;
+ try {
+ let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(
+ bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
+ let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
+ tokenId = appInfo.accessTokenId;
+ } catch (error) {
+ const err: BusinessError = error as BusinessError;
+ console.error(`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`);
+ }
+
+ // 3. 校验应用是否被授予权限
+ try {
+ grantStatus = await atManager.checkAccessToken(tokenId, permission);
+ } catch (error) {
+ const err: BusinessError = error as BusinessError;
+ console.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`);
+ }
+
+ return grantStatus;
+}
+
+
+export async function checkAndRequestPermissions(permissions: Permissions[], context: common.UIAbilityContext):
+ Promise {
+ let grantStatus: abilityAccessCtrl.GrantStatus = await checkPermissionGrant(permissions[0]);
+
+ if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
+ // 已经授权,可以继续访问目标操作
+ promptAction.showToast({
+ message: 'permission succeed!', // 显示文本
+ })
+ } else {
+ // 申请麦克风权限
+ reqPermissionsFromUser(permissions, context);
+ }
+}
+
+// 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContext
+export function reqPermissionsFromUser(permissions: Permissions[], context: common.UIAbilityContext): void {
+ // 1. 创建应用权限管理器
+ let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
+ // 2. 拉起弹框请求用户授权 requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
+ atManager.requestPermissionsFromUser(context, permissions).then((data) => {
+ let grantStatus: number[] = data.authResults;
+ let length: number = grantStatus.length;
+ for (let i = 0; i < length; i++) {
+ if (grantStatus[i] === 0) {
+ // 用户授权,可以继续访问目标操作
+ promptAction.showToast({
+ message: 'permission succeed!', // 显示文本
+ })
+ } else {
+ // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
+ promptAction.showToast({
+ message: 'user refused authorization!', // 显示文本
+ })
+ return;
+ }
+ }
+ // 授权成功
+ }).catch((err: BusinessError) => {
+ console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
+ })
+}
+
+
+
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/module.json5 b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..901eac0ee2211b3c6bbd1c2f3bbcc75a074febc6
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/module.json5
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+{
+ "module": {
+ "name": "entry",
+ "type": "entry",
+ "description": "$string:module_desc",
+ "mainElement": "EntryAbility",
+ "deviceTypes": [
+ "default",
+ "tablet"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false,
+ "pages": "$profile:main_pages",
+ "abilities": [
+ {
+ "name": "EntryAbility",
+ "srcEntry": "./ets/entryability/EntryAbility.ets",
+ "description": "$string:EntryAbility_desc",
+ "icon": "$media:icon",
+ "label": "$string:EntryAbility_label",
+ "startWindowIcon": "$media:startIcon",
+ "startWindowBackground": "$color:start_window_background",
+ "exported": true,
+ "skills": [
+ {
+ "entities": [
+ "entity.system.home"
+ ],
+ "actions": [
+ "action.system.home"
+ ]
+ }
+ ]
+ }
+ ],
+ "requestPermissions":[
+ {
+ "name" : "ohos.permission.CAMERA",
+ "reason": '$string:camera_reason',
+ "usedScene": {
+ "abilities": [
+ "FormAbility"
+ ],
+ "when":"always"
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/element/color.json b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#FFFFFF"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/element/float.json b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/element/float.json
new file mode 100644
index 0000000000000000000000000000000000000000..ab0a74ae696363379fac96661e7b22e4d1bebbf7
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/element/float.json
@@ -0,0 +1,92 @@
+{
+ "float": [
+ {
+ "name": "title_font_size",
+ "value": "20fp"
+ },
+ {
+ "name": "home_page_title_margin",
+ "value": "10"
+ },
+ {
+ "name": "home_page_title_height",
+ "value": "38"
+ },
+ {
+ "name": "title_image_width",
+ "value": "24vp"
+ },
+ {
+ "name": "title_image_height",
+ "value": "24vp"
+ },
+ {
+ "name": "title_size",
+ "value": "30"
+ },
+ {
+ "name": "filter_text_size",
+ "value": "10"
+ },
+ {
+ "name": "filter_number_size",
+ "value": "12"
+ },
+ {
+ "name": "button_width",
+ "value": "100"
+ },
+ {
+ "name": "filter_info_size",
+ "value": "16"
+ },
+ {
+ "name": "filter_info_opacity",
+ "value": "0.8"
+ },
+ {
+ "name": "divider_height",
+ "value": "2"
+ },
+ {
+ "name": "dialog_title_size",
+ "value": "18"
+ },
+ {
+ "name": "search_size",
+ "value": "20"
+ },
+ {
+ "name": "bottom_size",
+ "value": "10"
+ },
+ {
+ "name": "value_max",
+ "value": "100"
+ },
+ {
+ "name": "check_box_width",
+ "value": "10"
+ },
+ {
+ "name": "check_box_height",
+ "value": "14"
+ },
+ {
+ "name": "margin_left",
+ "value": "2"
+ },
+ {
+ "name": "margin",
+ "value": "24"
+ },
+ {
+ "name": "offset_x",
+ "value": "0"
+ },
+ {
+ "name": "offset_y",
+ "value": "220"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/element/string.json b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..7a8ea7c056bf0fead29f21fa68e789f2348f08b1
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/element/string.json
@@ -0,0 +1,48 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "ImageEffect"
+ },
+ {
+ "name": "image_edit",
+ "value": "imageEdit"
+ },
+ {
+ "name": "btn_search",
+ "value": "Search"
+ },
+ {
+ "name": "look_up",
+ "value": "LookUp"
+ },
+ {
+ "name": "btn_confirm",
+ "value": "btn_confirm"
+ },
+ {
+ "name": "btn_cancel",
+ "value": "Cancel"
+ },
+ {
+ "name": "camera_reason",
+ "value": "用于相机预览"
+ },
+ {
+ "name": "native_buffer_description",
+ "value": "此场景无图片演示,请观察日志信息"
+ },
+ {
+ "name": "select_description",
+ "value": "请选择输入场景"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/ic_1080x1920.jpg b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/ic_1080x1920.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..0c68bf944bae012f5a2a6ece0e172cd45f5308ce
Binary files /dev/null and b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/ic_1080x1920.jpg differ
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/ic_700x700.jpg b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/ic_700x700.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5df7ffe5de575590f93a1370baadeaf5513ab6cf
Binary files /dev/null and b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/ic_700x700.jpg differ
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/ic_public_arrow_right.svg b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/ic_public_arrow_right.svg
new file mode 100644
index 0000000000000000000000000000000000000000..48ed31efd130cec98c0df8b8093cb1071136608c
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/ic_public_arrow_right.svg
@@ -0,0 +1,15 @@
+
+
+
+ Public/ic_public_arrow_right
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/ic_public_search.svg b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/ic_public_search.svg
new file mode 100644
index 0000000000000000000000000000000000000000..d3cbb73618e6909fd7f99f7b471ebfca626b020c
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/ic_public_search.svg
@@ -0,0 +1,13 @@
+
+
+ Public/ic_public_search_filled
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/ic_public_settings.svg b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/ic_public_settings.svg
new file mode 100644
index 0000000000000000000000000000000000000000..06e75695970159e41db7cc8d37f6c8f684ee25a5
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/ic_public_settings.svg
@@ -0,0 +1,13 @@
+
+
+ Public/ic_public_settings
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/icon.png b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..cd45accb1dfd2fd0da16c732c72faa6e46b26521
Binary files /dev/null and b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/icon.png differ
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/startIcon.png b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/startIcon.png
new file mode 100644
index 0000000000000000000000000000000000000000..366f76459ffd4494ec40d0ddd5c59385b9c5da11
Binary files /dev/null and b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/media/startIcon.png differ
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/profile/main_pages.json b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/profile/main_pages.json
new file mode 100644
index 0000000000000000000000000000000000000000..000ae3dbfb3815af6ac343d515ad23a2b973082e
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/base/profile/main_pages.json
@@ -0,0 +1,5 @@
+{
+ "src": [
+ "pages/ImageEditPage"
+ ]
+}
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/en_US/element/string.json b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/en_US/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..27653e87f7d312db10a08ed5c9fdcf343ffa58c2
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/en_US/element/string.json
@@ -0,0 +1,40 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "ImageEffect"
+ },
+ {
+ "name": "btn_search",
+ "value": "Search"
+ },
+ {
+ "name": "look_up",
+ "value": "LookUp"
+ },
+ {
+ "name": "btn_confirm",
+ "value": "Confirm"
+ },
+ {
+ "name": "btn_cancel",
+ "value": "Cancel"
+ },
+ {
+ "name": "image_edit",
+ "value": "imageEdit"
+ },
+ {
+ "name": "camera_reason",
+ "value": "For camera preview"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/zh_CN/element/string.json b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/zh_CN/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..3006b4b15ceda27ff80e500a00be05fd2725867e
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/main/resources/zh_CN/element/string.json
@@ -0,0 +1,48 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "模块描述"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "ImageEffect"
+ },
+ {
+ "name": "btn_search",
+ "value": "查询"
+ },
+ {
+ "name": "look_up",
+ "value": "LookUp"
+ },
+ {
+ "name": "btn_confirm",
+ "value": "确认"
+ },
+ {
+ "name": "btn_cancel",
+ "value": "取消"
+ },
+ {
+ "name": "native_buffer_description",
+ "value": "此场景无图片演示,请观察日志信息"
+ },
+ {
+ "name": "camera_reason",
+ "value": "用于相机预览"
+ },
+ {
+ "name": "image_edit",
+ "value": "imageEdit"
+ },
+ {
+ "name": "select_description",
+ "value": "请选择输入场景"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/mock/libentry.mock.ets b/code/DocsSample/Media/Image/ImageEffect/entry/src/mock/libentry.mock.ets
new file mode 100644
index 0000000000000000000000000000000000000000..82fa70b5693ddab96d237d2d17d943d866b61465
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/mock/libentry.mock.ets
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+const NativeMock: Record = {
+ 'add': (a: number, b: number) => {
+ return a + b;
+ },
+};
+
+export default NativeMock;
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/mock/mock-config.json5 b/code/DocsSample/Media/Image/ImageEffect/entry/src/mock/mock-config.json5
new file mode 100644
index 0000000000000000000000000000000000000000..b9f11f82926f2ff0add26f1393f04785c4e250ab
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/mock/mock-config.json5
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+{
+ "libentry.so": {
+ "source": "src/mock/libentry.mock.ets"
+ }
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/test/Ability.test.ets b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/test/Ability.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..d591c1910ee11325a122aae3027c7d5c6f25bf7c
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/test/Ability.test.ets
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+
+import hilog from '@ohos.hilog';
+import { describe, it } from '@ohos/hypium';
+import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
+import { Driver, ON } from '@ohos.UiTest';
+import { getString } from '../utils/ResourceUtil';
+
+const TAG: string = '[Sample_ImageEffect]';
+const DOMAIN: number = 0xF811;
+const BUNDLE: string = 'ImageEffect';
+const DELAY_LONG: number = 1000;
+const DELAY_SHORT: number = 300;
+const SLIDER_Y: number = 100; // 滑动组件向右滑动距离,单位像素点
+
+async function openDialog() {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickSettingBtn_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ let btSetting: string = getString($r('app.string.btn_setting'));
+ hilog.info(DOMAIN, TAG, BUNDLE + 'lsq:' + btSetting);
+ await driver.assertComponentExist(ON.id(btSetting));
+ let setting = await driver.findComponent(ON.id(btSetting));
+ await setting.click();
+ await driver.delayMs(DELAY_SHORT);
+ let confirm: string = getString($r('app.string.btn_dialog_confirm'));
+ await driver.assertComponentExist(ON.id(confirm));
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickSettingBtn_001 end');
+}
+
+async function confirmDialog() {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickConfirmBtn_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ let btnDialogConfirm: string = getString($r('app.string.btn_dialog_confirm'));
+ await driver.assertComponentExist(ON.id(btnDialogConfirm));
+ let dialogConfirm = await driver.findComponent(ON.id(btnDialogConfirm));
+ await dialogConfirm.click();
+ await driver.delayMs(DELAY_SHORT);
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickConfirmBtn_001 end');
+}
+
+async function apply() {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickApplyBtn_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ let btnApply: string = getString($r('app.string.btn_apply'));
+ await driver.assertComponentExist(ON.id(btnApply));
+ let apply = await driver.findComponent(ON.id(btnApply));
+ await apply.click();
+ await driver.delayMs(DELAY_SHORT);
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickApplyBtn_001 end');
+}
+
+export default function abilityTest() {
+ describe('ActsAbilityTest', () => {
+ /**
+ * @tc.number StartAbility_001
+ * @tc.name StartAbility_001
+ * @tc.desc 启动Ability
+ */
+ it('StartAbility_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'StartAbility_001 begin');
+ let abilityDelegatorRegistry = AbilityDelegatorRegistry.getAbilityDelegator();
+ await abilityDelegatorRegistry.executeShellCommand('aa start -a EntryAbility -b com.samples.ImageEffect');
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'StartAbility_001 end');
+ })
+
+ /**
+ * @tc.number RequestPermissionFunction_001
+ * @tc.name RequestPermissionFunction_001
+ * @tc.desc 获取权限
+ */
+ it('RequestPermissionFunction_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'RequestPermissionFunction_001 begin');
+ let driver: Driver = Driver.create();
+ await driver.delayMs(DELAY_LONG);
+ let tipAllow: string = getString($r('app.string.allow'));
+ await driver.assertComponentExist(ON.text(tipAllow));
+ let stack = await driver.findComponent(ON.text(tipAllow));
+ await stack.click();
+ await driver.assertComponentExist(ON.text(getString($r('app.string.Permission_Succeed'))));
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'RequestPermissionFunction_001 end');
+ })
+
+ /**
+ * @tc.number ClickDialogCancelBtn_001
+ * @tc.name ClickDialogCancelBtn_001
+ * @tc.desc 点击dialog取消按钮,关闭参数页面
+ */
+ it('ClickDialogCancelBtn_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickDialogCancelBtn_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ await openDialog();
+ let btnCancel: string = getString($r('app.string.btn_dialog_cancel'));
+ await driver.assertComponentExist(ON.id(btnCancel));
+ let cancel = await driver.findComponent(ON.id(btnCancel));
+ await cancel.click();
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickDialogCancelBtn_001 end');
+ })
+
+ /**
+ * @tc.number AdjustBrightness_001
+ * @tc.name AdjustBrightness_001
+ * @tc.desc Brightness滤镜
+ */
+ it('AdjustBrightness_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'AdjustBrightness_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ await openDialog();
+ let checkboxBrightnessStr: string = getString($r('app.string.checkbox_brightness'));
+ await driver.assertComponentExist(ON.id(checkboxBrightnessStr));
+ let checkboxBrightness = await driver.findComponent(ON.id(checkboxBrightnessStr));
+ await checkboxBrightness.click();
+ await driver.delayMs(DELAY_SHORT);
+ let sliderBrightnessStr: string = getString($r('app.string.slider_brightness'));
+ await driver.assertComponentExist(ON.id(sliderBrightnessStr));
+ let sliderBrightness = await driver.findComponent(ON.id(sliderBrightnessStr));
+ let point = await sliderBrightness.getBoundsCenter();
+ await driver.swipe(point.x, point.y, point.x + SLIDER_Y, point.y);
+ await driver.delayMs(DELAY_SHORT);
+ await confirmDialog();
+ await apply();
+ await driver.delayMs(DELAY_SHORT);
+ await driver.assertComponentExist(ON.text(getString($r('app.string.PixelMapNative_Succeed'))));
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'AdjustBrightness_001 end');
+ })
+
+ /**
+ * @tc.number AdjustContrast_001
+ * @tc.name AdjustContrast_001
+ * @tc.desc Contrast滤镜
+ */
+ it('AdjustContrast_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'AdjustContrast_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ await openDialog();
+ let checkboxContrastStr: string = getString($r('app.string.checkbox_contrast'));
+ await driver.assertComponentExist(ON.id(checkboxContrastStr));
+ let checkboxContrast = await driver.findComponent(ON.id(checkboxContrastStr));
+ await checkboxContrast.click();
+ await driver.delayMs(DELAY_SHORT);
+ let sliderContrastStr: string = getString($r('app.string.slider_contrast'));
+ await driver.assertComponentExist(ON.id(sliderContrastStr));
+ let sliderContrast = await driver.findComponent(ON.id(sliderContrastStr));
+ let point = await sliderContrast.getBoundsCenter();
+ await driver.swipe(point.x, point.y, point.x + SLIDER_Y, point.y);
+ await driver.delayMs(DELAY_SHORT);
+ await confirmDialog();
+ await apply();
+ await driver.delayMs(DELAY_SHORT);
+ await driver.assertComponentExist(ON.text(getString($r('app.string.PixelMapNative_Succeed'))));
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'AdjustContrast_001 end');
+ })
+
+ /**
+ * @tc.number AdjustCrop_001
+ * @tc.name AdjustCrop_001
+ * @tc.desc Crop滤镜
+ */
+ it('AdjustCrop_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'AdjustCrop_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ await openDialog();
+ let checkboxCropStr: string = getString($r('app.string.checkbox_crop'));
+ await driver.assertComponentExist(ON.id(checkboxCropStr));
+ let checkboxCrop = await driver.findComponent(ON.id(checkboxCropStr));
+ await checkboxCrop.click();
+ await driver.delayMs(DELAY_SHORT);
+ let sliderCropStr: string = getString($r('app.string.slider_crop'));
+ await driver.assertComponentExist(ON.id(sliderCropStr));
+ let sliderCrop = await driver.findComponent(ON.id(sliderCropStr));
+ let point = await sliderCrop.getBoundsCenter();
+ await driver.swipe(point.x, point.y, point.x + SLIDER_Y, point.y);
+ await driver.delayMs(DELAY_SHORT);
+ await confirmDialog();
+ await apply();
+ await driver.delayMs(DELAY_SHORT);
+ await driver.assertComponentExist(ON.text(getString($r('app.string.PixelMapNative_Succeed'))));
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'AdjustCrop_001 end');
+ })
+
+ /**
+ * @tc.number AdjustCustomBrightness_001
+ * @tc.name AdjustCustomBrightness_001
+ * @tc.desc CustomBrightness滤镜
+ */
+ it('AdjustCustomBrightness_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'AdjustCustomBrightness_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ await openDialog();
+ let checkboxCustomStr: string = getString($r('app.string.checkbox_custom_brightness'));
+ await driver.assertComponentExist(ON.id(checkboxCustomStr));
+ let checkboxCustom = await driver.findComponent(ON.id(checkboxCustomStr));
+ await checkboxCustom.click();
+ await driver.delayMs(DELAY_SHORT);
+ let sliderCustomStr: string = getString($r('app.string.slider_custom_brightness'));
+ await driver.assertComponentExist(ON.id(sliderCustomStr));
+ let sliderCustom = await driver.findComponent(ON.id(sliderCustomStr));
+ let point = await sliderCustom.getBoundsCenter();
+ await driver.swipe(point.x, point.y, point.x + SLIDER_Y, point.y);
+ await driver.delayMs(DELAY_SHORT);
+ await confirmDialog();
+ await apply();
+ await driver.delayMs(DELAY_SHORT);
+ await driver.assertComponentExist(ON.text(getString($r('app.string.PixelMapNative_Succeed'))));
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'AdjustCustomBrightness_001 end');
+ })
+
+ /**
+ * @tc.number AdjustCustomCrop_001
+ * @tc.name AdjustCustomCrop_001
+ * @tc.desc CustomCrop滤镜
+ */
+ it('AdjustCustomCrop_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'AdjustCustomCrop_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ await openDialog();
+ let checkboxCustomStr: string = getString($r('app.string.checkbox_custom_crop'));
+ await driver.assertComponentExist(ON.id(checkboxCustomStr));
+ let checkboxCustom = await driver.findComponent(ON.id(checkboxCustomStr));
+ await checkboxCustom.click();
+ await driver.delayMs(DELAY_SHORT);
+ let sliderCustomStr: string = getString($r('app.string.slider_custom_crop'));
+ await driver.assertComponentExist(ON.id(sliderCustomStr));
+ let sliderCustom = await driver.findComponent(ON.id(sliderCustomStr));
+ let point = await sliderCustom.getBoundsCenter();
+ await driver.swipe(point.x, point.y, point.x + SLIDER_Y, point.y);
+ await driver.delayMs(DELAY_SHORT);
+ await confirmDialog();
+ await apply();
+ await driver.delayMs(DELAY_SHORT);
+ await driver.assertComponentExist(ON.text(getString($r('app.string.PixelMapNative_Succeed'))));
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'AdjustCustomCrop_001 end');
+ })
+
+ /**
+ * @tc.number ClickResetBtn_001
+ * @tc.name ClickResetBtn_001
+ * @tc.desc 点击Reset按钮,图像效果复原
+ */
+ it('ClickResetBtn_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickResetBtn_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ let btnReset: string = getString($r('app.string.btn_reset'));
+ await driver.assertComponentExist(ON.id(btnReset));
+ let reset = await driver.findComponent(ON.id(btnReset));
+ await reset.click();
+ await driver.delayMs(DELAY_SHORT);
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickResetBtn_001 end');
+ })
+
+ /**
+ * @tc.number ClickBrightnessSearchBtn_001
+ * @tc.name ClickBrightnessSearchBtn_001
+ * @tc.desc Brightness查询按钮,显示Brightness滤镜信息
+ */
+ it('ClickBrightnessSearchBtn_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickBrightnessSearchBtn_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ await openDialog();
+ let btnBrightnessSearch: string = getString($r('app.string.btn_search_brightness'));
+ await driver.assertComponentExist(ON.id(btnBrightnessSearch));
+ let brightnessSearch = await driver.findComponent(ON.id(btnBrightnessSearch));
+ await brightnessSearch.click();
+ await driver.delayMs(DELAY_SHORT);
+ let filterInfoStr: string = getString($r('app.string.filter_info_menu'));
+ await driver.assertComponentExist(ON.id(filterInfoStr));
+ await driver.findComponent(ON.id(filterInfoStr));
+ await driver.delayMs(DELAY_LONG);
+ await driver.assertComponentExist(ON.text(getString($r('app.string.query_brightness'))));
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickBrightnessSearchBtn_001 end');
+ })
+
+ /**
+ * @tc.number ClickContrastSearchBtn_001
+ * @tc.name ClickContrastSearchBtn_001
+ * @tc.desc Contrast查询按钮,显示Contrast滤镜信息
+ */
+ it('ClickContrastSearchBtn_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickContrastSearchBtn_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ await openDialog();
+ let btnContrastSearch: string = getString($r('app.string.btn_search_contrast'));
+ await driver.assertComponentExist(ON.id(btnContrastSearch));
+ let contrastSearch = await driver.findComponent(ON.id(btnContrastSearch));
+ await contrastSearch.click();
+ await driver.delayMs(DELAY_SHORT);
+ let filterInfoStr: string = getString($r('app.string.filter_info_menu'));
+ await driver.assertComponentExist(ON.id(filterInfoStr));
+ await driver.findComponent(ON.id(filterInfoStr));
+ await driver.delayMs(DELAY_LONG);
+ await driver.assertComponentExist(ON.text(getString($r('app.string.query_contrast'))));
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickContrastSearchBtn_001 end');
+ })
+
+ /**
+ * @tc.number ClickCropSearchBtn_001
+ * @tc.name ClickCropSearchBtn_001
+ * @tc.desc Crop查询按钮,显示Crop滤镜信息
+ */
+ it('ClickCropSearchBtn_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickCropSearchBtn_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ await openDialog();
+ let btnCropSearch: string = getString($r('app.string.btn_search_crop'));
+ await driver.assertComponentExist(ON.id(btnCropSearch));
+ let cropSearch = await driver.findComponent(ON.id(btnCropSearch));
+ await cropSearch.click();
+ await driver.delayMs(DELAY_SHORT);
+ let filterInfoStr: string = getString($r('app.string.filter_info_menu'));
+ await driver.assertComponentExist(ON.id(filterInfoStr));
+ await driver.findComponent(ON.id(filterInfoStr));
+ await driver.delayMs(DELAY_LONG);
+ await driver.assertComponentExist(ON.text(getString($r('app.string.query_crop'))));
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickCropSearchBtn_001 end');
+ })
+
+ /**
+ * @tc.number ClickCustomBrightnessSearchBtn_001
+ * @tc.name ClickCustomBrightnessSearchBtn_001
+ * @tc.desc CustomBrightness查询按钮,显示CustomBrightness滤镜信息
+ */
+ it('ClickCustomBrightnessSearchBtn_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickCustomBrightnessSearchBtn_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ await openDialog();
+ let btnCustomSearch: string = getString($r('app.string.btn_search_custom_brightness'));
+ await driver.assertComponentExist(ON.id(btnCustomSearch));
+ let customSearch = await driver.findComponent(ON.id(btnCustomSearch));
+ await customSearch.click();
+ await driver.delayMs(DELAY_SHORT);
+ let filterInfoStr: string = getString($r('app.string.filter_info_menu'));
+ await driver.assertComponentExist(ON.id(filterInfoStr));
+ await driver.findComponent(ON.id(filterInfoStr));
+ await driver.delayMs(DELAY_LONG);
+ await driver.assertComponentExist(ON.text(getString($r('app.string.query_custom_brightness'))));
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickCustomBrightnessSearchBtn_001 end');
+ })
+
+ /**
+ * @tc.number ClickCustomCropSearchBtn_001
+ * @tc.name ClickCustomCropSearchBtn_001
+ * @tc.desc CustomCrop查询按钮,显示CustomBrightness滤镜信息
+ */
+ it('ClickCustomCropSearchBtn_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickCustomCropSearchBtn_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ await openDialog();
+ let btnCustomSearch: string = getString($r('app.string.btn_search_custom_crop'));
+ await driver.assertComponentExist(ON.id(btnCustomSearch));
+ let customSearch = await driver.findComponent(ON.id(btnCustomSearch));
+ await customSearch.click();
+ await driver.delayMs(DELAY_SHORT);
+ let filterInfoStr: string = getString($r('app.string.filter_info_menu'));
+ await driver.assertComponentExist(ON.id(filterInfoStr));
+ await driver.findComponent(ON.id(filterInfoStr));
+ await driver.delayMs(DELAY_LONG);
+ await driver.assertComponentExist(ON.text(getString($r('app.string.query_custom_crop'))));
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickCustomCropSearchBtn_001 end');
+ })
+
+ /**
+ * @tc.number ClickSearchBtn_001
+ * @tc.name ClickSearchBtn_001
+ * @tc.desc 点击查询按钮,显示滤镜滤镜信息
+ */
+ it('ClickSearchBtn_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickSearchBtn_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ await openDialog();
+ let btnSearch: string = getString($r('app.string.btn_search'));
+ await driver.assertComponentExist(ON.id(btnSearch));
+ let search = await driver.findComponent(ON.id(btnSearch));
+ await search.click();
+ await driver.delayMs(DELAY_SHORT);
+ let menuCategory: string = getString($r('app.string.menu_category'));
+ await driver.assertComponentExist(ON.id(menuCategory));
+ let category = await driver.findComponent(ON.id(menuCategory));
+ await category.click();
+ await driver.delayMs(DELAY_SHORT);
+ let menuFormat: string = getString($r('app.string.menu_format'));
+ await driver.assertComponentExist(ON.id(menuFormat));
+ let format = await driver.findComponent(ON.id(menuFormat));
+ await format.click();
+ await driver.delayMs(DELAY_LONG);
+ await driver.assertComponentExist(ON.text(getString($r('app.string.query_rgba_8888'))));
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'ClickSearchBtn_001 end');
+ })
+
+ /**
+ * @tc.number NativeBuffer_001
+ * @tc.name NativeBuffer_001
+ * @tc.desc 切换输入场景为NativeBuffer,应用滤镜
+ */
+ it('NativeBuffer_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'NativeBuffer_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ await openDialog();
+ await driver.assertComponentExist(ON.id('select_input'));
+ let select = await driver.findComponent(ON.id('select_input'));
+ await select.click();
+ await driver.delayMs(DELAY_SHORT);
+ let selectNativeBufferStr: string = getString($r('app.string.NativeBuffer'));
+ await driver.assertComponentExist(ON.text(selectNativeBufferStr));
+ let selectNativeBuffer = await driver.findComponent(ON.text(selectNativeBufferStr));
+ await selectNativeBuffer.click();
+ await confirmDialog();
+ await apply();
+ await driver.delayMs(DELAY_SHORT);
+ await driver.assertComponentExist(ON.text(getString($r('app.string.NativeBuffer_Succeed'))));
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'NativeBuffer_001 end');
+ })
+
+ /**
+ * @tc.number URI_001
+ * @tc.name URI_001
+ * @tc.desc 切换输入场景为URI,应用滤镜
+ */
+ it('URI_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'URI_001 begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ await openDialog();
+ await driver.assertComponentExist(ON.id('select_input'));
+ let select = await driver.findComponent(ON.id('select_input'));
+ await select.click();
+ await driver.delayMs(DELAY_SHORT);
+ let selectURIStr: string = getString($r('app.string.URI'));
+ await driver.assertComponentExist(ON.text(selectURIStr));
+ let selectURI = await driver.findComponent(ON.text(selectURIStr));
+ await selectURI.click();
+ await confirmDialog();
+ await apply();
+ await driver.delayMs(DELAY_SHORT);
+ await driver.assertComponentExist(ON.text(getString($r('app.string.URI_Succeed'))));
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'URI_001 end');
+ })
+
+ /**
+ * @tc.number NativeWindow_001
+ * @tc.name NativeWindow_001
+ * @tc.desc 切换输入场景为NativeWindow,应用滤镜
+ */
+ it('NativeWindow_001', 0, async (done: Function) => {
+ hilog.info(DOMAIN, TAG, BUNDLE + 'NativeWindow begin');
+ let driver = Driver.create();
+ await driver.delayMs(DELAY_SHORT);
+ await openDialog();
+ await driver.assertComponentExist(ON.id('select_input'));
+ let select = await driver.findComponent(ON.id('select_input'));
+ await select.click();
+ await driver.delayMs(DELAY_SHORT);
+ let selectNativeWindowStr: string = getString($r('app.string.NativeWindow'));
+ await driver.assertComponentExist(ON.text(selectNativeWindowStr));
+ let selectNativeWindow = await driver.findComponent(ON.text(selectNativeWindowStr));
+ await selectNativeWindow.click();
+ await confirmDialog();
+ await apply();
+ await driver.delayMs(DELAY_SHORT);
+ await driver.assertComponentExist(ON.text(getString($r('app.string.NativeWindow_Succeed'))));
+ done();
+ hilog.info(DOMAIN, TAG, BUNDLE + 'NativeWindow end');
+ })
+ })
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/test/List.test.ets b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/test/List.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..1eac52fcebe8958e19a7b8fed2e8f39c520a3e42
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/test/List.test.ets
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+
+import abilityTest from './Ability.test';
+
+export default function testsuite() {
+ abilityTest();
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/testability/TestAbility.ets b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/testability/TestAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..29fff7b38662d6b311c35ee5d86741097085289c
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/testability/TestAbility.ets
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+
+import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
+import { abilityDelegatorRegistry } from '@kit.TestKit';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { window } from '@kit.ArkUI';
+import { Hypium } from '@ohos/hypium';
+import testsuite from '../test/List.test';
+
+export default class TestAbility extends UIAbility {
+ onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate');
+ hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');
+ hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? '');
+ let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator;
+ abilityDelegator = abilityDelegatorRegistry.getAbilityDelegator();
+ let abilityDelegatorArguments: abilityDelegatorRegistry.AbilityDelegatorArgs;
+ abilityDelegatorArguments = abilityDelegatorRegistry.getArguments();
+ hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!');
+ Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
+ }
+
+ onDestroy() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy');
+ }
+
+ onWindowStageCreate(windowStage: window.WindowStage) {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate');
+ windowStage.loadContent('testability/pages/Index', (err, data) => {
+ if (err.code) {
+ hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
+ return;
+ }
+ hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s',
+ JSON.stringify(data) ?? '');
+ });
+ }
+
+ onWindowStageDestroy() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy');
+ }
+
+ onForeground() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground');
+ }
+
+ onBackground() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground');
+ }
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/testability/pages/Index.ets b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/testability/pages/Index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..4485363990eb700840c40779f2fa9b057c17c230
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/testability/pages/Index.ets
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2024 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.
+ */
+
+@Entry
+@Component
+struct Index {
+ @State message: string = 'Hello World';
+
+ build() {
+ Row() {
+ Column() {
+ Text(this.message)
+ .fontWeight(FontWeight.Bold)
+ }
+ .width('100%')
+ }
+ .height('100%')
+ }
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ets b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ets
new file mode 100644
index 0000000000000000000000000000000000000000..c45af6753a33cb2f60908304a1da18f90a55d0c7
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ets
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+
+import { abilityDelegatorRegistry, TestRunner } from '@kit.TestKit';
+import { UIAbility, Want } from '@kit.AbilityKit';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { resourceManager } from '@kit.LocalizationKit';
+import { util } from '@kit.ArkTS';
+
+let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator;
+let abilityDelegatorArguments: abilityDelegatorRegistry.AbilityDelegatorArgs;
+let jsonPath: string = 'mock/mock-config.json';
+let tag: string = 'testTag';
+
+async function onAbilityCreateCallback(data: UIAbility) {
+ hilog.info(0x0000, 'testTag', 'onAbilityCreateCallback, data: ${}', JSON.stringify(data));
+}
+
+async function addAbilityMonitorCallback(err: BusinessError) {
+ hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? '');
+}
+
+export default class OpenHarmonyTestRunner implements TestRunner {
+ constructor() {
+ }
+
+ onPrepare() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare');
+ }
+
+ async onRun() {
+ let tag = 'testTag';
+ hilog.info(0x0000, tag, '%{public}s', 'OpenHarmonyTestRunner onRun run');
+ abilityDelegatorArguments = abilityDelegatorRegistry.getArguments()
+ abilityDelegator = abilityDelegatorRegistry.getAbilityDelegator()
+ let moduleName = abilityDelegatorArguments.parameters['-m'];
+ let context = abilityDelegator.getAppContext().getApplicationContext().createModuleContext(moduleName);
+ let mResourceManager = context.resourceManager;
+ await checkMock(abilityDelegator, mResourceManager);
+ const bundleName = abilityDelegatorArguments.bundleName;
+ const testAbilityName: string = 'TestAbility';
+ let lMonitor: abilityDelegatorRegistry.AbilityMonitor = {
+ abilityName: testAbilityName,
+ onAbilityCreate: onAbilityCreateCallback,
+ moduleName: moduleName
+ };
+ abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
+ const want: Want = {
+ bundleName: bundleName,
+ abilityName: testAbilityName,
+ moduleName: moduleName
+ };
+ abilityDelegator.startAbility(want, (err: BusinessError, data: void) => {
+ hilog.info(0x0000, tag, 'startAbility : err : %{public}s', JSON.stringify(err) ?? '');
+ hilog.info(0x0000, tag, 'startAbility : data : %{public}s', JSON.stringify(data) ?? '');
+ })
+ hilog.info(0x0000, tag, '%{public}s', 'OpenHarmonyTestRunner onRun end');
+ }
+}
+
+async function checkMock(abilityDelegator: abilityDelegatorRegistry.AbilityDelegator, resourceManager: resourceManager.ResourceManager) {
+ let rawFile: Uint8Array;
+ try {
+ rawFile = resourceManager.getRawFileContentSync(jsonPath);
+ hilog.info(0x0000, tag, 'MockList file exists');
+ let mockStr: string = util.TextDecoder.create("utf-8", { ignoreBOM: true }).decodeWithStream(rawFile);
+ let mockMap: Record = getMockList(mockStr);
+ try {
+ abilityDelegator.setMockList(mockMap)
+ } catch (error) {
+ let code = (error as BusinessError).code;
+ let message = (error as BusinessError).message;
+ hilog.error(0x0000, tag, `abilityDelegator.setMockList failed, error code: ${code}, message: ${message}.`);
+ }
+ } catch (error) {
+ let code = (error as BusinessError).code;
+ let message = (error as BusinessError).message;
+ hilog.error(0x0000, tag, `ResourceManager:callback getRawFileContent failed, error code: ${code}, message: ${message}.`);
+ }
+}
+
+function getMockList(jsonStr: string) {
+ let jsonObj: Record = JSON.parse(jsonStr);
+ let map: Map = new Map(Object.entries(jsonObj));
+ let mockList: Record = {};
+ map.forEach((value: object, key: string) => {
+ let realValue: string = value['source'].toString();
+ mockList[key] = realValue;
+ });
+ hilog.info(0x0000, tag, '%{public}s', 'mock-json value:' + JSON.stringify(mockList) ?? '');
+ return mockList;
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/utils/ResourceUtil.ets b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/utils/ResourceUtil.ets
new file mode 100644
index 0000000000000000000000000000000000000000..2f9ce1c69f2ce87df5b40069123735ed279055f8
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/ets/utils/ResourceUtil.ets
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+
+import abilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
+
+const delegator = abilityDelegatorRegistry.getAbilityDelegator();
+
+export function getString(resourceData: Resource): string {
+ let manage = delegator.getAppContext().resourceManager;
+ return manage.getStringSync(resourceData)
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/module.json5 b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..d01177ee217f3b90c539608d0e4ae624054e485d
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/module.json5
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+{
+ "module": {
+ "name": "entry_test",
+ "type": "feature",
+ "description": "$string:module_test_desc",
+ "mainElement": "TestAbility",
+ "deviceTypes": [
+ "default",
+ "tablet"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false,
+ "pages": "$profile:test_pages",
+ "abilities": [
+ {
+ "name": "TestAbility",
+ "srcEntry": "./ets/testability/TestAbility.ets",
+ "description": "$string:TestAbility_desc",
+ "icon": "$media:icon",
+ "label": "$string:TestAbility_label",
+ "exported": true,
+ "startWindowIcon": "$media:icon",
+ "startWindowBackground": "$color:start_window_background",
+ "skills": [
+ {
+ "actions": [
+ "action.system.home"
+ ],
+ "entities": [
+ "entity.system.home"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/base/element/color.json b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/base/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#FFFFFF"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/base/element/string.json b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..6dc7d26630af72d76e9ccc7bfdf023db6a8a4905
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/base/element/string.json
@@ -0,0 +1,197 @@
+{
+ "string": [
+ {
+ "name": "module_test_desc",
+ "value": "test ability description"
+ },
+ {
+ "name": "TestAbility_desc",
+ "value": "the test ability"
+ },
+ {
+ "name": "TestAbility_label",
+ "value": "test label"
+ },
+ {
+ "name": "btn_setting",
+ "value": "btn_setting"
+ },
+ {
+ "name": "btn_dialog_confirm",
+ "value": "btn_dialog_confirm"
+ },
+ {
+ "name": "btn_dialog_cancel",
+ "value": "btn_dialog_cancel"
+ },
+ {
+ "name": "checkbox_brightness",
+ "value": "checkbox_brightness"
+ },
+ {
+ "name": "slider_brightness",
+ "value": "slider_brightness"
+ },
+ {
+ "name": "btn_apply",
+ "value": "btn_apply"
+ },
+ {
+ "name": "btn_reset",
+ "value": "btn_reset"
+ },
+ {
+ "name": "checkbox_contrast",
+ "value": "checkbox_contrast"
+ },
+ {
+ "name": "slider_contrast",
+ "value": "slider_contrast"
+ },
+ {
+ "name": "checkbox_crop",
+ "value": "checkbox_crop"
+ },
+ {
+ "name": "slider_crop",
+ "value": "slider_crop"
+ },
+ {
+ "name": "checkbox_custom_brightness",
+ "value": "checkbox_custom_brightness"
+ },
+ {
+ "name": "checkbox_custom_crop",
+ "value": "checkbox_custom_crop"
+ },
+ {
+ "name": "slider_custom_brightness",
+ "value": "slider_custom_brightness"
+ },
+ {
+ "name": "slider_custom_crop",
+ "value": "slider_custom_crop"
+ },
+ {
+ "name": "btn_search_brightness",
+ "value": "btn_search_brightness"
+ },
+ {
+ "name": "filter_info_menu",
+ "value": "filter_info_menu"
+ },
+ {
+ "name": "btn_search_contrast",
+ "value": "btn_search_contrast"
+ },
+ {
+ "name": "btn_search_crop",
+ "value": "btn_search_crop"
+ },
+ {
+ "name": "btn_search_custom_brightness",
+ "value": "btn_search_custom_brightness"
+ },
+ {
+ "name": "btn_search_custom_crop",
+ "value": "btn_search_custom_crop"
+ },
+ {
+ "name": "slider_custom",
+ "value": "slider_custom"
+ },
+ {
+ "name": "checkbox_custom",
+ "value": "checkbox_custom"
+ },
+ {
+ "name": "btn_search",
+ "value": "btn_search"
+ },
+ {
+ "name": "menu_category",
+ "value": "menu_category"
+ },
+ {
+ "name": "menu_format",
+ "value": "menu_format"
+ },
+ {
+ "name": "btn_search_custom",
+ "value": "btn_search_custom"
+ },
+ {
+ "name": "allow",
+ "value": "允许"
+ },
+ {
+ "name": "native_buffer_description",
+ "value": "此场景无图片演示,请观察日志信息"
+ },
+ {
+ "name": "select_description",
+ "value": "请选择输入场景"
+ },
+ {
+ "name": "PixelmapNative",
+ "value": "PixelmapNative"
+ },
+ {
+ "name": "NativeBuffer",
+ "value": "NativeBuffer"
+ },
+ {
+ "name": "URI",
+ "value": "URI"
+ },
+ {
+ "name": "NativeWindow",
+ "value": "NativeWindow"
+ },
+ {
+ "name": "PixelMapNative_Succeed",
+ "value": "apply PixelMapNative succeed!"
+ },
+ {
+ "name": "NativeBuffer_Succeed",
+ "value": "apply NativeBuffer succeed!"
+ },
+ {
+ "name": "URI_Succeed",
+ "value": "apply URI succeed!"
+ },
+ {
+ "name": "NativeWindow_Succeed",
+ "value": "apply NativeWindow succeed!"
+ },
+ {
+ "name": "Permission_Succeed",
+ "value": "permission succeed!"
+ },
+ {
+ "name": "query_brightness",
+ "value": "name:Brightness, supportedBufferType: {Texture Pixel }supportedFormat: {YUVNV12 YUVNV21 RGBA8888 }"
+ },
+ {
+ "name": "query_contrast",
+ "value": "name:Contrast, supportedBufferType: {Texture Pixel }supportedFormat: {YUVNV12 YUVNV21 RGBA8888 }"
+ },
+ {
+ "name": "query_crop",
+ "value": "name:Crop, supportedBufferType: {Pixel }supportedFormat: {unknown RGBA8888 }"
+ },
+
+ {
+ "name": "query_custom_brightness",
+ "value": "name:CustomBrightness, supportedBufferType: {Pixel }supportedFormat: {RGBA8888 }"
+ },
+ {
+ "name": "query_custom_crop",
+ "value": "name:CustomCrop, supportedBufferType: {Pixel }supportedFormat: {RGBA8888 }"
+ },
+ {
+ "name": "query_rgba_8888",
+ "value": "Filters:\nsize: 5, name: Brightness | Contrast | Crop | CustomBrightness | CustomCrop"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/base/media/icon.png b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/base/media/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..cd45accb1dfd2fd0da16c732c72faa6e46b26521
Binary files /dev/null and b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/base/media/icon.png differ
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/base/profile/test_pages.json b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/base/profile/test_pages.json
new file mode 100644
index 0000000000000000000000000000000000000000..b7e7343cacb32ce982a45e76daad86e435e054fe
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/base/profile/test_pages.json
@@ -0,0 +1,5 @@
+{
+ "src": [
+ "testability/pages/Index"
+ ]
+}
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/en_US/element/string.json b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/en_US/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..8be430b5e5bc7bb24f695a48e997f056b99cee36
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/en_US/element/string.json
@@ -0,0 +1,120 @@
+{
+ "string": [
+ {
+ "name": "module_test_desc",
+ "value": "test ability description"
+ },
+ {
+ "name": "TestAbility_desc",
+ "value": "the test ability"
+ },
+ {
+ "name": "TestAbility_label",
+ "value": "test label"
+ },
+ {
+ "name": "btn_setting",
+ "value": "btn_setting"
+ },
+ {
+ "name": "btn_dialog_confirm",
+ "value": "btn_dialog_confirm"
+ },
+ {
+ "name": "btn_dialog_cancel",
+ "value": "btn_dialog_cancel"
+ },
+ {
+ "name": "checkbox_brightness",
+ "value": "checkbox_brightness"
+ },
+ {
+ "name": "slider_brightness",
+ "value": "slider_brightness"
+ },
+ {
+ "name": "btn_apply",
+ "value": "btn_apply"
+ },
+ {
+ "name": "btn_reset",
+ "value": "btn_reset"
+ },
+ {
+ "name": "checkbox_contrast",
+ "value": "checkbox_contrast"
+ },
+ {
+ "name": "slider_contrast",
+ "value": "slider_contrast"
+ },
+ {
+ "name": "checkbox_crop",
+ "value": "checkbox_crop"
+ },
+ {
+ "name": "slider_crop",
+ "value": "slider_crop"
+ },
+ {
+ "name": "checkbox_custom",
+ "value": "checkbox_custom"
+ },
+ {
+ "name": "slider_custom",
+ "value": "slider_custom"
+ },
+ {
+ "name": "btn_search_brightness",
+ "value": "btn_search_brightness"
+ },
+ {
+ "name": "filter_info_menu",
+ "value": "filter_info_menu"
+ },
+ {
+ "name": "btn_search_contrast",
+ "value": "btn_search_contrast"
+ },
+ {
+ "name": "btn_search_crop",
+ "value": "btn_search_crop"
+ },
+ {
+ "name": "btn_search_custom",
+ "value": "btn_search_custom"
+ },
+ {
+ "name": "btn_search",
+ "value": "btn_search"
+ },
+ {
+ "name": "menu_category",
+ "value": "menu_category"
+ },
+ {
+ "name": "menu_format",
+ "value": "menu_format"
+ },
+ {
+ "name": "query_brightness",
+ "value": "name:Brightness, supportedBufferType: {Texture Pixel }supportedFormat: {YUVNV12 YUVNV21 RGBA8888 }"
+ },
+ {
+ "name": "query_contrast",
+ "value": "name:Contrast"
+ },
+ {
+ "name": "query_crop",
+ "value": "name:Crop"
+ },
+ {
+ "name": "query_custom_brightness",
+ "value": "name:CustomBrightness"
+ },
+ {
+ "name": "query_custom_crop",
+ "value": "name:CustomCrop"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/zh_CN/element/string.json b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/zh_CN/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..8fc7ab33d2bb72c822d1b43a3c2fb5980099d3b7
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/ohosTest/resources/zh_CN/element/string.json
@@ -0,0 +1,100 @@
+{
+ "string": [
+ {
+ "name": "module_test_desc",
+ "value": "test ability description"
+ },
+ {
+ "name": "TestAbility_desc",
+ "value": "the test ability"
+ },
+ {
+ "name": "TestAbility_label",
+ "value": "test label"
+ },
+ {
+ "name": "btn_setting",
+ "value": "btn_setting"
+ },
+ {
+ "name": "btn_dialog_confirm",
+ "value": "btn_dialog_confirm"
+ },
+ {
+ "name": "btn_dialog_cancel",
+ "value": "btn_dialog_cancel"
+ },
+ {
+ "name": "checkbox_brightness",
+ "value": "checkbox_brightness"
+ },
+ {
+ "name": "slider_brightness",
+ "value": "slider_brightness"
+ },
+ {
+ "name": "btn_apply",
+ "value": "btn_apply"
+ },
+ {
+ "name": "btn_reset",
+ "value": "btn_reset"
+ },
+ {
+ "name": "checkbox_contrast",
+ "value": "checkbox_contrast"
+ },
+ {
+ "name": "slider_contrast",
+ "value": "slider_contrast"
+ },
+ {
+ "name": "checkbox_crop",
+ "value": "checkbox_crop"
+ },
+ {
+ "name": "slider_crop",
+ "value": "slider_crop"
+ },
+ {
+ "name": "checkbox_custom",
+ "value": "checkbox_custom"
+ },
+ {
+ "name": "slider_custom",
+ "value": "slider_custom"
+ },
+ {
+ "name": "btn_search_brightness",
+ "value": "btn_search_brightness"
+ },
+ {
+ "name": "filter_info_menu",
+ "value": "filter_info_menu"
+ },
+ {
+ "name": "btn_search_contrast",
+ "value": "btn_search_contrast"
+ },
+ {
+ "name": "btn_search_crop",
+ "value": "btn_search_crop"
+ },
+ {
+ "name": "btn_search_custom",
+ "value": "btn_search_custom"
+ },
+ {
+ "name": "btn_search",
+ "value": "btn_search"
+ },
+ {
+ "name": "menu_category",
+ "value": "menu_category"
+ },
+ {
+ "name": "menu_format",
+ "value": "menu_format"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/test/List.test.ets b/code/DocsSample/Media/Image/ImageEffect/entry/src/test/List.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..a60c87c5cbb0badf7c3fd8975034590e6fafa992
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/test/List.test.ets
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+import localUnitTest from './LocalUnit.test';
+
+export default function testsuite() {
+ localUnitTest();
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/entry/src/test/LocalUnit.test.ets b/code/DocsSample/Media/Image/ImageEffect/entry/src/test/LocalUnit.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..67e83a9c66754d010effd79867127595c74aa569
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/entry/src/test/LocalUnit.test.ets
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
+
+export default function localUnitTest() {
+ describe('localUnitTest',() => {
+ // Defines a test suite. Two parameters are supported: test suite name and test suite function.
+ beforeAll(() => {
+ // Presets an action, which is performed only once before all test cases of the test suite start.
+ // This API supports only one parameter: preset action function.
+ });
+ beforeEach(() => {
+ // Presets an action, which is performed before each unit test case starts.
+ // The number of execution times is the same as the number of test cases defined by **it**.
+ // This API supports only one parameter: preset action function.
+ });
+ afterEach(() => {
+ // Presets a clear action, which is performed after each unit test case ends.
+ // The number of execution times is the same as the number of test cases defined by **it**.
+ // This API supports only one parameter: clear action function.
+ });
+ afterAll(() => {
+ // Presets a clear action, which is performed after all test cases of the test suite end.
+ // This API supports only one parameter: clear action function.
+ });
+ it('assertContain', 0, () => {
+ // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
+ let a = 'abc';
+ let b = 'b';
+ // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
+ expect(a).assertContain(b);
+ expect(a).assertEqual(a);
+ });
+ });
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/hvigor/hvigor-config.json5 b/code/DocsSample/Media/Image/ImageEffect/hvigor/hvigor-config.json5
new file mode 100644
index 0000000000000000000000000000000000000000..3c65000c6222235ea087259854b7254b4a89d7f0
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/hvigor/hvigor-config.json5
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+{
+ "modelVersion": "5.0.0",
+ "dependencies": {
+ },
+ "execution": {
+ // "analyze": "default", /* Define the build analyze mode. Value: [ "default" | "verbose" | false ]. Default: "default" */
+ // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */
+ // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */
+ // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */
+ // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */
+ },
+ "logging": {
+ // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
+ },
+ "debugging": {
+ // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */
+ },
+ "nodeOptions": {
+ // "maxOldSpaceSize": 4096 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process */
+ }
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/hvigorfile.ts b/code/DocsSample/Media/Image/ImageEffect/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6b365cacd0191d3b1178eb6b9807b1ae0add6271
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/hvigorfile.ts
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+import { appTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/code/DocsSample/Media/Image/ImageEffect/oh-package.json5 b/code/DocsSample/Media/Image/ImageEffect/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..76e2eed90601dd2a7bea71c509c77de015b347f5
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/oh-package.json5
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2025 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.
+ */
+{
+ "modelVersion": "5.0.0",
+ "name": "imageeffect",
+ "version": "1.0.0",
+ "description": "Please describe the basic information.",
+ "main": "",
+ "author": "",
+ "license": "",
+ "dependencies": {
+ },
+ "devDependencies": {
+ "@ohos/hypium": "1.0.15",
+ "@ohos/hamock": "1.0.0"
+ }
+}
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/ohosTest.md b/code/DocsSample/Media/Image/ImageEffect/ohosTest.md
new file mode 100644
index 0000000000000000000000000000000000000000..51908a3daf88aa5c3df6511f17bec58e74aa55ad
--- /dev/null
+++ b/code/DocsSample/Media/Image/ImageEffect/ohosTest.md
@@ -0,0 +1,24 @@
+# ImageEffect测试用例归档
+
+## 用例表
+
+| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 |
+|--------------------| ---------------- | ------------------------------------------------------------ | ------------------------------ | -------- | -------- |
+| 拉起应用 | 设备正常运行 | | 成功拉起应用 | 是 | Pass |
+| 申请相机权限 | 进入主界面 | 点击允许按钮 | 成功获取相机权限 | 是 | Pass |
+| 关闭参数设置页面 | 进入参数设置页面 | 点击dialog取消按钮 | 成功关闭参数设置页面 | 是 | Pass |
+| 亮度滤镜功能 | 进入参数设置页面 | 点击Brightness按钮,滑动Brightness滑动条,点击确认与Apply按钮 | 成功调节图片亮度 | 是 | Pass |
+| 对比度滤镜功能 | 进入参数设置页面 | 点击Contrast按钮,滑动Contrast滑动条,点击确认与Apply按钮 | 成功调节图片对比度 | 是 | Pass |
+| 裁剪滤镜功能 | 进入参数设置页面 | 点击Crop按钮,滑动Crop滑动条,点击确认与Apply按钮 | 成功裁剪图片大小 | 是 | Pass |
+| 自定义亮度滤镜功能 | 进入参数设置页面 | 点击CustomBright按钮,滑动CustomBright滑动条,点击确认与Apply按钮 | CustomBright滤镜效果应用成功 | 是 | Pass |
+| 自定义裁剪滤镜功能 | 进入参数设置页面 | 点击CustomCrop按钮,滑动CustomCrop滑动条,点击确认与Apply按钮 | CustomCrop滤镜效果应用成功 | 是 | Pass |
+| 重置滤镜功能 | 进入主界面 | 点击Reset按钮 | 图像效果成功复原 | 是 | Pass |
+| 查询Brightness滤镜信息 | 进入参数设置页面 | 点击Brightness滑动条旁的查询按钮 | 显示Brightness滤镜信息 | 是 | Pass |
+| 查询Contrast滤镜信息 | 进入参数设置页面 | 点击Contrast滑动条旁的查询按钮 | 显示Contrast滤镜信息 | 是 | Pass |
+| 查询Crop滤镜信息 | 进入参数设置页面 | 点击Crop滑动条旁的查询按钮 | 显示Crop滤镜信息 | 是 | Pass |
+| 查询CustomBright滤镜信息 | 进入参数设置页面 | 点击CustomBright滑动条旁的查询按钮 | 显示CustomBright滤镜信息 | 是 | Pass |
+| 查询CustomCrop滤镜信息 | 进入参数设置页面 | 点击CustomCrop滑动条旁的查询按钮 | 显示CustomCrop滤镜信息 | 是 | Pass |
+| 根据编码格式查询滤镜信息 | 进入参数设置页面 | 点击查询按钮,点击编码格式 | 显示对应编码格式支持的滤镜信息 | 是 | Pass |
+| 测试NativeBuffer输入场景 | 进入参数设置页面 | 切换输入场景为NativeBuffer,点击确认与Apply按钮 | 在NativeBuffer场景下成功应用滤镜链 | 是 | Pass |
+| 测试URI输入场景 | 进入参数设置页面 | 切换输入场景为URI,点击确认与Apply按钮 | 在URI场景下成功应用滤镜链 | 是 | Pass |
+| 测试NativeWindow输入场景 | 进入参数设置页面 | 切换输入场景为NativeWindow,点击确认与Apply按钮 | 在NativeWindow场景下成功应用滤镜链 | 是 | Pass |
\ No newline at end of file
diff --git a/code/DocsSample/Media/Image/ImageEffect/screenshots/ImageEffect_Filter.jpeg b/code/DocsSample/Media/Image/ImageEffect/screenshots/ImageEffect_Filter.jpeg
new file mode 100644
index 0000000000000000000000000000000000000000..7b6f3d799ac3b6fdb1d000d19ee1e3bbb26154a6
Binary files /dev/null and b/code/DocsSample/Media/Image/ImageEffect/screenshots/ImageEffect_Filter.jpeg differ
diff --git a/code/DocsSample/Media/Image/ImageEffect/screenshots/ImageEffect_FilterInfo.jpeg b/code/DocsSample/Media/Image/ImageEffect/screenshots/ImageEffect_FilterInfo.jpeg
new file mode 100644
index 0000000000000000000000000000000000000000..c934fcff381c08a18025b7046081e1fb70d508f2
Binary files /dev/null and b/code/DocsSample/Media/Image/ImageEffect/screenshots/ImageEffect_FilterInfo.jpeg differ
diff --git a/code/DocsSample/Media/Image/ImageEffect/screenshots/ImageEffect_InputType.jpeg b/code/DocsSample/Media/Image/ImageEffect/screenshots/ImageEffect_InputType.jpeg
new file mode 100644
index 0000000000000000000000000000000000000000..6f2fe216f55d6797841319d678b29c47365b3001
Binary files /dev/null and b/code/DocsSample/Media/Image/ImageEffect/screenshots/ImageEffect_InputType.jpeg differ
diff --git a/code/DocsSample/Media/Image/ImageEffect/screenshots/ImageEffect_MainPage.jpeg b/code/DocsSample/Media/Image/ImageEffect/screenshots/ImageEffect_MainPage.jpeg
new file mode 100644
index 0000000000000000000000000000000000000000..abb78cd3218c4d47461e5faf2912d9b786ff1217
Binary files /dev/null and b/code/DocsSample/Media/Image/ImageEffect/screenshots/ImageEffect_MainPage.jpeg differ