diff --git a/thirdparty/image-knife-c/.gitignore b/thirdparty/image-knife-c/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /dev/null +++ b/thirdparty/image-knife-c/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer \ No newline at end of file diff --git a/thirdparty/image-knife-c/AppScope/app.json5 b/thirdparty/image-knife-c/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..a2af8405c4f836aef64fa8fe548519c631d5e63f --- /dev/null +++ b/thirdparty/image-knife-c/AppScope/app.json5 @@ -0,0 +1,10 @@ +{ + "app": { + "bundleName": "com.example.imageknifec", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/thirdparty/image-knife-c/AppScope/resources/base/element/string.json b/thirdparty/image-knife-c/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..38f789be28aeef7be4ee91ac93a0cb64aefc066b --- /dev/null +++ b/thirdparty/image-knife-c/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "ImageKnifeC" + } + ] +} diff --git a/thirdparty/image-knife-c/AppScope/resources/base/media/app_icon.png b/thirdparty/image-knife-c/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/thirdparty/image-knife-c/AppScope/resources/base/media/app_icon.png differ diff --git a/thirdparty/image-knife-c/LICENSE b/thirdparty/image-knife-c/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..8dada3edaf50dbc082c9a125058f25def75e625a --- /dev/null +++ b/thirdparty/image-knife-c/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. diff --git a/thirdparty/image-knife-c/NOTICE b/thirdparty/image-knife-c/NOTICE new file mode 100644 index 0000000000000000000000000000000000000000..03bba5bc00ce3d6d6dc71bf8b9905394843f5735 --- /dev/null +++ b/thirdparty/image-knife-c/NOTICE @@ -0,0 +1,8 @@ +OPEN SOURCE SOFTWARE NOTICE + +Please note we provide an open source software notice for the third party open source software along with this software and/or this software component (in the following just “this SOFTWARE”). The open source software licenses are granted by the respective right holders. + +Warranty Disclaimer +THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. + +Copyright Notice and License Texts diff --git a/thirdparty/image-knife-c/README.md b/thirdparty/image-knife-c/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f4a10e82f038b97a96535cde0d293c4d1ccc7813 --- /dev/null +++ b/thirdparty/image-knife-c/README.md @@ -0,0 +1,367 @@ +# ImageKnifeC + +## 简介 + +ImageKnifeC是一个OpenHarmony/HarmonyOS图片加载缓存库,特点如下: +- 提供js api和c api两种使用方式:既提供js组件方式给arkts原生应用使用,也提供Native组件的方式给RN等框架映射使用。 +- 内置使用系统网络KIT CAPI下载和系统Image CAPI渲染,图片加载更快。 +- 内置内存和文件两级缓存。 +- 支持通过拦截器的方式,自定义网络下载,解码,缓存策略,缓存key(**目前仅提供capi自定义拓展**)。 +- 支持预加载图片。 + +## 下载安装 +尚未发布OpenHarmony中心仓,暂时只提供源码引入方式:把library目录拷贝到应用目录下使用。 + +如果需要用文件缓存,需要提前初始化文件缓存 +ImageKnife.GetInstance().InitFileCache(context, 256, 256 * 1024 * 1024) + +## 使用方式 +- arkts使用示例 +``` +ImageKnifeComponent( + { + imageKnifeOption: new ImageKnifeOption({ + loadSrc: "https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", + placeholderSrc: "占位图", + errorholderSrc:"错误图", + onLoadListener:{ + onLoadStart:()=>{ + console.log("onLoad start") + }, + onLoadSuccess:(data,imageKnifeData)=>{ + console.log("onLoad success: " + data) + } + }, + objectFit: ImageFit.Contain, + border: { radius: { topLeft: 50, bottomRight: 50 } }// 圆角设置 + }), + syncLoad:false // 是否同步加载 + } +).width('100%').height(200) +``` +**注意:因为无法在c++子线程里执行ArkTs自定义下载,缓存,图形变化等方法,所以目前只能在c++侧进行自定义实现** + +- c++使用示例 + +引入`imageKnife.h`头文件,在工程的napi init函数中对ImageKnife进行初始化,创建默认的imageLoader并设置为全局默认的loader。 +loader包含了通过多种拦截器实现,提供图片加载,解码,缓存等能力。 +```cpp +// 1.创建默认ImageLoader,或通过拦截器自定义Loader +auto imageLoader = ImageKnifeC::ImageKnifeLoader::CreateDefaultImageLoader(); +//2. 将创建的ImageLoader设置为全局的loader +ImageKnifeC::ImageKnife::GetInstance().SetDefaultImageKnifeLoader(imageLoader); + +//3.创建ImageKnifeOption和imageKnifeNode +auto imageKnifeOption = std::make_shared(); +auto imageKnifeNode = std::make_shared(std::string(componentId), imageKnifeOption); + +//4.挂载imageNode到页面上,并管理声明周期,如OH_ArkUI_NodeContent_AddNode + +//5.执行请求,加载图片 +ImageKnife::GetInstance().Execute(imageKnifeNode->GetImageKnifeRequest()); + +//6.销毁图片 +// 将imageNode从页面中移除,释放node,option对象,如OH_ArkUI_NodeContent_RemoveNode +``` +如果需要创建空的ImageKnifeLoader, 则使用`ImageKnifeC::ImageKnifeLoader::createEmptyImageLoader()`。 +空的loader不包含默认的拦截器实现,可以后续添加指定的默认拦截器或自定义拦截器来实现下载解码等功能。 + +### 通过c++拦截器自定义实现 +#### 拦截器用法 +* 支持下载,内存缓存,文件缓存,解码4种拦截器扩展默认实现 +* 每个拦截器需要继承对应的基类实现对应的虚函数,Resolve负责拦截器的功能实现,Cancel负责取消Resolve中的耗时动作。 +* Resolve返回true则代表执行成功,责任链终止,进入下一个流程。返回false则代表执行失败,交由责任链上后一个拦截器。 +* 拦截器需添加至ImageLoader中,当前只支持设置全局的一个ImageLoader,后续支持针对某个Option单独分别设置ImageLoader。 + +#### 拦截器传递数据ImageKnifeTask +* 拦截器通过`ImageKnifeTask`来传递参数和执行结构,其中`product`成员为拦截器生成的产品,执行结果需写回至`product`的成员上来传递至下一流程。 +* `imageSrc`成员为当前加载任务对应的图片数据类型,可能是网络图片url 或本地Resource资源图(js层传入的pixelmap将直接进行图形变换后显示) +* 默认的下载拦截器下载的图片数据在`product.response`中,而内存磁盘缓存以及Resource加载的图片数据在`product.imageBuffer`中,并由`product.imageLength`标明图片长度。两者不混用 +* `product.pixelmapCached`用于标识当前的`product.pixelmap`是否被缓存,如果当前的拦截器需要产出新的pixelmap,在没有被缓存的情况下,需要先使用`OH_PixelmapNative_Release(task->product.pixelmap);`来释放内存。 +* 数据将在任务结束后自动释放内存。 +```cpp +class ImageKnifeTask { +public: + struct Product{ + // 网络下载session,用于取消下载 + Rcp_Session* session = nullptr; + // 网络下载request,用于取消下载 + Rcp_Request* request = nullptr; + // 网络下载, http响应数据 + Rcp_Response* response = nullptr; + // 原始图片buffer, + uint8_t* imageBuffer = nullptr; + // 原始图片长度 + uint32_t imageLength = 0; + // pixelmap 图片 + OH_PixelmapNative* pixelmap = nullptr; + // 标记是否任务结束后立即释放pixelmap 内存 + bool pixelmapCached = false; + // 标记当前是需要写缓存还是读缓存 + bool writeCache = false; + } + // 拦截器执行结果 + Product product; + // ImageKnife请求 + std::shared_ptr request; + // 请求图片来源类型标识: 主图,错误图,占位图 + const ImageKnifeRequestSource type; + // 请求图片数据类型标识: String | Pixelmap | Resource + const ImageData* imageSrc; + // 错误信息 + std::string lastError; + // 取消信息 + std::string cancelInfo; +}; +``` +#### 拦截器自定义数据 +* `ImageKnifeOption`中预留了`void* customData`成员,用户可以将自定义数据类型赋给改成员,并在拦截器中通过`ImageKnifeTask`的`request->GetImageKnifeOption()->customData`取得。 +* 通过设置`ImageKnifeOption`中的`std::function onFinalize`成员来完成了对`customData`的析构以及其他操作。 + 该函数指针将保证在整个图片请求(包含主图,占位图,错误图)完成后触发,即在请求失败,成功,取消结束后回调。 + + + +#### 拦截器示例 +- 【c++】自定义图片下载 +```cpp +class MyDownloadInterceptor: public ImageKnifeC::DownloadInterceptor{ +public: + bool Resolve(ImageKnifeTask* task) override + { + // 自实现网络请求,图片加载类型通过task->type 获取,数据通过task->product传递 + // 图片source信息由task->imageSrc描述 + std::string url; + if (task->imageSrc->GetString(url)) { + // 数据写入至product对应成员 + return loadImageFromUrl(url, task); // 如执行成功,下载责任链结束 + } + + // 执行失败或不支持,将执行责任链的下一个拦截器 + return false; + } + +}; + + +EXTERN_C_START +static napi_value init(napi_env env, napi_value exports) +{ + // ImageKnifeC 初始化 + ImageKnifeC::ImageKnife::GetInstance().init(env, exports); + // 创建默认ImageLoader + auto imageLoader = ImageKnifeC::ImageKnifeLoader::CreateDefaultImageLoader(); + + // 添加自定义网络下载拦截器,默认添加至责任链开头 + imageLoader->AddDownloadInterceptor(std::make_shared()); + // 将创建的ImageLoader设置为全局的loader + ImageKnifeC::ImageKnife::GetInstance().SetDefaultImageKnifeLoader(imageLoader); + +// napi_property_descriptor desc[] = {}; +// napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + return exports; +} +EXTERN_C_END +``` + +- 【c++】自定义解码图片 +```cpp +class MyDecodeInterceptor: public ImageKnifeC::DecodeInterceptor{ +public: + bool Resolve(ImageKnifeTask* task) override + { + //自定义解码实现 + //产出可以写入 task->product.pixelmap + //加载流程的产出可能在 task->product.response 或 task->product.imageBuffer中 + return true;// 执行成功,责任链结束 + return false; // 执行失败或不支持,将执行责任链的下一个拦截器 + } +}; + +EXTERN_C_START +static napi_value init(napi_env env, napi_value exports) +{ + // ImageKnifeC 初始化 + ImageKnifeC::ImageKnife::GetInstance().init(env, exports); + // 创建默认ImageLoader + auto imageLoader = ImageKnifeC::ImageKnifeLoader::CreateDefaultImageLoader(); + + // 添加自定义解码图片拦截器,添加至责任链末尾 + imageLoader->AddDownloadInterceptor(std::make_shared(), + ImageKnifeC::ImageKnifeLoader::Postion::END); + // 将创建的ImageLoader设置为全局的loader + ImageKnifeC::ImageKnife::GetInstance().SetDefaultImageKnifeLoader(imageLoader); + +// napi_property_descriptor desc[] = {}; +// napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + return exports; +} +EXTERN_C_END +``` +- 【c++】自定义内存缓存 +```cpp +class MyMemoryInterceptor: public ImageKnifeC::MemoryCacheInterceptor{ +public: + + bool Resolve(ImageKnifeTask* task) override + { + // 自定义缓存实现 + // task->product->writeCache 为true表示当前流程是需要写缓存,否则需要读缓存。 + // 内存缓存读取或写入使用 task->product->pixelmap + return true;// 执行成功,责任链结束 + return false; // 执行失败或不支持,将执行责任链的下一个拦截器 + } +}; + +EXTERN_C_START +static napi_value init(napi_env env, napi_value exports) +{ + // ImageKnifeC 初始化 + ImageKnifeC::ImageKnife::GetInstance().init(env, exports); + // 创建默认ImageLoader + auto imageLoader = ImageKnifeC::ImageKnifeLoader::CreateDefaultImageLoader(); + + // 添加自定义内存缓存拦截器,添加至责任链末尾 + imageLoader->AddDownloadInterceptor(std::make_shared(), + ImageKnifeC::ImageKnifeLoader::Postion::END); + // 将创建的ImageLoader设置为全局的loader + ImageKnifeC::ImageKnife::GetInstance().SetDefaultImageKnifeLoader(imageLoader); + +// napi_property_descriptor desc[] = {}; +// napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + return exports; +} +EXTERN_C_END +``` + +- 【c++】自定义文件缓存 +```cpp +class MyFileInterceptor: public ImageKnifeC::FileCacheInterceptor{ +public: + + bool Resolve(ImageKnifeTask* task) override + { + // 自定义文件缓存实现 + // task->product->writeCache 为true表示当前流程是需要写缓存,否则需要读缓存。 + // 文件缓存写入来源使用task->response, 使用task->product->imageBuffer读取 + return true;// 执行成功,责任链结束 + return false; // 执行失败或不支持,将执行责任链的下一个拦截器 + } +}; + +EXTERN_C_START +static napi_value init(napi_env env, napi_value exports) +{ + // ImageKnifeC 初始化 + ImageKnifeC::ImageKnife::GetInstance().init(env, exports); + // 创建默认ImageLoader + auto imageLoader = ImageKnifeC::ImageKnifeLoader::CreateDefaultImageLoader(); + + // 添加自定义内存缓存拦截器,添加至责任链末尾 + imageLoader->AddDownloadInterceptor(std::make_shared(), + ImageKnifeC::ImageKnifeLoader::Postion::END); + // 将创建的ImageLoader设置为全局的loader + ImageKnifeC::ImageKnife::GetInstance().SetDefaultImageKnifeLoader(imageLoader); + +// napi_property_descriptor desc[] = {}; +// napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + return exports; +} +EXTERN_C_END +``` +- 【c++】自定义图形变化 +``` +// 待定 + +``` +#### border 设置边框圆角 +暂时实现了border width与radius的支持,设置的数据类型为number,**其他类型尚未实现暂不支持** + +**border color与style 尚未实现暂不支持** +``` +imageKnifeOption: new ImageKnifeOption({ + loadSrc: $r('app.media.pngSample'), + objectFit:ImageFit.Fill, + border:{radius:50,width:1} //圆角边框设置 +}) +``` + + +## 与ImageKnife3.x特性对比 +#### ImageKnifeOption +| 属性 | ImageKnife3.x(js api) | ImageKnifeC(js api) |ImageKnifeC(c api) | +| --------------------- | ----------------------------------------------------- | ------------------------------ |------------------------------ | +| 主图 | loadSrc:string, PixelMap, Resource | 一致 | | +| 占位图 | placeholderSrc?: string,PixelMap,Resource | 一致 | | +| 错误图 | errorholderSrc?: string,PixelMap,Resource | 一致 | | +| http请求头 | headerOption?: Array | 一致(待实现) | | +| 自定义关键字 | signature?: string | 一致 | | +| 主图缩放效果 | objectFit?: ImageFit | 一致 | | +| 占位图缩放效果 | placeholderObjectFit?: ImageFit | 一致 | | +| 错误图缩放效果 | errorholderObjectFit?: ImageFit | 一致 | | +| 自定义下载方法 | customGetImage:function | 不一致(待C侧实现) | 拦截器实现 | +| 圆角边框 | border?: BorderOptions | 一致 | | +| 写缓存策略 | writeCacheStrategy?: CacheStrategy | 一致(待实现) | | +| 仅使用缓存加载 | onlyRetrieveFromCache?: boolean | 一致(待实现) | | +| 请求优先级 | priority?: taskpool.Priority | 一致(待实现) | | +| 页面上下文 | context?: common.UIAbilityContext | 一致 | | +| 下载进度监听 | progressListener?: (progress: number) => void | 一致(待实现) | | +| 图形变化 | transformation?: PixelMapTransformation |不一致(待C侧实现) | | +| 请求回调 | onLoadListener?: OnLoadCallBack,undefined) | 一致 | | +| 渲染完成回调 | onComplete?:(event:EventImage,undefined) => void | 一致(待实现) | | +| 颜色修改 | drawingColorFilter?: ColorFilter,drawing.ColorFilter | 一致(待实现) | | +| 降采样策略 | downsampleOf?: DownsampleStrategy | 一致(待实现) | | +| http ca证书 | caPath?: string | 一致(待实现) | | + + +#### ImageKnife全局方法 +| 方法 | ImageKnife3.x(js api) | ImageKnifeC(js api) |ImageKnifeC(c api) | +| --------------------- | ----------------------------------------------------- | ------------------------------ |------------------------------ | +| 全局主线程加载 | isRequestInSubThread(value: boolean) | 一致(待实现) | | +| 初始化文件缓存 | InitFileCache(context: Context, size: number = 256, memory: number = 256 * 1024 * 1024,path?: string) | 一致(待实现) | | +| 判断文件缓存是否已完成初始化 | isFileCacheInit(): boolean | 一致(待实现) | | +| 重新加载 | reload(request: ImageKnifeRequest) | 一致(待实现) | | +| 全局添加单个请求头header | addHeader(key: string, value: Object) | 一致(待确认) | | +| 全局设置请求头header | serHeaderOptions(options) | 一致(待实现) | | +| 删除单个请求头header | deleteHeader(key: string) | 一致(待实现) | | +| 设置自定义的内存缓存 | initMemoryCache(newMemoryCache: IMemoryCache) | 不一致(拦截器实现) | | +| 清除所有内存缓存 | removeAllMemoryCache() | 一致(待实现) | | +| 清除指定内存缓存 | removeMemoryCache(url: string \|ImageKnifeOption) | 一致(待实现) | | +| 预加载 | preload(loadSrc:string \| ImageKnifeOption) | 一致(待实现) | | +| 取消图片请求 | Cancel(request:ImageKnifeRequest) | 一致(待实现) | | +| 预加载图片到文件缓存,返回文件路径 | preLoadCache(loadSrc: string \| ImageKnifeOption) | 一致(待确认) | | +| 从内存或文件缓存中获取图片数据 | getCacheImage(loadSrc: string,cacheType: CacheStrategy = CacheStrategy.Default, signature?: string) | 一致(待确认) | | +| 预加载缓存(用于外部已获取pixelmap,需要加入imageknife缓存的场景) | PutCacheImage(url: string, pixelMap: PixelMap, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string) | 一致(待确认) | | +| 清除所有文件缓存 | removeAllFileCache() | 一致(待实现) | | +| 清除指定文件缓存 | removeFileCache(url: string \| ImageKnifeOption) | 一致(待实现) | | +| 设置请求并发数量 | setMaxRequests(concurrency: number) | 一致(待实现) | | +| 根据key从文件缓存获取buffer | getFileCacheByFile(context: Context, key: string) | 一致(待实现) | | +| 根据key从内存缓存获取pixelmap | LoadFromMemoryCache(key: string) | 一致(待实现) | | +| 设置请求并发数量 | setMaxRequests(concurrency: number) | 一致(待实现) | | +| 获取缓存限制的大小 | getCacheLimitSize(cacheType?: CacheStrategy) | 一致(待实现) | | +| 获取缓存限制的数量 | getCurrentCacheNum(cacheType: CacheStrategy) | 一致(待实现) | | +| 获取当前缓存大小 | getCurrentCacheSize(cacheType: CacheStrategy) | 一致(待实现) | | +| 自定义缓存key生成方法 | SetEngineKeyImpl(impl: IEngineKey) | 不一致(待C侧实现) | | +| 全局设置自定义下载 | setCustomGetImage(...) | 不一致(待C侧实现) | | +| 全局获取自定义下载 | getCustomGetImage() | 不一致(待C侧实现) | | + +#### 其它属性 +| 属性 | ImageKnife3.x(js api) | ImageKnifeC(js api) |ImageKnifeC(c api) | +| --------------------- | ----------------------------------------------------- | ------------------------------ |------------------------------ | +| 同步加载 | syncLoad: boolean | 一致(待实现) | | +| 动图控制及回调 | animatorOption: AnimatorOption | 一致(待实现) | | +| 放大缩小等组件缩放 | Transform(matrix:object) | 一致(待实现) | | +| 组件自适应图片宽高 | ImageFit.Auto | 一致(待实现) | | + + + + + + +## Benchmark +待测试比较imageknife3.x,imageknifeC,系统image,安卓fresco/glide 加载图片速度和白块率。 + + +## 开源协议 + +本项目基于 [Apache License 2.0](https://gitee.com/openharmony-tpc/ImageKnife/blob/master/LICENSE) ,请自由的享受和参与开源。 + diff --git a/thirdparty/image-knife-c/build-profile.json5 b/thirdparty/image-knife-c/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..f14f4bd0e5d733f242bd17a385418db66a2f7e01 --- /dev/null +++ b/thirdparty/image-knife-c/build-profile.json5 @@ -0,0 +1,57 @@ +{ + "app": { + "signingConfigs": [ + ], + "products": [ + { + "name": "default", + "signingConfig": "default", + "compatibleSdkVersion": "5.0.0(12)", + "runtimeOS": "HarmonyOS", + "buildOption": { + "strictMode": { + "caseSensitiveCheck": true + } + } + } + ], + "buildModeSet": [ + { + "name": "debug", + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + }, + { + "name": "library", + "srcPath": "./library", + }, + { + "name": "sharedlibrary", + "srcPath": "./sharedlibrary", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/code-linter.json5 b/thirdparty/image-knife-c/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..77b31b517a3e5c2f34c3ae1bf44083c0c06cbd6d --- /dev/null +++ b/thirdparty/image-knife-c/code-linter.json5 @@ -0,0 +1,20 @@ +{ + "files": [ + "**/*.ets" + ], + "ignore": [ + "**/src/ohosTest/**/*", + "**/src/test/**/*", + "**/src/mock/**/*", + "**/node_modules/**/*", + "**/oh_modules/**/*", + "**/build/**/*", + "**/.preview/**/*" + ], + "ruleSet": [ + "plugin:@performance/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/.gitignore b/thirdparty/image-knife-c/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/thirdparty/image-knife-c/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/build-profile.json5 b/thirdparty/image-knife-c/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..d7bb3d441e30e7286ac9ad6b83337e0d3c530021 --- /dev/null +++ b/thirdparty/image-knife-c/entry/build-profile.json5 @@ -0,0 +1,34 @@ +{ + "apiType": "stageMode", + "buildOption": { + }, + "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/thirdparty/image-knife-c/entry/hvigorfile.ts b/thirdparty/image-knife-c/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..c6edcd90486dd5a853cf7d34c8647f08414ca7a3 --- /dev/null +++ b/thirdparty/image-knife-c/entry/hvigorfile.ts @@ -0,0 +1,6 @@ +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/thirdparty/image-knife-c/entry/obfuscation-rules.txt b/thirdparty/image-knife-c/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..69c4d6a8a5531548e4886fa766090c5c157a87d9 --- /dev/null +++ b/thirdparty/image-knife-c/entry/obfuscation-rules.txt @@ -0,0 +1,18 @@ +# 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://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# 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 \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/oh-package-lock.json5 b/thirdparty/image-knife-c/entry/oh-package-lock.json5 new file mode 100644 index 0000000000000000000000000000000000000000..46eedb597131e6e57a980bc5dca7f1bc8020bbd0 --- /dev/null +++ b/thirdparty/image-knife-c/entry/oh-package-lock.json5 @@ -0,0 +1,36 @@ +{ + "meta": { + "stableOrder": true + }, + "lockfileVersion": 3, + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", + "specifiers": { + "@ohos/imageknifec@../library": "@ohos/imageknifec@../library", + "@ohos/sharedlibrary@../sharedlibrary": "@ohos/sharedlibrary@../sharedlibrary", + "libimageknifec.so@../library/src/main/cpp/types/libentry": "libimageknifec.so@../library/src/main/cpp/types/libentry" + }, + "packages": { + "@ohos/imageknifec@../library": { + "name": "@ohos/imageknifec", + "version": "1.0.0", + "resolved": "../library", + "registryType": "local", + "dependencies": { + "libimageknifec.so": "file:./src/main/cpp/types/libentry" + } + }, + "@ohos/sharedlibrary@../sharedlibrary": { + "name": "sharedlibrary", + "version": "1.0.0", + "resolved": "../sharedlibrary", + "registryType": "local", + "packageType": "InterfaceHar" + }, + "libimageknifec.so@../library/src/main/cpp/types/libentry": { + "name": "libimageknifec.so", + "version": "1.0.0", + "resolved": "../library/src/main/cpp/types/libentry", + "registryType": "local" + } + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/oh-package.json5 b/thirdparty/image-knife-c/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..bc3b69fbb210ce1175acc9e4588fd7710c8f9ab6 --- /dev/null +++ b/thirdparty/image-knife-c/entry/oh-package.json5 @@ -0,0 +1,12 @@ +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": { + "@ohos/imageknifec": "file:../library", + "@ohos/sharedlibrary": "file:../sharedlibrary" + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/ets/entryability/EntryAbility.ets b/thirdparty/image-knife-c/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..30580b7ce4ce4163f6d503cc8d673e5d2070f89e --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,54 @@ +import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; +import { ImageKnife } from '@ohos/imageknifec'; + +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'); + + //Initialize the fileCache + ImageKnife.getInstance().initFileCache(this.context, 256, 256 * 1024 * 1024) + .then((result: string) => { + console.log("File cache initialization completed:", result); + }) + .catch((error: Error) => { + console.error("File cache initialization failed:", error); + }); + + //Set max requests + ImageKnife.getInstance().setMaxRequests(8); + + windowStage.loadContent('pages/Index', (err) => { + 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.'); + }); + } + + 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/thirdparty/image-knife-c/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/thirdparty/image-knife-c/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..dc55c03d3eea7ce53d5346c732a39ce9bf5267e1 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,12 @@ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/AutoImageFit.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/AutoImageFit.ets new file mode 100644 index 0000000000000000000000000000000000000000..de5327f4ee39931f29ae8954014e2475fb1eceaa --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/AutoImageFit.ets @@ -0,0 +1,49 @@ +/* + * 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. + */ +import { ImageKnifeComponent } from '@ohos/imageknifec'; + +@Entry +@Component +struct AutoImageFit { + @State width1: Length = '100%' + + build() { + Scroll() { + Column() { + Button($r('app.string.adjust_size')).onClick(() => { + if (this.width1.toString() == '100%') { + this.width1 = '60%'; + } else { + this.width1 = '100%'; + } + }).width('100%') + Text('Image') + Image('https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/56/v3/8MdhfSsCSMKj4sA6okUWrg/5uBx56tLTUO3RYQl-E5JiQ.jpg') + .width('100%') + .objectFit(ImageFit.Auto) + Text('ImageKnife') + ImageKnifeComponent({ + imageKnifeOption: { + loadSrc: 'https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/56/v3/8MdhfSsCSMKj4sA6okUWrg/5uBx56tLTUO3RYQl-E5JiQ.jpg', + objectFit: ImageFit.Contain, + } + }).width('100%') + + }.width(this.width1).border({ width: 1 }) + } + } +} + + diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/Index.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..33eb842a3ce7090ab40f07718763dc1661387356 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,93 @@ +/* + * 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. + */ +import { router } from '@kit.ArkUI' + + +@Entry +@Component +struct Index { + + getResourceString(res:Resource){ + return getContext().resourceManager.getStringSync(res.id) + } + + + aboutToAppear(): void { + + } + + build() { + Scroll(){ + Column() { + Button("单个图片").onClick(()=>{ + router.pushUrl({ + url: 'pages/SingleImage', + }); + }) + Button("本地图片").margin({top:10}).onClick(()=>{ + router.pushUrl({ + url: 'pages/LocalImage', + }); + }) + Button("Image-ObjectFit").margin({top:10}).onClick(()=>{ + router.pushUrl({ + url: 'pages/TestObjectFit', + }); + }) + Button("边框与圆角").margin({top:10}).onClick(()=>{ + router.pushUrl({ + url: 'pages/TestBorder', + }); + }) + Button("LazyForEach").margin({top:10}).onClick(()=>{ + router.pushUrl({ + url: 'pages/LazyForEach', + }); + }) + Button("Reuse + LazyForEach").margin({top:10}).onClick(()=>{ + router.pushUrl({ + url: 'pages/ReuseLazyForEach', + }); + }) + Button('缩放图片').margin({top:10}).onClick(()=>{ + router.pushUrl({ + url: 'pages/TransformPage', + }); + }) + Button('prefetch+cachecount动态预加载').margin({top:10}).onClick(()=>{ + router.pushUrl({ + url: 'pages/PrefetchAndPreload', + }); + }) + Button('ImageFit.Auto长图显示').margin({top:10}).onClick(()=>{ + router.pushUrl({ + url: 'pages/LongImagePage', + }); + }) + Button('ImageFit.Auto自适应图片高度').margin({top:10}).onClick(()=>{ + router.pushUrl({ + url: 'pages/AutoImageFit', + }); + }) + Button('测试Listner回调数量').margin({top:10}).onClick(()=>{ + router.pushUrl({ + url: 'pages/MultipleImageCallBack', + }); + }) + } + } .width('100%') + .height('100%') + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/LazyForEach.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/LazyForEach.ets new file mode 100644 index 0000000000000000000000000000000000000000..5c1c8caab3f244dee00f3cd218340a15dfe480f6 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/LazyForEach.ets @@ -0,0 +1,51 @@ +/* + * 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. + */ +import { ImageKnifeComponent } from '@ohos/imageknifec'; +import { CommonDataSource } from './model/CommonDataSource'; +import { dataArray } from './model/ImageUrlData'; + +@Entry +@ComponentV2 +export struct LazyForEachCount { + @Local hotCommendList:CommonDataSource = new CommonDataSource([]) + aboutToAppear(): void { + this.hotCommendList.addData(this.hotCommendList.totalCount(),dataArray) + } + build() { + Column() { + WaterFlow() { + LazyForEach(this.hotCommendList,(item: string,index:number)=>{ + FlowItem() { + Column(){ + ImageKnifeComponent({ + imageKnifeOption: { + loadSrc: item, + placeholderSrc: $r("app.media.loading"), + errorholderSrc: $r("app.media.failed"), + } + }).width("50%").height(160) + Text(index + "") + } + }.height(200) + .backgroundColor("#95efd2") + },(item: string) => item) + }.columnsTemplate("1fr 1fr") + .columnsGap(10) + .rowsGap(5) + .backgroundColor(0xFAEEE0) + .width("100%").height("100%") + } + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/LocalImage.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/LocalImage.ets new file mode 100644 index 0000000000000000000000000000000000000000..2ef83f14fa7d330a38bc66620f2812165132d895 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/LocalImage.ets @@ -0,0 +1,79 @@ +/* + * 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. + */ +import { ImageKnifeComponent } from '@ohos/imageknifec'; +import fs from '@ohos.file.fs'; + +@Entry +@Component +struct LocalImage { + scroller: Scroller = new Scroller; + localFile: string = getContext(this).filesDir + '/icon.png' + + aboutToAppear(): void { + // 拷贝本地文件 + let icon: Uint8Array = getContext(this).resourceManager.getMediaContentSync($r('app.media.startIcon')); + let file = fs.openSync(this.localFile, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE); + fs.writeSync(file.fd, icon.buffer); + fs.fsyncSync(file.fd); + fs.closeSync(file); + } + + build() { + Scroll(this.scroller) { + Column() { + Text($r('app.string.local_r_file')) + .fontSize(30) + .fontWeight(FontWeight.Bold) + ImageKnifeComponent({ + imageKnifeOption: { + loadSrc: $r('app.media.startIcon'), + objectFit: ImageFit.Contain + } + }).width(100).height(100) + Text($r('app.string.local_rawfile')) + .fontSize(30) + .fontWeight(FontWeight.Bold) + ImageKnifeComponent({ + imageKnifeOption: { + loadSrc: $rawfile("image/startIcon.png"), + objectFit: ImageFit.Contain + } + }).width(100).height(100) + //Image($rawfile("image/startIcon.png")).width(100).height(100) + Text($r('app.string.Under_context_file')) + .fontSize(30) + .fontWeight(FontWeight.Bold) + ImageKnifeComponent({ + imageKnifeOption: { + loadSrc: this.localFile, + objectFit: ImageFit.Contain + } + }).width(100).height(100) + Text($r('app.string.local_other_module')) + .fontSize(30) + .fontWeight(FontWeight.Bold) + ImageKnifeComponent({ + imageKnifeOption: { + loadSrc: $r('[sharedlibrary].media.startIcon'), + objectFit: ImageFit.Contain + } + }).width(100).height(100) + } + .width('100%') + } + .height('100%') + } +} + diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/LongImagePage.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/LongImagePage.ets new file mode 100644 index 0000000000000000000000000000000000000000..b4da9dd713a75f4391f86a241c6b07b89993785c --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/LongImagePage.ets @@ -0,0 +1,38 @@ +/* + * 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. + */ +import { ImageKnifeComponent } from '@ohos/imageknifec' + +@Entry +@Component +struct LongImagePage { + build() { + Scroll() { + ImageKnifeComponent({ + imageKnifeOption: { + loadSrc: 'https://wx2.sinaimg.cn/mw690/006HyQKGgy1hnqp08dw09j30u04twu0x.jpg', + //src:$r('app.media.aaa'), + placeholderSrc: $r('app.media.loading'), + errorholderSrc: $r('app.media.failed'), + httpOption: { + connectTimeout: 60000, + readTimeout: 60000 + }, + objectFit: ImageFit.Auto + } + }) + } + .height('100%').width('100%') + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/MultipleImageCallBack.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/MultipleImageCallBack.ets new file mode 100644 index 0000000000000000000000000000000000000000..54e9712811ee2737272ab0b13446aab6a93ae99e --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/MultipleImageCallBack.ets @@ -0,0 +1,149 @@ +/* + * 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. + */ +import { ImageKnifeComponent,ImageKnifeOption } from '@ohos/imageknifec'; +import { LogUtil } from '../util/LogUtil'; +import { CommonDataSource } from './model/CommonDataSource' + +@Entry +@Component +struct MultipleImageCallBack { + @State hotCommendList: CommonDataSource = new CommonDataSource([]) + @State componentIndex: number = 0 + @State startIndex: number = 0 + @State successIndex: number = 0 + @State failIndex: number = 0 + @State cancelJobIndex: number = 0 + @State cancelLoadIndex: number = 0 + @State memoryIndex: number = 0 + @State fileCacheIndex: number = 0 + @State netIndex: number = 0 + @State checkText: string = '' + private data: Array = [] + + aboutToAppear(): void { + for (let index = 0; index < 100; index++) { + this.data.push(`https://img-blog.csdn.net/20140514114029140?${index}`); + } + this.hotCommendList.addData(this.hotCommendList.totalCount(), this.data); + } + + build() { + Column() { + Row() { + Column() { + Text('图片总数:' + this.componentIndex) + Text('开始回调:' + this.startIndex) + Text('成功回调:' + this.successIndex) + Text('失败回调:' + this.failIndex) + Text('队列取消回调:' + this.cancelJobIndex) + Text('加载取消回调:' + this.cancelLoadIndex) + Text('内存数量:' + this.memoryIndex) + Text('文件数量:' + this.fileCacheIndex) + Text('网络数量:' + this.netIndex) + }.width('50%') + Column() { + Button('check') + .onClick(()=>{ + this.checkText = '' + if (this.componentIndex !== this.startIndex + this.cancelJobIndex) { + this.checkText = this.checkText + '图片总数!=开始+队列取消\r\n'; + } + if(this.startIndex !== this.successIndex + this.failIndex + this.cancelLoadIndex) { + this.checkText = this.checkText + '开始回调!=成功+失败+加载取消\r\n'; + } + if(this.successIndex !== this.memoryIndex + this.fileCacheIndex + this.netIndex) { + this.checkText = this.checkText + '成功回调!=内存+文件+网络'; + } + if(this.checkText == '') { + this.checkText = 'check正确'; + } + }) + Text(this.checkText) + }.width('50%') + }.width('100%') + Column() { + WaterFlow() { + LazyForEach(this.hotCommendList, (item: string,index: number) => { + FlowItem() { + Column() { + Text(index + '') + ImageComponent({ + imageKnifeOption: { + loadSrc: item, + placeholderSrc: $r('app.media.loading'), + errorholderSrc: $r('app.media.failed'), + onLoadListener: { + onLoadStart:()=>{ + this.startIndex++ + LogUtil.info('image load multiple loadStart:' + this.startIndex) + }, + onLoadSuccess:(pixelmap,imageData,request)=>{ + this.successIndex++; + let memory = request?.imageKnifeData?.timeInfo?.memoryCheckEndTime ? 1 : 0; + let fileCache = request?.imageKnifeData?.timeInfo?.diskCheckEndTime ? 1 : 0; + let net = request?.imageKnifeData?.timeInfo?.netRequestEndTime ? 1 : 0; + memory = memory - fileCache; + fileCache = fileCache - net; + this.memoryIndex = this.memoryIndex + memory; + this.fileCacheIndex = this.fileCacheIndex + fileCache; + this.netIndex = this.netIndex + net; + LogUtil.info('image load multiple loadSuccess:' + this.successIndex); + }, + onLoadFailed:()=>{ + this.failIndex++ + LogUtil.info('image load multiple loadFail:' + this.failIndex); + }, + onLoadCancel:(message,request)=>{ + let flag = request?.imageKnifeData?.type ? true : false; + if (flag) { + this.cancelLoadIndex++; + } else { + this.cancelJobIndex++; + } + LogUtil.info('image load multiple cancelJobIndex:' + this.cancelJobIndex,'cancelLoadIndex' + this.cancelLoadIndex); + } + } + },index:this.componentIndex + }).width('50%').height(160) + } + }.height(200) + .backgroundColor('#95efd2') + }, (item: string) => item) + } + .cachedCount(0) + .columnsTemplate('1fr 1fr') + .columnsGap(10) + .rowsGap(5) + .backgroundColor(0xFAEEE0) + .width('100%') + } + .height('80%') + }.width('100%') + .height('100%') + } +} +@Component +struct ImageComponent { + @State imageKnifeOption: ImageKnifeOption = new ImageKnifeOption() + @Link index: number + aboutToAppear(): void { + this.index++ + } + build() { + ImageKnifeComponent({ + imageKnifeOption: this.imageKnifeOption + }) + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/PrefetchAndPreload.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/PrefetchAndPreload.ets new file mode 100644 index 0000000000000000000000000000000000000000..160cfc45d7646059caed13bf20d6c6137a250b4b --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/PrefetchAndPreload.ets @@ -0,0 +1,57 @@ +/* + * 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. + */ +import { BasicPrefetcher } from '@kit.ArkUI'; +import { dataArray } from './model/ImageUrlData'; +import { ImageKnifeComponent } from '@ohos/imageknifec'; +import DataSourcePrefetchingImageKnife from './model/DataSourcePrefetching'; + +@Entry +@Component +export struct PrefetchAndPreload { + // 创建DataSourcePrefetchingImageKnife对象,具备任务预取、取消能力的数据源 + private readonly dataSource = new DataSourcePrefetchingImageKnife(dataArray); + // 创建BasicPrefetcher对象,默认的动态预取算法实现 + private readonly prefetcher = new BasicPrefetcher(this.dataSource); + + build() { + Column() { + List({ space: 16 }) { + LazyForEach(this.dataSource, (item: string, index: number) => { + ListItem() { + Column({ space: 12 }) { + ImageKnifeComponent({ + imageKnifeOption: { + loadSrc: item, + placeholderSrc: $r('app.media.loading') + } + }).width(100).height(100) + Text(`${index}`) + }.border({ width: 5, color: '#000000' }) + } + .reuseId('imageKnife') + }) + } + .cachedCount(5) + .onScrollIndex((start: number, end: number) => { + // 列表滚动触发visibleAreaChanged,实时更新预取范围,触发调用prefetch、cancel接口 + this.prefetcher.visibleAreaChanged(start, end) + }) + .width('100%') + .height('100%') + .margin({ left: 10, right: 10 }) + .layoutWeight(1) + } + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/ReuseLazyForEach.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/ReuseLazyForEach.ets new file mode 100644 index 0000000000000000000000000000000000000000..ba5f8bc4f02cde630aa91c81aab8545ee4eb5901 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/ReuseLazyForEach.ets @@ -0,0 +1,69 @@ +/* + * 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. + */ +import { CommonDataSource } from './model/CommonDataSource' +import { UserAvatar } from './model/User' +import { dataArray } from './model/ImageUrlData'; + +@Entry +@Component +struct Index { + @State hotCommendList:CommonDataSource = new CommonDataSource([]) + aboutToAppear(): void { + this.hotCommendList.addData(this.hotCommendList.totalCount(), dataArray) + AppStorage.set('WeLink_Mob_fontSize_multiple', 1) + } + + build() { + Column() { + Button('bigger').onClick(()=>{ + AppStorage.set('WeLink_Mob_fontSize_multiple',1.6) + }) + Button('small').onClick(()=>{ + AppStorage.set('WeLink_Mob_fontSize_multiple',0.8) + }) + List(){ + LazyForEach(this.hotCommendList,(item:string)=>{ + ListItem(){ + ReuseImage({ + userInfo:item + }).width('100%').height('100%').backgroundColor(Color.Yellow) + }.width(200).height(200).margin({bottom:5}) + }) + } + .cachedCount(3) + .width('100%') + .height('100%') + .backgroundColor(0xFAEEE0) + }.width('100%').height('100%') + } +} + + +@Reusable +@Component +struct ReuseImage { + @State userInfo:string = '' + aboutToReuse(params: ESObject): void { + this.userInfo = params.userInfo + } + + build() { + Column(){ + UserAvatar({ + userInfo:this.userInfo + }) + }.width('100%').height('100%') + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/SingleImage.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/SingleImage.ets new file mode 100644 index 0000000000000000000000000000000000000000..abe1c7d9e69035de768f65b92bfc78db4b24398e --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/SingleImage.ets @@ -0,0 +1,73 @@ +/* + * 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. + */ +import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/imageknifec'; + +@Entry +@Component +struct SingleImage { + build() { + Row() { + Column() { + Text("网络资源").fontSize(30).fontWeight(FontWeight.Bold) + ImageKnifeComponent( + { + imageKnifeOption: { + loadSrc: "https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", + placeholderSrc: $r('app.media.loading'), + errorholderSrc: $r('app.media.failed'), + onLoadListener:{ + onLoadStart:()=>{ + console.log("onLoad start(net-resource)") + }, + onLoadFailed:(err)=>{ + console.error("onLoad onLoadFailed(net-resource) " + err) + }, + onLoadSuccess: (data, imageKnifeData) =>{ + console.log("onLoad onLoadSuccess(net-resource)") + } + }, + objectFit:ImageFit.Contain, + } + } + ).width(100).height(100) + + + Text("占位图显示").fontSize(30).fontWeight(FontWeight.Bold).margin({top:10}) + ImageKnifeComponent( + { + imageKnifeOption: { + loadSrc: "https://github.com/taglib/taglib/releases/download/v2.0.2/taglib-2.0.2.tar.gz", + placeholderSrc: $r('app.media.loading'), + objectFit:ImageFit.Contain, + onLoadListener:{ + onLoadStart:()=>{ + console.log("onLoad start(net-resource)") + }, + onLoadFailed:(err)=>{ + console.error("onLoad onLoadFailed(net-resource) " + err) + }, + onLoadSuccess: (data, imageKnifeData) =>{ + console.log("onLoad onLoadSuccess(net-resource)") + } + }, + } + } + ).width(100).height(100) + } + .width('100%') + } + .height('100%') + } +} diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/TestBorder.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/TestBorder.ets new file mode 100644 index 0000000000000000000000000000000000000000..558401c54e2f656cc4bdc3d9778e3a615174eb73 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/TestBorder.ets @@ -0,0 +1,79 @@ +/* + * 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. + */ +import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/imageknifec' + +@Entry +@Component +struct TestBorder { + imageRadius: number = 50 + imageWidth: number = 1 + @State imageKnifeOption: ImageKnifeOption = new ImageKnifeOption() + + build() { + Column({ space: 20 }) { + Row() { + Text('Radius:').fontSize(20) + TextArea({ + text: this.imageRadius.toString() + }).type(TextAreaType.NUMBER) + .onChange((value: string) => { + this.imageRadius = parseInt(value) + }) + .width(150).fontSize(20) + } + + Row() { + Text('Width:').fontSize(20) + TextArea({ + text: this.imageWidth.toString(), + }).type(TextAreaType.NUMBER) + .onChange((value: string) => { + this.imageWidth = parseInt(value) + }) + .width(150).fontSize(20) + } + + Button("设置边框").onClick(() => { + this.imageKnifeOption = { + loadSrc: "https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", + placeholderSrc: $r('app.media.loading'), + errorholderSrc: $r('app.media.failed'), + onLoadListener: { + onLoadStart: () => { + console.log("onLoad start(net-resource)") + }, + onLoadFailed: (err) => { + console.error("onLoad onLoadFailed(net-resource) " + err) + }, + onLoadSuccess: (data, imageKnifeData) => { + console.log("onLoad onLoadSuccess(net-resource)") + } + }, + objectFit: ImageFit.Contain, + border: { radius: this.imageRadius, width: this.imageWidth } + } + }).fontSize(20).padding(10) + + ImageKnifeComponent( + { + imageKnifeOption: this.imageKnifeOption + } + ).width(200).height(200) + } + .height('100%') + .width('100%') + .padding(20) + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/TestObjectFit.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/TestObjectFit.ets new file mode 100644 index 0000000000000000000000000000000000000000..0f9f59a57c0996d8866fe90ff118c95e5f108e35 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/TestObjectFit.ets @@ -0,0 +1,145 @@ +/* + * 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. + */ +import { ImageKnifeComponent } from '@ohos/imageknifec'; + +@Entry +@Component +struct TestObjectFit { + build() { + Scroll() { + Column() { + Text("左侧图:1050px*1894px 右侧图:268px * 140px") + .font({size:16,weight:FontWeight.Bolder}) + .fontColor("#ff0000") + Text("Contain-图片宽高等比例缩放至全部居中展示") + .margin({top:10,bottom:10}) + Flex() { + ImageKnifeComponent( + { + imageKnifeOption: { + loadSrc: $r('app.media.pngSample'), + objectFit:ImageFit.Contain, + border:{color:"#000000",width:1} + } + } + ).height(px2vp(200)).width("50%") + ImageKnifeComponent( + { + imageKnifeOption: { + loadSrc: $r('app.media.test'), + objectFit:ImageFit.Contain, + border:{color:"#000000",width:1} + } + } + ).height(px2vp(200)).width("50%") + + } + Text("Cover-保持图片宽高比不变,短的部分缩放至组件大小,超出部分全部裁剪") + .margin({top:10,bottom:10}) + Flex() { + ImageKnifeComponent( + { + imageKnifeOption: { + loadSrc: $r('app.media.pngSample'), + objectFit:ImageFit.Cover, + border:{color:"#000000",width:1} + } + } + ).height(px2vp(200)).width("50%") + ImageKnifeComponent( + { + imageKnifeOption: { + loadSrc: $r('app.media.test'), + objectFit:ImageFit.Cover, + border:{color:"#000000",width:1} + } + } + ).height(px2vp(200)).width("50%") + } + Text("Fill-不保持宽高比,进行缩放,图片充满显示边界") + .margin({top:10,bottom:10}) + Flex() { + ImageKnifeComponent( + { + imageKnifeOption: { + loadSrc: $r('app.media.pngSample'), + objectFit:ImageFit.Fill, + border:{color:"#000000",width:1} + } + } + ).height(px2vp(200)).width("50%") + ImageKnifeComponent( + { + imageKnifeOption: { + loadSrc: $r('app.media.test'), + objectFit:ImageFit.Fill, + border:{color:"#000000",width:1} + } + } + ).height(px2vp(200)).width("50%") + } + Text("None-图像显示居中展示,不缩放") + .margin({top:10,bottom:10}) + Flex() { + ImageKnifeComponent( + { + imageKnifeOption: { + loadSrc: $r('app.media.pngSample'), + objectFit:ImageFit.None, + border:{color:"#000000",width:1} + } + } + ).height(px2vp(200)).width("50%") + ImageKnifeComponent( + { + imageKnifeOption: { + loadSrc: $r('app.media.test'), + objectFit:ImageFit.None, + border:{color:"#000000",width:1} + } + } + ).height(px2vp(200)).width("50%") + } + Text("ScaleDown-图像大于组件则执行Contain,小于组件则None") + .margin({top:10,bottom:10}) + Flex() { + ImageKnifeComponent( + { + imageKnifeOption: { + loadSrc: $r('app.media.pngSample'), + objectFit:ImageFit.ScaleDown, + border:{color:"#000000",width:1} + } + } + ).height(px2vp(200)).width("50%") + ImageKnifeComponent( + { + imageKnifeOption: { + loadSrc: $r('app.media.test'), + objectFit:ImageFit.ScaleDown, + border:{color:"#000000",width:1} + } + } + ).height(px2vp(200)).width("50%") + } + Text("图片组件宽高:50% * 200px") + .font({size:20,weight:FontWeight.Bolder}) + .fontColor("#ff0000") + .margin({top:10,bottom:10}) + } + }.width("100%") + .height("100%") + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/TransformPage.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/TransformPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..12b1cc34f1c6f494f726de977d0c25c44f32a8bb --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/TransformPage.ets @@ -0,0 +1,50 @@ +/* + * 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. + */ +import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/imageknifec' +import matrix4 from '@ohos.matrix4' + +@Entry +@Component +struct TransformPage { + private custom_scale: number = 1 + @State matrix1: object = matrix4.identity().scale({ x: 1, y: 1 }) + @State ImageKnifeOption: ImageKnifeOption = { + loadSrc: $r('app.media.test'), + placeholderSrc: $r('app.media.loading'), + errorholderSrc: $r('app.media.app_icon'), + objectFit: ImageFit.Contain, + border: { radius: 50 } + } + + build() { + Column() { + ImageKnifeComponent({ imageKnifeOption: this.ImageKnifeOption }).height(200).width(200) + .transform(this.matrix1) + // Image($r('app.media.rabbit')).objectFit(ImageFit.Contain).height(200).width(200).transform(this.matrix1) + Button('放大').onClick(() => { + this.custom_scale = this.custom_scale * 2 + this.matrix1 = matrix4.identity().scale({ x: this.custom_scale, y: this.custom_scale }) + }) + + Button('缩小').onClick(() => { + this.custom_scale = this.custom_scale / 2 + this.matrix1 = matrix4.identity().scale({ x: this.custom_scale, y: this.custom_scale }) + }) + } + .width('100%') + + .height('100%') + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/model/CommonDataSource.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/model/CommonDataSource.ets new file mode 100644 index 0000000000000000000000000000000000000000..d6b16c0933dc6d17aeefc19faed482c4ec38bb02 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/model/CommonDataSource.ets @@ -0,0 +1,54 @@ +/* + * 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. + */ +export class CommonDataSource implements IDataSource { + private dataArray: T[] = [] + private listeners: DataChangeListener[] = [] + + constructor(element: []) { + this.dataArray = element + } + + public getData(index: number) { + return this.dataArray[index] + } + + public totalCount(): number { + return this.dataArray.length + } + + public addData(index: number, data: T[]): void { + this.dataArray = this.dataArray.concat(data) + this.notifyDataAdd(index) + } + + unregisterDataChangeListener(listener: DataChangeListener): void { + const pos = this.listeners.indexOf(listener); + if (pos >= 0) { + this.listeners.splice(pos, 1); + } + } + + registerDataChangeListener(listener: DataChangeListener): void { + if (this.listeners.indexOf(listener) < 0) { + this.listeners.push(listener) + } + } + + notifyDataAdd(index: number): void { + this.listeners.forEach((listener: DataChangeListener) => { + listener.onDataAdd(index) + }) + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/model/DataSourcePrefetching.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/model/DataSourcePrefetching.ets new file mode 100644 index 0000000000000000000000000000000000000000..b8ace805c378ab5d26cfb601f371a84bcd6687ce --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/model/DataSourcePrefetching.ets @@ -0,0 +1,94 @@ +/* + * 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. + */ +import { ImageKnife, ImageKnifeRequest } from '@ohos/imageknifec' +import { IDataSourcePrefetching } from '@kit.ArkUI'; +import { HashMap } from '@kit.ArkTS'; +import { LogUtil } from '../../util/LogUtil'; + +export default class DataSourcePrefetchingImageKnife implements IDataSourcePrefetching { + private dataArray: Array; + private readonly requestList: HashMap = new HashMap(); + private listeners: DataChangeListener[] = []; + + constructor(dataArray: Array) { + this.dataArray = dataArray; + } + + public getData(index: number) { + return this.dataArray[index]; + } + + public totalCount(): number { + return this.dataArray.length; + } + + public addData(index: number, data: string[]): void { + this.dataArray = this.dataArray.concat(data); + this.notifyDataAdd(index); + } + + unregisterDataChangeListener(listener: DataChangeListener): void { + const pos = this.listeners.indexOf(listener); + if (pos >= 0) { + this.listeners.splice(pos, 1); + } + } + + registerDataChangeListener(listener: DataChangeListener): void { + if (this.listeners.indexOf(listener) < 0) { + this.listeners.push(listener); + } + } + + notifyDataAdd(index: number): void { + this.listeners.forEach((listener: DataChangeListener) => { + listener.onDataAdd(index); + }) + } + + async prefetch(index: number): Promise { + let item = this.dataArray[index]; + LogUtil.info("DataSourcePrefetchingImageKnife preload: index = %{public}d , loadsrc = %{public}s", index, item); + // 图片预加载 + let request = ImageKnife.getInstance().preload({ + loadSrc: item, + onLoadListener: { + onLoadSuccess: () => { + // 预加载成功,删除成功请求 + this.requestList.remove(index); + }, + onLoadFailed: () => { + // 移除失败请求 + this.requestList.remove(index); + } + } + }) + this.requestList.set(index, request); + } + + // 取消请求处理 + cancel(index: number) { + if (this.requestList.hasKey(index)) { + // 返回MAP对象指定元素 + const request = this.requestList.get(index); + LogUtil.info("DataSourcePrefetchingImageKnife cancel: index = %{public}d , loadsrc = %{public}s", index, + request?.imageKnifeOption?.loadSrc); + // 取消请求 + ImageKnife.getInstance().cancel(request); + // 移除被取消的请求对象 + this.requestList.remove(index); + } + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/model/ImageUrlData.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/model/ImageUrlData.ets new file mode 100644 index 0000000000000000000000000000000000000000..05c90a9fbc501f60f4a4d49515a129b29e6c937a --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/model/ImageUrlData.ets @@ -0,0 +1,103 @@ +export let dataArray:Array = [ + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/56/v3/8MdhfSsCSMKj4sA6okUWrg/5uBx56tLTUO3RYQl-E5JiQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/e2/v3/4zI1Xm_3STmV30aZXWRrKw/6aN7WodDRUiBApgffiLPCg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/42/v3/2dSQCqERTP2TTPyssOMEbQ/zL1ebnKKQ_ilqTDcwCAkOw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/78/v3/qQJpAtRGQe2e_VhbGHDgIw/b3zlit99S6GybD3XdNwqJw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/55/v3/5DZ2LLqYSsK85-shqgLveQ/7ZXcyCWNTvOzQP5FFLBGkg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/3e/v3/LqRoLI-PRSu9Nqa8KdJ-pQ/dSqskBpSR9eraAMn7NBdqA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/25/v3/jgB2ekkTRX-3yTYZalnANQ/xff_x9cbSPqb7fbNwgJa7A.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/fb/v3/alXwXLHKSyCAIWt_ydgD2g/BCCuu25TREOitQxM7eYOEw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/63/v3/qbe6NZkCQyGcITvdWoZBgg/Y-5U1z3GT_yaK8CBD3jkwg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/16/v3/fm2tO4TsRH6mv_D_nSSd5w/FscLpLwQQ-KuV7oaprFK2Q.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/89/v3/UAUvtPHqRD-GWWANsEC57Q/zcRJCQebQ322Aby4jzmwmQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/30/v3/tUUzzx73R4yp8G--lMhuWQ/EBbcu_dLTT-Jj68XAh6mtA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/76/v3/EyF6z4FISpCHhae38eEexw/OtyAiu-zSSevNQYvUdtVmA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/37/v3/12rH1yiEQmK9wlOOcy5avQ/RzBXiEBRRqOC7LRkwNj6VA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/9a/v3/TpRN4AIzRoyUXIqWdKoE0g/ShOnD_tfS46HDbpSWhbCkQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/03/v3/H3X17s8eTdS2w56JgbB5jQ/a45sT-j8Sbe8sSQXTzeYvQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/10/v3/qaEzwkU0QeKb1yehnP2Xig/q7fxAlgMQKup-HUBayRLGQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/96/v3/rMJJoAflTDSWa1z2pHs2wg/8dOqD0GlQBOCL5AvQok9FQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/ed/v3/KMO4D6D2QGuVOCLX4AhOFA/ef51xAaLQuK7BsnuD9abog.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/d9/v3/FSZH0aTdSqWxeAaxoPvi0g/RqxPxUCXQFiTMBfKTF9kkw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/bf/v3/lSjrRwFcS-ez6jp1ALSQFg/0n7R7XinSPyrYLqDu_1dfw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/8a/v3/ZKzYV5BJTuCk5hCE0y_xNA/8JT95OQnSZSd6_xQQUONhQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/1/v3/sTXb_I7URBKjdMyLDYa19w/qpcwa_FNQmi3-EzjbGsJ8A.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/e5/v3/m7wFvw_eQIuDV0Mk0IKi8g/gJU4migzTHKYk5KrgdZbBw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/3f/v3/k_UWbB5_RGW7JemQZ0OQdw/_DUdmaZRQyG-Oyvkb663Bw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/39/v3/rFRN7G_VSo-p4mBjTZtkRw/gBwTI-ieSIqSsSmLNBEcgw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/04/v3/6K8BPYKVQFOr7KCuAG9nog/qKd3pZlrQy2M-feB3ycVPA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/7d/v3/f0GQFzm1T6eduVeMUhO3Wg/-4cvzIJiRCegjIno3ofIbQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/e4/v3/C0xxsSeySxW-2iYR5OEbpQ/f1GlaD3zTeKPX8Vd-M1oVQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/c2/v3/32LCyXN4TuWKWcdf9gAwWw/ej14_BCJQNCaWOKoI9aZAw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/fd/v3/LyYJMdMmQNaC5GyBYEZ5Pw/uFLiovypRSagKyIS-UJPVw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/15/v3/MHM9KaWGTgubn6M8-B_6nw/1YO9JyYhTHSBWsoiqYkGZw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/4c/v3/UdYfbv1_QYqn_ulDHp89OA/VkjexMluTqGO3yt3gPK1DA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/e8/v3/N8blT_7qSK-tRtahIyov7g/M_kjGEEmSzOlTc47Zrfozg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/28/v3/VS_h3m4YRrSgbgxnqE3vtQ/h-2Q1Qy2SSGEuXM36-Rq_w.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/2e/v3/R-BaM5ToRNGq5rwtNTcnww/Q2e01VHiR2y9KtFaZmpmNQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/88/v3/3djkAJKKTdC539XqMdstSg/wHO7DxvXQS2xbt2Y_-4BNg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/fb/v3/guw4eiggR3uWjscFTxITYg/TzRB35iPTdCztrZUUaNuFg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/93/v3/UvSh_f1LT66i0-3hvsYN_A/eYnE3Z8YT5Sk7F-vS2ZmCQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/5/v3/tv8Vqf9hQrKpozGeZWg2mw/VEICB-bmQYi0Iv6TGADbhw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/30/v3/4v1Ot5BRR6OFVQ9MGn9Xxg/xrPgRn0LS1ep-r7ewIuwiw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/2c/v3/l1QUrFI5QH2iRuhWJQ3TFA/ENot_8t2RRGUHcoa7-NCzA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/67/v3/nAO3aBX0QJWAN9KlS-KNlw/BEZxxNxgQmOSPPGol8rFjw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/26/v3/v77spiS2Tkuhna5amMgmoQ/_1-gABWGRHSYGx7UGTzKCA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/22/v3/LKtJB68-RtyrtmC0PQrGZg/p5xqi4a5TGGbpakgFLqVbg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/ee/v3/888sLvj9SjyetNDIV9FAMg/yuovYaLZSoa8ZVH9SLxY0g.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/34/v3/7njRsvfvR163YkhCsU6mgg/1kRaxKyfRb-6AFN7wlqqIQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/94/v3/RRdj_UMtS7GmDk0JBF38TQ/HMf-OvvUSz2rPKH-pR9ANw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/61/v3/8qWvaPT7QMOdYNAxc3n8qQ/862TSxO1Q9C4QTsxP4j0Lg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/b3/v3/AJ75mLaFSzSA2iGOyoxLMw/L4inOMvSRvSy7DM8-JX7IA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/a1/v3/PSWhcHgsR-aXR82I11Eezg/Z0dynQyIRvOa5SOWB_cz-A.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/6d/v3/hlqEVRr1QFm9QjvLm7Z1Nw/ahFOKVlrRImef44Xy8qqDw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/19/v3/2zGcg1HbQp6Br0tOMIqqPA/NEHwmb0VTtS1UDVg0U0S3A.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/ae/v3/WWm7sZvRSfy13WscmtIfsQ/L-hXcMSHTemLsijPWV1WGA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/fd/v3/XoXdJAO4QH2EkgBity2OBQ/0UtnnXm4QlqBVC25Dlyp3g.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/e9/v3/Mnf5zu2eR6yesosee0sc_Q/yiRJP2ZFQZqAhHrFnnoFgg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/2e/v3/exuDoepKQFCNlNMdOgbn3Q/YMH4h7ABSFik3tdNYhj4Jg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/f6/v3/m7WR37B9RgmdR_DLgTYpfw/JRQGwwGiS3WK3Qamoelklg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/1d/v3/62wv0XRtQ_KDw1DXPtQopQ/xFmiTttgRA2c5OpnOzjmMg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/cf/v3/PGWeVKxUQfSWStVtdan7-g/nCExbJqEQ_ezP8HL7HZVAw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/f4/v3/drqhiCE0SbmDeMadnA8ENg/9U5ihEybRASYW6vBCKBJiA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/41/v3/sWSL_fqYRiSylaNUcXzRHw/bvLytABOSF6q1TdaznKqxQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/3c/v3/1E0n8xbBRYuDL-U1MtS3aQ/97Kqi-zORsSMuBbKyUHRew.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/84/v3/byKXtXhjT9O_n8aZcq-cyw/D5wnxLFeQACLgBAVSb3-Eg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/23/v3/BN1570FsS_yA5o4hUfhbQQ/s76PbX6jSkS0uE-ktxs2YQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/28/v3/mai24I8STNuYRpxI9LJ-iA/SRhtH1OeTjWoS_odzKcAIQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/5d/v3/mhnTdR5ZT7uJ6l8CiNlsCg/OWdKa6pzT0acDNBYhN9G0g.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/f2/v3/2hsTuJMSRRu7TU97TTXPPw/XjYtxDjHQGKcU70H_I2bjQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/82/v3/w7a1NYvXSZSauI1jq3ExYg/uepjCnB6RYatEWRd-s6KXA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/70/v3/SrQzm4HlQzqJcqOtcQwQAA/ZtSdZJPBSrGmG2s8w0157w.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/8b/v3/82Y4V0BZQs21EYQm-_qzyQ/PEQUu0FjT6yXqyrRhcBvoA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/7e/v3/kbAC4rijQD-NIkX6qHgeZw/IyDrcjhNTbaSka54QZ4aFA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/45/v3/4TLlhct_S3W803VYUQMvtg/f7So2mAuTb2hpg_Ei1QxFg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/31/v3/365zN999S0CCD8Gfd95vIA/itPvMkVVR_msdgytMn4pfw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/c3/v3/jJ8t7VgeTu6i7ieEUePr_Q/aluxAl3AT565KuLrBWOLYA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/b4/v3/cHf7nUp_Sxaqe9jzKf1fRQ/8qLLjMbiR8Sdtbb-MWc2ww.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/9c/v3/lLo2e03jRcauAfu86dxaTg/uHqL35O1ROS85fOrQq1l6w.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/a1/v3/VuXG53nMTY2gJFL3pIiqyQ/Ep0eStRjSIOaMFC2LxYFPQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/18/v3/V4ssBbHcQdK6651A5KST6Q/u40BfxroSmu2pRohukh-CQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/db/v3/cdROH6VpQHmOWhrl5vtpCw/SzCPpa7wSa6Gg4PAhsKBUQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/aa/v3/Msd_urqQRuCLJGXY6gTJLg/HlTLr1ifQYKeqxpwNUr6hA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/09/v3/AkfhUmKeQHCRrUJ_PTMt_A/YY83jgqlSBKhAHXl38XsjA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/0/v3/hk8xXCo5SViVm5vWwMeJ9Q/rsrcnaZiQx2-8dn6DAKJtw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/58/v3/T5OactpUSzWk16hwB4Rtkw/IX_nKuloSc2IY01fLE-RnA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/71/v3/Qj3g-5w8R9yI8fnBTp9P8g/z98MyWFfRGukEK0dGSMMMw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/bc/v3/bRv2215bTXOTcKCM4XixKA/_O4g9kxARcyLSl5rMwtnwg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/d7/v3/2H37VrsATpq09l3mt3Yykw/78SVBL4sRM2jEJFq2UvTzQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/72/v3/QrAxeG-FRF28TU_hVH9q6g/cf-flN3gTxuZ3KpfVza2KA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/4e/v3/L0aHZTdoTMSLcAyo6P3FVA/LAH0tap6Qky9zGjbx8-gbg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/2d/v3/40nIrNNLQWawV6dRadLvbg/5KHHIl_FT6qENgCoEN8k3g.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/db/v3/Qm2yemnoTxu79RjKQySZQQ/m4ZougRDRk-0iRLzDJdS-A.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/9b/v3/J7XZtzXNRtynbaXBxsj-Ew/_nACGy5eSGaEMGl9lF7Mzw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/ab/v3/qp_OjhopRGCzgOl0A4VCrw/JqnY3vUzTTir4jOJViZyJg.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/9b/v3/xIh5DVyRRYWz5SZtzoW5tQ/LzvuOKcfTpGnkL1CHlSaiA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/1a/v3/T0CGaE-IT8GftXlOXPo9Iw/H7h-6XlaRFGK5sYt4ViLsA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/2a/v3/VdYheCq0QYiLNnczwqJmfw/lHpW-aiCS0i3Pg6UgSq6Og.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/47/v3/DtPSM2VOT9q6vLK8jVMO6Q/4ho6UeHcQSuUCG89zEOuZw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/36/v3/NdraU__PR-O5VgS9EkhY0w/zp2qkaulTeqiL-zNgEv-yA.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/1b/v3/hqYz4jzWQE--GljcuYcXNA/77P60HCtQCed3GjJmPGMSQ.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/cd/v3/znrV_ormRReyTZRX2zMRtQ/E_lGhanMRgSNZJHgBEL9fw.jpg", + "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/e7/v3/f1-IfawGRYGhbro2kE2chw/JTI0vU88TZSezCBz_s2MWQ.jpg", +] \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/ets/pages/model/User.ets b/thirdparty/image-knife-c/entry/src/main/ets/pages/model/User.ets new file mode 100644 index 0000000000000000000000000000000000000000..3b9ef7874e5ceb31d0a5836e2dd0417c214d2268 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/pages/model/User.ets @@ -0,0 +1,74 @@ +/* + * 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. + */ +import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/imageknifec'; + + +@Component +export struct UserAvatar { + @Prop @Watch('userInfoUpdate') userInfo: string = '' + // @Prop userInfo: string = '' + imgSize: number = 100 + radius: number = 12 + borderSize: number = 0 + imgSizes: number = 1 + @State imageKnifeOption: ImageKnifeOption = new ImageKnifeOption() + @StorageProp('WeLink_Mob_fontSize_multiple') @Watch('updateImgSize') WeLink_Mob_fontSize_multiple: number = 0 + scalable: boolean = true; + @State calcImgSize: number = 100 + + aboutToAppear(): void { + this.userInfoUpdate() + this.setImageSize() + } + + setImageSize() { + if (!this.scalable) { + this.calcImgSize = this.imgSize + } else if (this.WeLink_Mob_fontSize_multiple < 0.9) { + this.calcImgSize = this.imgSize * 0.9 + } else if (this.WeLink_Mob_fontSize_multiple > 1.6) { + this.calcImgSize = this.imgSize * 1.6 + } else { + this.calcImgSize = this.imgSize * this.WeLink_Mob_fontSize_multiple + } + } + + updateImgSize() { + this.setImageSize() + } + + aboutToReuse(param: ESObject) { + this.userInfoUpdate() + } + + userInfoUpdate() { + this.imageKnifeOption = { + //TODO:写死loadSRC,场景:变更组件大小,所有图片不显示 + loadSrc: this.userInfo, + placeholderSrc: $r('app.media.loading'), + errorholderSrc: $r('app.media.failed'), + objectFit:ImageFit.Contain + } + } + + build() { + ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption }) + .borderRadius(this.radius) + .clip(true) + .width(this.calcImgSize) + .height(this.calcImgSize) + .backgroundColor(Color.Pink) + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/ets/util/LogUtil.ets b/thirdparty/image-knife-c/entry/src/main/ets/util/LogUtil.ets new file mode 100644 index 0000000000000000000000000000000000000000..8e77bdc150386fa4ca1ef96183bd9022ae6bf55c --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/ets/util/LogUtil.ets @@ -0,0 +1,36 @@ +/* + * 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. + */ +import { hilog } from '@kit.PerformanceAnalysisKit'; + +export class LogUtil { + public static readonly DOMAIN: number = 0xD002221; + public static readonly TAG: string = "ImageKnifeEntry"; + + public static debug(message: string, ...args: Object[]) { + hilog.debug(LogUtil.DOMAIN, LogUtil.TAG, message, args) + } + + public static info(message: string, ...args: Object[]) { + hilog.info(LogUtil.DOMAIN, LogUtil.TAG, message, args) + } + + public static warn(message: string, ...args: Object[]) { + hilog.warn(LogUtil.DOMAIN, LogUtil.TAG, message, args) + } + + public static error(message: string, ...args: Object[]) { + hilog.error(LogUtil.DOMAIN, LogUtil.TAG, message, args) + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/module.json5 b/thirdparty/image-knife-c/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..0b54fe18ba925cbad8c40811973e060bb9954563 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/module.json5 @@ -0,0 +1,63 @@ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ], + } + ], + "requestPermissions": [ + { + "name": "ohos.permission.INTERNET", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + } + ] + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/resources/base/element/color.json b/thirdparty/image-knife-c/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/thirdparty/image-knife-c/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/thirdparty/image-knife-c/entry/src/main/resources/base/element/string.json b/thirdparty/image-knife-c/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..961dcabe9677a3823812413be0b5858d35d49a7c --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/resources/base/element/string.json @@ -0,0 +1,40 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "label" + }, + { + "name": "adjust_size", + "value": "Adjust size" + }, + { + "name": "local_r_file", + "value": "Local $r file" + }, + { + "name": "local_rawfile", + "value": "Local rawfile" + }, + { + "name": "Under_context_file", + "value": "Files under context file" + }, + { + "name": "local_other_module", + "value": "Local other module" + }, + { + "name": "in_other_module", + "value": "in other module" + } + ] +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/resources/base/media/background.png b/thirdparty/image-knife-c/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d Binary files /dev/null and b/thirdparty/image-knife-c/entry/src/main/resources/base/media/background.png differ diff --git a/thirdparty/image-knife-c/entry/src/main/resources/base/media/failed.png b/thirdparty/image-knife-c/entry/src/main/resources/base/media/failed.png new file mode 100644 index 0000000000000000000000000000000000000000..94c63eb88bea46d4b4b46d26df81ffe4f7a9be86 Binary files /dev/null and b/thirdparty/image-knife-c/entry/src/main/resources/base/media/failed.png differ diff --git a/thirdparty/image-knife-c/entry/src/main/resources/base/media/foreground.png b/thirdparty/image-knife-c/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902 Binary files /dev/null and b/thirdparty/image-knife-c/entry/src/main/resources/base/media/foreground.png differ diff --git a/thirdparty/image-knife-c/entry/src/main/resources/base/media/layered_image.json b/thirdparty/image-knife-c/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/resources/base/media/loading.png b/thirdparty/image-knife-c/entry/src/main/resources/base/media/loading.png new file mode 100644 index 0000000000000000000000000000000000000000..e7ddd2ec0991a25a57c437eaa7894a020e6490f4 Binary files /dev/null and b/thirdparty/image-knife-c/entry/src/main/resources/base/media/loading.png differ diff --git a/thirdparty/image-knife-c/entry/src/main/resources/base/media/pngSample.png b/thirdparty/image-knife-c/entry/src/main/resources/base/media/pngSample.png new file mode 100644 index 0000000000000000000000000000000000000000..df4a14034f8ebb2b9587c2640bb0e2af3db8e451 Binary files /dev/null and b/thirdparty/image-knife-c/entry/src/main/resources/base/media/pngSample.png differ diff --git a/thirdparty/image-knife-c/entry/src/main/resources/base/media/startIcon.png b/thirdparty/image-knife-c/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/thirdparty/image-knife-c/entry/src/main/resources/base/media/startIcon.png differ diff --git a/thirdparty/image-knife-c/entry/src/main/resources/base/media/test.png b/thirdparty/image-knife-c/entry/src/main/resources/base/media/test.png new file mode 100644 index 0000000000000000000000000000000000000000..7d52bd6ca6799001f934ea28e6ebc4a3eb0deda7 Binary files /dev/null and b/thirdparty/image-knife-c/entry/src/main/resources/base/media/test.png differ diff --git a/thirdparty/image-knife-c/entry/src/main/resources/base/profile/backup_config.json b/thirdparty/image-knife-c/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/resources/base/profile/main_pages.json b/thirdparty/image-knife-c/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..bf9c4d309bae62b61123edd4555d9606d235e971 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,16 @@ +{ + "src": [ + "pages/Index", + "pages/SingleImage", + "pages/TestObjectFit", + "pages/LazyForEach", + "pages/ReuseLazyForEach", + "pages/TestBorder", + "pages/TransformPage", + "pages/PrefetchAndPreload", + "pages/AutoImageFit", + "pages/MultipleImageCallBack", + "pages/LongImagePage", + "pages/LocalImage" + ] +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/main/resources/rawfile/image/startIcon.png b/thirdparty/image-knife-c/entry/src/main/resources/rawfile/image/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..366f76459ffd4494ec40d0ddd5c59385b9c5da11 Binary files /dev/null and b/thirdparty/image-knife-c/entry/src/main/resources/rawfile/image/startIcon.png differ diff --git a/thirdparty/image-knife-c/entry/src/main/resources/zh_CN/element/string.json b/thirdparty/image-knife-c/entry/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..073f01c20a0e848e513a4e93c7a0771c38ad0f15 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,36 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "模块描述" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "label" + }, + { + "name": "adjust_size", + "value": "调整大小" + }, + { + "name": "local_r_file", + "value": "本地$r文件" + }, + { + "name": "local_rawfile", + "value": "本地rawfile文件" + }, + { + "name": "Under_context_file", + "value": "本地沙箱路径文件" + }, + { + "name": "local_other_module", + "value": "本地其他模块文件" + } + ] +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/mock/Libentry.mock.ets b/thirdparty/image-knife-c/entry/src/mock/Libentry.mock.ets new file mode 100644 index 0000000000000000000000000000000000000000..c2171716d040a605ef6af71e90b937a945f2677d --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/mock/Libentry.mock.ets @@ -0,0 +1,7 @@ +const NativeMock: Record = { + 'add': (a: number, b: number) => { + return a + b; + }, +}; + +export default NativeMock; \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/mock/mock-config.json5 b/thirdparty/image-knife-c/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..6540976c9acc8afbd45895db6404334cff195465 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/mock/mock-config.json5 @@ -0,0 +1,5 @@ +{ + "libentry.so": { + "source": "src/mock/Libentry.mock.ets" + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/ohosTest/ets/test/Ability.test.ets b/thirdparty/image-knife-c/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..85c78f67579d6e31b5f5aeea463e216b9b141048 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,35 @@ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function abilityTest() { + describe('ActsAbilityTest', () => { + // 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. + hilog.info(0x0000, 'testTag', '%{public}s', 'it begin'); + 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/thirdparty/image-knife-c/entry/src/ohosTest/ets/test/List.test.ets b/thirdparty/image-knife-c/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..794c7dc4ed66bd98fa3865e07922906e2fcef545 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,5 @@ +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/ohosTest/module.json5 b/thirdparty/image-knife-c/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..55725a929993a8a18b3808d41ef037759440488b --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/ohosTest/module.json5 @@ -0,0 +1,13 @@ +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/thirdparty/image-knife-c/entry/src/test/List.test.ets b/thirdparty/image-knife-c/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..bb5b5c3731e283dd507c847560ee59bde477bbc7 --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/test/List.test.ets @@ -0,0 +1,5 @@ +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/entry/src/test/LocalUnit.test.ets b/thirdparty/image-knife-c/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..165fc1615ee8618b4cb6a622f144a9a707eee99f --- /dev/null +++ b/thirdparty/image-knife-c/entry/src/test/LocalUnit.test.ets @@ -0,0 +1,33 @@ +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/thirdparty/image-knife-c/hvigor/hvigor-config.json5 b/thirdparty/image-knife-c/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..06b2783670a348f95533b352c1ceda909a842bbc --- /dev/null +++ b/thirdparty/image-knife-c/hvigor/hvigor-config.json5 @@ -0,0 +1,22 @@ +{ + "modelVersion": "5.0.0", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "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": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/thirdparty/image-knife-c/hvigorfile.ts b/thirdparty/image-knife-c/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..f3cb9f1a87a81687554a76283af8df27d8bda775 --- /dev/null +++ b/thirdparty/image-knife-c/hvigorfile.ts @@ -0,0 +1,6 @@ +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/thirdparty/image-knife-c/library/.gitignore b/thirdparty/image-knife-c/library/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/thirdparty/image-knife-c/library/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/BuildProfile.ets b/thirdparty/image-knife-c/library/BuildProfile.ets new file mode 100644 index 0000000000000000000000000000000000000000..3a501e5ddee8ea6d28961648fc7dd314a5304bd4 --- /dev/null +++ b/thirdparty/image-knife-c/library/BuildProfile.ets @@ -0,0 +1,17 @@ +/** + * Use these variables when you tailor your ArkTS code. They must be of the const type. + */ +export const HAR_VERSION = '1.0.0'; +export const BUILD_MODE_NAME = 'debug'; +export const DEBUG = true; +export const TARGET_NAME = 'default'; + +/** + * BuildProfile Class is used only for compatibility purposes. + */ +export default class BuildProfile { + static readonly HAR_VERSION = HAR_VERSION; + static readonly BUILD_MODE_NAME = BUILD_MODE_NAME; + static readonly DEBUG = DEBUG; + static readonly TARGET_NAME = TARGET_NAME; +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/FindImageKnifeC.cmake b/thirdparty/image-knife-c/library/FindImageKnifeC.cmake new file mode 100755 index 0000000000000000000000000000000000000000..5bd2a0105eff0f666a5940baa84e3b6f9acc050e --- /dev/null +++ b/thirdparty/image-knife-c/library/FindImageKnifeC.cmake @@ -0,0 +1,96 @@ + +if(NOT IMAGEKNIFEC_ROOT_PATH) + message(FATAL_ERROR "-- [IMAGEKNIFEC]: IMAGEKNIFEC_ROOT_PATH must be setted up at first.") +endif() + +set(IMAGEKNIFEC_SEARCH_PATH ${IMAGEKNIFEC_ROOT_PATH}) +set(CMAKE_CXX_STANDARD 17) +# find base path +find_path(IMAGEKNIFEC_PATH + NAMES include/ImageKnife.h + PATHS ${IMAGEKNIFEC_SEARCH_PATH} + CMAKE_FIND_ROOT_PATH_BOTH + ) + +# find includes +if(NOT IMAGEKNIFEC_INCLUDE_DIRS) + find_path(IMAGEKNIFEC_INCLUDE_DIR + NAMES Imageknife.h + PATHS ${IMAGEKNIFEC_PATH} + PATH_SUFFIXES include + CMAKE_FIND_ROOT_PATH_BOTH + ) + + set(IMAGEKNIFEC_INCLUDE_DIRS + ${IMAGEKNIFEC_INCLUDE_DIR}) +endif() + +# find link directories +if(NOT IMAGEKNIFEC_LINK_DIRS) + find_path(IMAGEKNIFEC_LIB_LINK_DIRS + NAMES libimageknifec.so + PATHS "${IMAGEKNIFEC_PATH}" + PATH_SUFFIXES "libs/${CMAKE_OHOS_ARCH_ABI}" + CMAKE_FIND_ROOT_PATH_BOTH + ) + + set(IMAGEKNIFEC_LINK_DIRS + ${IMAGEKNIFEC_LIB_LINK_DIRS}) + +endif() + +# find librarys +if(NOT IMAGEKNIFEC_LIBRARIS) + find_library(IMAGEKNIFEC_LIBRARY + NAMES imageknifec + PATHS "${IMAGEKNIFEC_PATH}" + PATH_SUFFIXES "libs/${CMAKE_OHOS_ARCH_ABI}" + CMAKE_FIND_ROOT_PATH_BOTH + ) + + set(IMAGEKNIFEC_LIBRARIS + imageknifec + ace_napi.z + ace_ndk.z + rcp_c + image_source + pixelmap + rawfile.z + ohresmgr + hilog_ndk.z + ohcrypto) + +endif() + +# 编译宏 +if(NOT IMAGEKNIFEC_DEFINITIONS) + if(OHOS) + set(IMAGEKNIFEC_DEFINITIONS ${IMAGEKNIFEC_DEFINITIONS} "IMAGEKNIFEC_ENABLE_NAPI=1") + endif() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(IMAGEKNIFEC DEFAULT_MSG + IMAGEKNIFEC_INCLUDE_DIRS + IMAGEKNIFEC_LIBRARIS +) + +if(IMAGEKNIFEC_FOUND AND NOT TARGET Imageknifec::libimageknifec) + # 创建接口lib + add_library(Imageknifec::libimageknifec INTERFACE IMPORTED) + + # 设置target 头文件依赖 + target_include_directories(Imageknifec::libimageknifec INTERFACE ${IMAGEKNIFEC_INCLUDE_DIRS}) + + # 设置target link依赖路径 + target_link_directories(Imageknifec::libimageknifec INTERFACE ${IMAGEKNIFEC_LINK_DIRS}) + + # 设置target lib依赖 + target_link_libraries(Imageknifec::libimageknifec INTERFACE ${IMAGEKNIFEC_LIBRARIS}) + + # 设置target 编译宏 + target_compile_definitions(Imageknifec::libimageknifec INTERFACE ${IMAGEKNIFEC_DEFINITIONS}) + + # 安全编译选项 NO Rpath 规则 + set(CMAKE_SKIP_RPATH TRUE) +endif() diff --git a/thirdparty/image-knife-c/library/Index.ets b/thirdparty/image-knife-c/library/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..4397ac9180bfdcdc5b1dd7909562a99c2ff2c62c --- /dev/null +++ b/thirdparty/image-knife-c/library/Index.ets @@ -0,0 +1,7 @@ +export { ImageKnifeComponent } from './src/main/ets/components/ImageKnifeComponent' + +export { ImageKnifeOption } from './src/main/ets/model/ImageKnifeOption' + +export { ImageKnifeRequest } from './src/main/ets/model/ImageKnifeRequest' + +export { ImageKnife } from './src/main/ets/ImageKnife' diff --git a/thirdparty/image-knife-c/library/build-profile.json5 b/thirdparty/image-knife-c/library/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..60f3a14a9eecc1bdce3dd96dad9637a4046d216f --- /dev/null +++ b/thirdparty/image-knife-c/library/build-profile.json5 @@ -0,0 +1,36 @@ +{ + "apiType": "stageMode", + "buildOption": { + "externalNativeOptions": { + "path": "./src/main/cpp/CMakeLists.txt", + "arguments": "", + "cppFlags": "", + } + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": true, + "files": [ + "./obfuscation-rules.txt" + ] + }, + "consumerFiles": [ + "./consumer-rules.txt" + ] + } + }, + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest" + } + ] +} diff --git a/thirdparty/image-knife-c/library/consumer-rules.txt b/thirdparty/image-knife-c/library/consumer-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/thirdparty/image-knife-c/library/hvigorfile.ts b/thirdparty/image-knife-c/library/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..42187071482d292588ad40babeda74f7b8d97a23 --- /dev/null +++ b/thirdparty/image-knife-c/library/hvigorfile.ts @@ -0,0 +1,6 @@ +import { harTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/thirdparty/image-knife-c/library/obfuscation-rules.txt b/thirdparty/image-knife-c/library/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..69c4d6a8a5531548e4886fa766090c5c157a87d9 --- /dev/null +++ b/thirdparty/image-knife-c/library/obfuscation-rules.txt @@ -0,0 +1,18 @@ +# 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://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# 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 \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/oh-package-lock.json5 b/thirdparty/image-knife-c/library/oh-package-lock.json5 new file mode 100644 index 0000000000000000000000000000000000000000..37141d1f1827dd990188899789f17a6eccc058f5 --- /dev/null +++ b/thirdparty/image-knife-c/library/oh-package-lock.json5 @@ -0,0 +1,18 @@ +{ + "meta": { + "stableOrder": true + }, + "lockfileVersion": 3, + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", + "specifiers": { + "libimageknifec.so@src/main/cpp/types/libentry": "libimageknifec.so@src/main/cpp/types/libentry" + }, + "packages": { + "libimageknifec.so@src/main/cpp/types/libentry": { + "name": "libimageknifec.so", + "version": "1.0.0", + "resolved": "src/main/cpp/types/libentry", + "registryType": "local" + } + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/oh-package.json5 b/thirdparty/image-knife-c/library/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ced766969c70d0486cd726fec2be3dddf621681e --- /dev/null +++ b/thirdparty/image-knife-c/library/oh-package.json5 @@ -0,0 +1,11 @@ +{ + "name": "@ohos/imageknifec", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "Index.ets", + "author": "", + "license": "Apache-2.0", + "dependencies": { + "libimageknifec.so": "file:./src/main/cpp/types/libentry" + } +} diff --git a/thirdparty/image-knife-c/library/src/main/cpp/CMakeLists.txt b/thirdparty/image-knife-c/library/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d232e05e597cb81af726000b2216a4258575b3f1 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/CMakeLists.txt @@ -0,0 +1,50 @@ +# the minimum version of CMake. +cmake_minimum_required(VERSION 3.5.0) +project(image-knife-c) + +option(IMAGEKNIFEC_ENABLE_INSTALL "" ON) + +set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +if(DEFINED PACKAGE_FIND_FILE) + include(${PACKAGE_FIND_FILE}) +endif() + +# Specify the C++ standard to use +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +include_directories(${NATIVERENDER_ROOT_PATH} + ${NATIVERENDER_ROOT_PATH}/include + ${NATIVERENDER_ROOT_PATH}/node + ${NATIVERENDER_ROOT_PATH}/cache + ${NATIVERENDER_ROOT_PATH}/interceptor) + +add_library(imageknifec SHARED napi_init.cpp + imageKnife_napi.cpp + imageKnife_internal.cpp + imageKnife_dispatcher.cpp + request/imageKnife_request_internal.cpp + imageKnife_task_internal.cpp + interceptor/interceptor.cpp + cache/lru_cache.cpp + key/default_engine_key.cpp + cache/file_cache.cpp + loader/imageKnife_loader.cpp + loader/imageKnife_loader_internal.cpp + node/imageKnife_node.cpp + node/imageKnife_data.cpp + node/imageKnife_option.cpp + queue/default_job_queue.cpp) +target_link_libraries(imageknifec PUBLIC libace_napi.z.so libace_ndk.z.so librcp_c.so + libimage_source.so libpixelmap.so librawfile.z.so libohresmgr.so libhilog_ndk.z.so + libohcrypto.so) + +target_link_directories(imageknifec PUBLIC ${HMOS_SDK_NATIVE}/sysroot/usr/lib/aarch64-linux-ohos) + +if (IMAGEKNIFEC_ENABLE_INSTALL) +set(IMAGEKNIFEC_INSTALL_PATH "${CMAKE_SOURCE_DIR}/../../../") +add_custom_command(TARGET imageknifec POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/include ${IMAGEKNIFEC_INSTALL_PATH}/include) +endif() diff --git a/thirdparty/image-knife-c/library/src/main/cpp/cache/file_cache.cpp b/thirdparty/image-knife-c/library/src/main/cpp/cache/file_cache.cpp new file mode 100644 index 0000000000000000000000000000000000000000..de6b6be5d5681772b5a741e4ec8aac542fc9395c --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/cache/file_cache.cpp @@ -0,0 +1,349 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "native_entry.h" +#include "imageKnife.h" +#include "file_cache.h" + +namespace ImageKnifeC { + +const long FileCache::defaultSize = 512; +const long FileCache::defaultMemory = 128 * 1024 * 1024; +const long FileCache::defaultMaxSize = 4096; +const long FileCache::defaultMaxMemory = 512 * 1024 * 1024; +FileCache::AsyncData *FileCache::asyncData = new FileCache::AsyncData(); + +FileCache *FileCache::fileCachePtr = nullptr; +lru11::Cache *FileCache::cachePtr = nullptr; + +void FileCache::Init(int size, int memory) +{ + if (!cachePtr) { + cachePtr = new lru11::Cache(size, 0); + } + + allowMaxSize_ = (size > 0 && size <= defaultMaxSize) ? size : defaultSize; + allowMaxMemory_ = (memory > 0 && memory <= defaultMaxMemory) ? memory : defaultMemory; +} + +FileCache *FileCache::GetInstance() +{ + if (!fileCachePtr) { + // 未正确调用情况下使用的默认数据 + const size_t allowMaxsize = 50; + const size_t allowMaxMemory = 100 * 1024 * 1024; + fileCachePtr = new FileCache(allowMaxsize, allowMaxMemory); + } + return fileCachePtr; +} + +void FileCache::DestroyInstance() +{ + if (fileCachePtr) { + delete fileCachePtr; + fileCachePtr = nullptr; + } + if (asyncData) { + delete asyncData; + asyncData = nullptr; + } + + if (cachePtr) { + delete cachePtr; + cachePtr = nullptr; + } +} + +FileCache::FileCache(size_t allowMaxsize, size_t allowMaxMemory) + : allowMaxSize_(allowMaxsize > 0 && allowMaxsize <= defaultMaxSize ? allowMaxsize : defaultSize), + allowMaxMemory_(allowMaxMemory > 0 && allowMaxMemory <= defaultMaxMemory ? allowMaxMemory : defaultMemory), + currentMemory_(0), + isFileInitComplete_(false) +{ +} + +void FileCache::Put(const std::string &key, size_t value) +{ + if (!isFileInitComplete_) { + return; + } + + if (key == "") { + return ; + } + + while (currentMemory_ >= allowMaxMemory_ || cachePtr->size() >= allowMaxSize_) { + std::string keyOut; + size_t valueOut; + if (cachePtr->getTail(keyOut, valueOut)) { + cachePtr->remove(keyOut); + DeleteFile(keyOut); + RemoveMemorySize(valueOut); + } + } + cachePtr->insert(key, value); + AddMemorySize(value); +} + +size_t FileCache::Size() +{ + return cachePtr->size(); +} + +bool FileCache::Empty() +{ + return cachePtr->empty(); +} + +size_t FileCache::Get(const std::string &key) +{ + if (!isFileInitComplete_) { + return 0; + } + size_t fileSize = 0; + + bool result = cachePtr->tryGet(key, fileSize); + if (!result) { + return 0; + } + return fileSize; +} + +bool FileCache::Contains(const std::string &key) const +{ + return cachePtr->contains(key); +} + +bool FileCache::DeleteFile(const std::string &fileName) +{ + std::string path = filePath + "/" + fileName; + if (remove(path.c_str()) != 0) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "FileCache::DeleteFile", "DeleteFile failed"); + return false; + } + return true; +} + +void FileCache::InitFileCache() +{ + DIR* dir = opendir(filePath.c_str()); + if (dir == nullptr) { + OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, "FileCache::DeleteFile", + "Cannot open directory %{public}s", filePath.c_str()); + + // 设置promise为错误信息 + promise.set_value("Error: Cannot open directory: " + filePath); + return; + } + struct dirent *entry; + std::vector filesVector; + while ((entry = readdir(dir)) != nullptr) { + std::string fileName = entry->d_name; + + // 跳过 "." 和 ".." 目录 + if (fileName == "." || fileName == "..") { + continue; + } + + std::string fullPath = filePath + "/" + fileName; + + struct stat fileStat; + if (stat(fullPath.c_str(), &fileStat) == 0) { + // 如果是普通文件,将其添加到 filesVector 中 + if (S_ISREG(fileStat.st_mode)) { + FileInfo fileInfo; + fileInfo.fileName = fileName; + // 访问时间 + fileInfo.lastAccessTime = fileStat.st_atime; + // 文件大小 + fileInfo.fileSize = fileStat.st_size; + filesVector.push_back(fileInfo); + } + } + } + + closedir(dir); + + // 最近访问的排在后面 + std::sort(filesVector.begin(), filesVector.end(), [](const FileInfo &a, const FileInfo &b) { + return a.lastAccessTime < b.lastAccessTime; + }); + + for (const auto &fileInfo : filesVector) { + while (currentMemory_ >= allowMaxMemory_ || cachePtr->size() >= allowMaxSize_) { + std::string keyOut; + size_t valueOut; + if (cachePtr->getTail(keyOut, valueOut)) { + cachePtr->remove(keyOut); + DeleteFile(keyOut); + RemoveMemorySize(valueOut); + } + } + cachePtr->insert(fileInfo.fileName, fileInfo.fileSize); + AddMemorySize(fileInfo.fileSize); + } + // 标识位置true + isFileInitComplete_ = true; + + // 设置promise为成功信息 + promise.set_value("File cache initialized successfully"); +} + +void FileCache::AddMemorySize(size_t value) +{ + currentMemory_ += value; +} + +void FileCache::RemoveMemorySize(size_t value) +{ + currentMemory_ -= value; +} + +void FileCache::SaveImageToDisk(const char *buffer, uint32_t length, std::string &fileKey) +{ + if (filePath == "") { + return; + } + + if (mkdir(filePath.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) { + if (errno == EEXIST) { + OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, + "FileCache::SaveImageToDisk", + "Directory already exists"); + } else { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "FileCache::SaveImageToDisk", + "Failed to create directory"); + return; + } + } + + std::lock_guard lock(lock_); + std::string fullPath = filePath + "/" + fileKey; + FILE *fp = fopen(fullPath.c_str(), "w"); + if (fp) { + size_t itemsWritten = fwrite(buffer, sizeof(char), length, fp); + fclose(fp); + if (itemsWritten == length) { + // insert into LRU + Put(fileKey, length); + } else { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "FileCache::SaveImageToDisk", + "Failed to write all items to file"); + } + } else { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "FileCache::SaveImageToDisk", + "write to file Failed!!"); + } +} + +bool FileCache::GetImageFromDisk(std::string &fileKey, FileData &fileData) +{ + std::lock_guard lock(lock_); + if (Get(fileKey) == 0) { + return false; + } + + std::string fullPath = filePath + "/" + fileKey; + + // 打开文件 + FILE *fp = fopen(fullPath.c_str(), "rb"); + if (!fp) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeNode", + "open file failed"); + return false; + } + + // 获取文件大小 + fseek(fp, 0, SEEK_END); + fileData.size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + // 使用 new 直接分配堆内存 + fileData.buffer = std::shared_ptr(new (std::nothrow) uint8_t[fileData.size]); + if (!fileData.buffer) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeNode", + "Memory allocation failed"); + fclose(fp); + return false; + } + + // 读取文件内容到堆上的内存 + const size_t chunkSize = 1024 * 1024; + fread(fileData.buffer.get(), chunkSize, fileData.size, fp); + + if (ferror(fp)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeNode", + "Error reading file: %{public}s", + strerror(errno)); + fclose(fp); + return false; + } + fclose(fp); + + return true; +} +void FileCache::StartFileCacheInitThread(napi_env env, void *data) +{ + ImageKnifeC::ImageKnife::GetInstance().InitFileCache(FileCache::asyncData->fileDir, + FileCache::asyncData->size, + FileCache::asyncData->memory, + FileCache::asyncData->path); +} + +void FileCache::FileCacheInitComplete(napi_env env, napi_status status, void *data) +{ + napi_value result; + + // 判断任务是否成功完成,给 result 赋值 + if (status == napi_ok) { + // 如果成功,可以设置一个成功的结果 + const char *successMessage = "File cache initialization completed successfully."; + napi_create_string_utf8(env, successMessage, NAPI_AUTO_LENGTH, &result); + + // 解决 deferred Promise,传递成功的 result + napi_resolve_deferred(env, FileCache::asyncData->deferred, result); + } else { + // 如果发生错误,传递错误信息 + const char* errorMessage = "File cache initialization failed."; + napi_create_string_utf8(env, errorMessage, NAPI_AUTO_LENGTH, &result); + + // 拒绝 deferred Promise,传递错误的 result + napi_reject_deferred(env, FileCache::asyncData->deferred, result); + } + + napi_delete_async_work(env, FileCache::asyncData->asyncWork); + // 释放 AsyncData 结构体的内存 + FileCache::asyncData->asyncWork = nullptr; + delete FileCache::asyncData; + FileCache::asyncData = nullptr; +} +} diff --git a/thirdparty/image-knife-c/library/src/main/cpp/cache/file_cache.h b/thirdparty/image-knife-c/library/src/main/cpp/cache/file_cache.h new file mode 100644 index 0000000000000000000000000000000000000000..79dcb9cbe3c7c64c50c13718c69a4c6ea93561d7 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/cache/file_cache.h @@ -0,0 +1,120 @@ +/* + * 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_KNIFE_C_FILE_CACHE_H +#define IMAGE_KNIFE_C_FILE_CACHE_H +#include +#include +#include + +#include "lru_cache.h" +#include "thirdparty/LRUCache11.h" +#include "imageKnife_request.h" +#include "imageKnife_task.h" + +namespace ImageKnifeC { +class FileCache { +public: + struct FileData { + std::shared_ptr buffer = nullptr; + uint32_t size = 0; + }; + + struct FileInfo { + std::string fileName; + time_t lastAccessTime; + size_t fileSize; // 文件大小 + }; + + struct AsyncData { + std::string fileDir; + int size; + int memory; + std::string path; + napi_deferred deferred; + napi_async_work asyncWork; + }; + + static FileCache *GetInstance(); + static void DestroyInstance(); + + // 初始化lru,内存数量和大小 + void Init(int size, int memory); + + // 禁止复制构造和赋值 + FileCache(const FileCache&) = delete; + FileCache& operator=(const FileCache&) = delete; + + size_t Size(); + + bool Empty(); + + void Put(const std::string &key, size_t value); + + size_t Get(const std::string &key); + + bool Contains(const std::string &key) const; + + void InitFileCache(); + + void SaveImageToDisk(const char *buffer, uint32_t length, std::string &fileKey); + bool GetImageFromDisk(std::string &fileKey, FileData &fileData); + + static void StartFileCacheInitThread(napi_env env, void *arg); + static void FileCacheInitComplete(napi_env env, napi_status status, void *data); + + std::string filePath; + bool isFileInitComplete_; + + static AsyncData *asyncData; + std::promise promise; + +private: + explicit FileCache(size_t allowMaxsize, size_t allowMaxMemory); + ~FileCache() = default; + + bool DeleteFile(const std::string &fileName); + + void AddMemorySize(size_t value); + void RemoveMemorySize(size_t value); + + static const long defaultSize; + static const long defaultMemory; + static const long defaultMaxSize; + static const long defaultMaxMemory; + + // 聚合的缓存实例 + static lru11::Cache *cachePtr; + static FileCache *fileCachePtr; + + long allowMaxSize_; + long allowMaxMemory_; + long currentMemory_; + + // 记录线程中图片下载/加载/更新中的错误信息 + std::string lastError_; + + // pixelMap native + OH_PixelmapNative *pixelMap_ = nullptr; + + // pixelMap图片desc + void *imgDesc_ = nullptr; + + std::mutex lock_; +}; + +} // namespace ImageKnifeC + +#endif // IMAGE_KNIFE_C_FILE_CACHE_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/cache/lru_cache.cpp b/thirdparty/image-knife-c/library/src/main/cpp/cache/lru_cache.cpp new file mode 100644 index 0000000000000000000000000000000000000000..514b0edec97424967a139833c2eefc7f0b4bbeb8 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/cache/lru_cache.cpp @@ -0,0 +1,83 @@ +/* + * 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. + */ + +#include "lru_cache.h" +#include + +namespace ImageKnifeC { +const long LruCache::defaultSize = 50; +const long LruCache::defaultMemory = 128 * 1024 * 1024; +const long LruCache::defaultMaxSize = 4096; +const long LruCache::defaultMaxMemory = 1024 * 1024 * 1024; + +LruCache *LruCache::cachePtr = nullptr; + +LruCache *LruCache::GetInstance() +{ + if (!cachePtr) { + // js层传入的参数 + const size_t allowMaxsize = 10; + const size_t allowMaxMemory = 1024 * 1024; + cachePtr = new LruCache(allowMaxsize, allowMaxMemory); + } + return cachePtr; +} + +void LruCache::DestroyInstance() +{ + if (cachePtr) { + delete cachePtr; + cachePtr = nullptr; + } +} + +LruCache::LruCache(size_t allowMaxsize, size_t allowMaxMemory) + : allowMaxSize_(allowMaxsize > 0 && allowMaxsize <= defaultMaxSize ? allowMaxsize : defaultSize), + allowMaxMemory_(allowMaxMemory > 0 && allowMaxMemory <= defaultMaxMemory ? allowMaxMemory : defaultMemory), + currentMemory_(0), + cache_(static_cast(allowMaxSize_), 0) +{ +} + +void LruCache::Put(const std::string &key, std::shared_ptr value) +{ + cache_.insert(key, value); +} + +size_t LruCache::Size() +{ + return cache_.size(); +} + +bool LruCache::Empty() +{ + return cache_.empty(); +} + +std::shared_ptr LruCache::Get(const std::string &key) +{ + std::shared_ptr pixelmap; + bool result = cache_.tryGet(key, pixelmap); + if (result) { + return pixelmap; + } + return nullptr; +} + +bool LruCache::Contains(const std::string &key) const +{ + return cache_.contains(key); +} +} diff --git a/thirdparty/image-knife-c/library/src/main/cpp/cache/lru_cache.h b/thirdparty/image-knife-c/library/src/main/cpp/cache/lru_cache.h new file mode 100644 index 0000000000000000000000000000000000000000..b0a17a942e720744e884266d8191878fc461d043 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/cache/lru_cache.h @@ -0,0 +1,55 @@ +/* + * 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_KNIFE_C_LRU_CACHE_H +#define IMAGE_KNIFE_C_LRU_CACHE_H +#include +#include "thirdparty/LRUCache11.h" +#include +#include "imageKnife_task.h" + +namespace ImageKnifeC { +class LruCache { +public: + static LruCache* GetInstance(); + static void DestroyInstance(); + // 禁止复制构造和赋值 + LruCache(const LruCache&) = delete; + LruCache& operator=(const LruCache&) = delete; + size_t Size(); + bool Empty(); + void Put(const std::string &key, std::shared_ptr value); + std::shared_ptr Get(const std::string &key); + bool Contains(const std::string &key) const; + +private: + explicit LruCache(size_t allowMaxsize, size_t allowMaxMemory); + ~LruCache() = default; + + static const long defaultSize; + static const long defaultMemory; + static const long defaultMaxSize; + static const long defaultMaxMemory; + static LruCache *cachePtr; + long allowMaxSize_; + long allowMaxMemory_; + long currentMemory_; + std::mutex lock_; + // 聚合的缓存实例 + lru11::Cache, std::mutex> cache_; +}; + +} // namespace ImageKnifeC +#endif // IMAGE_KNIFE_C_LRU_CACHE_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_dispatcher.cpp b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_dispatcher.cpp new file mode 100644 index 0000000000000000000000000000000000000000..44a4646336490bc022838ea695f1c96c65d15b79 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_dispatcher.cpp @@ -0,0 +1,496 @@ +/* + * 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. + */ + + +#include "imageKnife_dispatcher.h" +#include "task_worker.h" +#include "native_entry.h" +#include "lru_cache.h" +#include "imageKnife_loader.h" +#include "task_worker.h" +#include "imageKnife_internal.h" +#include "imageKnife_task_internal.h" +#include "loader/imageKnife_loader_internal.h" + +namespace ImageKnifeC { + +ImageKnifeDispatcher::ImageKnifeDispatcher() +{ +} + +ImageKnifeDispatcher::~ImageKnifeDispatcher() +{ + if (jobQueuePtr_ != nullptr) { + delete jobQueuePtr_; + } +} + +void ImageKnifeDispatcher::Enqueue(std::shared_ptr request) +{ + // js层start回调 + if (request->GetImageKnifeOption()->onLoadListener.onLoadStart != nullptr) { + request->GetImageKnifeOption()->onLoadListener.onLoadStart(); + } + + if (request->GetImageKnifeOption()->imageLoader == nullptr) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "Enqueue", + "Can't find ImageKnifeLoader"); + if (request->GetImageKnifeOption()->onLoadListener.onLoadFailed != nullptr) { + request->GetImageKnifeOption()->onLoadListener.onLoadFailed("Can't find ImageKnifeLoader"); + } + return; + } + + // 1.内存有的话直接渲染 + if (LoadSrcFromMemory(request, ImageKnifeRequestSource::MAINSRC)) { + return; + } + + bool foundPlaceHolder = LoadSrcFromMemory(request, ImageKnifeRequestSource::PLACESRC); + + // 判断是否排队 + if (executingJobMap_.size() >= maxRequests) { + DefaultJobQueue::QueueElement mainQueueElement(request, ImageKnifeRequestSource::MAINSRC); + jobQueuePtr_->Add(mainQueueElement); + + if (!foundPlaceHolder && !request->IsSyncLoad()) { + DefaultJobQueue::QueueElement placeQueueElement(request, ImageKnifeRequestSource::PLACESRC); + jobQueuePtr_->Add(placeQueueElement); + } + return; + } + + // 启动加载主图 + ExecuteJob(ImageKnifeRequestSource::MAINSRC, request); + + // 启动加载占位图 + if (!foundPlaceHolder && !request->IsSyncLoad()) { + ExecuteJob(ImageKnifeRequestSource::PLACESRC, request); + } +} + +void ImageKnifeDispatcher::LoadImageSource(void *arg) +{ + ImageKnifeTaskInternal *task = static_cast(arg); + auto request = static_cast(task->request.get()); + auto imageLoader = static_cast(request->GetImageKnifeOption()->imageLoader.get()); + + // 检查文件缓存 + bool loadEnd = imageLoader->LoadFromFile(task); + bool writeFileCache = !loadEnd; + + if (request->IsDestroy() || task->IsFatalErrorHappened()) { + return; + } + + // 加载结束 + if (!loadEnd) { + loadEnd = imageLoader->DownloadImage(task); + } + + if (request->IsDestroy() || task->IsFatalErrorHappened()) { + return; + } + + if (!loadEnd) { + if (task->GetLastError().empty()) { + task->EchoError("load Image Failed! No useful error message (Loading)"); + } + return; + } + + // 图片解码 + if (!imageLoader->DecodeImage(task) || task->IsFatalErrorHappened()) { + if (task->GetLastError().empty()) { + task->EchoError("image Decode error! No useful error message (Loading)"); + } + return; + } + + if (request->IsDestroy() || task->IsFatalErrorHappened()) { + return; + } + + // 解码成功后写原始文件缓存,下载的文件不一定是有效图片 + if (writeFileCache) { + imageLoader->WriteCacheToFile(task); + } + + if (request->IsDestroy()) { + return; + } + + // 图片形变, 默认没有图片形变 + TransformImage(task); + + if (request->IsDestroy() || task->IsFatalErrorHappened()) { + return; + } + + // 写内存缓存 + imageLoader->WriteCacheToMemory(task); + + task->QueryDisplayPixelmapInfo(); + task->MarkSuccess(); +} + +void ImageKnifeDispatcher::OnComplete(void *arg) +{ + ImageKnifeTaskInternal *task = static_cast(arg); + auto request = static_cast(task->request.get()); + + try { + for (DefaultJobQueue::QueueElement queueElement : executingJobMap_[task->memoryKey]) { + auto option = queueElement.request->GetImageKnifeOption(); + if (request->IsDestroy()) { + // 任务在执行中被取消 + if (option->onLoadListener.onLoadCancel != nullptr) { + option->onLoadListener.onLoadCancel(task->GetTaskInfo(task->type, + task->request.get()) + "Request Abort"); + } + } else if (task->IsSuccess()) { + if (queueElement.type != ImageKnifeRequestSource::PLACESRC) { + queueElement.request->MarkStatusComplete(); + } + // 显示前打印图片信息info日志 + std::string info = ImageKnifeTaskInternal::GetTaskInfo(queueElement.type, queueElement.request.get()); + info += task->GetDisplayPixelmapInfo(); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "Display", "%{public}s ,Form Loading", info.c_str()); + + queueElement.request->MarkDisplayStartTime(queueElement.type, false); + + bool trigerCallback = true; + // preload只加载不显示 + if (!queueElement.request->IsPreload()) { + trigerCallback = DisplayImage(queueElement.request, queueElement.type, task->product.pixelmap); + } + if (queueElement.type == ImageKnifeRequestSource::MAINSRC && + option->onLoadListener.onLoadSuccess != nullptr && trigerCallback) { + // 触发onLoadSuccess回调 + ImageKnifeData data; + ImageDataBack pixelmapCallbackData; + if (task->product.pixelmap != nullptr) { + pixelmapCallbackData.CopyFromPixelmap(task->product.pixelmap->GetPixelMap()); + } + + option->onLoadListener.onLoadSuccess(pixelmapCallbackData, data); + } + } else if (queueElement.type == ImageKnifeRequestSource::MAINSRC) { + // 任务执行失败 + if (option->onLoadListener.onLoadFailed != nullptr) { + option->onLoadListener.onLoadFailed(task->GetLastError()); + } + // 主图失败启动错误占位图 + queueElement.request->MarkStatusError(); + // 有缓存不会启用task加载,finalize会在更新或析构时调用的CancelRequest时触发,与错误图未启用时一样 + if (!LoadSrcFromMemory(queueElement.request, ImageKnifeRequestSource::ERRORSRC)) { + ExecuteJob(ImageKnifeRequestSource::ERRORSRC, queueElement.request); + } + } + } + } catch (std::exception err) { + task->FatalError("Dispatcher::OnComplete " + std::string(err.what())); + } + + executingJobMap_.erase(task->memoryKey); + DispatchNextJob(); + + // 移除task记录 + RemoveTask(task); +} + +bool ImageKnifeDispatcher::DisplayImage(std::shared_ptr request, + ImageKnifeRequestSource type, + std::shared_ptr pixelmap) +{ + auto arkUINode = NativeEntry::GetInstance()->GetArkUIBaseNode(request->GetNodeId()); + if (arkUINode == nullptr || arkUINode->GetNodeState() == ArkUIBaseNode::NodeState::Cleared || + arkUINode->GetNodeVersion() != request->GetVersion()) { + // 状态不处于available 或 request版本号不是最新则不进行显示 + if (type == ImageKnifeRequestSource::MAINSRC && + request->GetImageKnifeOption()->onLoadListener.onLoadCancel != nullptr) { + request->GetImageKnifeOption()-> + onLoadListener.onLoadCancel(ImageKnifeTaskInternal:: + GetTaskInfo(type, request.get()) + "Request Overdue"); + } + return false; + } + + if (type == ImageKnifeRequestSource::PLACESRC && request->IsMainSrcComplete()) { + // 主图已显示的情况下,不显示占位图 + return false; + } + + if (arkUINode != nullptr) { + // 设置图片填充效果 + ArkUI_ObjectFit fitEnum = ARKUI_OBJECT_FIT_COVER; + switch (type) { + case ImageKnifeRequestSource::MAINSRC: + fitEnum = request->GetImageKnifeOption()->objectFit; + break; + case ImageKnifeRequestSource::PLACESRC: + fitEnum = request->GetImageKnifeOption()->placeholderObjectFit; + break; + case ImageKnifeRequestSource::ERRORSRC: + fitEnum = request->GetImageKnifeOption()->errorholderObjectFit; + break; + default: + break; + } + arkUINode->FitImage(static_cast(fitEnum)); + + // 显示图片 + if (pixelmap != nullptr && pixelmap->GetPixelMap() != nullptr) { + arkUINode->Display(OH_ArkUI_DrawableDescriptor_CreateFromPixelMap(pixelmap->GetPixelMap())); + return true; + } else { + std::string errorInfo = ImageKnifeTaskInternal::GetTaskInfo(type, request.get()) + + "Empty Pixelmap (Display Image)"; + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "DisplayImage", "%{public}s", errorInfo.c_str()); + if (type == ImageKnifeRequestSource::MAINSRC && + request->GetImageKnifeOption()->onLoadListener.onLoadFailed != nullptr) { + request->GetImageKnifeOption()->onLoadListener.onLoadFailed(errorInfo); + } + } + } + + return false; +} + +bool ImageKnifeDispatcher::LoadSrcFromMemory(std::shared_ptr request, + ImageKnifeRequestSource type) +{ + try { + ImageData *data = GetImageSrc(request, type); + if (data == nullptr) { + return false; + } + + auto imageLoader = static_cast(request-> + GetImageKnifeOption()->imageLoader.get()); + ImageKnifeTaskInternal task(type, request, data); + if (imageLoader->LoadFromMemory(&task)) { + // 显示前打印图片信息info日志 + task.QueryDisplayPixelmapInfo(); + std::string info = ImageKnifeTaskInternal::GetTaskInfo(type, request.get()); + info += task.GetDisplayPixelmapInfo(); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, + "Display", "%{public}s ,Form Memory", + info.c_str()); + + // 用内存缓存直接显示 + request->MarkDisplayStartTime(type, true); + + bool trigerCallback = true; + // preload 只加载不显示 + if (!request->IsPreload()) { + trigerCallback = DisplayImage(request, type, task.product.pixelmap); + } + + if (type == ImageKnifeRequestSource::MAINSRC && + request->GetImageKnifeOption()->onLoadListener.onLoadSuccess != nullptr && trigerCallback) { + // 拷贝pixelmap用于回调 + ImageDataBack pixelmapCallbackData; + pixelmapCallbackData.CopyFromPixelmap(task.product.pixelmap->GetPixelMap()); + ImageKnifeData data; + request->GetImageKnifeOption()->onLoadListener.onLoadSuccess(pixelmapCallbackData, data); + } + if (type != ImageKnifeRequestSource::PLACESRC) { + request->MarkStatusComplete(); + } + return true; + } + } catch (std::exception err) { + std::string info = ImageKnifeTaskInternal::GetTaskInfo(type, request.get()); + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "Dispatcher", + "%{public}s [Fatal Error] %{public}s (LoadSrcFromMemory)", + info.c_str(), + err.what()); + } + + return false; +} + +ImageData *ImageKnifeDispatcher::GetImageSrc(std::shared_ptr request, + ImageKnifeRequestSource type) +{ + ImageData *data = nullptr; + switch (type) { + case ImageKnifeRequestSource::MAINSRC: + data = &request->GetImageKnifeOption()->loadSrc; + break; + case ImageKnifeRequestSource::PLACESRC: + data = &request->GetImageKnifeOption()->placeholderSrc; + break; + case ImageKnifeRequestSource::ERRORSRC: + data = &request->GetImageKnifeOption()->errorholderSrc; + break; + default: + break; + } + + if (data == nullptr || data->GetType() == DataType::UNDEFINED) { + // 该图片类型未启用 + if (type == ImageKnifeRequestSource::MAINSRC) { + std::string errorInfo = ImageKnifeTaskInternal::GetTaskInfo(type, request.get()) + + "Empty MAINSRC (GetImageSrc)"; + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "Dispatcher", "%{public}s", errorInfo.c_str()); + if (request->GetImageKnifeOption()->onLoadListener.onLoadFailed != nullptr) { + request->GetImageKnifeOption()->onLoadListener.onLoadFailed(errorInfo); + } + } + return nullptr; + } + return data; +} + +bool ImageKnifeDispatcher::ExecuteJob(ImageKnifeRequestSource type, + std::shared_ptr request) +{ + ImageData *data = GetImageSrc(request, type); + if (data == nullptr) { + return false; + } + + std::string memoryKey; + std::shared_ptr imageKnifeOption = request->GetImageKnifeOption(); + + // 设置默认执行:图片url,resource 进行加载解码,图形变换 + AsyncFunc func = [this](void* data) { + this->LoadImageSource(data); + }; + memoryKey = ImageKnife::GetInstance().GetEngineKeyImpl()->GenerateMemoryKey(data, type, + imageKnifeOption.get(), request->GetImageKnifeOption()->signature); + + DefaultJobQueue::QueueElement queueElement(request, type); + + if (!memoryKey.empty()) { + if (executingJobMap_.find(memoryKey) == executingJobMap_.end()) { + executingJobMap_.emplace(memoryKey, std::list({std::move(queueElement)})); + } else { + executingJobMap_[memoryKey].emplace_back(std::move(queueElement)); + return false; + } + } + + ImageKnifeTaskInternal* task = new ImageKnifeTaskInternal(type, request, data); + task->memoryKey = memoryKey; + + OH_PixelmapNative *pixelmap = nullptr; + if (data->MovePixelMap(pixelmap)) { + task->product.pixelmap = std::make_shared(pixelmap); + // 设置执行函数:pixelmap直接图片变换 + func = [this](void* data) { + this->TransformImage(data); + }; + } + + if (request->IsSyncLoad()) { + func(task); + OnComplete(task); + } else { + AsyncFunc completeCallback = [this](void *data) { + this->OnComplete(data); + }; + std::string errorInfo; + void *taskId = TaskWorker::GetInstance()->PushTask(func, completeCallback, task, errorInfo); + if (taskId != nullptr) { + task->SetTaskId(taskId); + request->InsertTask(task, type); + // 线程任务push时info日志 + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, + "ExecuteJob", + "%{public}s Push Task Success", + ImageKnifeTaskInternal::GetTaskInfo(type, request.get()).c_str()); + } else { + task->EchoError(errorInfo + " (Create Task)"); + if (request->GetImageKnifeOption()->onLoadListener.onLoadFailed != nullptr) { + request->GetImageKnifeOption()->onLoadListener.onLoadFailed(task->GetLastError()); + } + request->Destroy(); + delete task; + return false; + } + } + return true; +} + +void ImageKnifeDispatcher::TransformImage(void *arg) +{ + ImageKnifeTask* task = static_cast(arg); + auto option = task->request->GetImageKnifeOption(); + if (option->multiTransformation != nullptr) { + option->multiTransformation->Transform(task); + } else if (option->transformation != nullptr) { + option->transformation->Transform(task); + } +} + +// 在主线程中调用 +void ImageKnifeDispatcher::CancelRequest(std::shared_ptr request) +{ + request->Destroy(); + + // 调用对应interceptor的cancel函数 + CancelInterceptor(request, ImageKnifeRequestSource::MAINSRC); + CancelInterceptor(request, ImageKnifeRequestSource::PLACESRC); + CancelInterceptor(request, ImageKnifeRequestSource::ERRORSRC); +} + +void ImageKnifeDispatcher::CancelInterceptor(std::shared_ptr request, + ImageKnifeRequestSource type) +{ + ImageKnifeTaskInternal *task = static_cast(request->GetTask(type)); + if (task != nullptr) { + auto interceptor = task->GetCurrentInterceptor(); + if (interceptor != nullptr) { + interceptor->Cancel(task); + } + } +} + +void ImageKnifeDispatcher::RemoveTask(ImageKnifeTaskInternal *task) +{ + if (task != nullptr) { + static_cast(task->request.get())->RemoveTask(task->type); + delete task; + } +} + +void ImageKnifeDispatcher::DispatchNextJob() +{ + if (executingJobMap_.size() >= maxRequests) { + return; + } + while (true) { + DefaultJobQueue::QueueElement queueElement = jobQueuePtr_->Pop(); + ImageKnifeRequest::Status status = queueElement.request->GetStatus(); + if (queueElement.request == nullptr) { + break; + } else if (status == ImageKnifeRequest::Status::PROGRESS || status == ImageKnifeRequest::Status::ERROR) { + // 任务开启成功 + if (ExecuteJob(queueElement.type, queueElement.request)) { + break; + } + } else if (status == ImageKnifeRequest::Status::DESTROY && + queueElement.request->GetImageKnifeOption()->onLoadListener.onLoadCancel != nullptr) { + queueElement.request->GetImageKnifeOption()->onLoadListener.onLoadCancel( + ImageKnifeTaskInternal::GetTaskInfo(queueElement.type, queueElement.request.get()) + "Request DESTROY"); + } + } +} +} // end of namespace \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_dispatcher.h b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_dispatcher.h new file mode 100644 index 0000000000000000000000000000000000000000..169a7f747b6b112dd410807d6fd8c6f4e53cabc2 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_dispatcher.h @@ -0,0 +1,68 @@ +/* + * 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_KNIFE_C_IMAGEKNIFE_DISPATCHER_H +#define IMAGE_KNIFE_C_IMAGEKNIFE_DISPATCHER_H +#include +#include + +#include "request/imageKnife_request_internal.h" +#include "interceptor.h" +#include "queue/IJob_queue.h" +#include "queue/default_job_queue.h" +#include "imageKnife_task_internal.h" + +namespace ImageKnifeC { + +class ImageKnifeDispatcher { +public: + ImageKnifeDispatcher(); + ~ImageKnifeDispatcher(); + + void Enqueue(std::shared_ptr request); + + void CancelRequest(std::shared_ptr request); + + int maxRequests = 8; + +private: + std::unordered_map> executingJobMap_; + IJobQueue *jobQueuePtr_ = new DefaultJobQueue(); + + bool ExecuteJob(ImageKnifeRequestSource type, std::shared_ptr request); + + bool LoadSrcFromMemory(std::shared_ptr request, ImageKnifeRequestSource type); + + ImageData *GetImageSrc(std::shared_ptr request, ImageKnifeRequestSource type); + + void LoadImageSource(void *arg); + + void OnComplete(void *arg); + + bool DisplayImage(std::shared_ptr request, ImageKnifeRequestSource type, + std::shared_ptr pixelmap); + + void TransformImage(void *arg); + + void DispatchNextJob(); + + void CancelInterceptor(std::shared_ptr request, ImageKnifeRequestSource type); + + void RemoveTask(ImageKnifeTaskInternal *task); +}; + +} + +#endif //IMAGE_KNIFE_C_IMAGEKNIFE_DISPATCHER_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_internal.cpp b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_internal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d88117859a9966357886af2ed5b00fd4e244bc97 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_internal.cpp @@ -0,0 +1,105 @@ +/* + * 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. + */ + +#include +#include "imageKnife_internal.h" +#include "file_cache.h" +#include "key/default_engine_key.h" +#include "imageKnife_internal.h" + +namespace ImageKnifeC { + +// static +ImageKnife &ImageKnife::GetInstance() +{ + static ImageKnifeInternal imageKnifeInternal; + return imageKnifeInternal; +} + +void ImageKnifeInternal::Execute(std::shared_ptr request) +{ + this->dispatcher->Enqueue(std::static_pointer_cast(request)); +} + +void ImageKnifeInternal::CancelRequest(std::shared_ptr request) +{ + this->dispatcher->CancelRequest(std::static_pointer_cast(request)); +} + +std::shared_future ImageKnifeInternal::InitFileCacheAsync(std::string cachePath, int size, int memory, std::string path) +{ + // 创建线程对象并分离线程 + std::thread initThread(&ImageKnifeInternal::InitFileCache, this, cachePath, size, memory, path); + initThread.detach(); // 分离线程,主线程不需要等待 + return ImageKnifeC::FileCache::GetInstance()->promise.get_future().share(); +} + +void ImageKnifeInternal::InitFileCache(std::string cachePath, int size, int memory, std::string path) +{ + if (path.empty()) { + path = "ImageKnife"; + } + + // 初始化文件缓存 + ImageKnifeC::FileCache::GetInstance()->Init(size,memory); + ImageKnifeC::FileCache::GetInstance()->filePath = cachePath + "/" + path; + + ImageKnifeC::FileCache::GetInstance()->InitFileCache(); +} + +void ImageKnifeInternal::SetEngineKeyImpl(IEngineKey *keyPtr) +{ + keyPtr_ = keyPtr; +} + +IEngineKey *ImageKnifeInternal::GetEngineKeyImpl() const +{ + return keyPtr_; +} + +void ImageKnifeInternal::SetMaxRequests(int concurrency) +{ + dispatcher->maxRequests = concurrency; +} + +std::shared_ptr ImageKnifeInternal::GetDefaultImageKnifeLoader() const +{ + return imageLoader_; +} + +void ImageKnifeInternal::SetDefaultImageKnifeLoader(std::shared_ptr imageLoader) +{ + imageLoader_ = imageLoader; +} + +std::shared_ptr ImageKnifeInternal::Preload(std::shared_ptr imageKnifeOption) +{ + auto request = std::make_shared(imageKnifeOption); + ImageKnife::GetInstance().Execute(request); + return request; +} + +void ImageKnifeInternal::Cancel(std::shared_ptr request) +{ + if (request == nullptr) { + return; + } + // 使用 static_pointer_cast 进行类型转换 + auto internalRequest = std::static_pointer_cast(request); + + // 调用 Destroy 方法 + internalRequest->Destroy(); +} +} // namespace ImageKnifeC \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_internal.h b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..820f31e7184517ce485e7b854ab17e9333cb910d --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_internal.h @@ -0,0 +1,71 @@ +/* + * 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_KNIFE_C_KEKE_IMAGEKNIFE_INTERNAL_H +#define IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_INTERNAL_H + +#include "imageKnife.h" +#include "imageKnife_dispatcher.h" + +namespace ImageKnifeC { + +class ImageKnifeInternal : public ImageKnife { +public: + void Execute(std::shared_ptr request) override; + + void CancelRequest(std::shared_ptr request) override; + + std::shared_ptr GetDefaultImageKnifeLoader() const override; + + void SetDefaultImageKnifeLoader(std::shared_ptr imageLoader) override; + + virtual std::shared_future InitFileCacheAsync(std::string cachePath, int size, int memory, + std::string path) override ; + + void InitFileCache(std::string cachePath = "", int size = 256, + int memory = 256 * 1024 * 1024, std::string path = "ImageKnife") override; + + void SetEngineKeyImpl(IEngineKey *keyPtr) override; + + IEngineKey *GetEngineKeyImpl() const override; + + std::shared_ptr Preload(std::shared_ptr imageKnifeOption) override ; + + void Cancel(std::shared_ptr request) override ; + + void SetMaxRequests(int concurrency) override; +private: + std::shared_ptr dispatcher = std::make_shared(); + + std::shared_ptr imageLoader_ = nullptr; + IEngineKey *keyPtr_ = nullptr; + + ImageKnifeInternal() = default; + ImageKnifeInternal(const ImageKnifeInternal&) = delete; + ImageKnifeInternal &operator = (const ImageKnifeInternal&) = delete; + friend ImageKnife &ImageKnife::GetInstance(); + + ~ImageKnifeInternal() override + { + if (keyPtr_ != nullptr) { + delete keyPtr_; + keyPtr = nullptr; + } + } +}; + +} // end of namespace + +#endif // IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_INTERNAL_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_napi.cpp b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_napi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b32def4e210ad8a9eb2581d41489a39f238a6d7b --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_napi.cpp @@ -0,0 +1,368 @@ +/* + * 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. + */ + +#include "imageKnife_napi.h" +#include "imageKnife_internal.h" +#include "imageKnife.h" +#include "imageKnife_request.h" +#include "file_cache.h" + +namespace ImageKnifeC { + +// static +napi_value ImageKnifeNapi::CreateNativeRoot(napi_env env, napi_callback_info info) +{ + size_t argc = 4; + const size_t syncLoadIndex = 3; + const size_t optionIndex = 2; + napi_value args[4] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + // 获取NodeContent + ArkUI_NodeContentHandle contentHandle; + OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); + + // 获取componentId + size_t length; + napi_get_value_string_utf8(env, args[1], nullptr, 0, &length); + char componentId[length + 1]; + napi_get_value_string_utf8(env, args[1], componentId, length + 1, nullptr); + + // 获取ImageKnifeOption及创建imageKnifeNode + auto imageKnifeOption = std::make_shared(env, args[optionIndex]); + + // 获取syncLoad + bool syncLoad = false; + napi_get_value_bool(env, args[syncLoadIndex], &syncLoad); + + auto imageKnifeNode = std::make_shared(std::string(componentId), imageKnifeOption); + imageKnifeNode->SyncLoad(syncLoad); + // 设置contentHandle, 挂载imageNode, 保持Native侧对象到管理类中,维护生命周期。 + NativeEntry::GetInstance()->SetRootNode(componentId, contentHandle, imageKnifeNode); + + ImageKnife::GetInstance().Execute(imageKnifeNode->GetImageKnifeRequest()); + + return nullptr; +} + +napi_value ImageKnifeNapi::UpdateNativeRoot(napi_env env, napi_callback_info info) +{ + size_t argc = 4; + const size_t componentVersionIndex = 2; + const size_t syncLoadIndex = 3; + napi_value args[4] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + // 获取componentId + size_t length; + napi_get_value_string_utf8(env, args[0], nullptr, 0, &length); + char componentId[length + 1]; + napi_get_value_string_utf8(env, args[0], componentId, length + 1, nullptr); + + // 获取imageKnifeOption + auto imageKnifeOption = std::make_shared(env, args[1]); + + // 获取componentVersion + int componentVersion; + napi_get_value_int32(env, args[componentVersionIndex], &componentVersion); + + // 获取syncLoad + bool syncLoad = false; + napi_get_value_bool(env, args[syncLoadIndex], &syncLoad); + // 找到ImageNode + auto baseNode = NativeEntry::GetInstance()->GetArkUIBaseNode(componentId).get(); + if (baseNode != nullptr) { + ImageKnifeNode* imageKnifeNode = static_cast(baseNode); + imageKnifeNode->Reuse(componentVersion); + + ImageKnife::GetInstance().CancelRequest(imageKnifeNode->GetImageKnifeRequest()); + // 通过imageKnifeOption 更新请求 + imageKnifeNode->UpdateImageKnifeRequest(imageKnifeOption); + // request 更新完成后,更新request的 syncLoad状态 + imageKnifeNode->SyncLoad(syncLoad); + ImageKnife::GetInstance().Execute(imageKnifeNode->GetImageKnifeRequest()); + } + + return nullptr; +} + +napi_value ImageKnifeNapi::ClearNativeRoot(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + // 获取componentId + size_t length; + napi_get_value_string_utf8(env, args[0], nullptr, 0, &length); + char componentId[length + 1]; + napi_get_value_string_utf8(env, args[0], componentId, length + 1, &length); + + auto baseNode = NativeEntry::GetInstance()->GetArkUIBaseNode(componentId).get(); + if (baseNode != nullptr) { + ImageKnifeNode *imageKnifeNode = static_cast(baseNode); + imageKnifeNode->Clear(); + ImageKnife::GetInstance().CancelRequest(imageKnifeNode->GetImageKnifeRequest()); + } + return nullptr; +} + +napi_value ImageKnifeNapi::DestroyNativeRoot(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value arg; + napi_get_cb_info(env, info, &argc, &arg, nullptr, nullptr); + + size_t length; + napi_get_value_string_utf8(env, arg, nullptr, 0, &length); + char componentId[length + 1]; + napi_get_value_string_utf8(env, arg, componentId, length + 1, &length); + + std::string id = componentId; + + auto baseNode = NativeEntry::GetInstance()->GetArkUIBaseNode(componentId).get(); + if (baseNode != nullptr) { + ImageKnifeNode *imageKnifeNode = static_cast(baseNode); + ImageKnife::GetInstance().CancelRequest(imageKnifeNode->GetImageKnifeRequest()); + + // 从管理类中释放Native侧对象。 + NativeEntry::GetInstance()->DisposeRootNode(id); + } + + return nullptr; +} + +napi_value ImageKnifeNapi::InitFileCache(napi_env env, napi_callback_info info) +{ + // 创建 Promise + napi_status status; + napi_value promise; + + status = napi_create_promise(env, &FileCache::asyncData->deferred, &promise); + if (status != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeNapi::InitFileCache", + "Failed to create promise"); + napi_value result; + napi_create_string_utf8(env, "Failed to create promise", NAPI_AUTO_LENGTH, &result); + napi_reject_deferred(env, FileCache::asyncData->deferred, result); + delete FileCache::asyncData; + FileCache::asyncData = nullptr; + return promise; + } + + // 定义错误处理 lambda + auto handleError = [env](const char *message)->napi_value { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeNapi::InitFileCache", + "%{public}s", + message); + napi_value result; + napi_create_string_utf8(env, message, NAPI_AUTO_LENGTH, &result); + napi_reject_deferred(env, FileCache::asyncData->deferred, result); + delete FileCache::asyncData; + FileCache::asyncData = nullptr; + }; + + // 获取传递的参数 + size_t argc = 4; + napi_value args[argc]; + status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + if (status != napi_ok) { + handleError("Failed to get callback info"); + return promise; + } + + // 获取 filesDir 参数 + napi_value jsFilesDir = args[0]; + size_t strLength; + status = napi_get_value_string_utf8(env, jsFilesDir, nullptr, 0, &strLength); + if (status != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeNapi::InitFileCache", + "status is: %{public}d", + status); + handleError("Failed to get 'filesDir' length"); + return promise; + } + + FileCache::asyncData->fileDir.resize(strLength); + status = napi_get_value_string_utf8(env, jsFilesDir, + &FileCache::asyncData->fileDir[0], + strLength + 1, + &strLength); + if (status != napi_ok) { + handleError("Failed to get 'filesDir' parameter"); + return promise; + } + + // 获取 size 参数 + napi_value jsSize = args[1]; + status = napi_get_value_int32(env, jsSize, &FileCache::asyncData->size); + if (status != napi_ok) { + handleError("Failed to get 'size' parameter"); + return promise; + } + + // 获取 memory 参数 + napi_value jsMemory = args[2]; + status = napi_get_value_int32(env, jsMemory, &FileCache::asyncData->memory); + if (status != napi_ok) { + handleError("Failed to get 'memory' parameter"); + return promise; + } + + // 获取 path 参数 + napi_value jsPath = args[3]; + size_t pathLength = 0; + status = napi_get_value_string_utf8(env, jsPath, nullptr, 0, &pathLength); + if (status == napi_ok) { + FileCache::asyncData->path.resize(pathLength); + status = napi_get_value_string_utf8(env, jsPath, + &FileCache::asyncData->path[0], + pathLength + 1, + &pathLength); + if (status != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeNapi::InitFileCache", + "Failed to get 'path' parameter"); + } + } else { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeNapi::InitFileCache", + "Failed to get 'path' length"); + } + + // 创建异步工作的名称 + napi_value asyncWorkName; + status = napi_create_string_utf8(env, "InitFileCache", NAPI_AUTO_LENGTH, &asyncWorkName); + if (status != napi_ok) { + handleError("Failed to create async work name"); + return promise; + } + + // 创建异步工作项 + status = napi_create_async_work(env, nullptr, asyncWorkName, + FileCache::StartFileCacheInitThread, + FileCache::FileCacheInitComplete, + FileCache::asyncData, + &FileCache::asyncData->asyncWork); + if (status != napi_ok) { + handleError("Failed to create async work"); + return promise; + } + + // 将异步工作项加入队列 + status = napi_queue_async_work_with_qos(env, FileCache::asyncData->asyncWork, napi_qos_default); + if (status != napi_ok) { + handleError("Failed to queue async work"); + napi_delete_async_work(env, FileCache::asyncData->asyncWork); + return promise; + } + + return promise; +} + +napi_value ImageKnifeNapi::Preload(napi_env env, napi_callback_info info) +{ + napi_status status; + size_t argc = 1; + napi_value args[1] = {nullptr}; + status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + // 获取传入的 request 参数 + napi_value jsRequest = args[0]; + + // 从 request 中获取 imageKnifeOption 属性 + napi_value jsImageKnifeOption; + status = napi_get_named_property(env, jsRequest, "imageKnifeOption", &jsImageKnifeOption); + if (status != napi_ok) { + napi_throw_error(env, "ImageKnifeNapi::Preload", "Failed to get 'imageKnifeOption' property from request"); + return nullptr; + } + + auto imageKnifeOption = std::make_shared(env, jsImageKnifeOption); + + std::shared_ptr request = + std::dynamic_pointer_cast(ImageKnife::GetInstance().Preload(imageKnifeOption)); + if (!request) { + napi_throw_error(env, "ImageKnifeNapi::Preload", "Failed to cast request"); + return nullptr; + } + + request->SetEnv(env); + + // 创建对 jsRequest 的引用并保存到 request 中 + napi_ref jsRequestRef = nullptr; + + // 第四个参数必填项,即使不使用 + status = napi_wrap(env, args[0], request.get(), [](napi_env env, void* data, void* hint) {}, + nullptr, &jsRequestRef); + if (status != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "ImageKnifeNapi::Preload", "Failed to bind the JavaScript object"); + } + + request->SetJsRequestRef(jsRequestRef); + return jsRequest; +} + +napi_value ImageKnifeNapi::Cancel(napi_env env, napi_callback_info info) +{ + napi_status status; + size_t argc = 1; + napi_value args[1] = {nullptr}; + status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + if (status != napi_ok) { + return nullptr; + } + + ImageKnifeRequestInternal* request = nullptr; + status = napi_unwrap(env, args[0], (void**)&request); + if (status != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "ImageKnifeNapi::Cancel", "Failed to unwrap"); + return nullptr; + } + + if (request == nullptr) { + OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, "ImageKnifeNapi::Cancel", "request is null"); + return nullptr; + } + // 恢复成智能指针 + auto requestSharePtr = request->shared_from_this(); + ImageKnife::GetInstance().Cancel(requestSharePtr); + return nullptr; +} + +napi_value ImageKnifeNapi::SetMaxRequests(napi_env env, napi_callback_info info) +{ + // 获取 concurrency 参数 + napi_status status; + // 获取传递的参数数量 + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + napi_value jsConrrency = args[0]; + int concurrency = 0; + status = napi_get_value_int32(env, jsConrrency, &concurrency); + if (status != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeNapi::SetMaxRequests", + "Failed to get 'concurrency' parameter"); + } + ImageKnife::GetInstance().SetMaxRequests(concurrency); + return nullptr; +} + +} // end of namespace diff --git a/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_napi.h b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_napi.h new file mode 100644 index 0000000000000000000000000000000000000000..884c75279f29e8e69857aed36132730298a589f3 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_napi.h @@ -0,0 +1,63 @@ +/* + * 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_KNIFE_C_IMAGEKNIFE_NAPI_H +#define IMAGE_KNIFE_C_IMAGEKNIFE_NAPI_H + +#include "native_entry.h" +#include +#include "node/imageKnife_node.h" +#include "task_worker.h" +#include "imageKnife.h" +#include "file_cache.h" +#include "imageKnife_internal.h" + +namespace ImageKnifeC { + +class ImageKnifeNapi { +public: + static void Init(napi_env env, napi_value &exports) + { + // 设置env + TaskWorker::GetInstance()->SetEnv(env); + NativeModuleInstance::GetInstance()->SetNapiEnv(env); + + napi_property_descriptor desc[] = { + {"createNativeRoot", nullptr, CreateNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"updateNativeRoot", nullptr, UpdateNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"clearNativeRoot", nullptr, ClearNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"destroyNativeRoot", nullptr, DestroyNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"initFileCache", nullptr, InitFileCache, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"preload", nullptr, Preload, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"cancel", nullptr, Cancel, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"setMaxRequests", nullptr, SetMaxRequests, nullptr, nullptr, nullptr, napi_default, nullptr} + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + } +private: + static napi_value CreateNativeRoot(napi_env env, napi_callback_info info); + static napi_value UpdateNativeRoot(napi_env env, napi_callback_info info); + static napi_value ClearNativeRoot(napi_env env, napi_callback_info info); + static napi_value DestroyNativeRoot(napi_env env, napi_callback_info info); + static napi_value InitFileCache(napi_env env, napi_callback_info info); + static napi_value Preload(napi_env env, napi_callback_info info); + + // 用于取消等待队列的任务 + static napi_value Cancel(napi_env env, napi_callback_info info); + static napi_value SetMaxRequests(napi_env env, napi_callback_info info); +}; +} // end of namespace + +#endif // IMAGE_KNIFE_C_IMAGEKNIFE_NAPI_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_task_internal.cpp b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_task_internal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70f52f10e1e4f4a1d39213733a0bd010bb1ea756 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_task_internal.cpp @@ -0,0 +1,120 @@ +/* + * 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. + */ + +#include "imageKnife_task_internal.h" + +namespace ImageKnifeC { + +std::string ImageKnifeTaskInternal::GetTaskInfo(ImageKnifeRequestSource type, ImageKnifeRequest *request) +{ + if (request == nullptr) { + return "[Null Request] "; + } + + std::string source; + switch (type) { + case ImageKnifeRequestSource::MAINSRC: + source = "MainSrc"; + break; + case ImageKnifeRequestSource::PLACESRC: + source = "PlaceSrc"; + break; + case ImageKnifeRequestSource::ERRORSRC: + source = "ErrorSrc"; + break; + default: + break; + } + return "[ID:" + request->GetNodeId() + " VersionID:" + std::to_string(request->GetVersion()) + + " Type:" + source + "] "; +} + +void ImageKnifeTaskInternal::QueryDisplayPixelmapInfo() +{ + if (product.pixelmap == nullptr || product.pixelmap->GetPixelMap() == nullptr) { + return; + } + + OH_Pixelmap_ImageInfo* imageInfo = nullptr; + if (OH_PixelmapImageInfo_Create(&imageInfo) != IMAGE_SUCCESS) { + return; + } + + if (OH_PixelmapNative_GetImageInfo(product.pixelmap->GetPixelMap(), imageInfo) != IMAGE_SUCCESS) { + return; + } + + int32_t pixelFormat = PIXEL_FORMAT_UNKNOWN; + OH_PixelmapImageInfo_GetWidth(imageInfo, &pixelmapInfo.width); + OH_PixelmapImageInfo_GetHeight(imageInfo, &pixelmapInfo.height); + OH_PixelmapImageInfo_GetPixelFormat(imageInfo, &pixelFormat); + OH_PixelmapImageInfo_Release(imageInfo); + const int half = 2; + const int four = 4; + if (pixelFormat == PIXEL_FORMAT_NV21 || pixelFormat == PIXEL_FORMAT_NV12) { + pixelmapInfo.size = pixelmapInfo.width * pixelmapInfo.height + + ((pixelmapInfo.width + 1) / half) * ((pixelmapInfo.height + 1) / half) * half; + } else { + pixelmapInfo.size = pixelmapInfo.width * pixelmapInfo.height * four; + } + + switch (pixelFormat) { + case PIXEL_FORMAT_RGB_565 : + pixelmapInfo.pixelFormat = "RGB_565"; + break; + case PIXEL_FORMAT_RGBA_8888 : + pixelmapInfo.pixelFormat = "RGBA_8888"; + break; + case PIXEL_FORMAT_BGRA_8888 : + pixelmapInfo.pixelFormat = "BGRA_8888"; + break; + case PIXEL_FORMAT_RGB_888 : + pixelmapInfo.pixelFormat = "RGB_888"; + break; + case PIXEL_FORMAT_ALPHA_8 : + pixelmapInfo.pixelFormat = "ALPHA_8"; + break; + case PIXEL_FORMAT_RGBA_F16 : + pixelmapInfo.pixelFormat = "RGBA_F16"; + break; + case PIXEL_FORMAT_NV21 : + pixelmapInfo.pixelFormat = "NV21"; + break; + case PIXEL_FORMAT_NV12 : + pixelmapInfo.pixelFormat = "NV12"; + break; + case PIXEL_FORMAT_RGBA_1010102 : + pixelmapInfo.pixelFormat = "RGBA_1010102"; + break; + case PIXEL_FORMAT_YCBCR_P010 : + pixelmapInfo.pixelFormat = "YCBCR_P010"; + break; + case PIXEL_FORMAT_YCRCB_P010 : + pixelmapInfo.pixelFormat = "YCRCB_P010"; + break; + default : + pixelmapInfo.pixelFormat = "Unknown"; + break; + } +} + +std::string ImageKnifeTaskInternal::GetDisplayPixelmapInfo() const +{ + return "Pixelmap Info: width:" + std::to_string(pixelmapInfo.width) + + " height:" + std::to_string(pixelmapInfo.height) + + " size:" + std::to_string(pixelmapInfo.size) + + " format:" + pixelmapInfo.pixelFormat; +} +} // end of namespace diff --git a/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_task_internal.h b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_task_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..f2c170966638b5481d4cf7e9f02f92f4a1158659 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/imageKnife_task_internal.h @@ -0,0 +1,120 @@ +/* + * 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_KNIFE_C_KEKE_IMAGEKNIFE_TASK_INTERNAL_H +#define IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_TASK_INTERNAL_H + +#include "imageKnife_task.h" +#include "imageKnife_request.h" +#include + +namespace ImageKnifeC { + +class ImageKnifeTaskInternal : public ImageKnifeTask { +public: + // 用于onLoadSuccess 回调的pixelmap拷贝 + ImageDataBack pixelmapCallbackData; + std::string memoryKey; + + ImageKnifeTaskInternal(ImageKnifeRequestSource type, std::shared_ptr request, + ImageData *imageSrc) : ImageKnifeTask(type, request, imageSrc) + { + } + + Interceptor *GetCurrentInterceptor() const + { + return interceptor_; + } + + void SetInterceptor(Interceptor *interceptor) + { + interceptor_ = interceptor; + } + + void ClearInterceptorPtr() + { + interceptor_ = nullptr; + } + + bool IsSuccess() const + { + return success_; + } + + void MarkSuccess() + { + success_ = true; + } + + void SetTaskId(void *id) + { + taskId_ = id; + } + + void *GetTaskId() const + { + return taskId_; + } + + void FatalError(std::string errorInfo) + { + fatalError_ = true; + EchoError("[Fatal Error] " + errorInfo); + } + + void EchoError(std::string errorInfo) override + { + std::string source; + if (interceptor_ != nullptr) { + source = " (" + interceptor_.load()->name + ") "; + } + lastError_ = GetTaskInfo(type, request.get()) + errorInfo + source; + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "TaskError", "%{public}s", lastError_.c_str()); + } + + std::string GetLastError() const + { + return lastError_; + } + + bool IsFatalErrorHappened() + { + return fatalError_; + } + + static std::string GetTaskInfo(ImageKnifeRequestSource type, ImageKnifeRequest *request); + + void QueryDisplayPixelmapInfo(); + + std::string GetDisplayPixelmapInfo() const; + +private: + struct PixelmapInfo { + uint32_t width = 0; + uint32_t height = 0; + size_t size = 0; + std::string pixelFormat = "Unknown"; + }; + + PixelmapInfo pixelmapInfo; + + std::atomic interceptor_ = nullptr; + bool success_ = false; + bool fatalError_ = false; + void *taskId_ = nullptr; + std::string lastError_; +}; +} // end of namespace +#endif // IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_TASK_INTERNAL_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/include/imageKnife.h b/thirdparty/image-knife-c/library/src/main/cpp/include/imageKnife.h new file mode 100644 index 0000000000000000000000000000000000000000..2f505f1dc3c0874bfbdd9322c4d5ffef6d8196ce --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/include/imageKnife.h @@ -0,0 +1,39 @@ +/* + * 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 IMAGEKNIFEC_IMAGEKNIFE_H +#define IMAGEKNIFEC_IMAGEKNIFE_H + +#include "imageKnife_request.h" +#include "key/IEngine_key.h" + +namespace ImageKnifeC { +class ImageKnife { +public: + static ImageKnife& GetInstance(); + virtual void Execute(std::shared_ptr request) = 0; + virtual void CancelRequest(std::shared_ptr request) = 0; + virtual void InitFileCache(std::string, int size, int memory, std::string path) = 0; + virtual void SetDefaultImageKnifeLoader(std::shared_ptr imageLoader) = 0; + virtual std::shared_ptr GetDefaultImageKnifeLoader() const = 0; + virtual void SetMaxRequests(int concurrency) = 0; + virtual void SetEngineKeyImpl(IEngineKey *keyPtr) = 0; + virtual IEngineKey *GetEngineKeyImpl() const = 0; + virtual ~ImageKnife() = default; +}; + +} + +#endif // IMAGEKNIFEC_IMAGEKNIFE_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/include/imageKnife_loader.h b/thirdparty/image-knife-c/library/src/main/cpp/include/imageKnife_loader.h new file mode 100644 index 0000000000000000000000000000000000000000..43ebf03a8d85cd533d3c22444c84493672e61710 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/include/imageKnife_loader.h @@ -0,0 +1,48 @@ +/* + * 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_KNIFE_C_IMAGEKNIFE_LOADER_H +#define IMAGE_KNIFE_C_IMAGEKNIFE_LOADER_H + +#include "interceptor.h" + +namespace ImageKnifeC { +class ImageKnifeLoader { +public: + enum class Position { + FRONT, + END + }; + + virtual void AddMemoryCacheInterceptor(std::shared_ptr interceptor, + Position postion = Position::FRONT) = 0; + + virtual void AddFileCacheInterceptor(std::shared_ptr interceptor, + Position postion = Position::FRONT) = 0; + + virtual void AddDownloadInterceptor(std::shared_ptr interceptor, + Position postion = Position::FRONT) = 0; + + virtual void AddDecodeInterceptor(std::shared_ptr interceptor, + Position postion = Position::FRONT) = 0; + + static std::shared_ptr CreateDefaultImageLoader(); + static std::shared_ptr CreateEmptyImageLoader(); + virtual ~ImageKnifeLoader() = default; +}; + +} // end of namespace + +#endif // IMAGE_KNIFE_C_IMAGEKNIFE_LOADER_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/include/imageKnife_request.h b/thirdparty/image-knife-c/library/src/main/cpp/include/imageKnife_request.h new file mode 100644 index 0000000000000000000000000000000000000000..4c7443fe2ddc954ad74049b7017d3cccb1edb8d7 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/include/imageKnife_request.h @@ -0,0 +1,42 @@ +/* + * 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_KNIFE_C_IMAGEKNIFE_REQUEST_H +#define IMAGE_KNIFE_C_IMAGEKNIFE_REQUEST_H + +#include "imageKnife_option.h" + +namespace ImageKnifeC { +class ImageKnifeRequest { +public: + enum class Status { + PROGRESS, + COMPLETE, + ERROR, + ERRORCOMPLETE, + DESTROY + }; + + virtual std::string GetNodeId() const = 0; + virtual int GetVersion() const = 0; + virtual Status GetStatus() const = 0; + virtual std::shared_ptr GetImageKnifeOption() const = 0; + virtual ~ImageKnifeRequest() = default; +}; + +} // end of namespace + +#endif // IMAGE_KNIFE_C_IMAGEKNIFE_REQUEST_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/include/imageKnife_task.h b/thirdparty/image-knife-c/library/src/main/cpp/include/imageKnife_task.h new file mode 100644 index 0000000000000000000000000000000000000000..498f85705f309a0e1098559b6d85ef703a2a8ac2 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/include/imageKnife_task.h @@ -0,0 +1,103 @@ +/* + * 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_KNIFE_C_IMAGEKNIFE_TASK_H +#define IMAGE_KNIFE_C_IMAGEKNIFE_TASK_H + +#include "RemoteCommunicationKit/rcp.h" +#include +#include +#include +#include "hilog/log.h" +#include "imageKnife_data.h" + +namespace ImageKnifeC { +class ImageKnifeRequest; +class ImageData; +class Interceptor; +enum class ImageKnifeRequestSource { + MAINSRC, + PLACESRC, + ERRORSRC +}; + +struct PixelMapWrapper { +public: + PixelMapWrapper(OH_PixelmapNative *pixelmap) : pixelmap_(pixelmap) + { + } + + OH_PixelmapNative *GetPixelMap() + { + return pixelmap_; + } + + ~PixelMapWrapper() + { + if (pixelmap_ == nullptr) { + return; + } + + OH_PixelmapNative_Release(pixelmap_); + } +private: + // 禁止修改pixelmap地址,防止错误析构和内存泄漏 + OH_PixelmapNative *pixelmap_ = nullptr; +}; + +class ImageKnifeTask { +public: + struct Product { + // 网络下载session,用于取消下载 + Rcp_Session *session = nullptr; + // 网络下载request,用于取消下载 + Rcp_Request *request = nullptr; + // 网络下载, http响应数据 + Rcp_Response *response = nullptr; + // 原始图片buffer + std::shared_ptr imageBuffer = nullptr; + // 原始图片长度 + uint32_t imageLength = 0; + // pixelmap 图片 + std::shared_ptr pixelmap = nullptr; + // 标记当前是需要写缓存还是读缓存 + bool writeCache = false; + + ~Product() + { + if (response != nullptr) { + response->destroyResponse(response); + } + } + }; + + const std::shared_ptr request; + const ImageKnifeRequestSource type; + const ImageData *imageSrc; + Product product; + std::string cancelInfo; + + virtual ~ImageKnifeTask() = default; + virtual void EchoError(std::string errorInfo) = 0; +protected: + ImageKnifeTask(ImageKnifeRequestSource type, std::shared_ptr request, ImageData *imageSrc) + : type(type), request(request), imageSrc(imageSrc) + { + } +}; + +} + +#endif // IMAGE_KNIFE_C_IMAGEKNIFE_TASK_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/include/interceptor.h b/thirdparty/image-knife-c/library/src/main/cpp/include/interceptor.h new file mode 100644 index 0000000000000000000000000000000000000000..f67e1d406004493e678ffeb63580d12bc8ea13e3 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/include/interceptor.h @@ -0,0 +1,67 @@ +/* + * 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_KNIFE_C_INTERCEPTOROH_H +#define IMAGE_KNIFE_C_INTERCEPTOROH_H + +#include "imageKnife_task.h" + +namespace ImageKnifeC { +class Interceptor { +public: + // 仅用于日志调试中标识身份 + std::string name; + + bool Process(ImageKnifeTask *task); + virtual bool Resolve(ImageKnifeTask *task) = 0; + virtual void Cancel(ImageKnifeTask *task) {} + virtual ~Interceptor() {} +protected: + std::shared_ptr next_ = nullptr; +}; + +class MemoryCacheInterceptor : public Interceptor { +public: + void SetNext(std::shared_ptr interceptor) + { + next_ = interceptor; + } +}; + +class FileCacheInterceptor : public Interceptor { +public: + void SetNext(std::shared_ptr interceptor) + { + next_ = interceptor; + } +}; + +class DownloadInterceptor : public Interceptor { +public: + void SetNext(std::shared_ptr interceptor) + { + next_ = interceptor; + } +}; + +class DecodeInterceptor : public Interceptor { +public: + void SetNext(std::shared_ptr interceptor) + { + next_ = interceptor; + } +}; +}; +#endif // IMAGE_KNIFE_C_INTERCEPTOROH_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/interceptor/decode_interceptor_OH.h b/thirdparty/image-knife-c/library/src/main/cpp/interceptor/decode_interceptor_OH.h new file mode 100644 index 0000000000000000000000000000000000000000..08560d15fc9bd9716fee00ee3597057d4c27f0cd --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/interceptor/decode_interceptor_OH.h @@ -0,0 +1,67 @@ +/* + * 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_KNIFE_C_DECODE_INTERCEPTOR_OH_H +#define IMAGE_KNIFE_C_DECODE_INTERCEPTOR_OH_H + +#include "interceptor.h" +#include "imageKnife_request.h" +#include + +namespace ImageKnifeC { +class DecodeInterceptorOH : public DecodeInterceptor { +public: + DecodeInterceptorOH() + { + name = "Default DecodeInterceptor"; + } + + bool Resolve(ImageKnifeTask *task) override + { + // 确定数据来源是网络下载response 还是本地文件buffer + if (task->product.response != nullptr) { + return Decode((uint8_t*)(task->product.response->body.buffer), task->product.response->body.length, task); + } else if (task->product.imageBuffer != nullptr) { + return Decode(task->product.imageBuffer.get(), task->product.imageLength, task); + } + return false; + } + +private: + bool Decode(uint8_t *buffer, uint32_t length, ImageKnifeTask *task) + { + OH_ImageSourceNative *source = nullptr; + Image_ErrorCode imgErrorCode = OH_ImageSourceNative_CreateFromData(buffer, length, &source); + if (imgErrorCode != IMAGE_SUCCESS) { + task->EchoError("create ImageSource failed, error code: " + std::to_string(imgErrorCode)); + return false; + } + + OH_PixelmapNative *pixelmap = nullptr; + imgErrorCode = OH_ImageSourceNative_CreatePixelmap(source, nullptr, &pixelmap); + if (imgErrorCode != IMAGE_SUCCESS) { + task->EchoError("decode image to pixelMap failed, error code: " + std::to_string(imgErrorCode)); + return false; + } + + task->product.pixelmap = std::make_shared(pixelmap); + OH_ImageSourceNative_Release(source); + return true; + } +}; + +}; + +#endif // IMAGE_KNIFE_C_DECODE_INTERCEPTOR_OH_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/interceptor/download_interceptor_OH.h b/thirdparty/image-knife-c/library/src/main/cpp/interceptor/download_interceptor_OH.h new file mode 100644 index 0000000000000000000000000000000000000000..9b97fbe8254930b65486277829e5f3972bf3f3d3 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/interceptor/download_interceptor_OH.h @@ -0,0 +1,140 @@ +/* + * 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_KNIFE_C_DOWNLOAD_INTERCEPTOR_OH_H +#define IMAGE_KNIFE_C_DOWNLOAD_INTERCEPTOR_OH_H + +#include "interceptor.h" +#include "imageKnife_request.h" + +namespace ImageKnifeC { +class DownloadInterceptorOH : public DownloadInterceptor { +public: + DownloadInterceptorOH() + { + name = "Default DownloadInterceptor"; + } + + bool Resolve(ImageKnifeTask *task) override + { + std::string url; + if (task->imageSrc->GetString(url)) { + return LoadImageFromUrl(url, task); + } + + return false; + } + + void Cancel(ImageKnifeTask *task) override + { + return; + const uint64_t errorCode = 1007900993; + if (task->product.request != nullptr && task->product.session != nullptr) { + uint32_t errorCode = HMS_Rcp_CancelRequest(task->product.session, task->product.request); + uint32_t errCodeSession = HMS_Rcp_CancelSession(task->product.session); + if (!errorCode) { + task->cancelInfo = "Cancel download success: " + std::to_string(errCodeSession); + } else if (errorCode == errorCode) { + task->cancelInfo = "Cancel Failed: Session is closed or not work," + std::to_string(errCodeSession); + } else { + task->cancelInfo = "Cancel Failed, error code: " + + std::to_string(errorCode) + " , : " + std::to_string(errCodeSession); + } + } + } + +private: + struct CallbackData { + bool fetchFinished = false; + std::string errorInfo; + Rcp_Response* response = nullptr; + }; + + bool LoadImageFromUrl(std::string url, ImageKnifeTask *task) + { + task->product.request = HMS_Rcp_CreateRequest(url.c_str()); + ConfigHttpRequest(task->product.request); + + uint32_t errCode = 0; + task->product.session = HMS_Rcp_CreateSession(NULL, &errCode); + if (errCode) { + task->EchoError("create Session error: " + std::to_string(errCode)); + HMS_Rcp_DestroyRequest(task->product.request); + return false; + } + + bool result = HttpFetchSync(task->product.session, task->product.request, task); + HMS_Rcp_DestroyRequest(task->product.request); + HMS_Rcp_CloseSession(&task->product.session); + return result; + } + + void ConfigHttpRequest(Rcp_Request *request) + { + // 设置为Get请求 + request->method = RCP_METHOD_GET; + Rcp_EventsHandler evenHandler; + Rcp_Configuration config; + config.tracingConfiguration.httpEventsHandler = evenHandler; + } + + static void ResponseCallback(void *usrCtx, Rcp_Response *response, uint32_t errCode) + { + CallbackData *data = static_cast(usrCtx); + if (errCode) { + // 1007900992 represent http download has been canceled + if (errCode != 1007900992) { + data->errorInfo = "HttpFetch HMS_Rcp_Fetch error:" + std::to_string(errCode); + } + } + + if (response != NULL) { + if (response->statusCode != RCP_OK) { + data->errorInfo = "HttpFetch response error, statusCode: " + std::to_string(response->statusCode); + response->destroyResponse(response); + } else { + data->response = response; + } + } + + data->fetchFinished = true; + } + + bool HttpFetchSync(Rcp_Session *session, Rcp_Request *request, ImageKnifeTask *task) + { + uint32_t errCode = 0; + Rcp_Response *response = HMS_Rcp_FetchSync(session, request, &errCode); + if (errCode) { + task->EchoError("HttpFetch HMS_Rcp_Fetch error:" + std::to_string(errCode)); + return false; + } + + if (response != NULL) { + if (response->statusCode != RCP_OK) { + task->EchoError("HttpFetch response error, statusCode: " + std::to_string(response->statusCode)); + response->destroyResponse(response); + } else { + task->product.response = response; + return true; + } + } + + return false; + } +}; + +}; + +#endif // IMAGE_KNIFE_C_DOWNLOAD_INTERCEPTOR_OH_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/interceptor/file_cache_interceptor_OH.h b/thirdparty/image-knife-c/library/src/main/cpp/interceptor/file_cache_interceptor_OH.h new file mode 100644 index 0000000000000000000000000000000000000000..16a9f83a3dd4c15ab2eec5eec2dcd60b7abc6b22 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/interceptor/file_cache_interceptor_OH.h @@ -0,0 +1,75 @@ +/* + * 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_KNIFE_C_FILE_CACHE_INTERCEPTOR_OH_H +#define IMAGE_KNIFE_C_FILE_CACHE_INTERCEPTOR_OH_H + +#include +#include "interceptor.h" +#include "imageKnife_request.h" +#include "file_cache.h" +#include "imageKnife_internal.h" + +namespace ImageKnifeC { +class FileCacheInterceptorOH : public FileCacheInterceptor { +public: + FileCacheInterceptorOH() + { + name = "Default FileCacheInterceptor"; + } + + bool Resolve(ImageKnifeTask *task) override + { + if (task->product.writeCache) { + return Write(task); + } else { + return Read(task); + } + } + +private: + bool Read(ImageKnifeTask *task) + { + std::string fileKey; + if (!task->imageSrc->GetString(fileKey)) { + return false; + } + fileKey = ImageKnife::GetInstance().GetEngineKeyImpl()-> + GenerateFileKey(task->imageSrc, task->request->GetImageKnifeOption()->signature); + FileCache::FileData fileData; + if (FileCache::GetInstance()->GetImageFromDisk(fileKey, fileData)) { + task->product.imageBuffer = fileData.buffer; + task->product.imageLength = fileData.size; + return true; + } + return false; + } + + bool Write(ImageKnifeTask *task) + { + std::string fileKey; + if (!task->imageSrc->GetString(fileKey)) { + return false; + } + fileKey = ImageKnife::GetInstance().GetEngineKeyImpl()-> + GenerateFileKey(task->imageSrc, task->request->GetImageKnifeOption()->signature); + FileCache::GetInstance()->SaveImageToDisk(task->product.response->body.buffer, + task->product.response->body.length, + fileKey); + return true; + } +}; +}; + +#endif // IMAGE_KNIFE_C_FILE_CACHE_INTERCEPTOR_OH_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/interceptor/interceptor.cpp b/thirdparty/image-knife-c/library/src/main/cpp/interceptor/interceptor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf86647550d56027c18cb956bcaba7f640c9487d --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/interceptor/interceptor.cpp @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#include "interceptor.h" +#include "imageKnife_task_internal.h" +#include +namespace ImageKnifeC { + +bool Interceptor::Process(ImageKnifeTask *task) +{ + ImageKnifeTaskInternal *taskInternal = static_cast(task); + if (taskInternal->IsFatalErrorHappened()) { + return false; + } + taskInternal->SetInterceptor(this); + + auto start = std::chrono::high_resolution_clock::now(); + if (Resolve(task)) { + auto end = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(end - start); + + OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, + "Performance", + "[%{public}lld] %{public}s %{public}s Finished WirteMode: %{public}d", + duration.count(), + ImageKnifeTaskInternal::GetTaskInfo(task->type, task->request.get()).c_str(), + name.c_str(), + task->product.writeCache); + + taskInternal->ClearInterceptorPtr(); + return true; + } else if (next_ != nullptr) { + return next_->Process(task); + } else { + taskInternal->ClearInterceptorPtr(); + return false; + } +} + +} // end of namespace diff --git a/thirdparty/image-knife-c/library/src/main/cpp/interceptor/memory_cache_interceptor_OH.h b/thirdparty/image-knife-c/library/src/main/cpp/interceptor/memory_cache_interceptor_OH.h new file mode 100644 index 0000000000000000000000000000000000000000..d550d80d65270370fe6e072326dd1b3dfa2ffb55 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/interceptor/memory_cache_interceptor_OH.h @@ -0,0 +1,85 @@ +/* + * 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_KNIFE_C_MEMORY_CACHE_INTERCEPTOR_OH_H +#define IMAGE_KNIFE_C_MEMORY_CACHE_INTERCEPTOR_OH_H + +#include "interceptor.h" +#include "imageKnife_request.h" +#include "lru_cache.h" +#include "native_entry.h" +#include "imageKnife_internal.h" +#include + +namespace ImageKnifeC { +class MemoryCacheInterceptorOH : public MemoryCacheInterceptor { +public: + MemoryCacheInterceptorOH() + { + name = "Default MemoryCacheInterceptor"; + } + + bool Resolve(ImageKnifeTask *task) override + { + if (task->product.writeCache) { + return Write(task); + } else { + return Read(task); + } + } + +private: + bool Read(ImageKnifeTask *task) + { + std::shared_ptr imageKnifeOption = task->request->GetImageKnifeOption(); + std::string memoryKey = ImageKnife::GetInstance().GetEngineKeyImpl()-> + GenerateMemoryKey(task->imageSrc, + task->type, + imageKnifeOption.get(), + task->request->GetImageKnifeOption()->signature); + if (LruCache::GetInstance()->Contains(memoryKey)) { + task->product.pixelmap = LruCache::GetInstance()->Get(memoryKey); + + if (task->product.pixelmap == nullptr) { + task->EchoError("pixelmap is nullptr"); + return false; + } + return true; + } + return false; + } + + bool Write(ImageKnifeTask *task) + { + std::shared_ptr imageKnifeOption = task->request->GetImageKnifeOption(); + std::string memoryKey = ImageKnife::GetInstance().GetEngineKeyImpl()-> + GenerateMemoryKey(task->imageSrc, + task->type, + imageKnifeOption.get(), + task->request->GetImageKnifeOption()->signature); + + if (task->product.pixelmap != nullptr && task->product.pixelmap->GetPixelMap() != nullptr) { + LruCache::GetInstance()->Put(memoryKey, task->product.pixelmap); + return true; + } else { + task->EchoError("Try to Cache nullptr pixelmap"); + return false; + } + } +}; + +}; + +#endif // IMAGE_KNIFE_C_MEMORY_CACHE_INTERCEPTOR_OH_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/interceptor/resource_interceptor_OH.h b/thirdparty/image-knife-c/library/src/main/cpp/interceptor/resource_interceptor_OH.h new file mode 100644 index 0000000000000000000000000000000000000000..5ddbf8441afbfb3c7a7db63d450f99a161edc464 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/interceptor/resource_interceptor_OH.h @@ -0,0 +1,78 @@ +/* + * 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_KNIFE_C_RESOURCE_INTERCEPTOR_OH_H +#define IMAGE_KNIFE_C_RESOURCE_INTERCEPTOR_OH_H + +#include "interceptor.h" +#include "imageKnife_request.h" +#include + +namespace ImageKnifeC { +class ResourceInterceptorOH : public DownloadInterceptor { +public: + ResourceInterceptorOH() + { + name = "Default ResourceInterceptor"; + } + + bool Resolve(ImageKnifeTask *task) override + { + Resource resource; + if (task->imageSrc->GetResource(resource)) { + return LoadImageFromResource(resource, task); + } + + return false; + } + +private: + bool LoadImageFromResource(Resource resource, ImageKnifeTask *task) + { + auto option = task->request->GetImageKnifeOption(); + if (option->context.resourceManager == nullptr) { + task->EchoError("Get context.resourceManager failed"); + return false; + } + + uint64_t length = 0; + ResourceManager_ErrorCode errCode; + uint8_t *buffer = nullptr; + errCode = OH_ResourceManager_GetMedia(option->context.resourceManager, + resource.id, + &buffer, + &length); + if (errCode != ResourceManager_ErrorCode::SUCCESS) { + // 获取图片资源失败 + task->EchoError("Get image from resource failed, error code: " + std::to_string(errCode)); + return false; + } + + if (length > UINT32_MAX) { + // 默认拦截器支持的length类型为uint32_t + free(buffer); + task->EchoError("Resource Image size out of range!"); + return false; + } + + task->product.imageBuffer = std::shared_ptr(buffer); + task->product.imageLength = length; + return true; + } +}; + +}; + +#endif // IMAGE_KNIFE_C_RESOURCE_INTERCEPTOR_OH_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/key/IEngine_key.h b/thirdparty/image-knife-c/library/src/main/cpp/key/IEngine_key.h new file mode 100644 index 0000000000000000000000000000000000000000..92c50ad484c39fd75398d0d9de18a41670c28aaf --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/key/IEngine_key.h @@ -0,0 +1,52 @@ +/* + * 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_KNIFE_C_IENGINE_KEY_H +#define IMAGE_KNIFE_C_IENGINE_KEY_H +#include +#include + +#include "CryptoArchitectureKit/crypto_common.h" +#include "CryptoArchitectureKit/crypto_digest.h" +#include "node/imageKnife_data.h" +#include "imageKnife_task.h" +#include "imageKnife_option.h" + +namespace ImageKnifeC { +class IEngineKey { +public: + // 构造函数 + IEngineKey() = default; + + // 析构函数 + virtual ~IEngineKey() = default; + + // 生成文件缓存key + virtual std::string GenerateFileKey(const ImageData *imageData, + const std::string &signature = "", + bool isAnimator = false) = 0; + + // 生成内存缓存key + virtual std::string GenerateMemoryKey(const ImageData *imageData, + ImageKnifeC::ImageKnifeRequestSource type, + const ImageKnifeOption * const imageKnifeOption, + const std::string &signature = "", + bool isAnimator = false, + int width = 0, + int height = 0) = 0; +}; +} // namespace ImageKnifeC + +#endif // IMAGE_KNIFE_C_IENGINE_KEY_H \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/src/main/cpp/key/default_engine_key.cpp b/thirdparty/image-knife-c/library/src/main/cpp/key/default_engine_key.cpp new file mode 100644 index 0000000000000000000000000000000000000000..56ad39ff101452e89d92b833169cb86098cf4497 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/key/default_engine_key.cpp @@ -0,0 +1,103 @@ +/* + * 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. + */ +#include "default_engine_key.h" +#include +#include + +namespace ImageKnifeC { +std::string DefaultEngineKey::GenerateFileKey(const ImageData *imageData, const std::string &signature, bool isAnimator) +{ + std::ostringstream src; + std::string fileName; + std::string fileKey; + + imageData->GetString(fileKey); + src << (isAnimator ? "Animator=" : "loadSrc==") << fileKey << ";"; + + if (!signature.empty()) { + src << "signature=" << signature << ";"; + } + + DoMd5Hash(src.str(), fileName); + return fileName; +} + +std::string DefaultEngineKey::GenerateMemoryKey(const ImageData *imageData, + ImageKnifeC::ImageKnifeRequestSource type, + const ImageKnifeOption *const imageKnifeOption, + const std::string &signature, + bool isAnimator, + int width, + int height) +{ + std::string memoryKey; + Resource resource; + // 拼接 loadSrc 类型 + std::ostringstream key; + if (imageData->GetString(memoryKey)) { + key << "loadSrc=" << memoryKey << ";"; + } else { + imageData->GetResource(resource); + key << "loadSrc=" << resource.bundleName << "/" + << resource.moduleName << "/" + << resource.id << ";"; + } + + if (type == ImageKnifeC::ImageKnifeRequestSource::MAINSRC) { + if (!signature.empty()) { + key << "signature=" << signature << ";"; + } + } + return key.str(); +} + +OH_Crypto_ErrCode DefaultEngineKey::DoMd5Hash(const std::string &url, std::string &fileName) +{ + OH_Crypto_ErrCode ret; + OH_CryptoDigest *ctx = nullptr; + Crypto_DataBlob in = {.data = (uint8_t *)(url.c_str()), .len = strlen(url.c_str())}; + Crypto_DataBlob out = {.data = nullptr, .len = 0}; + int mdLen = 0; + ret = OH_CryptoDigest_Create("MD5", &ctx); + if (ret != CRYPTO_SUCCESS) { + return ret; + } + + do { + ret = OH_CryptoDigest_Update(ctx, &in); + if (ret != CRYPTO_SUCCESS) { + break; + } + ret = OH_CryptoDigest_Final(ctx, &out); + if (ret != CRYPTO_SUCCESS) { + break; + } + mdLen = OH_CryptoDigest_GetLength(ctx); + } while (0); + const size_t defaultW = 2; + for (int i = 0; i < out.len; ++i) { + std::ostringstream oss; + oss << std::setw(defaultW) << std::setfill('0') << std::hex << static_cast(out.data[i]); + fileName += oss.str(); + } + OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, + "ImageKnifeNode", + "The gethashFileName of data are : %{public}s", + fileName.c_str()); + OH_Crypto_FreeDataBlob(&out); + OH_DigestCrypto_Destroy(ctx); + return ret; +} +} diff --git a/thirdparty/image-knife-c/library/src/main/cpp/key/default_engine_key.h b/thirdparty/image-knife-c/library/src/main/cpp/key/default_engine_key.h new file mode 100644 index 0000000000000000000000000000000000000000..ef547b7f302f99915b5f62f45f6c3048479503e9 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/key/default_engine_key.h @@ -0,0 +1,49 @@ +/* + * 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_KNIFE_C_DEFAULT_ENGINE_KEY_H +#define IMAGE_KNIFE_C_DEFAULT_ENGINE_KEY_H + +#include "IEngine_key.h" +#include "CryptoArchitectureKit/crypto_common.h" +#include "CryptoArchitectureKit/crypto_digest.h" +#include "node/imageKnife_data.h" +#include "imageKnife_task.h" + +namespace ImageKnifeC { +class DefaultEngineKey : public IEngineKey { +public: + DefaultEngineKey() = default; + ~DefaultEngineKey() override = default; + + // MD5哈希计算 + OH_Crypto_ErrCode DoMd5Hash(const std::string &url, std::string &fileName); + + // 实现纯虚函数 + std::string GenerateFileKey(const ImageData *imageData, + const std::string& signature = "", + bool isAnimator = false) override; + std::string GenerateMemoryKey(const ImageData *imageData, + ImageKnifeC::ImageKnifeRequestSource type, + const ImageKnifeOption * const imageKnifeOption, + const std::string &signature = "", + bool isAnimator = false, + int width = 0, + int height = 0) override; +}; + +} // namespace ImageKnifeC + +#endif // IMAGE_KNIFE_C_DEFAULT_ENGINE_KEY_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/loader/imageKnife_loader.cpp b/thirdparty/image-knife-c/library/src/main/cpp/loader/imageKnife_loader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ee91beae588cabd69953aee4b3344ac99cf51cd5 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/loader/imageKnife_loader.cpp @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#include "imageKnife_loader.h" +#include "imageKnife_loader_internal.h" +#include "decode_interceptor_OH.h" +#include "download_interceptor_OH.h" +#include "file_cache_interceptor_OH.h" +#include "memory_cache_interceptor_OH.h" +#include "resource_interceptor_OH.h" + +namespace ImageKnifeC { + +// static +std::shared_ptr ImageKnifeLoader::CreateDefaultImageLoader() +{ + auto loader = std::make_shared(); + // 设置默认拦截器 + loader->AddMemoryCacheInterceptor(std::make_shared()); + loader->AddFileCacheInterceptor(std::make_shared()); + loader->AddDownloadInterceptor(std::make_shared()); + loader->AddDownloadInterceptor(std::make_shared()); + loader->AddDecodeInterceptor(std::make_shared()); + + return loader; +} + +// static +std::shared_ptr ImageKnifeLoader::CreateEmptyImageLoader() +{ + return std::make_shared(); +} +} // end of namespace \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/src/main/cpp/loader/imageKnife_loader_internal.cpp b/thirdparty/image-knife-c/library/src/main/cpp/loader/imageKnife_loader_internal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a270c2a5a20ea018af0e87d2941590df6c81196b --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/loader/imageKnife_loader_internal.cpp @@ -0,0 +1,204 @@ +/* + * 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. + */ + +#include "imageKnife_request.h" +#include "imageKnife_loader_internal.h" + +namespace ImageKnifeC { +void ImageKnifeLoaderInternal::AddMemoryCacheInterceptor(std::shared_ptr interceptor, + ImageKnifeLoader::Position position) +{ + if (interceptor == nullptr) { + return; + } + + // 责任链为空 + if (memoryInterceptorHead_ == nullptr) { + memoryInterceptorHead_ = memoryInterceptorTail_ = interceptor; + return; + } + + if (position == ImageKnifeLoader::Position::FRONT) { + interceptor->SetNext(memoryInterceptorHead_); + memoryInterceptorHead_ = interceptor; + } else { + memoryInterceptorTail_->SetNext(interceptor); + memoryInterceptorTail_ = interceptor; + } +} + +void ImageKnifeLoaderInternal::AddFileCacheInterceptor(std::shared_ptr interceptor, + ImageKnifeLoader::Position position) +{ + if (interceptor == nullptr) { + return; + } + + // 责任链为空 + if (fileInterceptorHead_ == nullptr) { + fileInterceptorHead_ = fileInterceptorTail_ = interceptor; + return; + } + + if (position == ImageKnifeLoader::Position::FRONT) { + interceptor->SetNext(fileInterceptorHead_); + fileInterceptorHead_ = interceptor; + } else { + fileInterceptorTail_->SetNext(interceptor); + fileInterceptorTail_ = interceptor; + } +} + +void ImageKnifeLoaderInternal::AddDownloadInterceptor(std::shared_ptr interceptor, + ImageKnifeLoader::Position position) +{ + if (interceptor == nullptr) { + return; + } + + // 责任链为空 + if (downloadInterceptorHead_ == nullptr) { + downloadInterceptorHead_ = downloadInterceptorTail_ = interceptor; + return; + } + + if (position == ImageKnifeLoader::Position::FRONT) { + interceptor->SetNext(downloadInterceptorHead_); + downloadInterceptorHead_ = interceptor; + } else { + downloadInterceptorTail_->SetNext(interceptor); + downloadInterceptorTail_ = interceptor; + } +} + + +void ImageKnifeLoaderInternal::AddDecodeInterceptor(std::shared_ptr interceptor, + ImageKnifeLoader::Position position) +{ + if (interceptor == nullptr) { + return; + } + + // 责任链为空 + if (decodeInterceptorHead_ == nullptr) { + decodeInterceptorHead_ = decodeInterceptorTail_ = interceptor; + return; + } + + if (position == ImageKnifeLoader::Position::FRONT) { + interceptor->SetNext(decodeInterceptorHead_); + decodeInterceptorHead_ = interceptor; + } else { + decodeInterceptorTail_->SetNext(interceptor); + decodeInterceptorTail_ = interceptor; + } +} + +bool ImageKnifeLoaderInternal::LoadFromMemory(ImageKnifeTaskInternal *task) +{ + if (memoryInterceptorHead_ == nullptr) { + task->FatalError("Not Find Memory Interceptor!"); + return false; + } + + try { + task->product.writeCache = false; + return memoryInterceptorHead_->Process(task); + } catch (std::exception err) { + task->FatalError("MemoryInterceptor: " + std::string(err.what())); + return false; + } +} + +bool ImageKnifeLoaderInternal::LoadFromFile(ImageKnifeTaskInternal *task) +{ + if (fileInterceptorHead_ == nullptr) { + task->FatalError("Not Find File Interceptor!"); + return false; + } + + try { + task->product.writeCache = false; + return fileInterceptorHead_->Process(task); + } catch (std::exception err) { + task->FatalError("FileInterceptor: " + std::string(err.what())); + return false; + } +} + + +bool ImageKnifeLoaderInternal::WriteCacheToMemory(ImageKnifeTaskInternal *task) +{ + if (memoryInterceptorHead_ == nullptr) { + task->FatalError("Not Find Memory Interceptor!"); + return false; + } + + try { + task->product.writeCache = true; + return memoryInterceptorHead_->Process(task); + } catch (std::exception err) { + task->FatalError("MemoryInterceptor: " + std::string(err.what())); + return false; + } +} + +bool ImageKnifeLoaderInternal::WriteCacheToFile(ImageKnifeTaskInternal *task) +{ + if (fileInterceptorHead_ == nullptr) { + task->FatalError("Not Find File Interceptor!"); + return false; + } + + try { + task->product.writeCache = true; + return fileInterceptorHead_->Process(task); + } catch (std::exception err) { + task->FatalError("FileInterceptor: " + std::string(err.what())); + return false; + } +} + +bool ImageKnifeLoaderInternal::DownloadImage(ImageKnifeTaskInternal *task) +{ + if (downloadInterceptorHead_ == nullptr) { + task->FatalError("Not Find Download Interceptor!"); + return false; + } + + try { + return downloadInterceptorHead_->Process(task); + } catch (std::exception err) { + task->FatalError("DownloadInterceptor: " + std::string(err.what())); + return false; + } +} + +bool ImageKnifeLoaderInternal::DecodeImage(ImageKnifeTaskInternal *task) +{ + if (decodeInterceptorHead_ == nullptr) { + task->FatalError("Not Find Decode Interceptor!"); + return false; + } + + try { + return decodeInterceptorHead_->Process(task); + } catch (std::exception err) { + task->FatalError("DecodeInterceptor: " + std::string(err.what())); + return false; + } +} + +} // end of namespace diff --git a/thirdparty/image-knife-c/library/src/main/cpp/loader/imageKnife_loader_internal.h b/thirdparty/image-knife-c/library/src/main/cpp/loader/imageKnife_loader_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..3b074783398cd9ba7a6a89fee5836464d4f32c83 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/loader/imageKnife_loader_internal.h @@ -0,0 +1,66 @@ +/* + * 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_KNIFE_C_KEKE_IMAGEKNIFE_LOADER_INTERNAL_H +#define IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_LOADER_INTERNAL_H + +#include "imageKnife_loader.h" +#include "imageKnife_task_internal.h" + +namespace ImageKnifeC { + +class ImageKnifeLoaderInternal : public ImageKnifeLoader { +public: + bool LoadFromMemory(ImageKnifeTaskInternal *task); + + bool LoadFromFile(ImageKnifeTaskInternal *task); + + bool WriteCacheToMemory(ImageKnifeTaskInternal *task); + + bool WriteCacheToFile(ImageKnifeTaskInternal *task); + + bool DownloadImage(ImageKnifeTaskInternal *task); + + bool DecodeImage(ImageKnifeTaskInternal *task); + + void AddMemoryCacheInterceptor(std::shared_ptr interceptor, + Position postion = Position::FRONT) override; + + void AddFileCacheInterceptor(std::shared_ptr interceptor, + Position postion = Position::FRONT) override; + + void AddDownloadInterceptor(std::shared_ptr interceptor, + Position postion = Position::FRONT) override; + + void AddDecodeInterceptor(std::shared_ptr interceptor, + Position postion = Position::FRONT) override; + +private: + std::shared_ptr memoryInterceptorHead_ = nullptr; + std::shared_ptr memoryInterceptorTail_ = nullptr; + + std::shared_ptr fileInterceptorHead_ = nullptr; + std::shared_ptr fileInterceptorTail_ = nullptr; + + std::shared_ptr downloadInterceptorHead_ = nullptr; + std::shared_ptr downloadInterceptorTail_ = nullptr; + + std::shared_ptr decodeInterceptorHead_ = nullptr; + std::shared_ptr decodeInterceptorTail_ = nullptr; +}; + +} // end of namespace + +#endif // IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_LOADER_INTERNAL_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/napi_init.cpp b/thirdparty/image-knife-c/library/src/main/cpp/napi_init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d3f3744f3f1f74564f5a0cc2bafd81cab88cd9b7 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/napi_init.cpp @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#include "napi/native_api.h" +#include "include/imageKnife.h" + +#include "imageKnife_napi.h" +#include "key/default_engine_key.h" + +EXTERN_C_START +static napi_value init(napi_env env, napi_value exports) +{ + ImageKnifeC::ImageKnifeNapi::Init(env, exports); + auto imageLoader = ImageKnifeC::ImageKnifeLoader::CreateDefaultImageLoader(); + ImageKnifeC::ImageKnife::GetInstance().SetDefaultImageKnifeLoader(imageLoader); + + ImageKnifeC::DefaultEngineKey *keyPtr = new ImageKnifeC::DefaultEngineKey(); + ImageKnifeC::ImageKnife::GetInstance().SetEngineKeyImpl(keyPtr); + return exports; +} +EXTERN_C_END + +static napi_module demoModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = init, + .nm_modname = "imageknifec", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__((constructor)) void registerEntryModule(void) +{ + napi_module_register(&demoModule); +} diff --git a/thirdparty/image-knife-c/library/src/main/cpp/native_entry.h b/thirdparty/image-knife-c/library/src/main/cpp/native_entry.h new file mode 100644 index 0000000000000000000000000000000000000000..b8e7191741f10bb5cf8080016873fc728ad117b5 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/native_entry.h @@ -0,0 +1,78 @@ +/* + * 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_KNIFE_C_NATIVE_ENTRY_H +#define IMAGE_KNIFE_C_NATIVE_ENTRY_H + +#include "arkUI_base_node.h" +#include +#include +#include +#include +#include + +namespace ImageKnifeC { +// 管理Native组件的生命周期和内存。 +class NativeEntry { +public: + static NativeEntry *GetInstance() + { + static NativeEntry nativeEntry; + return &nativeEntry; + } + + void SetRootNode(std::string id, ArkUI_NodeContentHandle handle, const std::shared_ptr &baseNode) + { + contentHandleMap_[id] = contentHandle({.imageNode = baseNode, .rootNode = handle}); + // 添加Native组件到NodeContent上用于挂载显示。 + OH_ArkUI_NodeContent_AddNode(handle, baseNode->GetHandle()); + } + + void DisposeRootNode(std::string id) + { + // 从NodeContent上卸载组件并销毁Native组件。 + OH_ArkUI_NodeContent_RemoveNode(contentHandleMap_[id].rootNode, contentHandleMap_[id].imageNode->GetHandle()); + contentHandleMap_[id].imageNode.reset(); + + // contentHandleMap_[id].rootNode 是js层传下来占位的contentSlot无需处理 + // contentHandleMap_ 移除item + contentHandleMap_.erase(id); + } + + std::shared_ptr GetArkUIBaseNode(std::string id) + { + if (contentHandleMap_.find(id) != contentHandleMap_.end()) { + return contentHandleMap_[id].imageNode; + } + + return nullptr; + } + + ~NativeEntry() + { + } + +private: + typedef struct { + std::shared_ptr imageNode; + ArkUI_NodeContentHandle rootNode; + } contentHandle; + + std::unordered_map contentHandleMap_; +}; + +} // namespace ImageKnifeC + +#endif // IMAGE_KNIFE_C_NATIVE_ENTRY_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/native_module.h b/thirdparty/image-knife-c/library/src/main/cpp/native_module.h new file mode 100644 index 0000000000000000000000000000000000000000..4a04df05f74db567796fd94e03d4d2bbe3bc1d89 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/native_module.h @@ -0,0 +1,64 @@ +/* + * 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_KNIFE_C_NATIVE_MODULE_H +#define IMAGE_KNIFE_C_NATIVE_MODULE_H + +#include +#include + +#include +#include "napi/native_api.h" + +namespace ImageKnifeC { + +class NativeModuleInstance { +public: + static NativeModuleInstance *GetInstance() + { + static NativeModuleInstance instance; + return &instance; + } + + void SetNapiEnv(napi_env env) + { + if (env_ == nullptr) { + env_ = env; + } + } + + napi_env GetNapiEnv() + { + return env_; + } + + NativeModuleInstance() + { + OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativeNodeApi_); + } + // 暴露给其他模块使用。 + ArkUI_NativeNodeAPI_1 *GetNativeNodeAPI() + { + return arkUINativeNodeApi_; + } + +private: + ArkUI_NativeNodeAPI_1 *arkUINativeNodeApi_ = nullptr; + napi_env env_ = nullptr; +}; + +} // namespace ImageKnifeC + +#endif // IMAGE_KNIFE_C_NATIVE_MODULE_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/node/arkUI_base_node.h b/thirdparty/image-knife-c/library/src/main/cpp/node/arkUI_base_node.h new file mode 100644 index 0000000000000000000000000000000000000000..3c2eb231fa72d4985b35bedfdc79ead84af03ecf --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/node/arkUI_base_node.h @@ -0,0 +1,123 @@ +/* + * 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_KNIFE_C_ARKUI_BASE_NODE_H +#define IMAGE_KNIFE_C_ARKUI_BASE_NODE_H + +#include +#include +#include +#include + +#include "native_module.h" + +namespace ImageKnifeC { +class ArkUIBaseNode { +public: + enum NodeState { + Available, + Cleared + }; + + explicit ArkUIBaseNode(ArkUI_NodeHandle handle) + : handle_(handle), nativeModule_(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()) {} + + virtual ~ArkUIBaseNode() + { + // 封装析构函数,实现子节点移除功能。 + if (!children_.empty()) { + for (const auto& child : children_) { + nativeModule_->removeChild(handle_, child->GetHandle()); + } + children_.clear(); + } + // 封装析构函数,统一回收节点资源. + nativeModule_->disposeNode(handle_); + } + + void AddChild(const std::shared_ptr &child) + { + children_.emplace_back(child); + OnAddChild(child); + } + + void RemoveChild(const std::shared_ptr &child) + { + children_.remove(child); + OnRemoveChild(child); + } + + void InsertChild(const std::shared_ptr &child, int32_t index) + { + if (index >= children_.size()) { + AddChild(child); + } else { + auto iter = children_.begin(); + std::advance(iter, index); + children_.insert(iter, child); + OnInsertChild(child, index); + } + } + + void Reuse(int version) + { + this->componentVersion_ = version; + this->nodeState_ = Available; + } + + void Clear() + { + this->nodeState_ = Cleared; + ClearDisplayedImage(); + } + + NodeState GetNodeState() + { + return nodeState_; + } + + int GetNodeVersion() + { + return componentVersion_; + } + + virtual void Display(void *data) = 0; + virtual void FitImage(int fitEnum) = 0; + virtual void ClearDisplayedImage() = 0; + + ArkUI_NodeHandle GetHandle() const + { + return handle_; + } + +protected: + // 针对父容器子类需要重载下面的函数,实现组件挂载和卸载。 + virtual void OnAddChild(const std::shared_ptr &child) {} + virtual void OnRemoveChild(const std::shared_ptr &child) {} + virtual void OnInsertChild(const std::shared_ptr &child, int32_t index) {} + + ArkUI_NodeHandle handle_; + ArkUI_NativeNodeAPI_1 *nativeModule_ = nullptr; + +private: + std::list> children_; + + int componentVersion_ = 0; + NodeState nodeState_ = Available; + bool syncLoad_ = false; +}; +} // namespace ImageKnifeC + +#endif // IMAGE_KNIFE_C_ARKUI_BASE_NODE_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/node/arkUI_node.h b/thirdparty/image-knife-c/library/src/main/cpp/node/arkUI_node.h new file mode 100644 index 0000000000000000000000000000000000000000..3936fe43a9938c4b1dd335a945a8748b7442722a --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/node/arkUI_node.h @@ -0,0 +1,85 @@ +/* + * 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_KNIFE_C_ARKUI_NODE_H +#define IMAGE_KNIFE_C_ARKUI_NODE_H + +#include "arkUI_base_node.h" +#include "native_module.h" +#include +#include + +namespace ImageKnifeC { +class ArkUINode : public ArkUIBaseNode { +public: + explicit ArkUINode(ArkUI_NodeHandle handle) : ArkUIBaseNode(handle) {} + + ~ArkUINode() override {} + + void SetWidth(float width) + { + ArkUI_NumberValue value[] = {{.f32 = width}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_WIDTH, &item); + } + + void SetPercentWidth(float percent) + { + ArkUI_NumberValue value[] = {{.f32 = percent}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_WIDTH_PERCENT, &item); + } + + void SetHeight(float height) + { + ArkUI_NumberValue value[] = {{.f32 = height}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_HEIGHT, &item); + } + + void SetPercentHeight(float percent) + { + ArkUI_NumberValue value[] = {{.f32 = percent}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_HEIGHT_PERCENT, &item); + } + + void SetBackgroundColor(uint32_t color) + { + ArkUI_NumberValue value[] = {{.u32 = color}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_BACKGROUND_COLOR, &item); + } + +protected: + // 组件树操作的实现类对接。 + void OnAddChild(const std::shared_ptr &child) override + { + nativeModule_->addChild(handle_, child->GetHandle()); + } + + void OnRemoveChild(const std::shared_ptr &child) override + { + nativeModule_->removeChild(handle_, child->GetHandle()); + } + + void OnInsertChild(const std::shared_ptr &child, int32_t index) override + { + nativeModule_->insertChildAt(handle_, child->GetHandle(), index); + } +}; +} // namespace ImageKnifeC + +#endif // IMAGE_KNIFE_C_ARKUI_NODE_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_data.cpp b/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..15e78b8de71ca0b07d3de705d3c87b3d353597fe --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_data.cpp @@ -0,0 +1,568 @@ +/* + * 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. + */ + + +#include "imageKnife_data.h" +#include +#include "hilog/log.h" + +namespace ImageKnifeC { +bool OptionData::GetString(std::string &result) const +{ + if ((DataType::STRING & availableType_) && (type_ == DataType::STRING)) { + result = data_.str; + return true; + } + return false; +} + +std::string OptionData::ToString() const +{ + if ((DataType::STRING & availableType_) && (type_ == DataType::STRING)) { + return data_.str; + } else if ((DataType::NUMBER & availableType_) && (type_ == DataType::NUMBER)) { + return std::to_string(data_.number); + } else if ((DataType::RESOURCE & availableType_) && (type_ == DataType::RESOURCE)) { + return "[Resource]: " + data_.resource.bundleName + "," + + data_.resource.moduleName + "," + std::to_string(data_.resource.id); + } else if (type_ == DataType::UNDEFINED) { + return "[Undefined]"; + } else { + return "[Object]"; + } +} + +bool OptionData::GetNumber(int& result) const +{ + if ((DataType::NUMBER & availableType_) && (type_ == DataType::NUMBER)) { + result = data_.number; + return true; + } + return false; +} + +bool OptionData::GetPixelMap(OH_PixelmapNative*& result) const +{ + if ((DataType::PIXELMAP & availableType_) && (type_ == DataType::PIXELMAP) && (data_.pixelMap != nullptr)) { + result = data_.pixelMap; + return true; + } + return false; +} + +bool OptionData::MovePixelMap(OH_PixelmapNative *&result) +{ + if ((DataType::PIXELMAP & availableType_) && (type_ == DataType::PIXELMAP) && (data_.pixelMap != nullptr)) { + result = data_.pixelMap; + data_.pixelMap = nullptr; + type_ = DataType::UNDEFINED; + return true; + } + return false; +} + +bool OptionData::GetResource(Resource &result) const +{ + if ((DataType::RESOURCE & availableType_) && (type_ == DataType::RESOURCE)) { + result = data_.resource; + return true; + } + return false; +} + +void OptionData::SetString(std::string str) +{ + if (!(DataType::STRING & availableType_)) { + return; + } + CleanData(); + new (&data_.str) std::string(str); + type_ = DataType::STRING; +} + +void OptionData::SetNumber(int number) +{ + if (!(DataType::NUMBER & availableType_)) { + return; + } + CleanData(); + data_.number = number; + type_ = DataType::NUMBER; +} + +void OptionData::SetPixelMap(OH_PixelmapNative *pixelMap) +{ + if (!(DataType::PIXELMAP & availableType_)) { + return; + } + CleanData(); + data_.pixelMap = pixelMap; + type_ = DataType::PIXELMAP; +} + +// 没有提供直接的拷贝接口,需要自己实现 +void OptionData::CopyFromPixelmap(OH_PixelmapNative *source) +{ + if (source == nullptr) { + return; + } + + if (!(DataType::PIXELMAP & availableType_)) { + return; + } + CleanData(); + data_.pixelMap = nullptr; + type_ = DataType::PIXELMAP; + + OH_Pixelmap_ImageInfo *imageInfo = nullptr; + if (OH_PixelmapImageInfo_Create(&imageInfo) != IMAGE_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "OptionData", + "CopyFromPixelmap create ImageInfo failed"); + return; + } + + if (OH_PixelmapNative_GetImageInfo(source, imageInfo) != IMAGE_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "OptionData", + "CopyFromPixelmap GetImageInfo failed"); + OH_PixelmapImageInfo_Release(imageInfo); + return; + } + + OH_Pixelmap_InitializationOptions *options; + if (OH_PixelmapInitializationOptions_Create(&options) != IMAGE_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "OptionData", + "CopyFromPixelmap create option failed"); + OH_PixelmapImageInfo_Release(imageInfo); + return; + } + + int32_t alphaType; + OH_PixelmapImageInfo_GetAlphaType(imageInfo, &alphaType); + OH_PixelmapInitializationOptions_SetAlphaType(options, alphaType); + + uint32_t height; + OH_PixelmapImageInfo_GetHeight(imageInfo, &height); + OH_PixelmapInitializationOptions_SetHeight(options, height); + + uint32_t width; + OH_PixelmapImageInfo_GetWidth(imageInfo, &width); + OH_PixelmapInitializationOptions_SetWidth(options, width); + + uint32_t rowStride; + OH_PixelmapImageInfo_GetRowStride(imageInfo, &rowStride); + OH_PixelmapInitializationOptions_SetRowStride(options, rowStride); + + int32_t pixelFormat; + OH_PixelmapImageInfo_GetPixelFormat(imageInfo, &pixelFormat); + OH_PixelmapInitializationOptions_SetPixelFormat(options, pixelFormat); + OH_PixelmapInitializationOptions_SetSrcPixelFormat(options, pixelFormat); + + // RGBA格式的缓冲区大小等于width * height * 4 + // NV21与NV12格式的缓冲区大小等于width * height+((width+1)/2) * ((height+1)/2) * 2 + size_t bufferSize; + const int half = 2; + const int four = 4; + if (pixelFormat == PIXEL_FORMAT_NV21 || pixelFormat == PIXEL_FORMAT_NV12) { + bufferSize = width * height + ((width + 1) / half) * ((height + 1) / half) * half; + } else { + bufferSize = width * height * four; + } + + OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, + "OptionData", + "CopyFromPixelmap bufferSize: %{public}d", + bufferSize); + uint8_t *buffer = static_cast(malloc(bufferSize)); + if (buffer == nullptr) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "OptionData", + "Failed to allocate memory, format:%{public}d , bufferSize:%{public}d", + pixelFormat, + bufferSize); + OH_PixelmapInitializationOptions_Release(options); + OH_PixelmapImageInfo_Release(imageInfo); + } + + if (OH_PixelmapNative_ReadPixels(source, buffer, &bufferSize) != IMAGE_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "OptionData", + "CopyFromPixelmap ReadPixels failed, format:%{public}d , bufferSize:%{public}ld", + pixelFormat, + bufferSize); + OH_PixelmapInitializationOptions_Release(options); + OH_PixelmapImageInfo_Release(imageInfo); + free(buffer); + return; + } + + // 使用buffer 新建pixelMap 完成拷贝 + if (OH_PixelmapNative_CreatePixelmap(buffer, bufferSize, options, &data_.pixelMap) != IMAGE_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "OptionData", + "CopyFromPixelmap Copy failed!"); + } + + OH_PixelmapInitializationOptions_Release(options); + OH_PixelmapImageInfo_Release(imageInfo); + if (buffer != nullptr) { + free(buffer); + buffer = nullptr; + } +} + +void OptionData::SetResource(Resource resource) +{ + if (!(DataType::RESOURCE & availableType_)) { + return; + } + CleanData(); + new (&data_.resource) Resource(resource); + type_ = DataType::RESOURCE; +} + +void OptionData::SetValue(napi_env env, napi_value &value) +{ + napi_valuetype type; + napi_status status = napi_typeof(env, value, &type); + + if (type == napi_string) { + SetString(ParseNapiString(env, value)); + } else if (type == napi_number) { + int num; + status = napi_get_value_int32(env, value, &num); + SetNumber(num); + } else if (type == napi_object) { + // 通过成员属性名判断是否为pixelMap + bool hasProperty = false; + status = napi_has_named_property(env, value, "createAlphaPixelmap", &hasProperty); + if (status == napi_ok && hasProperty) { + OH_PixelmapNative *pixelmap; + if (OH_PixelmapNative_ConvertPixelmapNativeFromNapi(env, value, &pixelmap) == IMAGE_SUCCESS) { + SetPixelMap(pixelmap); + } + return; + } + + // 通过成员属性名判断是否为Resource + status = napi_has_named_property(env, value, "id", &hasProperty); + if (status == napi_ok && hasProperty) { + Resource resource; + napi_value id, bundleName, moduleName, number; + status = napi_get_named_property(env, value, "id", &id); + if (status == napi_ok) { + napi_get_value_int32(env, id, &resource.id); + } + + status = napi_get_named_property(env, value, "bundleName", &bundleName); + if (status == napi_ok) { + resource.bundleName = ParseNapiString(env, bundleName); + } + + status = napi_get_named_property(env, value, "moduleName", &moduleName); + if (status == napi_ok) { + resource.moduleName = ParseNapiString(env, moduleName); + } + + status = napi_get_named_property(env, value, "number", &number); + if (status == napi_ok) { + napi_get_value_int32(env, number, &resource.number); + } + + SetResource(resource); + } + } +} + +std::string OptionData::ParseNapiString(napi_env env, napi_value value) +{ + size_t length; + napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &length); + char buf[length + 1]; + status = napi_get_value_string_utf8(env, value, buf, length + 1, nullptr); + return buf; +} + +bool OptionData::IsUndefined() +{ + if ((DataType::UNDEFINED & availableType_) && type_ == DataType::UNDEFINED) { + return true; + } + return false; +} + +void OptionData::SetUndefined() +{ + if (!(DataType::UNDEFINED & availableType_)) { + return; + } + CleanData(); + type_ = DataType::UNDEFINED; +} + +void OptionData::CleanData() +{ + if (type_ == DataType::UNDEFINED) { + return; + } + switch (type_) { + case DataType::STRING : + data_.str.~basic_string(); + break; + case DataType::RESOURCE : + data_.resource.~Resource(); + break; + case DataType::PIXELMAP : + if (data_.pixelMap != nullptr) { + OH_PixelmapNative_Release(data_.pixelMap); + data_.pixelMap = nullptr; + } + break; + default: + return; + } +} + +void Context::SetContext(napi_env env, napi_value value) +{ + bool hasProperty = false; + napi_status status = napi_has_named_property(env, value, "resourceManager", &hasProperty); + if (status == napi_ok && hasProperty) { + napi_value jsResMgr; + status = napi_get_named_property(env, value, "resourceManager", &jsResMgr); + if (status == napi_ok) { + resourceManager = OH_ResourceManager_InitNativeResourceManager(env, jsResMgr); + } + } +} + +void BorderOption::SetBorderOption(napi_env env, napi_value &value) +{ + napi_status status = napi_has_named_property(env, value, "width", &hasWidth); + if (status == napi_ok && hasWidth) { + napi_value width; + napi_get_named_property(env, value, "width", &width); + ParseWidth(env, width); + } + + status= napi_has_named_property(env, value, "color", &hasColor); + if (status == napi_ok && hasColor) { + napi_value color; + napi_get_named_property(env, value, "color", &color); + ParseColor(env, color); + } + + status= napi_has_named_property(env, value, "radius", &hasRadius); + if (status == napi_ok && hasRadius) { + napi_value radius; + napi_get_named_property(env, value, "radius", &radius); + ParseRadius(env, radius); + } + + status= napi_has_named_property(env, value, "style", &hasStyle); + if (status == napi_ok && hasStyle) { + napi_value style; + napi_get_named_property(env, value, "style", &style); + ParseStyle(env, style); + } +} + +void BorderOption::ParseWidth(napi_env env, napi_value &value) +{ + bool hasProperty = false; + bool typeMatched = false; + napi_status status; + + // LocalizedEdgeWidths + std::vector names = {"top", "end", "bottom", "start"}; + const int namesSize = 4; + for (int i = 0; i < namesSize; i++) { + napi_value lengthMetrics; + status = napi_has_named_property(env, value, names[i].c_str(), &hasProperty); + if (status == napi_ok && hasProperty) { + napi_get_named_property(env, value, names[i].c_str(), &lengthMetrics); + status = napi_has_named_property(env, lengthMetrics, "value", &hasProperty); + if (status == napi_ok && hasProperty) { + typeMatched = true; + } + } + } + + if (typeMatched) { + OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, + "BorderOption", + "Border width only support number for now"); + hasWidth = false; + return; + } + + // EdgeWidths + names = {"top", "right", "bottom", "left"}; + + for (int i = 0; i < namesSize; i++) { + napi_value length; + status = napi_has_named_property(env, value, names[i].c_str(), &hasProperty); + if (status == napi_ok && hasProperty) { + typeMatched = true; + napi_get_named_property(env, value, names[i].c_str(), &length); + width[i] = ParseLength(env, length); + } + } + + // Length for four edge + if (!typeMatched) { + width[0] = ParseLength(env, value); + } +} + +void BorderOption::ParseRadius(napi_env env, napi_value &value) +{ + bool hasProperty = false; + bool typeMatched = false; + napi_status status; + + std::vector names = {"topLeft", "topRight", "bottomLeft", "bottomRight"}; + const int namesSize = 4; + for (int i = 0; i < namesSize; i++) { + napi_value lengthValue; + status = napi_has_named_property(env, value, names[i].c_str(), &hasProperty); + if (status == napi_ok && hasProperty) { + typeMatched = true; + napi_get_named_property(env, value, names[i].c_str(), &lengthValue); + // LocalizedBorderRadiuses + status = napi_has_named_property(env, lengthValue, "value", &hasProperty); + if (status == napi_ok && hasProperty) { + OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, + "BorderOption", + "Border radius only support number for now"); + hasRadius = false; + } else { // BorderRadiuses + radius[i] = ParseLength(env, lengthValue); + } + } + } + + if (!typeMatched) { + radius[0] = ParseLength(env, value); + } +} + +void BorderOption::ParseColor(napi_env env, napi_value &value) +{ + bool hasProperty = false; + bool typeMatched = false; + napi_status status; + + // LocalizedEdgeColors | EdgeColors + napi_value resourceColor; + std::vector names = {"top", "end", "bottom", "start"}; + const int namesSize = 4; + for (int i = 0; i < namesSize; i++) { + status = napi_has_named_property(env, value, names[i].c_str(), &hasProperty); + if (status == napi_ok && hasProperty) { + typeMatched = true; + napi_get_named_property(env, value, names[i].c_str(), &resourceColor); + color[i] = ParseResourceColor(env, resourceColor); + } + } + + status = napi_has_named_property(env, value, "right", &hasProperty); + if (status == napi_ok && hasProperty) { + typeMatched = true; + napi_get_named_property(env, value, "right", &resourceColor); + color[1] = ParseResourceColor(env, resourceColor); + } + + status = napi_has_named_property(env, value, "left", &hasProperty); + const int colorLeftIndex = 3; + if (status == napi_ok && hasProperty) { + typeMatched = true; + napi_get_named_property(env, value, "left", &resourceColor); + color[colorLeftIndex] = ParseResourceColor(env, resourceColor); + } + + // ResourceColor + if (!typeMatched) { + color[0] = ParseResourceColor(env, value); + } +} + +void BorderOption::ParseStyle(napi_env env, napi_value &value) +{ + bool hasProperty = false; + bool typeMatched = false; + napi_status status; + + // EdgeStyles + napi_value styleValue; + std::vector names = {"top", "right", "bottom", "left"}; + const int namesSize = 4; + for (int i = 0; i < namesSize; i++) { + status = napi_has_named_property(env, value, names[i].c_str(), &hasProperty); + if (status == napi_ok && hasProperty) { + typeMatched = true; + napi_get_named_property(env, value, names[i].c_str(), &styleValue); + style[i] = parseBorderStyle(env, styleValue); + } + } + + if (!typeMatched) { + style[0] = parseBorderStyle(env, value); + } +} + +float BorderOption::ParseLength(napi_env env, napi_value &value) +{ + // string | number | Resource + napi_valuetype type; + if (napi_typeof(env, value, &type) == napi_ok && type == napi_string) { + size_t length; + napi_get_value_string_utf8(env, value, nullptr, 0, &length); + char buf[length + 1]; + napi_get_value_string_utf8(env, value, buf, length+1, nullptr); + return std::atof(buf); + } else if (napi_typeof(env, value, &type) == napi_ok && type == napi_number) { + double num; + napi_get_value_double(env, value, &num); + return num; + } else { + OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, + "BorderOption", + "Border only support Length:number for now"); + return 0; + } +} + +uint32_t BorderOption::ParseResourceColor(napi_env env, napi_value &value) +{ + OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, + "BorderOption", + "Border only support width radius for now"); + return 0; // black +} + +int32_t BorderOption::parseBorderStyle(napi_env env, napi_value &value) +{ + // C: ARKUI_BORDER_STYLE_SOLID = 0, ARKUI_BORDER_STYLE_DASHED, ARKUI_BORDER_STYLE_DOTTED + // JS: Dotted, Dashed, Solid + OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, + "BorderOption", + "Border only support width radius for now"); + return 0; +} + +} // end of namespace \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_data.h b/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_data.h new file mode 100644 index 0000000000000000000000000000000000000000..4ec6f5a4107a0a83adecf165ef5700ff1802fa05 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_data.h @@ -0,0 +1,204 @@ +/* + * 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_KNIFE_C_IMAGEKNIFE_DATA_H +#define IMAGE_KNIFE_C_IMAGEKNIFE_DATA_H + +#include "napi/native_api.h" +#include +#include +#include +#include + +namespace ImageKnifeC { + +enum DataType: unsigned int { + UNDEFINED = 1, + STRING = 1 << 1, + NUMBER = 1 << 2, + PIXELMAP = 1 << 3, + RESOURCE = 1 << 4, +}; + +struct ImageKnifeData { + // source: PixelMap | string + // OptionData source = OptionData(DataType::) + int imageWidth = 0; + int imageHeight = 0; + // type?:string + std::string type; + // imageAnimator?: Array +}; + +struct Resource { + std::string bundleName; + std::string moduleName; + int id; + int number = 0; + // params?: any[]; +}; + +// Js UIAbilityContext +struct Context { + NativeResourceManager *resourceManager = nullptr; + void SetContext(napi_env env, napi_value value); +}; + +struct BorderOption { + // 0: all border or top, 1: right, 2: bottom, 3: left + float width[4] = {0}; + float radius[4] = {0}; + uint32_t color[4] = {0}; + int32_t style[4] = {0}; + + bool percentageWidth = false; + bool percentageRadius = false; + + bool hasWidth = false; + bool hasColor = false; + bool hasRadius = false; + bool hasStyle = false; + + void SetBorderOption(napi_env env, napi_value &value); +private: + void ParseWidth(napi_env env, napi_value &value); + void ParseRadius(napi_env env, napi_value &value); + void ParseColor(napi_env env, napi_value &value); + void ParseStyle(napi_env env, napi_value &value); + + float ParseLength(napi_env env, napi_value &value); + uint32_t ParseResourceColor(napi_env env, napi_value &value); + int32_t parseBorderStyle(napi_env env, napi_value &value); +}; + +// ArkTs EventImage +struct EventImage { + int32_t loadingStatus; + float width; + float height; + float componentWidth; + float componentHeight; + float contentOffsetX; + float contentOffsetY; + float contentWidth; + float contentHeight; +}; + +struct OptionData { +public: + // 类型正确返回true + bool GetString(std::string &result) const; + + bool GetNumber(int &result) const; + // 获取pixelMap指针, pixelmap生命周期由该类管理进行释放。 + bool GetPixelMap(OH_PixelmapNative *&result) const; + // 移交pixelMap管理权,该类不进行pixelmap释放,操作成功返回true,并将类型设成undefined + bool MovePixelMap(OH_PixelmapNative *&result); + + bool GetResource(Resource &result) const; + + void SetString(std::string str); + + void SetNumber(int number); + // 设置pixelmap 指针,接管其生命周期 + void SetPixelMap(OH_PixelmapNative *pixelMap); + + void CopyFromPixelmap(OH_PixelmapNative *pixelMap); + + void SetResource(Resource resource); + + void SetValue(napi_env env, napi_value &value); + + bool IsUndefined(); + + void SetUndefined(); + + std::string ToString() const; + + DataType GetType() const + { + return type_; + } + + OptionData() : type_(DataType::UNDEFINED) {}; + explicit OptionData(unsigned int type) : type_(DataType::UNDEFINED), availableType_(type) {}; + ~OptionData() + { + CleanData(); + }; +private: + union ImageSrc { + std::string str; + int number; + // pixelMap has attr: createAlphaPixelmap + OH_PixelmapNative *pixelMap; + // Resource has attr: id + Resource resource; + // 由OptionData管理 + ImageSrc() : pixelMap(nullptr) {}; + ~ImageSrc() {}; + }; + + unsigned int availableType_; + DataType type_; + ImageSrc data_; + + void CleanData(); + std::string ParseNapiString(napi_env env, napi_value vaue); +}; + +struct ImageData : public OptionData { + ImageData() : OptionData(DataType::STRING | DataType::PIXELMAP | DataType::RESOURCE) + { + } + + explicit ImageData(std::string url) : ImageData() + { + SetString(url); + } + + explicit ImageData(const char* url) : ImageData(std::string(url)) + { + } + + explicit ImageData(OH_PixelmapNative *pixelMap) : ImageData() + { + SetPixelMap(pixelMap); + } + + explicit ImageData(Resource resource) : ImageData() + { + SetResource(resource); + } +}; + +struct ImageDataBack : public OptionData { + ImageDataBack() : OptionData(DataType::STRING | DataType::PIXELMAP | DataType::UNDEFINED) + { + } + + explicit ImageDataBack(std::string base64) : ImageDataBack() + { + SetString(base64); + } + + explicit ImageDataBack(OH_PixelmapNative *pixelMap) : ImageDataBack() + { + SetPixelMap(pixelMap); + } +}; +} // end of namespace + +#endif // IMAGE_KNIFE_C_IMAGEKNIFE_DATA_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_node.cpp b/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_node.cpp new file mode 100644 index 0000000000000000000000000000000000000000..870e07c0eaf05219a2938d27f54917d70f9f41d8 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_node.cpp @@ -0,0 +1,167 @@ +/* + * 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. + */ + + +#include "imageKnife_node.h" +#include "native_entry.h" +#include "task_worker.h" +#include "hilog/log.h" +#include "request/imageKnife_request_internal.h" + +namespace ImageKnifeC { + +void ImageKnifeNode::OnMeasure(ArkUI_NodeCustomEvent *event) +{ + auto layoutConstrain = OH_ArkUI_NodeCustomEvent_GetLayoutConstraintInMeasure(event); + nativeModule_->measureNode(handle_, layoutConstrain); + auto size = nativeModule_->getMeasuredSize(handle_); +} + +// static +void ImageKnifeNode::OnCustomEvent(ArkUI_NodeCustomEvent *event) +{ + // 获取组件实例对象,调用相关实例方法。 + auto customNode = reinterpret_cast(OH_ArkUI_NodeCustomEvent_GetUserData(event)); + auto type = OH_ArkUI_NodeCustomEvent_GetEventType(event); + switch (type) { + case ARKUI_NODE_CUSTOM_EVENT_ON_MEASURE: + customNode->OnMeasure(event); + break; + default: + break; + } +} + +void ImageKnifeNode::RegisterMeasureCallback() +{ + nativeModule_->addNodeCustomEventReceiver(handle_, OnCustomEvent); + nativeModule_->registerNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_MEASURE, 0, this); + // 自定义属性事件更新需要主动调用标记脏区接口。 + nativeModule_->markDirty(handle_, NODE_NEED_MEASURE); +} + +// 需在ImageKnifeRequest 构造完以后调用 +void ImageKnifeNode::RegisterNodeEvent() +{ + nativeModule_->setUserData(handle_, this); + nativeModule_->addNodeEventReceiver(handle_, OnNodeEvent); + + onImageComplete_ = imageKnifeRequest_->GetImageKnifeOption()->onComplete; + if (onImageComplete_ != nullptr) { + nativeModule_->registerNodeEvent(handle_, NODE_IMAGE_ON_COMPLETE, 0, nullptr); + } +} + +// static +void ImageKnifeNode::OnNodeEvent(ArkUI_NodeEvent *event) +{ + auto nodeHandle = OH_ArkUI_NodeEvent_GetNodeHandle(event); + ImageKnifeNode *node = reinterpret_cast(NativeModuleInstance:: + GetInstance()->GetNativeNodeAPI()->getUserData(nodeHandle)); + auto eventType = OH_ArkUI_NodeEvent_GetEventType(event); + + switch (eventType) { + case NODE_IMAGE_ON_COMPLETE: + node->OnImageComplete(event); + break; + default: + return; + } +} + +void ImageKnifeNode::OnImageComplete(ArkUI_NodeEvent *event) +{ + if (onImageComplete_ != nullptr) { + auto componetEvent = OH_ArkUI_NodeEvent_GetNodeComponentEvent(event); + if (componetEvent->data[0].i32 == 1) { + // 在渲染完成时标记时间 + static_cast(imageKnifeRequest_.get())->MarkDisplayEndTime(); + } + onImageComplete_({.loadingStatus = componetEvent->data[0].i32, + .width = componetEvent->data[1].f32, + .height = componetEvent->data[2].f32, + .componentWidth = componetEvent->data[3].f32, + .componentHeight = componetEvent->data[4].f32, + .contentOffsetX = componetEvent->data[5].f32, + .contentOffsetY = componetEvent->data[6].f32, + .contentWidth = componetEvent->data[7].f32, + .contentHeight = componetEvent->data[8].f32}); + } +} + +void ImageKnifeNode::ReleaseDrawableDescriptor() +{ + if (imageDesc_ != nullptr) { + OH_ArkUI_DrawableDescriptor_Dispose(imageDesc_); + imageDesc_ = nullptr; + } +} + +void ImageKnifeNode::SetBorder() +{ + BorderOption &border = imageKnifeRequest_->GetImageKnifeOption()->border; + for (int i = 0; i < sizeof(border.width) / sizeof(float); i++) { + borderWidth_[i].f32 = border.width[i]; + borderRadius_[i].f32 = border.radius[i]; + borderColor_[i].u32 = border.color[i]; + borderStyle_[i].i32 = border.style[i]; + } + + if (border.hasWidth) { + ArkUI_AttributeItem item = { .value = borderWidth_, .size=1}; + nativeModule_->setAttribute(this->handle_, NODE_BORDER_WIDTH, &item); + } + + if (border.hasRadius) { + ArkUI_AttributeItem item = { .value = borderRadius_, .size=1}; + nativeModule_->setAttribute(this->handle_, NODE_BORDER_RADIUS, &item); + } + + if (border.hasStyle) { + ArkUI_AttributeItem item = { .value = borderStyle_, .size=1}; + nativeModule_->setAttribute(this->handle_, NODE_BORDER_STYLE, &item); + } +} + +void ImageKnifeNode::UpdateImageKnifeRequest(std::shared_ptr option) +{ + imageKnifeRequest_ = std::make_shared(componentId_, option, GetNodeVersion()); + + if (option->onComplete == nullptr && onImageComplete_ != nullptr) { + // 避免遗漏事件反注册 + nativeModule_->unregisterNodeEvent(handle_, NODE_IMAGE_ON_COMPLETE); + } else if (option->onComplete != nullptr && onImageComplete_ == nullptr) { + // 旧的option没启用OnComplete 新的启用了,需注册事件 + nativeModule_->registerNodeEvent(handle_, NODE_IMAGE_ON_COMPLETE, 0, nullptr); + } + // 更新OnComplete 回调状态 + onImageComplete_ = option->onComplete; + SetBorder(); +} + +void ImageKnifeNode::init(std::shared_ptr option) +{ + imageKnifeRequest_ = std::make_shared(componentId_, option, GetNodeVersion()); + RegisterMeasureCallback(); + RegisterNodeEvent(); + SetBorder(); +} + +void ImageKnifeNode::SyncLoad(bool syncLoad) +{ + static_cast(imageKnifeRequest_.get())->SyncLoad(syncLoad); +} + +} // end of namespace \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_node.h b/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_node.h new file mode 100644 index 0000000000000000000000000000000000000000..68a932fae22ee16ba509b49d3f32791d4cb0f8a2 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_node.h @@ -0,0 +1,124 @@ +/* + * 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_KNIFE_C_IMAGEKNIFE_NODE_H +#define IMAGE_KNIFE_C_IMAGEKNIFE_NODE_H + +#include "imageKnife_option.h" +#include "arkUI_node.h" +#include +#include "hilog/log.h" + +namespace ImageKnifeC { + +class ImageKnifeNode : public ArkUINode { +public: + // 使用自定义组件类型ARKUI_NODE_IMAGE创建组件。 + ImageKnifeNode(std::string componentId, std::shared_ptr option) + : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_IMAGE)), + componentId_(componentId) + { + init(option); + } + + ~ImageKnifeNode() override + { + // 反注册自定义事件监听器。 + nativeModule_->removeNodeCustomEventReceiver(handle_, OnCustomEvent); + // 取消声明自定义事件。 + nativeModule_->unregisterNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_MEASURE); + + // 反注册NodeEvent + if (onImageComplete_ != nullptr) { + nativeModule_->unregisterNodeEvent(handle_, NODE_IMAGE_ON_COMPLETE); + } + nativeModule_->removeNodeEventReceiver(handle_, OnNodeEvent); + // 移除当前可能在显示的图片 + ClearDisplayedImage(); + } + + // 必需在主线程中运行 + void Display(void *data) override + { + if (data != nullptr) { + ArkUI_AttributeItem item = {.object = data}; + nativeModule_->setAttribute(this->handle_, NODE_IMAGE_SRC, &item); + + // 释放之前的图片描述内存, 并记录最新的imageDesc地址 + ReleaseDrawableDescriptor(); + imageDesc_ = static_cast(data); + } + } + + void FitImage(int fitEnum) override + { + imageFitEnum_.i32 = fitEnum; + ArkUI_AttributeItem item = {.value = &imageFitEnum_, .size = 1}; + nativeModule_->setAttribute(this->handle_, NODE_IMAGE_OBJECT_FIT, &item); + } + + void ClearDisplayedImage() override + { + ArkUI_AttributeItem item = {.object = nullptr}; + nativeModule_->setAttribute(this->handle_, NODE_IMAGE_SRC, &item); + ReleaseDrawableDescriptor(); + } + + std::shared_ptr GetImageKnifeRequest() + { + return imageKnifeRequest_; + } + + void UpdateImageKnifeRequest(std::shared_ptr option); + + void SyncLoad(bool syncLoad); + + void init(std::shared_ptr option); +private: + std::string componentId_; + // 保持request生命周期 + std::shared_ptr imageKnifeRequest_; + + ArkUI_DrawableDescriptor *imageDesc_ = nullptr; + + // ImageFit, ArkUI_ObjectFit 枚举入参类型 + ArkUI_NumberValue imageFitEnum_ = {.i32 = 1}; + + ArkUI_NumberValue borderWidth_[4]; + ArkUI_NumberValue borderRadius_[4]; + ArkUI_NumberValue borderColor_[4]; + ArkUI_NumberValue borderStyle_[4]; + + std::function onImageComplete_ = nullptr; + + void ReleaseDrawableDescriptor(); + + void RegisterMeasureCallback(); + + void RegisterNodeEvent(); + + static void OnNodeEvent(ArkUI_NodeEvent *event); + + static void OnCustomEvent(ArkUI_NodeCustomEvent *event); + + void OnImageComplete(ArkUI_NodeEvent *event); + // 测算事件回调 + void OnMeasure(ArkUI_NodeCustomEvent *event); + void SetBorder(); +}; + +} // namespace ImageKnifeC + +#endif // IMAGE_KNIFE_C_IMAGEKNIFE_NODE_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_option.cpp b/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_option.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc5b389cdedc2c0acdd0da700138a43288174269 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_option.cpp @@ -0,0 +1,346 @@ +/* + * 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. + */ + +#include "napi/native_api.h" +#include "imageKnife_option.h" +#include "hilog/log.h" +#include "imageKnife.h" + +namespace ImageKnifeC { +ImageKnifeOption::ImageKnifeOption(napi_env env, napi_value &jsObject) +{ + enableJsOption_ = true; + env_ = env; + napi_create_reference(env, jsObject, 1, &jsThis_); + imageLoader = ImageKnife::GetInstance().GetDefaultImageKnifeLoader(); + + napi_value value; + if (napi_get_named_property(env, jsObject, "loadSrc", &value) == napi_ok) { + loadSrc.SetValue(env, value); + } + + if (napi_get_named_property(env, jsObject, "placeholderSrc", &value) == napi_ok) { + placeholderSrc.SetValue(env, value); + } + + if (napi_get_named_property(env, jsObject, "errorholderSrc", &value) == napi_ok) { + errorholderSrc.SetValue(env, value); + } + + if (napi_get_named_property(env, jsObject, "signature", &value) == napi_ok) { + napi_valuetype type; + napi_status status = napi_typeof(env, value, &type); + if (type == napi_string) { + size_t length; + status = napi_get_value_string_utf8(env, value, nullptr, 0, &length); + char buf[length + 1]; + status = napi_get_value_string_utf8(env, value, buf, length + 1, nullptr); + signature = buf; + OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, + "ImageKnifeOption::ImageKnifeOption", + "signature is : %{public}s", + signature.c_str()); + } + } + + if (napi_get_named_property(env, jsObject, "priority", &value) == napi_ok) { + napi_valuetype type; + napi_status status = napi_typeof(env, value, &type); + if (type == napi_number) { + int32_t priorityValue = 0; + + // 获取整数值 + status = napi_get_value_int32(env, value, &priorityValue); + if (status == napi_ok) { + priority = priorityValue; + OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, + "ImageKnifeOption::ImageKnifeOption", + "priority is : %{public}d", + priorityValue); + } else { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeOption::ImageKnifeOption", + "Failed to get priority value as number."); + } + } + } + + if (napi_get_named_property(env, jsObject, "onLoadListener", &value) == napi_ok) { + onLoadListener.SetCallBack(env, value); + } + + if (napi_get_named_property(env, jsObject, "context", &value) == napi_ok) { + context.SetContext(env, value); + } + + if (napi_get_named_property(env, jsObject, "objectFit", &value) == napi_ok) { + objectFit = ParseImagFit(env, value); + } + + if (napi_get_named_property(env, jsObject, "placeholderObjectFit", &value) == napi_ok) { + placeholderObjectFit = ParseImagFit(env, value); + } + + if (napi_get_named_property(env, jsObject, "errorholderObjectFit", &value) == napi_ok) { + errorholderObjectFit = ParseImagFit(env, value); + } + + if (napi_get_named_property(env, jsObject, "border", &value) == napi_ok) { + border.SetBorderOption(env, value); + } + + if (napi_get_named_property(env, jsObject, "onComplete", &value) == napi_ok) { + napi_valuetype type; + napi_typeof(env, value, &type); + if (type != napi_undefined) { + napi_create_reference(env, value, 1, &onComplete_); + onComplete = [this](EventImage eventImage) { + this->CallJsOnComplete(eventImage); + }; + } + } +} + +ArkUI_ObjectFit ImageKnifeOption::ParseImagFit(napi_env env, napi_value &value) +{ + const int defaultValue = 2; + // default is Cover + int num = defaultValue; + napi_get_value_int32(env, value, &num); + // js 侧的枚举 ImageFit 与侧对应的ArkUI_ObjectFit 不一致,需要映射 + ArkUI_ObjectFit jsEnum[] = { + ARKUI_OBJECT_FIT_CONTAIN, + ARKUI_OBJECT_FIT_COVER, + ARKUI_OBJECT_FIT_AUTO, + ARKUI_OBJECT_FIT_FILL, + ARKUI_OBJECT_FIT_SCALE_DOWN, + ARKUI_OBJECT_FIT_NONE + }; + + // 如果给了异常值,默认cover模式 + if (num < 1 || num > sizeof(jsEnum) / sizeof(jsEnum[0])) { + num = defaultValue; + } + + return jsEnum[num - 1]; +} + +void ImageKnifeOption::CallJsOnComplete(EventImage &eventImage) +{ + napi_status status; + napi_value thisValue, jsFunc, eventImageValue, number; + + napi_create_object(env_, &eventImageValue); + + napi_create_int32(env_, eventImage.loadingStatus, &number); + napi_set_named_property(env_, eventImageValue, "loadingStatus", number); + + napi_create_double(env_, eventImage.width, &number); + napi_set_named_property(env_, eventImageValue, "width", number); + + napi_create_double(env_, eventImage.height, &number); + napi_set_named_property(env_, eventImageValue, "height", number); + + napi_create_double(env_, eventImage.componentWidth, &number); + napi_set_named_property(env_, eventImageValue, "componentWidth", number); + + napi_create_double(env_, eventImage.componentHeight, &number); + napi_set_named_property(env_, eventImageValue, "componentHeight", number); + + napi_create_double(env_, eventImage.contentOffsetX, &number); + napi_set_named_property(env_, eventImageValue, "contentOffsetX", number); + + napi_create_double(env_, eventImage.contentOffsetY, &number); + napi_set_named_property(env_, eventImageValue, "contentOffsetY", number); + + napi_create_double(env_, eventImage.contentWidth, &number); + napi_set_named_property(env_, eventImageValue, "contentWidth", number); + + napi_create_double(env_, eventImage.contentHeight, &number); + napi_set_named_property(env_, eventImageValue, "contentHeight", number); + + napi_get_reference_value(env_, jsThis_, &thisValue); + napi_get_reference_value(env_, onComplete_, &jsFunc); + status = napi_call_function(env_, thisValue, jsFunc, 1, &eventImageValue, nullptr); + if (status != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeOption", + "CallJsOnComplete failed, napi status: %{public}d", + status); + } +} + +void OnLoadCallBack::SetCallBack(napi_env env, napi_value value) +{ + enableJsFunction_ = true; + env_ = env; + napi_status status; + napi_create_reference(env, value, 1, &jsThis_); + + napi_valuetype type; + napi_typeof(env, value, &type); + if (type == napi_undefined) { + return; + } + + napi_value jsFunc; + status = napi_get_named_property(env, value, "onLoadStart", &jsFunc); + if (status == napi_ok) { + napi_typeof(env, jsFunc, &type); + if (type != napi_undefined) { + napi_create_reference(env, jsFunc, 1, &onLoadStart_); + onLoadStart = [this]() { + this->CallJsOnLoadStart(); + }; + } + } + + status = napi_get_named_property(env, value, "onLoadSuccess", &jsFunc); + if (status == napi_ok) { + napi_typeof(env, jsFunc, &type); + if (type != napi_undefined) { + napi_create_reference(env, jsFunc, 1, &onLoadSuccess_); + onLoadSuccess = [this](ImageDataBack &data, ImageKnifeData &imageKnifeData) { + this->CallJsOnLoadSuccess(data, imageKnifeData); + }; + } + } + + status = napi_get_named_property(env, value, "onLoadFailed", &jsFunc); + if (status == napi_ok) { + napi_typeof(env, jsFunc, &type); + if (type != napi_undefined) { + napi_create_reference(env, jsFunc, 1, &onLoadFailed_); + onLoadFailed = [this](std::string err) { + this->CallJsOnLoadFailed(err); + }; + } + } + + status = napi_get_named_property(env, value, "onLoadCancel", &jsFunc); + if (status == napi_ok) { + napi_typeof(env, jsFunc, &type); + if (type != napi_undefined) { + napi_create_reference(env, jsFunc, 1, &onLoadCancel_); + onLoadCancel = [this](std::string reason) { + this->CallJsOnLoadCancel(reason); + }; + } + } +} + +void OnLoadCallBack::CallJsOnLoadStart() +{ + napi_status status; + napi_value thisValue, jsFunc; + napi_get_reference_value(env_, jsThis_, &thisValue); + napi_get_reference_value(env_, onLoadStart_, &jsFunc); + status = napi_call_function(env_, thisValue, jsFunc, 0, nullptr, nullptr); + if (status != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeNode", + "call js onLoadStart failed, napi status: %{public}d", + status); + } +} + +void OnLoadCallBack::CallJsOnLoadSuccess(ImageDataBack &data, ImageKnifeData &imageKnifeData) +{ + // for test + std::string info; + napi_value args[2]; + OH_PixelmapNative *pixelmap; + if (data.GetString(info)) { + napi_create_string_utf8(env_, info.c_str(), NAPI_AUTO_LENGTH, &args[0]); + } else if (data.GetPixelMap(pixelmap)) { + OH_PixelmapNative_ConvertPixelmapNativeToNapi(env_, pixelmap, &args[0]); + } else { + napi_get_undefined(env_, &args[0]); + } + + napi_get_undefined(env_, &args[1]); + + napi_status status; + napi_value thisValue, jsFunc; + const int argv = 2; + napi_get_reference_value(env_, jsThis_, &thisValue); + napi_get_reference_value(env_, onLoadSuccess_, &jsFunc); + status = napi_call_function(env_, thisValue, jsFunc, argv, args, nullptr); + if (status != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeNode", + "call js onLoadSuccess failed, napi status: %{public}d", + status); + } +} + +void OnLoadCallBack::CallJsOnLoadFailed(std::string err) +{ + napi_value errInfo; + napi_create_string_utf8(env_, err.c_str(), NAPI_AUTO_LENGTH, &errInfo); + napi_status status; + napi_value thisValue, jsFunc; + napi_get_reference_value(env_, jsThis_, &thisValue); + napi_get_reference_value(env_, onLoadFailed_, &jsFunc); + status = napi_call_function(env_, thisValue, jsFunc, 1, &errInfo, nullptr); + if (status != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeNode", + "call js onLoadFailed failed, napi status: %{public}d", + status); + } +} + +void OnLoadCallBack::CallJsOnLoadCancel(std::string reason) +{ + napi_value info; + napi_create_string_utf8(env_, reason.c_str(), NAPI_AUTO_LENGTH, &info); + napi_status status; + napi_value thisValue, jsFunc; + napi_get_reference_value(env_, jsThis_, &thisValue); + napi_get_reference_value(env_, onLoadCancel_, &jsFunc); + status = napi_call_function(env_, thisValue, jsFunc, 1, &info, nullptr); + if (status != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeNode", + "call js onLoadCancel failed, napi status: %{public}d", + status); + } +} + +OnLoadCallBack::~OnLoadCallBack() +{ + if (enableJsFunction_) { + if (onLoadStart != nullptr) { + napi_delete_reference(env_, onLoadStart_); + } + + if (onLoadSuccess != nullptr) { + napi_delete_reference(env_, onLoadSuccess_); + } + + if (onLoadFailed != nullptr) { + napi_delete_reference(env_, onLoadFailed_); + } + + if (onLoadCancel != nullptr) { + napi_delete_reference(env_, onLoadCancel_); + } + + napi_delete_reference(env_, jsThis_); + } +} + +} // end of namespace \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_option.h b/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_option.h new file mode 100644 index 0000000000000000000000000000000000000000..ce86166aa444ce6fb4f33d3f9688e5074e620ca5 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/node/imageKnife_option.h @@ -0,0 +1,126 @@ +/* + * 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_KNIFE_C_IMAGEKNIFE_OPTION_H +#define IMAGE_KNIFE_C_IMAGEKNIFE_OPTION_H + +#include "imageKnife_loader.h" +#include "napi/native_api.h" +#include "imageKnife_data.h" +#include +#include +#include +#include "transformation/multi_transformation.h" + +namespace ImageKnifeC { + +struct OnLoadCallBack { + void SetCallBack(napi_env env, napi_value value); + std::function onLoadStart = nullptr; + std::function onLoadSuccess = nullptr; + std::function onLoadFailed = nullptr; + std::function onLoadCancel = nullptr; + ~OnLoadCallBack(); +private: + napi_env env_; + napi_ref jsThis_; + napi_ref onLoadStart_; + napi_ref onLoadSuccess_; + napi_ref onLoadFailed_; + napi_ref onLoadCancel_; + + // 标记使用的ArkTs传入的回调 还是C函数回调 + bool enableJsFunction_ = false; + + void CallJsOnLoadStart(); + + void CallJsOnLoadSuccess(ImageDataBack &data, ImageKnifeData &imageKnifeData); + + void CallJsOnLoadFailed(std::string err); + + void CallJsOnLoadCancel(std::string reason); +}; + +class ImageKnifeOption { +public: + // 主图资源: STRING | PIXELMAP | RESOURCE + ImageData loadSrc; + // 占位图: STRING | PIXELMAP | RESOURCE + ImageData placeholderSrc; + // error占位图: STRING | PIXELMAP | RESOURCE + ImageData errorholderSrc; + + std::string signature; + + int priority; + + // 主图填充效果 默认为cover + ArkUI_ObjectFit objectFit = ARKUI_OBJECT_FIT_COVER; + // 占位图填充效果 默认为cover + ArkUI_ObjectFit placeholderObjectFit = ARKUI_OBJECT_FIT_COVER; + // 错误图填充效果 默认为cover + ArkUI_ObjectFit errorholderObjectFit = ARKUI_OBJECT_FIT_COVER; + + BorderOption border; + + OnLoadCallBack onLoadListener; + // 加载显示完成后的回调 可映射ArtTs的onComplete + std::function onComplete = nullptr; + + Context context; + + std::shared_ptr imageLoader = nullptr; + + std::shared_ptr transformation = nullptr; + + std::shared_ptr multiTransformation = nullptr; + // 用户自定义数据类型,可在自定义拦截器中取得使用 + void* customData = nullptr; + // 用户自定义finalize回调,可用来析构用户自定义数据 + std::function onFinalize = nullptr; + + ImageKnifeOption(napi_env env, napi_value& jsObject); + + ~ImageKnifeOption() + { + if (onFinalize != nullptr) { + onFinalize(customData); + } + + if (enableJsOption_) { + if (onComplete != nullptr) { + napi_delete_reference(env_, onComplete_); + } + + napi_delete_reference(env_, jsThis_); + } + } + +private: + napi_env env_; + napi_ref jsThis_; + napi_ref onComplete_; + + // 标记使用的ArkTs传入option 还是C版本 + bool enableJsOption_ = false; + + ArkUI_ObjectFit ParseImagFit(napi_env env, napi_value &value); + + void CallJsOnComplete(EventImage &eventImage); +}; + +} // end of namespace + +#endif // IMAGE_KNIFE_C_IMAGEKNIFE_OPTION_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/queue/IJob_queue.h b/thirdparty/image-knife-c/library/src/main/cpp/queue/IJob_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..ab6c0effaf55c7617b15588f534d6611ea548f7c --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/queue/IJob_queue.h @@ -0,0 +1,50 @@ +/* + * 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_KNIFE_C_IJOB_QUEUE_H +#define IMAGE_KNIFE_C_IJOB_QUEUE_H +#include +#include "request/imageKnife_request_internal.h" + +namespace ImageKnifeC { +class IJobQueue { +public: + struct QueueElement { + QueueElement() = default; + + QueueElement(std::shared_ptr request, ImageKnifeRequestSource type) + : request(request), type(type) {} + + QueueElement(const QueueElement &queueElement) + : request(queueElement.request), type(queueElement.type) {} + + std::shared_ptr request = nullptr; + ImageKnifeRequestSource type; + }; + + IJobQueue() = default; + virtual ~IJobQueue() = default; + + // 获取队列长度 + virtual size_t GetQueueLength() = 0; + + // 添加队列元素 + virtual void Add(QueueElement queueElement) = 0; + + // 移除并返回队列头部元素 + virtual QueueElement Pop() = 0; +}; +} // namespace ImageKnightC +#endif // IMAGE_KNIFE_C_IJOB_QUEUE_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/queue/default_job_queue.cpp b/thirdparty/image-knife-c/library/src/main/cpp/queue/default_job_queue.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d9346a4ce68c677311409e7b9a47f84ac7bd9d97 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/queue/default_job_queue.cpp @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#include "default_job_queue.h" + +namespace ImageKnifeC { +size_t DefaultJobQueue::GetQueueLength() +{ + return highQueue_.size() + normalQueue_.size() + lowQueue_.size(); +} + +void DefaultJobQueue::Add(QueueElement queueElement) +{ + if (queueElement.request->GetImageKnifeOption()->priority == Priority::HIGH) { + highQueue_.push(queueElement); + } else if (queueElement.request->GetImageKnifeOption()->priority == Priority::MEDIUM) { + normalQueue_.push(queueElement); + } else { + lowQueue_.push(queueElement); + } +} + +DefaultJobQueue::QueueElement DefaultJobQueue::Pop() +{ + if (!highQueue_.empty()) { + return PopFromQueue(highQueue_); + } + + if (!normalQueue_.empty()) { + return PopFromQueue(normalQueue_); + } + + if (!lowQueue_.empty()) { + return PopFromQueue(lowQueue_); + } + + return QueueElement{}; +} + +DefaultJobQueue::QueueElement DefaultJobQueue::PopFromQueue(std::queue &queue) +{ + QueueElement queueElement = queue.front(); + queue.pop(); + return queueElement; +} + +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/src/main/cpp/queue/default_job_queue.h b/thirdparty/image-knife-c/library/src/main/cpp/queue/default_job_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..633142abd5da26b515f868cf81080397ce1f6628 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/queue/default_job_queue.h @@ -0,0 +1,45 @@ +/* + * 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_KNIFE_C_DEFAULT_JOB_QUEUE_H +#define IMAGE_KNIFE_C_DEFAULT_JOB_QUEUE_H +#include +#include "IJob_queue.h" + +namespace ImageKnifeC { +enum Priority { + HIGH = 0, + MEDIUM, + LOW +}; + +class DefaultJobQueue : public IJobQueue { +public: + DefaultJobQueue() = default; + ~DefaultJobQueue() override = default; + + size_t GetQueueLength() override; + + void Add(QueueElement queueElement) override; + + QueueElement Pop() override; +private: + std::queue highQueue_; + std::queue normalQueue_; + std::queue lowQueue_; + QueueElement PopFromQueue(std::queue &queue); +}; +} +#endif // IMAGE_KNIFE_C_DEFAULT_JOB_QUEUE_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/request/imageKnife_request_internal.cpp b/thirdparty/image-knife-c/library/src/main/cpp/request/imageKnife_request_internal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e10ffb3020cb03674ee42a13caa5c6551c4f3380 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/request/imageKnife_request_internal.cpp @@ -0,0 +1,147 @@ +/* + * 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. + */ + +#include "imageKnife_request_internal.h" +#include "imageKnife_task_internal.h" + +namespace ImageKnifeC { + +bool ImageKnifeRequestInternal::IsMainSrcComplete() const +{ + return status_ == Status::COMPLETE || status_ == Status::ERRORCOMPLETE; +} + +void ImageKnifeRequestInternal::MarkStatusComplete() +{ + if (status_ == Status::PROGRESS) { + status_ = Status::COMPLETE; + } else if (status_ == Status::ERROR) { + status_ = Status::ERRORCOMPLETE; + } +} + +void ImageKnifeRequestInternal::Destroy() +{ + status_ = Status::DESTROY; +} + +bool ImageKnifeRequestInternal::IsDestroy() const +{ + return status_ == Status::DESTROY; +} + +void ImageKnifeRequestInternal::MarkStatusError() +{ + if (status_ == Status::PROGRESS) { + status_ = Status::ERROR; + } +} + +void ImageKnifeRequestInternal::InsertTask(ImageKnifeTask *taskId, ImageKnifeRequestSource type) +{ + taskIdMap_[type] = taskId; +} + +ImageKnifeTask* ImageKnifeRequestInternal::GetTask(ImageKnifeRequestSource type) +{ + if (taskIdMap_.find(type) == taskIdMap_.end()) { + return nullptr; + } + return taskIdMap_[type]; +} + +void ImageKnifeRequestInternal::RemoveTask(ImageKnifeRequestSource type) +{ + if (taskIdMap_.find(type) != taskIdMap_.end()) { + taskIdMap_.erase(type); + } +} + +bool ImageKnifeRequestInternal::IsSyncLoad() const +{ + return syncLoad_; +} + +void ImageKnifeRequestInternal::SyncLoad(bool syncLoad) +{ + syncLoad_ = syncLoad; +} + +void ImageKnifeRequestInternal::MarkDisplayStartTime(ImageKnifeRequestSource type, bool fromMemory) +{ + displayType_ = type; + fromMemory_ = fromMemory; + displayStart_ = std::chrono::time_point_cast(std::chrono::high_resolution_clock::now()); +} + +void ImageKnifeRequestInternal::MarkDisplayEndTime() +{ + auto end = std::chrono::high_resolution_clock::now(); + auto totalTime = std::chrono::duration_cast(end - start_); + auto displayTime = std::chrono::duration_cast(end - displayStart_); + + std::string info = ImageKnifeTaskInternal::GetTaskInfo(displayType_, this); + if (fromMemory_) { + info += " From Memory"; + } else { + info += " From Loading"; + } + + OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, + "Performance", + "[%{public}lld] %{public}s Display Finished", + displayTime.count(), + info.c_str()); + OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, + "Performance", + "[%{public}lld] %{public}s All Finished (Total Time)", + totalTime.count(), + info.c_str()); +} + +std::string ImageKnifeRequestInternal::GetNodeId() const +{ + return componentId_; +} + +int ImageKnifeRequestInternal::GetVersion() const +{ + return componentVersion_; +} + +ImageKnifeRequest::Status ImageKnifeRequestInternal::GetStatus() const +{ + return status_; +} + +std::shared_ptr ImageKnifeRequestInternal::GetImageKnifeOption() const +{ + return imageKnifeOption_; +} +bool ImageKnifeRequestInternal::IsPreload() +{ + return isPreload_; +} + +void ImageKnifeRequestInternal::SetEnv(napi_env env) +{ + env_ = env; +} + +void ImageKnifeRequestInternal::SetJsRequestRef(napi_ref jsRequestRef) +{ + jsRequestRef_ = jsRequestRef; +} +} // end of namespace diff --git a/thirdparty/image-knife-c/library/src/main/cpp/request/imageKnife_request_internal.h b/thirdparty/image-knife-c/library/src/main/cpp/request/imageKnife_request_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..e5690181ac147c03517014be12af54c5737c7121 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/request/imageKnife_request_internal.h @@ -0,0 +1,122 @@ +/* + * 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_KNIFE_C_KEKE_IMAGEKNIFE_REQUEST_INTERNAL_H +#define IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_REQUEST_INTERNAL_H + +#include "imageKnife_request.h" + +namespace ImageKnifeC { + +class ImageKnifeRequestInternal : public ImageKnifeRequest { +public: + void InsertTask(ImageKnifeTask *taskId, ImageKnifeRequestSource type); + + ImageKnifeTask *GetTask(ImageKnifeRequestSource type); + + void RemoveTask(ImageKnifeRequestSource type); + + void MarkDisplayStartTime(ImageKnifeRequestSource type, bool fromMemory); + + void MarkDisplayEndTime(); + + void MarkStatusComplete(); + + void MarkStatusError(); + + void SyncLoad(bool syncLoad); + + void Destroy(); + + bool IsMainSrcComplete() const; + + bool IsDestroy() const; + + bool IsSyncLoad() const; + + std::string GetNodeId() const override; + + int GetVersion() const override; + + Status GetStatus() const override; + + std::shared_ptr GetImageKnifeOption() const override; + + bool IsPreload(); + + void SetEnv(napi_env env); + + void SetJsRequestRef(napi_ref jsRequestRef); + + ImageKnifeRequestInternal(std::string componentId, std::shared_ptr option, int componentVersion) + : componentId_(componentId), imageKnifeOption_(option), componentVersion_(componentVersion), isPreload_(false) + { + start_ = std::chrono::high_resolution_clock::now(); + } + + eplicit ImageKnifeRequestInternal(std::shared_ptr option) + :imageKnifeOption_(option), isPreload_(true) + { + } + + ~ImageKnifeRequestInternal() override + { + if (isPreload_) { + napi_value jsRequest = nullptr; + napi_status status = napi_get_reference_value(env_, jsRequestRef_, &jsRequest); + if (status != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeRequestInternal::~ImageKnifeRequestInternal", + "Failed to get jsRequest"); + } + + void *nativeObjectResult = nullptr; + status = napi_remove_wrap(env_, jsRequest, &nativeObjectResult); + if (status != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, + "ImageKnifeRequestInternal::~ImageKnifeRequestInternal", + "Failed to remove wrap in destructor"); + } + } + } + +private: + Status status_ = Status::PROGRESS; + std::shared_ptr imageKnifeOption_; + std::string componentId_ = "Preload"; + int componentVersion_; + bool syncLoad_ = false; + std::unordered_map taskIdMap_; + + // ---- 性能日志相关 ---- + typedef std::chrono::time_point TimePoint; + // 总开始时间 + TimePoint start_; + // 渲染开始时间 + TimePoint displayStart_; + // 显示图片类型, 不同类型不会同时渲染 + ImageKnifeRequestSource displayType_; + // 标记当前显示的图片是否来自内存缓存 + bool fromMemory_; + + // 判断是否显示图片 + bool isPreload_; + napi_env env_ = nullptr; + napi_ref jsRequestRef_ = nullptr; +}; + +} // end of namespace + +#endif // IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_REQUEST_INTERNAL_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/task_worker.h b/thirdparty/image-knife-c/library/src/main/cpp/task_worker.h new file mode 100644 index 0000000000000000000000000000000000000000..a10dced2faf976d7504a1ef93f856a35f550dfca --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/task_worker.h @@ -0,0 +1,141 @@ +/* + * 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_KNIFE_C_TASK_WORKER_H +#define IMAGE_KNIFE_C_TASK_WORKER_H + +#include "napi/native_api.h" +#include +#include "hilog/log.h" + +namespace ImageKnifeC { +typedef std::function AsyncFunc; +typedef std::function CustomCancelFunc; + +class TaskWorker { +public: + static TaskWorker *GetInstance() + { + static TaskWorker taskWorker; + return &taskWorker; + } + + void SetEnv(napi_env env) + { + if (env_ == nullptr) + env_ = env; + } + + void *PushTask(AsyncFunc execute, AsyncFunc completeCallback, void *data, std::string &errorInfo) + { + if (env_ == nullptr) { + errorInfo = "ImageKnifeC::TaskRunner::PushTask napi_env is null"; + return nullptr; + } + + InnerWorker *worker = new InnerWorker; + worker->data_ = data; + worker->execute_ = execute; + worker->completeCallback_ = completeCallback; + + napi_status status; + napi_value resourceId; + status = napi_create_string_utf8(env_, "ImageKnifeC TaskRunner", NAPI_AUTO_LENGTH, &resourceId); + if (status != napi_ok) { + delete worker; + errorInfo = "ImageKnifeC::TaskRunner::PushTask create resourceId failed, napi status: " + + std::to_string(status); + return nullptr; + } + + status = napi_create_async_work(env_, nullptr, resourceId, InnerWorker::ExecuteCallback, + InnerWorker::CompleteCallback, worker, &worker->worker_); + if (status != napi_ok) { + delete worker; + errorInfo = "ImageKnifeC::TaskRunner::PushTask create async work failed, napi status: " + + std::to_string(status); + return nullptr; + } + + status = napi_queue_async_work_with_qos(env_, worker->worker_, napi_qos_default); + if (status != napi_ok) { + napi_delete_async_work(env_, worker->worker_); + errorInfo = "ImageKnifeC::TaskRunner::PushTask queue async work failed, napi status: " + + std::to_string(status); + delete worker; + return nullptr; + } + + return worker; + } + + std::string CancelTask(void *task, CustomCancelFunc func, void *data) + { + if (task == nullptr) { + return "Cancel Failed: Task is null"; + } + + InnerWorker *worker = static_cast(task); + napi_status status = napi_cancel_async_work(env_, worker->worker_); + if (status == napi_generic_failure) { + // Task已经开始 + if (func) { + // 尝试用自定义func取消耗时操作 + return func(data); + } else { + return "Cancel Failed: Task is executing, can not cancel"; + } + } else if (status == napi_ok) { + // 成功取消, CompleteCallback 会被调用,对应status为 napi_cancelled + return "Cancel Success"; + } + return "Cancel Failed: unexpected error! napi status:" + std::to_string(status); + } + +private: + class InnerWorker { + public: + napi_async_work worker_; + void *data_; + AsyncFunc execute_; + AsyncFunc completeCallback_; + + static void ExecuteCallback(napi_env env, void *data) + { + InnerWorker* worker = static_cast(data); + if (worker->execute_ != nullptr) { + worker->execute_(worker->data_); + } + } + + static void CompleteCallback(napi_env env, napi_status status, void *data) + { + InnerWorker* worker = static_cast(data); + if (worker->completeCallback_ != nullptr && status != napi_cancelled) { + worker->completeCallback_(worker->data_); + } + + napi_delete_async_work(env, worker->worker_); + delete worker; + } + }; + + TaskWorker(){}; + napi_env env_ = nullptr; +}; + +} // end of namespace + +#endif // IMAGE_KNIFE_C_TASK_WORKER_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/thirdparty/LRUCache11.h b/thirdparty/image-knife-c/library/src/main/cpp/thirdparty/LRUCache11.h new file mode 100644 index 0000000000000000000000000000000000000000..8d5a0b4911786853200a2eff9c3a51e293f8a90f --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/thirdparty/LRUCache11.h @@ -0,0 +1,306 @@ +/* + * LRUCache11 - a templated C++11 based LRU cache class that allows + * specification of + * key, value and optionally the map container type (defaults to + * std::unordered_map) + * By using the std::unordered_map and a linked list of keys it allows O(1) insert, delete + * and + * refresh operations. + * + * This is a header-only library and all you need is the LRUCache11.hpp file + * + * Github: https://github.com/mohaps/lrucache11 + * + * This is a follow-up to the LRUCache project - + * https://github.com/mohaps/lrucache + * + * Copyright (c) 2012-22 SAURAV MOHAPATRA + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IMAGE_KNIFE_C_LRUCACHE11_H +#define IMAGE_KNIFE_C_LRUCACHE11_H +#include +#include +#include +#include +#include +#include +#include +#include +#include "hilog/log.h" + +namespace lru11 { +/* + * a noop lockable concept that can be used in place of std::mutex + */ +class NullLock { +public: + void lock() {} + void unlock() {} + bool try_lock() + { + return true; + } +}; + +/** + * error raised when a key not in cache is passed to get() + */ +class KeyNotFound : public std::invalid_argument { +public: + KeyNotFound() : std::invalid_argument("key_not_found") {} +}; + +template +struct KeyValuePair { +public: + K key; + V value; + + KeyValuePair(K k, V v) : key(std::move(k)), value(std::move(v)) {} +}; + +/** + * The LRU Cache class templated by + * Key - key type + * Value - value type + * MapType - an associative container like std::unordered_map + * LockType - a lock type derived from the Lock class (default: + *NullLock = no synchronization) + * + * The default NullLock based template is not thread-safe, however passing + *Lock=std::mutex will make it + * thread-safe + */ +template >::iterator>> +class Cache { +public: + typedef KeyValuePair node_type; + typedef std::list> list_type; + typedef Map map_type; + typedef Lock lock_type; + using Guard = std::lock_guard; + /** + * the maxSize is the soft limit of keys and (maxSize + elasticity) is the + * hard limit + * the cache is allowed to grow till (maxSize + elasticity) and is pruned back + * to maxSize keys + * set maxSize = 0 for an unbounded cache (but in that case, you're better off + * using a std::unordered_map + * directly anyway! :) + */ + explicit Cache(size_t maxSize = 64, size_t elasticity = 10) + : maxSize_(maxSize), elasticity_(elasticity) {} + virtual ~Cache() = default; + size_t size() const + { + Guard g(lock_); + return cache_.size(); + } + + bool empty() const + { + Guard g(lock_); + return cache_.empty(); + } + + void clear() + { + Guard g(lock_); + cache_.clear(); + keys_.clear(); + } + + void insert(const Key& k, Value v) + { + Guard g(lock_); + const auto iter = cache_.find(k); + if (iter != cache_.end()) { + iter->second->value = v; + keys_.splice(keys_.begin(), keys_, iter->second); + return; + } + + keys_.emplace_front(k, std::move(v)); + cache_[k] = keys_.begin(); + prune(); + } + + void emplace(const Key& k, Value&& v) + { + Guard g(lock_); + keys_.emplace_front(k, std::move(v)); + cache_[k] = keys_.begin(); + prune(); + } + + /** + for backward compatibity. redirects to tryGetCopy() + */ + bool tryGet(const Key& kIn, Value& vOut) + { + return tryGetCopy(kIn, vOut); + } + + bool tryGetCopy(const Key& kIn, Value& vOut) + { + Guard g(lock_); + Value tmp; + if (!tryGetRef_nolock(kIn, tmp)) { + return false; + } + vOut = tmp; + return true; + } + + bool tryGetRef(const Key& kIn, Value& vOut) + { + Guard g(lock_); + return tryGetRef_nolock(kIn, vOut); + } + /** + * The const reference returned here is only + * guaranteed to be valid till the next insert/delete + * in multi-threaded apps use getCopy() to be threadsafe + */ + const Value& getRef(const Key& k) + { + Guard g(lock_); + return get_nolock(k); + } + + /** + added for backward compatibility + */ + Value get(const Key& k) + { + return getCopy(k); + } + /** + * returns a copy of the stored object (if found) + * safe to use/recommended in multi-threaded apps + */ + Value getCopy(const Key& k) + { + Guard g(lock_); + return get_nolock(k); + } + + bool remove(const Key& k) + { + Guard g(lock_); + auto iter = cache_.find(k); + if (iter == cache_.end()) { + return false; + } + keys_.erase(iter->second); + cache_.erase(iter); + return true; + } + + bool contains(const Key k) const + { + Guard g(lock_); + return cache_.find(k) != cache_.end(); + } + + size_t getMaxSize() const + { + return maxSize_; + } + + size_t getElasticity() const + { + return elasticity_; + } + + size_t getMaxAllowedSize() const + { + return maxSize_ + elasticity_; + } + + template + void cwalk(F& f) const + { + Guard g(lock_); + std::for_each(keys_.begin(), keys_.end(), f); + } + + // New method to get the tail element + bool getTail(Key& key, Value& value) + { + Guard g(lock_); + if (keys_.empty()) { + return false; + } + const auto& tail = keys_.back(); + key = tail.key; + value = tail.value; + return true; + } + +protected: + const Value& get_nolock(const Key& k) + { + const auto iter = cache_.find(k); + if (iter == cache_.end()) { + throw KeyNotFound(); + } + keys_.splice(keys_.begin(), keys_, iter->second); + return iter->second->value; + } + + bool tryGetRef_nolock(const Key& kIn, Value& vOut) + { + const auto iter = cache_.find(kIn); + if (iter == cache_.end()) { + return false; + } + keys_.splice(keys_.begin(), keys_, iter->second); + vOut = iter->second->value; + return true; + } + + size_t prune() + { + size_t maxAllowed = maxSize_ + elasticity_; + if (maxSize_ == 0 || cache_.size() <= maxAllowed) { + return 0; + } + size_t count = 0; + while (cache_.size() > maxSize_) { + cache_.erase(keys_.back().key); + keys_.pop_back(); + ++count; + } + return count; + } + +private: + // Disallow copying. + Cache(const Cache&) = delete; + Cache& operator=(const Cache&) = delete; + + mutable Lock lock_; + Map cache_; + list_type keys_; + size_t maxSize_; + size_t elasticity_; +}; + +} // namespace LRUCache11 +#endif // IMAGE_KNIFE_C_LRUCACHE11_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/transformation/multi_transformation.h b/thirdparty/image-knife-c/library/src/main/cpp/transformation/multi_transformation.h new file mode 100644 index 0000000000000000000000000000000000000000..e416a67d5104dbc27b1e9517eef2a53c5fdb4b0c --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/transformation/multi_transformation.h @@ -0,0 +1,34 @@ +/* + * 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_KNIFE_C_MULTI_TRANSFORMATION_H +#define IMAGE_KNIFE_C_MULTI_TRANSFORMATION_H + +#include "transformation.h" + +namespace ImageKnifeC { + +class MultiTransformation { +public: + bool Transform(ImageKnifeTask *task) + { + return true; + } +private: + std::shared_ptr>> transformations_; +}; + +} // end of name +#endif // IMAGE_KNIFE_C_MULTI_TRANSFORMATION_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/transformation/transformation.h b/thirdparty/image-knife-c/library/src/main/cpp/transformation/transformation.h new file mode 100644 index 0000000000000000000000000000000000000000..cd5999de358bb5fbb70288c3e7a79b3649a02688 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/transformation/transformation.h @@ -0,0 +1,30 @@ +/* + * 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_KNIFE_C_TRANSFORMATION_H +#define IMAGE_KNIFE_C_TRANSFORMATION_H + +#include "imageKnife_task.h" + +namespace ImageKnifeC { + +class Transformation { +public: + virtual bool Transform(ImageKnifeTask* task) = 0; +}; + +} // end of namespace + +#endif // IMAGE_KNIFE_C_TRANSFORMATION_H diff --git a/thirdparty/image-knife-c/library/src/main/cpp/types/libentry/index.d.ets b/thirdparty/image-knife-c/library/src/main/cpp/types/libentry/index.d.ets new file mode 100644 index 0000000000000000000000000000000000000000..a089b919515e2b651da3f8de06ff770be16d7b72 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/types/libentry/index.d.ets @@ -0,0 +1,11 @@ +import { ImageKnifeRequest } from '../../../ets/model/ImageKnifeRequest'; +import { ImageKnifeOption } from '../../../ets/model/ImageKnifeOption'; + +export const createNativeRoot: (content: Object , componentId: string, imageKinfeOption: ImageKnifeOption, syncLoad: boolean) => void; +export const updateNativeRoot: (componentId: string, imageKinfeOption: Object, componentVersion: number, syncLoad: boolean) => void; +export const clearNativeRoot: (componentId: string) => void; +export const destroyNativeRoot: (componentId: string) => void; +export const initFileCache: (filesDir: string, size: number, memory: number, path?: string) => Promise; +export const setMaxRequests: (concurrency: number) => void; +export const preload: (imageKnifeRequest: ImageKnifeRequest) => ImageKnifeRequest; +export const cancel: (request: ImageKnifeRequest)=> void; diff --git a/thirdparty/image-knife-c/library/src/main/cpp/types/libentry/oh-package.json5 b/thirdparty/image-knife-c/library/src/main/cpp/types/libentry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..10271a22fa07f683f5fad627401ae4229d5b7fde --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/cpp/types/libentry/oh-package.json5 @@ -0,0 +1,6 @@ +{ + "name": "libimageknifec.so", + "types": "./index.d.ets", + "version": "1.0.0", + "description": "Please describe the basic information." +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/src/main/ets/ImageKnife.ets b/thirdparty/image-knife-c/library/src/main/ets/ImageKnife.ets new file mode 100644 index 0000000000000000000000000000000000000000..407d4be682dd620e035e91554b2c7209adb12f10 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/ets/ImageKnife.ets @@ -0,0 +1,89 @@ +/* + * 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. + */ +import { ImageKnifeRequest } from './model/ImageKnifeRequest'; +import nativeNode from 'libimageknifec.so'; +import { ImageKnifeOption } from './model/ImageKnifeOption'; +import { common } from '@kit.AbilityKit'; + +export class ImageKnife { + private static instance: ImageKnife; + + private constructor() { + + } + + public static getInstance(): ImageKnife { + if (!ImageKnife.instance) { + ImageKnife.instance = new ImageKnife(); + } + return ImageKnife.instance; + } + + /** + * 初始化文件缓存个数,大小,以及路径 + * @param context 上下文 + * @param size 缓存数量 + * @param memory 内存大小 + * @param path 文件目录 + */ + async initFileCache(context: Context, size: number = 256, memory: number = 256 * 1024 * 1024,path?: string): Promise { + return await nativeNode.initFileCache(context.filesDir, size, memory, path); + } + + /** + * 设置最大请求数量 + * @param concurrency 请求数量 + */ + public setMaxRequests(concurrency: number): void { + nativeNode.setMaxRequests(concurrency); + } + + /** + * 预加载 + * @param loadSrc 图片地址url + * @returns 图片请求request + */ + preload(loadSrc: string | ImageKnifeOption): ImageKnifeRequest { + let imageKnifeOption = new ImageKnifeOption() + if (typeof loadSrc == 'string') { + imageKnifeOption.loadSrc = loadSrc + } else { + imageKnifeOption = loadSrc; + } + // 创建 ImageKnifeRequest 实例,其他参数为空或使用默认值 + const request = new ImageKnifeRequest( + imageKnifeOption, + imageKnifeOption.context !== undefined ? imageKnifeOption.context : getContext() as common.UIAbilityContext, + 0, + 0, + 0 + ); + return nativeNode.preload(request) + } + /** + * 取消图片请求 + * @param request 图片请求request + */ + cancel(request: ImageKnifeRequest): void { + nativeNode.cancel(request) + } + + + + + async execute(request: ImageKnifeRequest,isAnimator?: boolean): Promise { + + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/src/main/ets/components/ImageKnifeComponent.ets b/thirdparty/image-knife-c/library/src/main/ets/components/ImageKnifeComponent.ets new file mode 100644 index 0000000000000000000000000000000000000000..f43fa5b03497f60d322216e6e3a1a03f03ba6779 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/ets/components/ImageKnifeComponent.ets @@ -0,0 +1,66 @@ +/* + * 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. + */ +import { ImageKnifeOption } from '../model/ImageKnifeOption'; +import common from '@ohos.app.ability.common'; +import { NodeContent } from '@ohos.arkui.node'; +import nativeNode from 'libimageknifec.so'; + +@Component +export struct ImageKnifeComponent { + // private componentId:string = util.generateRandomUUID(true) + private componentId:string = "" + syncLoad: boolean = false + private currentContext: common.UIAbilityContext | undefined = undefined + @Watch('watchImageKnifeOption') @ObjectLink imageKnifeOption: ImageKnifeOption + private rootSlot = new NodeContent(); + private componentVersion: number = 0 + + aboutToAppear(): void { + this.componentId = this.getUniqueId().toString() + this.fillImageKnifeOptionContext() + nativeNode.createNativeRoot(this.rootSlot, this.componentId, this.imageKnifeOption, this.syncLoad) + } + + aboutToDisappear(): void { + nativeNode.destroyNativeRoot(this.componentId) + } + + aboutToRecycle() { + nativeNode.clearNativeRoot(this.componentId) + } + + watchImageKnifeOption() { + this.componentVersion++ + this.fillImageKnifeOptionContext() + nativeNode.updateNativeRoot(this.componentId, this.imageKnifeOption, this.componentVersion, this.syncLoad) + } + + fillImageKnifeOptionContext() { + if (this.imageKnifeOption.context === undefined) { + this.imageKnifeOption.context = this.getCurrentContext() + } + } + + build() { + ContentSlot(this.rootSlot) + } + + getCurrentContext(): common.UIAbilityContext { + if (this.currentContext == undefined) { + this.currentContext = getContext(this) as common.UIAbilityContext + } + return this.currentContext + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/src/main/ets/model/ImageKnifeData.ets b/thirdparty/image-knife-c/library/src/main/ets/model/ImageKnifeData.ets new file mode 100644 index 0000000000000000000000000000000000000000..8284a7cd10190571cc6fd0beda56e4e7f068f3aa --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/ets/model/ImageKnifeData.ets @@ -0,0 +1,124 @@ +/* + * 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. + */ +import { HeaderOptions } from './ImageKnifeOption' +import { ImageKnifeRequest } from './ImageKnifeRequest' +import common from '@ohos.app.ability.common'; +import { Size } from '@kit.ArkUI' + +export interface ImageKnifeData { + source: PixelMap | string, // url + imageWidth: number, // 原始宽高大小 + imageHeight: number, + bufSize?: number, // 图片的字节数 + type?:string, + imageAnimator?: Array + frameCount ?: number // 帧 + decodeImages?: Array //Image组件或者ImageAnimator组件可以加载一张或者多张 + timeInfo?: TimeInfo // 加载图片的各个时间点 + errorInfo?: ErrorInfo // 错误 +} + +/** + * 解码后的图片的size + */ +export interface DecodeImageInfo { + contentWidth ?: number // 解码后宽高 + contentHeight?: number + contentSize ?: number // 大小 +} + +/** + * 加载的错误信息 + */ +export interface ErrorInfo { + phase: string, //图片加载阶段信息,如:网络加载阶段,缓存获取阶段及其解码阶段等 + code: number, + httpCode?: number +} + +/** + * load检查时间点 + */ +export interface TimeInfo { + requestStartTime?: number, + requestEndTime?: number, + requestCancelTime?: number, + memoryCheckStartTime?: number, + memoryCheckEndTime?: number, + diskCheckStartTime?: number, + diskCheckEndTime?: number, + netRequestStartTime?: number, + netRequestEndTime?: number, + decodeStartTime?: number, + decodeEndTime?: number, +} + + +/** + * onComplete成功回调 + */ +export interface EventImage { + width: number; + height: number; + componentWidth: number; + componentHeight: number; + loadingStatus: number; + contentWidth: number; + contentHeight: number; + contentOffsetX: number; + contentOffsetY: number; +} +/** + * 缓存策略 + */ +export enum CacheStrategy { + // 默认-写入/读取内存和文件缓存 + Default = 0, + // 只写入/读取内存缓存 + Memory = 1, + // 只写入/读取文件缓存 + File = 2 +} + +/** + * 区分是src,placehodler,还是error_holder + */ +export enum ImageKnifeRequestSource { + SRC, + PLACE_HOLDER, + ERROR_HOLDER +} + + +export interface ImageKnifeRequestWithSource { + request: ImageKnifeRequest + source: ImageKnifeRequestSource +} + +/** + * request子线程处理时的返回 + */ +export interface RequestJobResult { + pixelMap: PixelMap | string | undefined + bufferSize: number + fileKey: string + loadFail?: string, + size?:Size, + type?: string, + pixelMapList?:Array, + delayList?: Array +} + + diff --git a/thirdparty/image-knife-c/library/src/main/ets/model/ImageKnifeOption.ets b/thirdparty/image-knife-c/library/src/main/ets/model/ImageKnifeOption.ets new file mode 100644 index 0000000000000000000000000000000000000000..9a93c23902b98db206c32b3b3c0cf1d3f2b60014 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/ets/model/ImageKnifeOption.ets @@ -0,0 +1,153 @@ +/* + * 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. + */ +import taskpool from '@ohos.taskpool'; +import common from '@ohos.app.ability.common' +import { CacheStrategy, ImageKnifeData,EventImage } from './ImageKnifeData'; +import { drawing } from '@kit.ArkGraphics2D'; +import { ImageKnifeRequest } from './ImageKnifeRequest'; + +export interface HeaderOptions { + key: string; + value: Object; +} +interface AnimatorType { + state?: AnimationStatus + iterations?: number + reverse?: boolean + onStart?:()=>void + onFinish?:()=>void + onPause?:()=>void + onCancel?:()=>void + onRepeat?:()=>void +} +@ObservedV2 +export class AnimatorOption { + @Trace + state?: AnimationStatus = AnimationStatus.Running + @Trace + iterations?: number = -1 + @Trace + reverse?: boolean = false + @Trace + onStart?:()=>void + @Trace + onFinish?:()=>void + @Trace + onPause?:()=>void + @Trace + onCancel?:()=>void + @Trace + onRepeat?:()=>void + constructor(option?:AnimatorType) { + this.state = option?.state + this.iterations = option?.iterations + this.reverse = option?.reverse + this.onStart = option?.onStart + this.onFinish = option?.onFinish + this.onPause = option?.onPause + this.onCancel = option?.onCancel + this.onRepeat = option?.onRepeat + } +} +interface ImageOption { + // 主图资源 + loadSrc: string | PixelMap | Resource + // 占位图 + placeholderSrc?: string | PixelMap | Resource + // 失败占位图 + errorholderSrc?: string | PixelMap | Resource + headerOption?: Array; + // 自定义缓存关键字 + signature?: string + + // 主图填充效果 + objectFit?: ImageFit + // 占位图填充效果 + placeholderObjectFit?: ImageFit + // 错误图填充效果 + errorholderObjectFit?: ImageFit + customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise + border?: BorderOptions + // 缓存策略 + writeCacheStrategy?: CacheStrategy + // 仅使用缓存加载数据 + onlyRetrieveFromCache?: boolean; + priority?: taskpool.Priority + context?: common.UIAbilityContext; + progressListener?: (progress: number) => void; + onLoadListener?: OnLoadCallBack | undefined; + onComplete?:(event:EventImage | undefined) => void + drawingColorFilter?: ColorFilter | drawing.ColorFilter +} + +export interface HttpRequestOption { + caPath?: string // 自定义证书路径 + connectTimeout?: number // 连接超时 + readTimeout?: number // 读取超时 +} + +@Observed +export class ImageKnifeOption { + // 主图资源 + loadSrc: string | PixelMap | Resource = ""; + // 占位图 + placeholderSrc?: string | PixelMap | Resource; + // 失败占位图 + errorholderSrc?: string | PixelMap | Resource; + headerOption?: Array; + // 自定义缓存关键字 + signature?: string; + + // 主图填充效果 + objectFit?: ImageFit + // 占位图填充效果 + placeholderObjectFit?: ImageFit + // 错误图填充效果 + errorholderObjectFit?: ImageFit + customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise + border?: BorderOptions + // 缓存策略 + writeCacheStrategy?: CacheStrategy + // 仅使用缓存加载数据 + onlyRetrieveFromCache?: boolean = false; + priority?: taskpool.Priority = taskpool.Priority.LOW + context?: common.UIAbilityContext; + progressListener?: (progress: number) => void; + onLoadListener?: OnLoadCallBack | undefined; + onComplete?:(event:EventImage | undefined) => void + drawingColorFilter?: ColorFilter | drawing.ColorFilter + + // 自定义证书路径 + httpOption?: HttpRequestOption + + constructor() { + } +} + +/** + * 请求回调 + */ +export interface OnLoadCallBack { + // 请求开始 + onLoadStart?: (request?: ImageKnifeRequest) => void; + + // 请求成功 + onLoadSuccess?: (data: string | PixelMap | undefined, imageKnifeData: ImageKnifeData, request?: ImageKnifeRequest) => void; + + // 请求结束 + onLoadFailed?: (err: string, request?: ImageKnifeRequest) => void; + // 请求取消 + onLoadCancel?: (reason: string, request?: ImageKnifeRequest) => void; +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/src/main/ets/model/ImageKnifeRequest.ets b/thirdparty/image-knife-c/library/src/main/ets/model/ImageKnifeRequest.ets new file mode 100644 index 0000000000000000000000000000000000000000..90b03744affdfad1dfc75f5b550320ce05431269 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/ets/model/ImageKnifeRequest.ets @@ -0,0 +1,62 @@ +/* + * 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. + */ +import { ImageKnifeOption } from './ImageKnifeOption'; +import common from '@ohos.app.ability.common'; +import { ImageKnifeData } from './ImageKnifeData'; + + +export class ImageKnifeRequest { + id: string = "" + requestState: ImageKnifeRequestState = ImageKnifeRequestState.PROGRESS + componentWidth: number = 0 + componentHeight: number = 0 + drawPlayHolderSuccess: boolean = false + imageKnifeOption: ImageKnifeOption + context: common.UIAbilityContext + componentVersion: number = 0 + headers: Map = new Map() + imageKnifeData?: ImageKnifeData + constructor(option: ImageKnifeOption, + uIAbilityContext: common.UIAbilityContext, + width: number, + height: number, + version: number) { + this.imageKnifeOption = option + this.context = uIAbilityContext + this.componentWidth = width + this.componentHeight = height + this.componentVersion = version + } + // RequestOption调用header对于的方法 + addHeader(key: string, value: Object) { + this.headers.set(key, value); + } + + // 全局调用header对应的方法,包含RequestOption的形式 + addHeaderMap(map: Map) { + map.forEach((value, key) => { + if (!this.headers.has(key)) { + this.addHeader(key, value); + } + }) + } +} + +export enum ImageKnifeRequestState { + PROGRESS, + COMPLETE, + ERROR, + DESTROY +} diff --git a/thirdparty/image-knife-c/library/src/main/ets/utils/LogUtil.ets b/thirdparty/image-knife-c/library/src/main/ets/utils/LogUtil.ets new file mode 100644 index 0000000000000000000000000000000000000000..d59f5825badb868a5ffab392303bb2b8e6083aa3 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/ets/utils/LogUtil.ets @@ -0,0 +1,40 @@ +/* + * 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. + */ +import { hilog } from '@kit.PerformanceAnalysisKit'; + +export class LogUtil { + public static readonly DOMAIN: number = 0xD002220; + public static readonly TAG: string = "ImageKnife::"; + + public static debug(message: string, ...args: Object[]) { + hilog.debug(LogUtil.DOMAIN, LogUtil.TAG, message, args) + } + + public static info(message: string, ...args: Object[]) { + hilog.info(LogUtil.DOMAIN, LogUtil.TAG, message, args) + } + + public static log(message: string, ...args: Object[]) { + hilog.debug(LogUtil.DOMAIN, LogUtil.TAG, message, args) + } + + public static warn(message: string, ...args: Object[]) { + hilog.warn(LogUtil.DOMAIN, LogUtil.TAG, message, args) + } + + public static error(message: string, ...args: Object[]) { + hilog.error(LogUtil.DOMAIN, LogUtil.TAG, message, args) + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/src/main/module.json5 b/thirdparty/image-knife-c/library/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..0089cb0c103a668cff6b260eab00976b3db7132d --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/module.json5 @@ -0,0 +1,19 @@ +{ + "module": { + "name": "library", + "type": "har", + "deviceTypes": [ + "default", + "tablet", + "2in1" + ], + "requestPermissions": [ + { + "name": "ohos.permission.INTERNET" + }, + { + "name": "ohos.permission.GET_NETWORK_INFO" + } + ] + } +} diff --git a/thirdparty/image-knife-c/library/src/main/resources/base/element/string.json b/thirdparty/image-knife-c/library/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f51a9c8461a55f6312ef950344e3145b7f82d607 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "page_show", + "value": "page from package" + } + ] +} diff --git a/thirdparty/image-knife-c/library/src/main/resources/en_US/element/string.json b/thirdparty/image-knife-c/library/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f51a9c8461a55f6312ef950344e3145b7f82d607 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/resources/en_US/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "page_show", + "value": "page from package" + } + ] +} diff --git a/thirdparty/image-knife-c/library/src/main/resources/zh_CN/element/string.json b/thirdparty/image-knife-c/library/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f51a9c8461a55f6312ef950344e3145b7f82d607 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "page_show", + "value": "page from package" + } + ] +} diff --git a/thirdparty/image-knife-c/library/src/ohosTest/ets/test/Ability.test.ets b/thirdparty/image-knife-c/library/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..85c78f67579d6e31b5f5aeea463e216b9b141048 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,35 @@ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function abilityTest() { + describe('ActsAbilityTest', () => { + // 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. + hilog.info(0x0000, 'testTag', '%{public}s', 'it begin'); + 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/thirdparty/image-knife-c/library/src/ohosTest/ets/test/List.test.ets b/thirdparty/image-knife-c/library/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..794c7dc4ed66bd98fa3865e07922906e2fcef545 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,5 @@ +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/src/ohosTest/module.json5 b/thirdparty/image-knife-c/library/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..2d357bce9c10ce2146bf57f966d4e29f770ab067 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/ohosTest/module.json5 @@ -0,0 +1,13 @@ +{ + "module": { + "name": "library_test", + "type": "feature", + "deviceTypes": [ + "default", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/thirdparty/image-knife-c/library/src/test/List.test.ets b/thirdparty/image-knife-c/library/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..bb5b5c3731e283dd507c847560ee59bde477bbc7 --- /dev/null +++ b/thirdparty/image-knife-c/library/src/test/List.test.ets @@ -0,0 +1,5 @@ +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/library/src/test/LocalUnit.test.ets b/thirdparty/image-knife-c/library/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..165fc1615ee8618b4cb6a622f144a9a707eee99f --- /dev/null +++ b/thirdparty/image-knife-c/library/src/test/LocalUnit.test.ets @@ -0,0 +1,33 @@ +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/thirdparty/image-knife-c/oh-package-lock.json5 b/thirdparty/image-knife-c/oh-package-lock.json5 new file mode 100644 index 0000000000000000000000000000000000000000..f538ae290f499a46efa12e593420d47f6e9024ff --- /dev/null +++ b/thirdparty/image-knife-c/oh-package-lock.json5 @@ -0,0 +1,19 @@ +{ + "meta": { + "stableOrder": true + }, + "lockfileVersion": 3, + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", + "specifiers": { + "@ohos/hypium@1.0.19": "@ohos/hypium@1.0.19" + }, + "packages": { + "@ohos/hypium@1.0.19": { + "name": "@ohos/hypium", + "version": "1.0.19", + "integrity": "sha512-cEjDgLFCm3cWZDeRXk7agBUkPqjWxUo6AQeiu0gEkb3J8ESqlduQLSIXeo3cCsm8U/asL7iKjF85ZyOuufAGSQ==", + "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.19.har", + "registryType": "ohpm" + } + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/oh-package.json5 b/thirdparty/image-knife-c/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..74403844257d3f6ace7ecf165b99b4423ecf48b1 --- /dev/null +++ b/thirdparty/image-knife-c/oh-package.json5 @@ -0,0 +1,10 @@ +{ + "modelVersion": "5.0.0", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.19", +// "@ohos/hamock": "1.0.1-rc2" + } +} diff --git a/thirdparty/image-knife-c/sharedlibrary/.gitignore b/thirdparty/image-knife-c/sharedlibrary/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/thirdparty/image-knife-c/sharedlibrary/Index.ets b/thirdparty/image-knife-c/sharedlibrary/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..3cb1d2e3e323d0bf5b1976e1682033bf68d97c7e --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/Index.ets @@ -0,0 +1 @@ +export { add } from './src/main/ets/utils/Calc' \ No newline at end of file diff --git a/thirdparty/image-knife-c/sharedlibrary/build-profile.json5 b/thirdparty/image-knife-c/sharedlibrary/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ce80db2a169f21a98e0d82d0fb4e67d5be90ac53 --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/build-profile.json5 @@ -0,0 +1,28 @@ +{ + "apiType": "stageMode", + "buildOption": { + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + }, + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest" + } + ] +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/sharedlibrary/hvigorfile.ts b/thirdparty/image-knife-c/sharedlibrary/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..d993120bd71f5f5dfe04480be9dc5f73c00c2599 --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/hvigorfile.ts @@ -0,0 +1,6 @@ +import { hspTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hspTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/thirdparty/image-knife-c/sharedlibrary/obfuscation-rules.txt b/thirdparty/image-knife-c/sharedlibrary/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# 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://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# 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/thirdparty/image-knife-c/sharedlibrary/oh-package.json5 b/thirdparty/image-knife-c/sharedlibrary/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..9e47b3ecbdc8907bac50c727bfb4d70e3dc2ae77 --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/oh-package.json5 @@ -0,0 +1,11 @@ +{ + "name": "sharedlibrary", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "Index.ets", + "author": "", + "license": "Apache-2.0", + "packageType": "InterfaceHar", + "dependencies": { + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/sharedlibrary/src/main/ets/pages/Index.ets b/thirdparty/image-knife-c/sharedlibrary/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..423b4276eccd1d04d56471ae7a863c48015e8ae5 --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/src/main/ets/pages/Index.ets @@ -0,0 +1,17 @@ +@Entry +@Component +struct Index { + @State message: string = 'Hello World'; + + build() { + Row() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + } + .width('100%') + } + .height('100%') + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/sharedlibrary/src/main/ets/utils/Calc.ets b/thirdparty/image-knife-c/sharedlibrary/src/main/ets/utils/Calc.ets new file mode 100644 index 0000000000000000000000000000000000000000..08ab263da026007816dc1f175f5ebb19a989ec20 --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/src/main/ets/utils/Calc.ets @@ -0,0 +1,3 @@ +export function add(a: number, b: number) { + return a + b; +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/sharedlibrary/src/main/module.json5 b/thirdparty/image-knife-c/sharedlibrary/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..5ff0ab489351e929292f29c4cebeda3a2fd88a1d --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/src/main/module.json5 @@ -0,0 +1,14 @@ +{ + "module": { + "name": "sharedlibrary", + "type": "shared", + "description": "$string:shared_desc", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "pages": "$profile:main_pages" + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/sharedlibrary/src/main/resources/base/element/string.json b/thirdparty/image-knife-c/sharedlibrary/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..98e1d8a84b3d8539ea33e79fe2ac593a05d23bb4 --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/src/main/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "shared_desc", + "value": "description" + } + ] +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/sharedlibrary/src/main/resources/base/media/startIcon.png b/thirdparty/image-knife-c/sharedlibrary/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/thirdparty/image-knife-c/sharedlibrary/src/main/resources/base/media/startIcon.png differ diff --git a/thirdparty/image-knife-c/sharedlibrary/src/main/resources/base/profile/main_pages.json b/thirdparty/image-knife-c/sharedlibrary/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..1898d94f58d6128ab712be2c68acc7c98e9ab9ce --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/Index" + ] +} diff --git a/thirdparty/image-knife-c/sharedlibrary/src/ohosTest/ets/test/Ability.test.ets b/thirdparty/image-knife-c/sharedlibrary/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..85c78f67579d6e31b5f5aeea463e216b9b141048 --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,35 @@ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function abilityTest() { + describe('ActsAbilityTest', () => { + // 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. + hilog.info(0x0000, 'testTag', '%{public}s', 'it begin'); + 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/thirdparty/image-knife-c/sharedlibrary/src/ohosTest/ets/test/List.test.ets b/thirdparty/image-knife-c/sharedlibrary/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..794c7dc4ed66bd98fa3865e07922906e2fcef545 --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,5 @@ +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/sharedlibrary/src/ohosTest/module.json5 b/thirdparty/image-knife-c/sharedlibrary/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..09cdfe62a5ba64f71dc0e04a59a76cae6c511aeb --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/src/ohosTest/module.json5 @@ -0,0 +1,13 @@ +{ + "module": { + "name": "sharedlibrary_test", + "type": "feature", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/sharedlibrary/src/test/List.test.ets b/thirdparty/image-knife-c/sharedlibrary/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..bb5b5c3731e283dd507c847560ee59bde477bbc7 --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/src/test/List.test.ets @@ -0,0 +1,5 @@ +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/thirdparty/image-knife-c/sharedlibrary/src/test/LocalUnit.test.ets b/thirdparty/image-knife-c/sharedlibrary/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..165fc1615ee8618b4cb6a622f144a9a707eee99f --- /dev/null +++ b/thirdparty/image-knife-c/sharedlibrary/src/test/LocalUnit.test.ets @@ -0,0 +1,33 @@ +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