diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..6c3a6b9 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "gpu_transform/src/main/cpp/boundscheck/third_party_bounds_checking_function"] + path = gpu_transform/src/main/cpp/boundscheck/third_party_bounds_checking_function + url = https://gitee.com/openharmony/third_party_bounds_checking_function.git diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fd51a9..0e043d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## 3.0.2 +- ImageKnifeAnimatorComponent新增开始、结束、暂停的回调事件 +- 文件缓存数量负数和超过INT最大值时默认为INT最大值 +- 修复宽高不等svg图片显示有毛边 +- 部分静态webp图片有delay属性导致识别成动图,改用getFrameCount识别 +- 修复加载错误图后未去请求排队队列中的请求 +- 子线程本地Resource参数类型转换成number +- 修改使用hilog记录日志,默认打开debug级别的日志 +- 解码pixelMap默认不可编辑,图形变化可编辑 +- 修改网络请求超时设置 +- 重构代码:抽取ImageKnifeDispatcher子线程requestJob相关代码到ImageKnifeLoader中,降低函数复杂度 + ## 3.0.2-rc.0 - FileUtil.readFile接口和file格式图片同步关闭fd diff --git a/OAT.xml b/OAT.xml index 681e878..14adc5d 100644 --- a/OAT.xml +++ b/OAT.xml @@ -1,4 +1,21 @@ + diff --git a/README.OpenSource b/README.OpenSource index ac553d7..4737674 100644 --- a/README.OpenSource +++ b/README.OpenSource @@ -2,9 +2,9 @@ { "Name": "glide", "License": "Apache License 2.0", - "License File": "https://github.com/bumptech/glide/blob/master/LICENSE", + "License File": "LICENSE", "Version Number": "4.13.1", - "Owner" : "bumptech", + "Owner" : "xiafeng@huawei.com", "Upstream URL": "https://github.com/bumptech/glide", "Description": "An image loading and caching library focused on smooth scrolling" }, @@ -12,9 +12,9 @@ { "Name": "glide-transformations", "License": "Apache License 2.0", - "License File": "https://github.com/wasabeef/glide-transformations/blob/main/LICENSE", + "License File": "LICENSE", "Version Number": "4.3.0", - "Owner" : "wasabeef", + "Owner" : "xiafeng@huawei.com", "Upstream URL": "https://github.com/wasabeef/glide-transformations", "Description": " An transformation library providing a variety of image transformations for Glide. " }, @@ -22,9 +22,9 @@ { "Name": "fresco", "License": "MIT License", - "License File": "https://github.com/facebook/fresco/blob/main/LICENSE", + "License File": "LICENSE", "Version Number": "2.6.0", - "Owner" : "facebook", + "Owner" : "xiafeng@huawei.com", "Upstream URL": "https://github.com/facebook/fresco", "Description": " An library for managing images and the memory they use. " }, @@ -32,9 +32,9 @@ { "Name": "UPNG.js", "License": "MIT License", - "License File": "https://github.com/photopea/UPNG.js/blob/master/LICENSE", + "License File": "LICENSE", "Version Number": "1.0.0", - "Owner" : "photopea", + "Owner" : "xiafeng@huawei.com", "Upstream URL": "https://github.com/photopea/UPNG.js", "Description": " Fast and advanced PNG (APNG) decoder and encoder (lossy / lossless) " }, @@ -42,9 +42,9 @@ { "Name": "Luban", "License": "Apache License 2.0", - "License File": "https://github.com/Curzibn/Luban/blob/master/LICENSE", + "License File": "LICENSE", "Version Number": "1.1.8", - "Owner" : " Curzibn", + "Owner" : " xiafeng@huawei.com", "Upstream URL": "https://github.com/Curzibn/Luban", "Description": " Luban(鲁班)—Image compression with efficiency very close to WeChat Moments/可能是最接近微信朋友圈的图片压缩算法 " }, @@ -54,16 +54,16 @@ "License": "Apache License 2.0", "License File": "https://github.com/Yalantis/uCrop/blob/develop/README.md", "Version Number": "2.2.8", - "Owner" : " Yalantis", + "Owner" : " xiafeng@huawei.com", "Upstream URL": "https://github.com/Yalantis/uCrop", "Description": " Image Cropping Library " }, { "Name": "js-spark-md5", "License": "MIT", - "License File": "https://github.com/satazor/js-spark-md5/blob/master/LICENSE", + "License File": "LICENSE", "Version Number": "v3.0.2", - "Owner" : "satazor", + "Owner" : "xiafeng@huawei.com", "Upstream URL": "https://github.com/satazor/js-spark-md5", "Description": "Lightning fast normal and incremental md5 for javascript" } diff --git a/README_zh.md b/README_zh.md new file mode 100644 index 0000000..97522da --- /dev/null +++ b/README_zh.md @@ -0,0 +1,375 @@ +# ImageKnife + +**专门为OpenHarmony打造的一款图像加载缓存库,致力于更高效、更轻便、更简单。** + +## 简介 + +本项目参考开源库 [Glide](https://github.com/bumptech/glide) 进行OpenHarmony的自研版本: + +- 支持自定义内存缓存策略,支持设置内存缓存的大小(默认LRU策略)。 +- 支持磁盘二级缓存,对于下载图片会保存一份至磁盘当中。 +- 支持自定义实现图片获取/网络下载 +- 支持监听网络下载回调进度 +- 继承Image的能力,支持option传入border,设置边框,圆角 +- 继承Image的能力,支持option传入objectFit设置图片缩放,包括objectFit为auto时根据图片自适应高度 +- 支持通过设置transform缩放图片 +- 并发请求数量,支持请求排队队列的优先级 +- 支持生命周期已销毁的图片,不再发起请求 +- 自定义缓存key +- 自定义http网络请求头 +- 支持writeCacheStrategy控制缓存的存入策略(只存入内存或文件缓存) +- 支持preLoadCache预加载图片 +- 支持onlyRetrieveFromCache仅用缓存加载 +- 支持使用一个或多个图片变换,如模糊,高亮等 + +待实现特性 + +- 内存降采样优化,节约内存的占用 +- 支持自定义图片解码 + +注意:3.x版本相对2.x版本做了重大的重构,主要体现在: + +- 使用Image组件代替Canvas组件渲染 +- 重构Dispatch分发逻辑,支持控制并发请求数,支持请求排队队列的优先级 +- 支持通过initMemoryCache自定义策略内存缓存策略和大小 +- 支持option自定义实现图片获取/网络下载 + +因此API及能力上,目前有部分差异,主要体现在: + +- 不支持drawLifeCycle接口,通过canvas自会图片 +- mainScaleType,border等参数,新版本与系统Image保持一致 +- gif/webp动图播放与控制(ImageAnimator实现) +- 抗锯齿相关参数 + +## 下载安装 + +``` +ohpm install @ohos/imageknife + +// 如果需要用文件缓存,需要提前初始化文件缓存 +await ImageKnife.getInstance().initFileCache(context, 256, 256 * 1024 * 1024) +``` + +## 使用说明 + +#### 1.显示本地资源图片 + +``` +ImageKnifeComponent({ + ImageKnifeOption: new ImageKnifeOption({ + loadSrc: $r("app.media.app_icon"), + placeholderSrc: $r("app.media.loading"), + errorholderSrc: $r("app.media.app_icon"), + objectFit: ImageFit.Auto + }) +}).width(100).height(100) +``` + +#### 2.显示本地context files下文件 + +``` +ImageKnifeComponent({ + ImageKnifeOption: new ImageKnifeOption({ + loadSrc: this.localFile, + placeholderSrc: $r("app.media.loading"), + errorholderSrc: $r("app.media.app_icon"), + objectFit: ImageFit.Auto + }) +}).width(100).height(100) +``` + +#### 3.显示网络图片 + +``` +ImageKnifeComponent({ + ImageKnifeOption: new ImageKnifeOption({ + loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", + placeholderSrc: $r("app.media.loading"), + errorholderSrc: $r("app.media.app_icon"), + objectFit: ImageFit.Auto + }) +}).width(100).height(100) +``` + +#### 4.自定义下载图片 + +``` +ImageKnifeComponent({ + ImageKnifeOption: new ImageKnifeOption({ + loadSrc: "https://file.atomgit.com/uploads/user/1704857786989_8994.jpeg", + placeholderSrc: $r("app.media.loading"), + errorholderSrc: $r("app.media.app_icon"), + objectFit: ImageFit.Auto, + customGetImage: custom + }) +}).width(100).height(100) + +// 自定义实现图片获取方法,如自定义网络下载 +@Concurrent +async function custom(context: Context, src: string | PixelMap | Resource): Promise { + console.info("ImageKnife:: custom download:" + src) + // 举例写死从本地文件读取,也可以自己请求网络图片 + return context.resourceManager.getMediaContentSync($r("app.media.bb").id).buffer as ArrayBuffer +} +``` + +#### 5.监听网络下载进度 + +``` +ImageKnifeComponent({ + ImageKnifeOption: new ImageKnifeOption({ + loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", + progressListener:(progress:number)=>{console.info("ImageKinfe:: call back progress = " + progress)} + }) +}).width(100).height(100) +``` + +#### 6.支持option传入border,设置边框,圆角 + +``` +ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption( +{ + loadSrc: $r("app.media.rabbit"), + border: {radius:50} + }) +}).width(100).height(100) +``` + +#### 7.支持option图片变换 + +``` +ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption( +{ + loadSrc: $r("app.media.rabbit"), + border: {radius:50}, + transformation: new BlurTransformation(3) + }) +}).width(100).height(100) +``` +多种组合变换用法 + +``` +let transformations: collections.Array = new collections.Array(); +transformations.push(new BlurTransformation(5)); +transformations.push(new BrightnessTransformation(0.2)); +ImageKnifeComponent({ + imageKnifeOption: new ImageKnifeOption({ + loadSrc: $r('app.media.pngSample'), + placeholderSrc: $r("app.media.loading"), + errorholderSrc: $r("app.media.app_icon"), + objectFit: ImageFit.Contain, + border: { radius: { topLeft: 50, bottomRight: 50 } }, // 圆角设置 + transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined // 图形变换组 +}) +}).width(300) + .height(300) + .rotate({ angle: 90 }) // 旋转90度 + .contrast(12) // 对比度滤波器 +``` +其它变换相关属性,可叠加实现组合变换效果 + +圆形裁剪变换示例 + +``` +ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption( + { + loadSrc: $r('app.media.pngSample'), + objectFit: ImageFit.Cover, + border: { radius: 150 } +}) +}).width(300) + .height(300) +``` + +圆形裁剪带边框变换示例 + +``` +ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption( + { + loadSrc: $r('app.media.pngSample'), + objectFit: ImageFit.Cover, + border: { radius: 150, color: Color.Red, width: 5 } +}) +}).width(300) + .height(300) +``` + +对比度滤波变换示例 + +``` +ImageKnifeComponent({ + imageKnifeOption: new ImageKnifeOption({ + loadSrc: $r('app.media.pngSample') + }) +}).width(300) + .height(300) + .contrast(12) +``` + +旋转变换示例 + +``` +ImageKnifeComponent({ + imageKnifeOption: new ImageKnifeOption({ + loadSrc: $r('app.media.pngSample') + }) +}).width(300) + .height(300) + .rotate({angle:90}) + .backgroundColor(Color.Pink) +``` + +#### 8.监听图片加载成功与失败 + +``` +ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption( +{ + loadSrc: $r("app.media.rabbit"), + onLoadListener:{ + onLoadStart:()=>{ + this.starTime = new Date().getTime() + console.info("Load start: "); + }, + onLoadFailed: (err) => { + console.error("Load Failed Reason: " + err + " cost " + (new Date().getTime() - this.starTime) + " milliseconds"); + }, + onLoadSuccess: (data, imageData) => { + console.info("Load Successful: cost " + (new Date().getTime() - this.starTime) + " milliseconds"); + return data; + }, + onLoadCancel(err){ + console.info(err) + } + } + }) +}).width(100).height(100) +``` +#### 9.ImageKnifeComponent - syncLoad +设置是否同步加载图片,默认是异步加载。建议加载尺寸较小的Resource图片时将syncLoad设为true,因为耗时较短,在主线程上执行即可 +``` +ImageKnifeComponent({ + imageKnifeOption:new ImageKnifeOption({ + loadSrc:$r("app.media.pngSample"), + placeholderSrc:$r("app.media.loading") + }),syncLoad:true + }) +``` +#### 10.ImageKnifeAnimatorComponent 示例 +``` +ImageKnifeAnimatorComponent({ + imageKnifeOption:new ImageKnifeOption({ + loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", + placeholderSrc:$r('app.media.loading'), + errorholderSrc:$r('app.media.failed') + }),animatorOption:this.animatorOption + }).width(300).height(300).backgroundColor(Color.Orange).margin({top:30}) +``` +#### 复用场景 +在aboutToRecycle生命周期清空组件内容;通过watch监听触发图片的加载。 +## 接口说明 +### ImageKnife组件 +| 组件名称 | 入参内容 | 功能简介 | +|-----------------------------|---------------------------------|--------| +| ImageKnifeComponent | ImageKnifeOption | 图片显示组件 | +| ImageKnifeAnimatorComponent | ImageKnifeOption、AnimatorOption | 动图控制组件 | + +### AnimatorOption参数列表 +| 参数名称 | 入参内容 | 功能简介 | +|------------|-----------------|----------| +| state | AnimationStatus | 播放状态(可选) | +| iterations | number | 播放次数(可选) | +| reverse | boolean | 播放顺序(可选) | +| onStart | ()=>void | 动画开始播放时触发(可选) | +| onFinish | ()=>void | 动画播放完成时或者停止播放时触发(可选) | +| onPause | ()=>void | 动画暂停播放时触发(可选) | +| onCancel | ()=>void | 动画返回最初状态时触发(可选) | +| onRepeat | ()=>void | 动画重复播放时触发(可选) | + +### ImageKnifeOption参数列表 + +| 参数名称 | 入参内容 | 功能简介 | +|-----------------------|-------------------------------------------------------|-----------------| +| loadSrc | string、PixelMap、Resource | 主图展示 | +| placeholderSrc | PixelMap、Resource | 占位图图展示(可选) | +| errorholderSrc | PixelMap、Resource | 错误图展示(可选) | +| objectFit | ImageFit | 主图填充效果(可选) | +| placeholderObjectFit | ImageFit | 占位图填充效果(可选) | +| errorholderObjectFit | ImageFit | 错误图填充效果(可选) | +| writeCacheStrategy | CacheStrategyType | 写入缓存策略(可选) | +| onlyRetrieveFromCache | boolean | 是否跳过网络和本地请求(可选) | +| customGetImage | (context: Context, src: string | 自定义下载图片(可选) | | Resource | 错误占位图数据源 | +| border | BorderOptions | 边框圆角(可选) | +| priority | taskpool.Priority | 加载优先级(可选) | +| context | common.UIAbilityContext | 上下文(可选) | +| progressListener | (progress: number)=>void | 进度(可选) | +| signature | String | 自定义缓存关键字(可选) | +| headerOption | Array | 设置请求头(可选) | +| transformation | PixelMapTransformation | 图片变换(可选) | +| drawingColorFilter | ColorFilter | drawing.ColorFilter | 图片变换(可选) | +| onComplete | (event:EventImage | undefined) => voi | 颜色滤镜效果(可选) | +| onLoadListener | onLoadStart: () => void、onLoadSuccess: (data: string | PixelMap | undefined) => void、onLoadFailed: (err: string) => void| 监听图片加载成功与失败 | + +### ImageKnife接口 + +| 参数名称 | 入参内容 | 功能简介 | +|------------------|-------------------------------------------------------------------------------------------------------|---------------| +| initMemoryCache | newMemoryCache: IMemoryCache | 自定义内存缓存策略 | +| initFileCache | context: Context, size: number, memory: number | 初始化文件缓存数量和大小 | +| preLoadCache | loadSrc: string I ImageKnifeOption | 预加载并返回文件缓存路径 | +| getCacheImage | loadSrc: string, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string) | 从内存或文件缓存中获取资源 | +| addHeader | key: string, value: Object | 全局添加http请求头 | +| setHeaderOptions | Array | 全局设置http请求头 | +| deleteHeader | key: string | 全局删除http请求头 | +| setCustomGetImage | customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise | 全局设置自定义下载 | +| setEngineKeyImpl | IEngineKey | 全局配置缓存key生成策略 | +| putCacheImage | url: string, pixelMap: PixelMap, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string | 写入内存磁盘缓存 | +| removeMemoryCache| url: string | ImageKnifeOption | 清理指定内存缓存 | +| removeFileCache | url: string | ImageKnifeOption | 清理指定磁盘缓存 | +### 图形变换类型(需要为GPUImage添加依赖项) + +| 类型 | 相关描述 | +| ---------------------------------- | ----------------------------- | +| BlurTransformation | 模糊处理 | +| BrightnessTransformation | 亮度滤波器 | +| CropSquareTransformation | 正方形剪裁 | +| CropTransformation | 自定义矩形剪裁 | +| GrayScaleTransformation | 灰度级滤波器 | +| InvertTransformation | 反转滤波器 | +| KuwaharaTransformation | 桑原滤波器(使用GPUIImage) | +| MaskTransformation | 遮罩 | +| PixelationTransformation | 像素化滤波器(使用GPUIImage) | +| SepiaTransformation | 乌墨色滤波器(使用GPUIImage) | +| SketchTransformation | 素描滤波器(使用GPUIImage) | +| SwirlTransformation | 扭曲滤波器(使用GPUIImage) | +| ToonTransformation | 动画滤波器(使用GPUIImage) | +| VignetterTransformation | 装饰滤波器(使用GPUIImage) | + +## 下载安装GPUImage依赖 +方法一:在Terminal窗口中,执行如下命令安装三方包,DevEco Studio会自动在工程的oh-package.json5中自动添加三方包依赖。 +``` + ohpm install @ohos/gpu_transform +``` +方法二: 在工程的oh-package.json5中设置三方包依赖,配置示例如下: +``` + "dependencies": { + "@ohos/gpu_transform": "^1.0.2" + } +``` +## 约束与限制 + +在下述版本验证通过: +DevEco Studio 5.0 Canary3(5.0.3.502)--SDK:API12 (5.0.0.31) + +## 贡献代码 + +使用过程中发现任何问题都可以提 [issue](https://gitee.com/openharmony-tpc/ImageKnife/issues) +,当然,也非常欢迎发 [PR](https://gitee.com/openharmony-tpc/ImageKnife/pulls) 共建。 + +## 开源协议 + +本项目基于 [Apache License 2.0](https://gitee.com/openharmony-tpc/ImageKnife/blob/master/LICENSE) ,请自由的享受和参与开源。 + +## 遗留问题 + +- ImageKnifeAnimator组件无法设置ImageFit属性 +- ImageKnifeAnimator组件设置border属性无法将图片变为圆角 \ No newline at end of file diff --git a/build-profile.json5 b/build-profile.json5 index 90f6b5d..9c02fd6 100644 --- a/build-profile.json5 +++ b/build-profile.json5 @@ -7,9 +7,8 @@ { "name": "default", "signingConfig": "default", - "compileSdkVersion": "5.0.0(12)", - "compatibleSdkVersion": "5.0.0(12)", - "runtimeOS": "HarmonyOS", + "compileSdkVersion": 12, + "compatibleSdkVersion": 12 } ], "buildModeSet": [ @@ -38,6 +37,10 @@ "name": "library", "srcPath": "./library" }, + { + "name": "gpu_transform", + "srcPath": "./gpu_transform" + }, { "name": "sharedlibrary", "srcPath": "./sharedlibrary", diff --git a/entry/src/main/ets/entryability/EntryAbility.ets b/entry/src/main/ets/entryability/EntryAbility.ets index 488dcce..e19ffa7 100644 --- a/entry/src/main/ets/entryability/EntryAbility.ets +++ b/entry/src/main/ets/entryability/EntryAbility.ets @@ -47,7 +47,6 @@ export default class EntryAbility extends UIAbility { hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); - LogUtil.mLogLevel = LogUtil.ALL // 初始化ImageKnife的文件缓存 await InitImageKnife.init(this.context) ImageKnife.getInstance().setEngineKeyImpl(new CustomEngineKeyImpl()) diff --git a/entry/src/main/ets/pages/ImageAnimatorPage.ets b/entry/src/main/ets/pages/ImageAnimatorPage.ets index bde0508..9269280 100644 --- a/entry/src/main/ets/pages/ImageAnimatorPage.ets +++ b/entry/src/main/ets/pages/ImageAnimatorPage.ets @@ -1,3 +1,17 @@ +/* + * 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 { AnimatorOption, ImageKnifeAnimatorComponent } from "@ohos/libraryimageknife" @Entry diff --git a/entry/src/main/ets/pages/ImageTransformation.ets b/entry/src/main/ets/pages/ImageTransformation.ets index 844ed62..5e4e007 100644 --- a/entry/src/main/ets/pages/ImageTransformation.ets +++ b/entry/src/main/ets/pages/ImageTransformation.ets @@ -78,7 +78,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('模糊效果').fontSize(20) + Text($r('app.string.Blur_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -91,7 +91,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('高亮效果').fontSize(20) + Text($r('app.string.Highlighting_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -104,7 +104,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('灰化效果').fontSize(20) + Text($r('app.string.Ashing_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -117,7 +117,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('反转效果').fontSize(20) + Text($r('app.string.Inverse_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -130,7 +130,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('动画滤镜效果').fontSize(20) + Text($r('app.string.Animation_filter_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -143,7 +143,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('裁剪圆形效果').fontSize(20) + Text($r('app.string.Crop_circular_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -156,7 +156,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('裁剪圆形带边框效果').fontSize(20) + Text($r('app.string.Crop_circular_with_border_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -168,7 +168,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('对比度效果').fontSize(20) + Text($r('app.string.Contrast_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -181,7 +181,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('乌墨色滤波效果').fontSize(20) + Text($r('app.string.Black_ink_filtering_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -193,7 +193,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('旋转效果').fontSize(20) + Text($r('app.string.Rotate')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -206,7 +206,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('圆角效果').fontSize(20) + Text($r('app.string.Corners')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -219,7 +219,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('桑原滤波效果').fontSize(20) + Text($r('app.string.Kuwahara_Filter_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -232,7 +232,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('像素化滤波效果').fontSize(20) + Text($r('app.string.Pixelated_Filter_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -245,7 +245,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('素描滤波效果').fontSize(20) + Text($r('app.string.Sketch_Filter_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -258,7 +258,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('扭曲滤波效果').fontSize(20) + Text($r('app.string.Distortion_Filter_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -271,7 +271,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('装饰滤波效果').fontSize(20) + Text($r('app.string.Decorative_Filter_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -284,7 +284,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('正方形裁剪效果').fontSize(20) + Text($r('app.string.Square_cutting_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -297,7 +297,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('上方裁剪效果').fontSize(20) + Text($r('app.string.Top_cutting_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -310,7 +310,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('中间裁剪效果').fontSize(20) + Text($r('app.string.Middle_cutting_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -323,7 +323,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('底下裁剪效果').fontSize(20) + Text($r('app.string.Bottom_cutting_effect')).fontSize(20) } Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { @@ -336,7 +336,7 @@ struct ImageTransformation { }) .width(30) .height(30) - Text('遮罩效果').fontSize(20) + Text($r('app.string.Mask_effect')).fontSize(20) } if (this.isContrast) { diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets index 3383f6a..329e33a 100644 --- a/entry/src/main/ets/pages/Index.ets +++ b/entry/src/main/ets/pages/Index.ets @@ -18,6 +18,10 @@ import router from '@system.router'; @Component struct Index { + getResourceString(res:Resource){ + return getContext().resourceManager.getStringSync(res.id) + } + aboutToAppear(): void { @@ -26,95 +30,100 @@ struct Index { build() { Scroll(){ Column() { - Button("测试ImageAnimator组件").onClick(()=>{ + Button($r('app.string.Test_ImageAnimator')).onClick(()=>{ router.push({ uri: 'pages/ImageAnimatorPage', }); }) - Button("测试加载多张相同图片").margin({top:10}).onClick(()=>{ + Button($r('app.string.Test_multiple_images')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/TestCommonImage', }); }) - Button("测试HSP场景预加载").margin({top:10}).onClick(()=>{ + Button($r('app.string.Test_Task_error')).margin({top:10}).onClick(()=>{ + router.push({ + uri: 'pages/TestTaskResourcePage', + }); + }) + Button($r('app.string.Test_HSP')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/TestHspPreLoadImage', }); }) - Button("单个图片使用").margin({top:10}).onClick(()=>{ + Button($r('app.string.Test_SingleImage')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/SingleImage', }); }) - Button("全局自定义下载").margin({top:10}).onClick(()=>{ + Button($r('app.string.Test_custom_download')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/TestSetCustomImagePage', }); }) - Button("多图 + LazyForEach").margin({top:10}).onClick(()=>{ + Button(this.getResourceString($r('app.string.Multiple_images')) + " + LazyForEach").margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/ManyPhotoShowPage', }); }) - Button("多图 + reuse + LazyForeach").margin({top:10}).onClick(()=>{ + Button(this.getResourceString($r('app.string.Multiple_images')) + " + reuse + LazyForeach").margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/UserPage', }); }) - Button("长图显示").margin({top:10}).onClick(()=>{ + Button($r('app.string.Display_long_image')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/LongImagePage', }); }) - Button("缩放图片").margin({top:10}).onClick(()=>{ + Button($r('app.string.Image_scaling')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/TransformPage', }); }) - Button("消息+List").margin({top:10}).onClick(()=>{ + Button(this.getResourceString($r('app.string.Message_list')) + " + List").margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/TestImageFlash', }); }) - Button("自定义缓存key").margin({top:10}).onClick(()=>{ + Button($r('app.string.Custom_cache_key')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/SignatureTestPage', }); }) - Button("预加载图片到文件缓存").margin({top:10}).onClick(()=>{ + Button($r('app.string.Preloading_images_to_cache')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/TestPrefetchToFileCache', }); }) - Button("从缓存获取图片显示").margin({top:10}).onClick(()=>{ + Button($r('app.string.Retrieve_image_display_from_cache')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/TestIsUrlExist', }); }) - Button("测试单个请求头").margin({top:10}).onClick(()=>{ + Button($r('app.string.Test_single_request_header')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/TestHeader', }); }) - Button("测试写入缓存策略").margin({top:10}).onClick(()=>{ + Button($r('app.string.Test_write_cache_strategy')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/TestWriteCacheStage', }); }) - Button("图片变换").margin({top:10}).onClick(()=>{ + Button($r('app.string.Image_Transformation')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/ImageTransformation', @@ -122,7 +131,7 @@ struct Index { }) - Button("不同的ObjectFit").margin({top:10}).onClick(()=>{ + Button($r('app.string.Different_ObjectFit')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/ObjectFitPage', @@ -130,24 +139,24 @@ struct Index { }) - Button('测试图片加载成功/失败事件').margin({top:10}).onClick(()=>{ + Button($r('app.string.Test_image_loading_success_or_failure_events')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/LoadStatePage', }) }) - Button('测试移除图片缓存接口').margin({top:10}).onClick(()=>{ + Button($r('app.string.Test_removing_image_cache_interface')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/TestRemoveCache', }); }) - Button("测试错误图显示").margin({top:10}).onClick(()=>{ + Button($r('app.string.Test_error_image_display')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/TestErrorHolderPage', }); }) - Button("测试媒体url").margin({top:10}).onClick(()=>{ + Button($r('app.string.Test_media_URL')).margin({top:10}).onClick(()=>{ router.push({ uri: 'pages/dataShareUriLoadPage', diff --git a/entry/src/main/ets/pages/SignatureTestPage.ets b/entry/src/main/ets/pages/SignatureTestPage.ets index 42f49e4..5d60c3a 100644 --- a/entry/src/main/ets/pages/SignatureTestPage.ets +++ b/entry/src/main/ets/pages/SignatureTestPage.ets @@ -33,9 +33,9 @@ struct SignatureTestPage { Scroll() { Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Text("key固定为 1").fontSize(15) + Text($r('app.string.The_key_fixed_1')).fontSize(15) Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Button("加载") + Button($r('app.string.Load')) .onClick(() => { this.imageKnifeOption1 = { loadSrc: 'https://img-blog.csdn.net/20140514114029140', @@ -46,9 +46,9 @@ struct SignatureTestPage { ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).width(300).height(300) }.width('100%').backgroundColor(Color.Pink) - Text("key每次变化:时间戳").fontSize(15) + Text($r('app.string.The_key_changes_timestamp')).fontSize(15) Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Button("加载") + Button($r('app.string.Load')) .onClick(() => { this.imageKnifeOption2 = { loadSrc: 'https://img-blog.csdn.net/20140514114029140', diff --git a/entry/src/main/ets/pages/SingleImage.ets b/entry/src/main/ets/pages/SingleImage.ets index b7fc9b3..079c8e4 100644 --- a/entry/src/main/ets/pages/SingleImage.ets +++ b/entry/src/main/ets/pages/SingleImage.ets @@ -42,7 +42,7 @@ struct SingleImage { build() { Scroll(this.scroller) { Column() { - Text("本地资源svg图片") + Text($r('app.string.Local_SVG')) .fontSize(30) .fontWeight(FontWeight.Bold) ImageKnifeComponent({ @@ -56,7 +56,7 @@ struct SingleImage { .onClick(()=>{ this.DrawingColorFilter = drawing.ColorFilter.createBlendModeColorFilter(this.color, drawing.BlendMode.SRC_IN); }) - Text("本地context files下文件") + Text($r('app.string.Under_context_file')) .fontSize(30) .fontWeight(FontWeight.Bold) ImageKnifeComponent({ @@ -67,7 +67,7 @@ struct SingleImage { objectFit: ImageFit.Contain } }).width(100).height(100) - Text("网络图片") + Text($r('app.string.Network_images')) .fontSize(30) .fontWeight(FontWeight.Bold) ImageKnifeComponent({ @@ -79,7 +79,7 @@ struct SingleImage { progressListener:(progress:number)=>{console.info("ImageKnife:: call back progress = " + progress)} } }).width(100).height(100) - Text("自定义下载") + Text($r('app.string.Custom_network_download')) .fontSize(30) .fontWeight(FontWeight.Bold) ImageKnifeComponent({ @@ -92,7 +92,7 @@ struct SingleImage { transformation: new BlurTransformation(10) } }).width(100).height(100) - Text("pixelMap加载图片") + Text($r('app.string.PixelMap_loads_images')) .fontSize(30) .fontWeight(FontWeight.Bold) ImageKnifeComponent({ diff --git a/entry/src/main/ets/pages/TestImageFlash.ets b/entry/src/main/ets/pages/TestImageFlash.ets index 75144e0..53b9826 100644 --- a/entry/src/main/ets/pages/TestImageFlash.ets +++ b/entry/src/main/ets/pages/TestImageFlash.ets @@ -111,12 +111,12 @@ struct ImageTestPage { }) } Row(){ - Text("点击尺寸加50") + Text($r('app.string.Click_on_add')) .onClick(()=> { this.imageSize = this.imageSize + 50 }) .width('50%').backgroundColor(0x88ff0000).textAlign(TextAlign.Center).height(50) - Text("点击尺寸减50") + Text($r('app.string.Click_on_reduce')) .onClick(()=> { this.imageSize = Math.max(this.imageSize - 50, 0) }) diff --git a/entry/src/main/ets/pages/TestIsUrlExist.ets b/entry/src/main/ets/pages/TestIsUrlExist.ets index 1225edc..ad4daa6 100644 --- a/entry/src/main/ets/pages/TestIsUrlExist.ets +++ b/entry/src/main/ets/pages/TestIsUrlExist.ets @@ -28,11 +28,11 @@ struct TestIsUrlExist { build() { Column() { Flex() { - Button("预加载gif图").onClick(() => { + Button($r('app.string.Preloading_GIF')).onClick(() => { this.imageKnifeOption.loadSrc = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658" }) - Button("内存缓存获取gif").onClick(() => { + Button($r('app.string.Retrieve_GIF_from_memory')).onClick(() => { ImageKnife.getInstance() .getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", CacheStrategy.Memory) @@ -40,7 +40,7 @@ struct TestIsUrlExist { this.source = data !== undefined ? data.source : $r("app.media.startIcon") }) }) - Button("文件缓存获取gif").onClick(() => { + Button($r('app.string.Retrieve_GIF_from_disk')).onClick(() => { ImageKnife.getInstance() .getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", CacheStrategy.File) @@ -51,11 +51,11 @@ struct TestIsUrlExist { } Flex() { - Button("预加载静态图").onClick(() => { + Button($r('app.string.Preloading_static_images')).onClick(() => { this.imageKnifeOption.loadSrc = 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp' }) - Button("内存缓存获取").onClick(() => { + Button($r('app.string.Retrieve_images_from_memory')).onClick(() => { ImageKnife.getInstance() .getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', CacheStrategy.Memory) @@ -63,7 +63,7 @@ struct TestIsUrlExist { this.source = data!.source }) }) - Button("文件缓存获取").onClick(() => { + Button($r('app.string.Retrieve_images_from_disk')).onClick(() => { ImageKnife.getInstance() .getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', CacheStrategy.File) diff --git a/entry/src/main/ets/pages/TestPrefetchToFileCache.ets b/entry/src/main/ets/pages/TestPrefetchToFileCache.ets index eb735a7..a1a1787 100644 --- a/entry/src/main/ets/pages/TestPrefetchToFileCache.ets +++ b/entry/src/main/ets/pages/TestPrefetchToFileCache.ets @@ -32,13 +32,13 @@ struct TestPrefetchToFileCachePage { } build() { Column() { - Button("url预加载图片到文件缓存").margin({top:10}).onClick(async ()=>{ + Button($r('app.string.Preloading_images_to_file_cache_using_URL')).margin({top:10}).onClick(async ()=>{ await this.preload("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658") }) - Button("option预加载图片到文件缓存").margin({top:10}).onClick(async ()=>{ + Button($r('app.string.Preloading_images_to_file_cache_using_option')).margin({top:10}).onClick(async ()=>{ await this.preload1("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658") }) - Button("加载图片(预加载后可断网加载)").margin({top:10}).onClick(()=>{ + Button($r('app.string.Load_image_offline_after_preloading')).margin({top:10}).onClick(()=>{ this.imageKnifeOption.loadSrc = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658" }) ImageKnifeComponent({ diff --git a/entry/src/main/ets/pages/TestRemoveCache.ets b/entry/src/main/ets/pages/TestRemoveCache.ets index 13e7def..8a25454 100644 --- a/entry/src/main/ets/pages/TestRemoveCache.ets +++ b/entry/src/main/ets/pages/TestRemoveCache.ets @@ -29,12 +29,12 @@ struct TestRemoveCache { build() { Column() { Flex() { - Button("预加载gif图").onClick(() => { + Button($r('app.string.Preloading_GIF')).onClick(() => { this.imageKnifeOption.loadSrc = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658"; this.url = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658"; }) .margin({left:10}) - Button("内存缓存获取gif").onClick(() => { + Button($r('app.string.Retrieve_GIF_from_memory')).onClick(() => { ImageKnife.getInstance() .getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", CacheStrategy.Memory) @@ -43,7 +43,7 @@ struct TestRemoveCache { }) }) .margin({left:10}) - Button("文件缓存获取gif").onClick(() => { + Button($r('app.string.Retrieve_GIF_from_disk')).onClick(() => { ImageKnife.getInstance() .getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", CacheStrategy.File) @@ -55,12 +55,12 @@ struct TestRemoveCache { } Flex() { - Button("预加载静态图").onClick(() => { + Button($r('app.string.Preloading_static_images')).onClick(() => { this.imageKnifeOption.loadSrc = 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp'; this.url = 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp'; }) .margin({left:10}) - Button("内存缓存获取").onClick(() => { + Button($r('app.string.Retrieve_images_from_memory')).onClick(() => { ImageKnife.getInstance() .getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', CacheStrategy.Memory) @@ -69,7 +69,7 @@ struct TestRemoveCache { }) }) .margin({left:10}) - Button("文件缓存获取").onClick(() => { + Button($r('app.string.Retrieve_images_from_disk')).onClick(() => { ImageKnife.getInstance() .getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', CacheStrategy.File) @@ -81,19 +81,19 @@ struct TestRemoveCache { }.margin({ top: 10 }) Flex() { - Button("删除全部缓存").onClick(() => { + Button($r('app.string.Delete_all_caches')).onClick(() => { ImageKnife.getInstance() .removeAllMemoryCache() ImageKnife.getInstance() .removeAllFileCache() }) .margin({left:5}) - Button("删除全部内存缓存").onClick(() => { + Button($r('app.string.Delete_all_memory_caches')).onClick(() => { ImageKnife.getInstance() .removeAllMemoryCache() }) .margin({left:5}) - Button("删除全部文件缓存").onClick(() => { + Button($r('app.string.Delete_all_file_caches')).onClick(() => { ImageKnife.getInstance() .removeAllFileCache() }) @@ -101,12 +101,12 @@ struct TestRemoveCache { }.margin({ top: 10 }) Flex() { - Button("删除自定义内存缓存").onClick(() => { + Button($r('app.string.Delete_all_custom_memory_caches')).onClick(() => { ImageKnife.getInstance() .removeMemoryCache(this.url) }) .margin({left:20}) - Button("删除自定义文件缓存").onClick(() => { + Button($r('app.string.Delete_all_custom_file_caches')).onClick(() => { ImageKnife.getInstance() .removeFileCache(this.url) }) diff --git a/entry/src/main/ets/pages/TestTaskResourcePage.ets b/entry/src/main/ets/pages/TestTaskResourcePage.ets new file mode 100644 index 0000000..125d85e --- /dev/null +++ b/entry/src/main/ets/pages/TestTaskResourcePage.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/libraryimageknife" + +@ComponentV2 +export struct ZuImage { + @Param @Require src: PixelMap | ResourceStr | string | undefined + @Param @Require placeholderSrc: PixelMap | ResourceStr | string | undefined + @Local errorholderSrc: PixelMap | ResourceStr | string | undefined + + build() { + if (this.src) { + //当前版本存在bug + ImageKnifeComponent({ + imageKnifeOption: { + loadSrc: this.src, + placeholderSrc: this.placeholderSrc, + errorholderSrc: this.errorholderSrc ?? this.placeholderSrc, + objectFit: ImageFit.Cover + } + }) + } else { + Image(this.placeholderSrc) + .objectFit(ImageFit.Cover) + } + } +} + + +@Entry +@ComponentV2 +struct TestTaskResourcePage { + @Local stateMenus: Array = [ + "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB", + 'https://img-blog.csdnimg.cn/20191215043500229.png', + 'https://img-blog.csdn.net/20140514114029140', + 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', + ] + @Builder + _buildItem(item: string) { + Column({ space: 8 }) { + ZuImage({ + src: item, + placeholderSrc: $r("app.media.loading") + }).width(44) + .height(44) + } + } + build() { + + Grid() { + ForEach(this.stateMenus, (item: string) => { + GridItem() { + this._buildItem(item) + } + }) + }.width("100%") + .columnsTemplate('1fr 1fr 1fr 1fr 1fr') + .rowsGap(24) + .padding({ + top: 24, + bottom: 24, + left: 24, + right: 24 + }) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/pages/TransformPage.ets b/entry/src/main/ets/pages/TransformPage.ets index 7674156..29fbfd5 100644 --- a/entry/src/main/ets/pages/TransformPage.ets +++ b/entry/src/main/ets/pages/TransformPage.ets @@ -34,12 +34,12 @@ struct TransformPage { 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(()=>{ + Button($r('app.string.Enlarge')).onClick(()=>{ this.custom_scale = this.custom_scale * 2 this.matrix1 = matrix4.identity().scale({ x: this.custom_scale, y: this.custom_scale }) }) - Button("缩小").onClick(()=>{ + Button($r('app.string.Reduce')).onClick(()=>{ this.custom_scale = this.custom_scale / 2 this.matrix1 = matrix4.identity().scale({ x: this.custom_scale, y: this.custom_scale }) }) diff --git a/entry/src/main/ets/pages/dataShareUriLoadPage.ets b/entry/src/main/ets/pages/dataShareUriLoadPage.ets index bb71ac2..b3915b7 100644 --- a/entry/src/main/ets/pages/dataShareUriLoadPage.ets +++ b/entry/src/main/ets/pages/dataShareUriLoadPage.ets @@ -32,9 +32,9 @@ struct DataShareUriLoadPage { build() { Scroll() { Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Text("获取媒体图库的uri用ImageKnife展示").fontSize(15) + Text($r('app.string.Retrieve_media_gallery')).fontSize(15) Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Button("点击加载Uri并展示") + Button($r('app.string.Click_load_Uri')) .onClick(async () => { let photoSelectOptions = new photoAccessHelper.PhotoSelectOptions(); photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE; diff --git a/entry/src/main/module.json5 b/entry/src/main/module.json5 index 9036eb0..6c284c7 100644 --- a/entry/src/main/module.json5 +++ b/entry/src/main/module.json5 @@ -5,9 +5,8 @@ "description": "$string:module_desc", "mainElement": "EntryAbility", "deviceTypes": [ - "phone", - "tablet", - "2in1" + "default", + "tablet" ], "deliveryWithInstall": true, "installationFree": false, diff --git a/entry/src/main/resources/base/element/string.json b/entry/src/main/resources/base/element/string.json index 13c1fec..f982e81 100644 --- a/entry/src/main/resources/base/element/string.json +++ b/entry/src/main/resources/base/element/string.json @@ -19,6 +19,354 @@ { "name": "app_permission_READ_IMAGEVIDEO", "value": "获取读媒体资源权限" + }, + { + "name": "Test_ImageAnimator", + "value": "Test ImageAnimator component" + }, + { + "name": "Test_multiple_images", + "value": "Test loading multiple identical images" + }, + { + "name": "Test_Task_error", + "value": "Test placeholder map Task error" + }, + { + "name": "Test_HSP", + "value": "Test HSP scene preloading" + }, + { + "name": "Test_SingleImage", + "value": "SingleImage" + }, + { + "name": "Test_custom_download", + "value": "Global custom download" + }, + { + "name": "Multiple_images", + "value": "Multiple images" + }, + { + "name": "Display_long_image", + "value": "Display long image" + }, + { + "name": "Image_scaling", + "value": "Image scaling" + }, + { + "name": "Message_list", + "value": "Message list" + }, + { + "name": "Custom_cache_key", + "value": "Custom cache key" + }, + { + "name": "Preloading_images_to_cache", + "value": "Preloading images to file cache" + }, + { + "name": "Retrieve_image_display_from_cache", + "value": "Retrieve image display from cache" + }, + { + "name": "Test_single_request_header", + "value": "Test a single request header" + }, + { + "name": "Test_write_cache_strategy", + "value": "Test write cache strategy" + }, + { + "name": "Image_Transformation", + "value": "Image Transformation" + }, + { + "name": "Different_ObjectFit", + "value": "Different ObjectFit" + }, + { + "name": "Test_image_loading_success_or_failure_events", + "value": "Test image loading success/failure events" + }, + { + "name": "Test_removing_image_cache_interface", + "value": "Test removing image cache interface" + }, + { + "name": "Test_error_image_display", + "value": "Test error image display" + }, + { + "name": "Test_media_URL", + "value": "Test media URL" + }, + { + "name": "Display_the_first_frame", + "value": "Display the first frame of the animation" + }, + { + "name": "Display_the_last_frame", + "value": "Display the last frame of the animation" + }, + { + "name": "Play", + "value": "Play" + }, + { + "name": "Pause", + "value": "Pause" + }, + { + "name": "Stop", + "value": "Stop" + }, + { + "name": "Infinite_loop", + "value": "Infinite loop" + }, + { + "name": "Play_once", + "value": "Play once" + }, + { + "name": "Play_twice", + "value": "Play twice" + }, + { + "name": "Local_SVG", + "value": "Local SVG image" + }, + { + "name": "Under_context_file", + "value": "Files under context file" + }, + { + "name": "Network_images", + "value": "Network images" + }, + { + "name": "Custom_network_download", + "value": "Custom network download" + }, + { + "name": "PixelMap_loads_images", + "value": "PixelMap loads images" + }, + { + "name": "Enlarge", + "value": "Enlarge" + }, + { + "name": "Reduce", + "value": "Reduce" + }, + { + "name": "Click_on_add", + "value": "Click on the size to add 50" + }, + { + "name": "Click_on_reduce", + "value": "Click to reduce size by 50" + }, + { + "name": "The_key_fixed_1", + "value": "The key is fixed at 1" + }, + { + "name": "The_key_changes_timestamp", + "value": "Key changes every time: timestamp" + }, + { + "name": "Load", + "value": "Load" + }, + { + "name": "Preloading_images_to_file_cache_using_URL", + "value": "Preloading images to file cache using URL" + }, + { + "name": "Preloading_images_to_file_cache_using_option", + "value": "Preloading images to file cache using option" + }, + { + "name": "Load_image_offline_after_preloading", + "value": "Load image (can be loaded offline after preloading)" + }, + { + "name": "Preloading_GIF", + "value": "Preloading GIF" + }, + { + "name": "Retrieve_GIF_from_memory", + "value": "Retrieve GIF from memory cache" + }, + { + "name": "Retrieve_GIF_from_disk", + "value": "Retrieve GIF from disk cache" + }, + { + "name": "Preloading_static_images", + "value": "Preloading static images" + }, + { + "name": "Retrieve_images_from_memory", + "value": "Retrieve images from memory cache" + }, + { + "name": "Retrieve_images_from_disk", + "value": "Retrieve images from memory disk" + }, + { + "name": "Write_memory_and_file", + "value": "Write to memory and file cache" + }, + { + "name": "Write_memory", + "value": "Write to memory cache" + }, + { + "name": "Write_file", + "value": "Write to file cache" + }, + { + "name": "Main_image_Fill", + "value": "Main image Fill Stretch Fill" + }, + { + "name": "Maintain_proportion_filling", + "value": "Maintain proportion filling in the placeholder map 'Include'" + }, + { + "name": "Error_graph_None", + "value": "Error graph None remains unchanged" + }, + { + "name": "Test_failure_success", + "value": "Test failure/success" + }, + { + "name": "Custom_download_failed", + "value": "Custom download failed" + }, + { + "name": "Retrieve_media_gallery", + "value": "Retrieve the URI of the media gallery and display it using ImageKnife" + }, + { + "name": "Click_load_Uri", + "value": "Click to load Uri and display" + }, + { + "name": "Delete_all_caches", + "value": "Delete all caches" + }, + { + "name": "Delete_all_memory_caches", + "value": "Delete all memory caches" + }, + { + "name": "Delete_all_file_caches", + "value": "Delete all file caches" + }, + { + "name": "Delete_all_custom_memory_caches", + "value": "Delete all custom memory caches" + }, + { + "name": "Delete_all_custom_file_caches", + "value": "Delete all custom file caches" + }, + { + "name": "Blur_effect", + "value": "Blur effect" + }, + { + "name": "Highlighting_effect", + "value": "Highlighting effect" + }, + { + "name": "Ashing_effect", + "value": "Ashing effect" + }, + { + "name": "Inverse_effect", + "value": "Inverse effect" + }, + { + "name": "Animation_filter_effect", + "value": "Animation filter effect" + }, + { + "name": "Crop_circular_effect", + "value": "Crop circular effect" + }, + { + "name": "Crop_circular_with_border_effect", + "value": "Crop circular with border effect" + }, + { + "name": "Contrast_effect", + "value": "Contrast effect" + }, + { + "name": "Black_ink_filtering_effect", + "value": "Black ink filtering effect" + }, + { + "name": "Rotate", + "value": "Rotate" + }, + { + "name": "Corners", + "value": "Corners" + }, + { + "name": "Kuwahara_Filter_effect", + "value": "Kuwahara filter effect" + }, + { + "name": "Pixelated_Filter_effect", + "value": "Pixelated filtering effect" + }, + { + "name": "Sketch_Filter_effect", + "value": "Sketch Filter effect" + }, + { + "name": "Distortion_Filter_effect", + "value": "Distortion Filter effect" + }, + { + "name": "Decorative_Filter_effect", + "value": "Decorative Filter effect" + }, + { + "name": "Square_cutting_effect", + "value": "Square cutting effect" + }, + { + "name": "Top_cutting_effect", + "value": "Top cutting effect" + }, + { + "name": "Middle_cutting_effect", + "value": "Middle cutting effect" + }, + { + "name": "Bottom_cutting_effect", + "value": "Bottom cutting effect" + }, + { + "name": "Mask_effect", + "value": "Mask effect" + }, + { + "name": "TIPS", + "value": "Please shut down the network first and ensure that there is no cache of images from this network in the test failure scenario locally" } ] } \ No newline at end of file diff --git a/entry/src/main/resources/base/media/webpAtanta.webp b/entry/src/main/resources/base/media/webpAtanta.webp new file mode 100644 index 0000000..affe2a5 Binary files /dev/null and b/entry/src/main/resources/base/media/webpAtanta.webp differ diff --git a/entry/src/main/resources/base/media/yunHeic.heic b/entry/src/main/resources/base/media/yunHeic.heic new file mode 100644 index 0000000..161e3ca Binary files /dev/null and b/entry/src/main/resources/base/media/yunHeic.heic differ diff --git a/entry/src/main/resources/base/profile/main_pages.json b/entry/src/main/resources/base/profile/main_pages.json index 42b571c..de593dd 100644 --- a/entry/src/main/resources/base/profile/main_pages.json +++ b/entry/src/main/resources/base/profile/main_pages.json @@ -22,6 +22,7 @@ "pages/TestCommonImage", "pages/ImageAnimatorPage", "pages/TestSetCustomImagePage", - "pages/TestErrorHolderPage" + "pages/TestErrorHolderPage", + "pages/TestTaskResourcePage" ] } \ No newline at end of file diff --git a/entry/src/main/resources/zh_CN/element/string.json b/entry/src/main/resources/zh_CN/element/string.json index 6250115..74fedfe 100644 --- a/entry/src/main/resources/zh_CN/element/string.json +++ b/entry/src/main/resources/zh_CN/element/string.json @@ -19,6 +19,350 @@ { "name": "app_permission_READ_IMAGEVIDEO", "value": "获取读媒体资源权限" + }, + { + "name": "Test_ImageAnimator", + "value": "测试ImageAnimator组件" + }, + { + "name": "Test_multiple_images", + "value": "测试加载多张相同图片" + }, + { + "name": "Test_Task_error", + "value": "测试占位图Task报错" + }, + { + "name": "Test_HSP", + "value": "测试HSP场景预加载" + }, + { + "name": "Test_SingleImage", + "value": "单个图片使用" + }, + { + "name": "Test_custom_download", + "value": "全局自定义下载" + }, + { + "name": "Multiple_images", + "value": "多图" + }, + { + "name": "Display_long_image", + "value": "长图显示" + }, + { + "name": "Image_scaling", + "value": "缩放图片" + }, + { + "name": "Message_list", + "value": "消息列表" + }, + { + "name": "Custom_cache_key", + "value": "自定义缓存key" + }, + { + "name": "Preloading_images_to_cache", + "value": "预加载图片到文件缓存" + }, + { + "name": "Retrieve_image_display_from_cache", + "value": "从缓存获取图片显示" + }, + { + "name": "Test_single_request_header", + "value": "测试单个请求头" + }, + { + "name": "Test_write_cache_strategy", + "value": "测试写入缓存策略" + }, + { + "name": "Image_Transformation", + "value": "图片变换" + }, + { + "name": "Different_ObjectFit", + "value": "不同的ObjectFit" + }, + { + "name": "Test_image_loading_success_or_failure_events", + "value": "测试图片加载成功/失败事件" + }, + { + "name": "Test_removing_image_cache_interface", + "value": "测试移除图片缓存接口" + }, + { + "name": "Test_error_image_display", + "value": "测试错误图显示" + }, + { + "name": "Display_the_first_frame", + "value": "动画显示第一帧" + }, + { + "name": "Display_the_last_frame", + "value": "动画显示最后一帧" + }, + { + "name": "Play", + "value": "播放" + }, + { + "name": "Pause", + "value": "暂停" + }, + { + "name": "Stop", + "value": "停止" + }, + { + "name": "Infinite_loop", + "value": "无限循环" + }, + { + "name": "Play_once", + "value": "播放一次" + }, + { + "name": "Play_twice", + "value": "播放两次" + }, + { + "name": "Local_SVG", + "value": "本地资源SVG图片" + }, + { + "name": "Under_context_file", + "value": "本地context files下文件" + }, + { + "name": "Network_images", + "value": "网络图片" + }, + { + "name": "Custom_network_download", + "value": "自定义下载" + }, + { + "name": "PixelMap_loads_images", + "value": "PixelMap加载图片" + }, + { + "name": "Enlarge", + "value": "放大" + }, + { + "name": "Reduce", + "value": "缩小" + }, + { + "name": "Click_on_add", + "value": "点击尺寸加50" + }, + { + "name": "Click_on_reduce", + "value": "点击尺寸减50" + }, + { + "name": "The_key_fixed_1", + "value": "key固定为 1" + }, + { + "name": "The_key_changes_timestamp", + "value": "key每次变化:时间戳" + }, + { + "name": "Load", + "value": "加载" + }, + { + "name": "Preloading_images_to_file_cache_using_URL", + "value": "url预加载图片到文件缓存" + }, + { + "name": "Preloading_images_to_file_cache_using_option", + "value": "option预加载图片到文件缓存" + }, + { + "name": "Load_image_offline_after_preloading", + "value": "加载图片(预加载后可断网加载)" + }, + { + "name": "Preloading_GIF", + "value": "预加载gif图" + }, + { + "name": "Retrieve_GIF_from_memory", + "value": "内存缓存获取gif" + }, + { + "name": "Retrieve_GIF_from_disk", + "value": "文件缓存获取gif" + }, + { + "name": "Preloading_static_images", + "value": "预加载静态图" + }, + { + "name": "Retrieve_images_from_memory", + "value": "内存缓存获取" + }, + { + "name": "Retrieve_images_from_disk", + "value": "文件缓存获取" + }, + { + "name": "Write_memory_and_file", + "value": "写入内存文件缓存" + }, + { + "name": "Write_memory", + "value": "写入内存缓存" + }, + { + "name": "Write_file", + "value": "写入文件缓存" + }, + { + "name": "Main_image_Fill", + "value": "主图Fill拉伸填充" + }, + { + "name": "Maintain_proportion_filling", + "value": "占位图Contain保持比例填充" + }, + { + "name": "Error_graph_None", + "value": "错误图None不变化" + }, + { + "name": "Test_failure_success", + "value": "测试失败/成功场景" + }, + { + "name": "Custom_download_failed", + "value": "自定义下载失败" + }, + { + "name": "Retrieve_media_gallery", + "value": "获取媒体图库的uri用ImageKnife展示" + }, + { + "name": "Click_load_Uri", + "value": "点击加载Uri并展示" + }, + { + "name": "Delete_all_caches", + "value": "删除全部缓存" + }, + { + "name": "Delete_all_memory_caches", + "value": "删除全部内存缓存" + }, + { + "name": "Delete_all_file_caches", + "value": "删除全部文件缓存" + }, + { + "name": "Delete_all_custom_memory_caches", + "value": "删除自定义内存缓存" + }, + { + "name": "Delete_all_custom_file_caches", + "value": "删除自定义文件缓存" + }, + { + "name": "Blur_effect", + "value": "模糊效果" + }, + { + "name": "Highlighting_effect", + "value": "高亮效果" + }, + { + "name": "Ashing_effect", + "value": "灰化效果" + }, + { + "name": "Inverse_effect", + "value": "反转效果" + }, + { + "name": "Animation_filter_effect", + "value": "动画滤镜效果" + }, + { + "name": "Crop_circular_effect", + "value": "裁剪圆形效果" + }, + { + "name": "Crop_circular_with_border_effect", + "value": "裁剪圆形带边框效果" + }, + { + "name": "Contrast_effect", + "value": "对比度效果" + }, + { + "name": "Black_ink_filtering_effect", + "value": "乌墨色滤波效果" + }, + { + "name": "Rotate", + "value": "旋转效果" + }, + { + "name": "Corners", + "value": "圆角效果" + }, + { + "name": "Kuwahara_Filter_effect", + "value": "桑原滤波效果" + }, + { + "name": "Pixelated_Filter_effect", + "value": "像素化滤波效果" + }, + { + "name": "Sketch_Filter_effect", + "value": "素描滤波效果" + }, + { + "name": "Distortion_Filter_effect", + "value": "扭曲滤波效果" + }, + { + "name": "Decorative_Filter_effect", + "value": "装饰滤波效果" + }, + { + "name": "Square_cutting_effect", + "value": "正方形裁剪效果" + }, + { + "name": "Top_cutting_effect", + "value": "上方裁剪效果" + }, + { + "name": "Middle_cutting_effect", + "value": "中间裁剪效果" + }, + { + "name": "Bottom_cutting_effect", + "value": "底下裁剪效果" + }, + { + "name": "Mask_effect", + "value": "遮罩效果" + }, + { + "name": "TIPS", + "value": "测试失败场景请先关闭网络,并保证本地没有此网络图片的缓存" } ] } \ No newline at end of file diff --git a/entry/src/ohosTest/ets/test/DefaultJobQueueTest.test.ets b/entry/src/ohosTest/ets/test/DefaultJobQueueTest.test.ets index eb13a71..71dfa05 100644 --- a/entry/src/ohosTest/ets/test/DefaultJobQueueTest.test.ets +++ b/entry/src/ohosTest/ets/test/DefaultJobQueueTest.test.ets @@ -14,8 +14,8 @@ */ import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; import { ImageKnifeOption, ImageKnifeRequest } from '@ohos/imageknife/Index'; -import { DefaultJobQueue } from '@ohos/imageknife/src/main/ets/utils/DefaultJobQueue'; -import { IJobQueue } from '@ohos/imageknife/src/main/ets/utils/IJobQueue'; +import { DefaultJobQueue } from '@ohos/imageknife/src/main/ets/queue/DefaultJobQueue'; +import { IJobQueue } from '@ohos/imageknife/src/main/ets/queue/IJobQueue'; import taskpool from '@ohos.taskpool'; import common from '@ohos.app.ability.common'; @@ -70,10 +70,10 @@ export default function DefaultJobQueueTest() { } function makeRequest(src: string, context: common.UIAbilityContext, priority?: taskpool.Priority): ImageKnifeRequest { - let option: ImageKnifeOption = { + let option: ImageKnifeOption = new ImageKnifeOption({ loadSrc: src, priority: priority - } + }) return new ImageKnifeRequest( option, context, diff --git a/entry/src/ohosTest/ets/test/FileLruCache.test.ets b/entry/src/ohosTest/ets/test/FileLruCache.test.ets index 2dd76f3..ed4d183 100644 --- a/entry/src/ohosTest/ets/test/FileLruCache.test.ets +++ b/entry/src/ohosTest/ets/test/FileLruCache.test.ets @@ -17,7 +17,7 @@ import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from import Constants from '../../../main/ets/common/Constants'; import taskpool from '@ohos.taskpool'; import { GlobalContext } from '../../../main/ets/common/GlobalContext'; -import { FileCache } from '@ohos/imageknife/src/main/ets/utils/FileCache'; +import { FileCache } from '@ohos/imageknife/src/main/ets/cache/FileCache'; import { IEngineKey, ImageKnifeOption } from '@ohos/imageknife'; import { DefaultEngineKey } from '@ohos/imageknife/src/main/ets/key/DefaultEngineKey'; @@ -153,9 +153,9 @@ export default function FileLruCacheTest() { }); it('fileCacheEngineKey', 0, () => { let engineKey: IEngineKey = new DefaultEngineKey() - let imageKnifeOption: ImageKnifeOption = { + let imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ loadSrc:"abc" - } + }) let imageKey = engineKey.generateFileKey(imageKnifeOption.loadSrc,"") let imageAnimatorKey = engineKey.generateFileKey(imageKnifeOption.loadSrc,"",true) expect(imageKey == imageAnimatorKey).assertFalse() diff --git a/entry/src/ohosTest/ets/test/ImageKnife.test.ets b/entry/src/ohosTest/ets/test/ImageKnife.test.ets index 8c6811f..7df3605 100644 --- a/entry/src/ohosTest/ets/test/ImageKnife.test.ets +++ b/entry/src/ohosTest/ets/test/ImageKnife.test.ets @@ -40,10 +40,10 @@ export default function ImageKnifeTest() { it('removeMemoryCache', 0, async () => { let a = 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp'; - let option: ImageKnifeOption = { + let option: ImageKnifeOption = new ImageKnifeOption({ loadSrc: 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', signature: '' - } + }) let key = ImageKnife.getInstance() .getEngineKeyImpl() .generateMemoryKey('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', ImageKnifeRequestSource.SRC, option) diff --git a/entry/src/ohosTest/ets/test/ImageKnifeOption.test.ets b/entry/src/ohosTest/ets/test/ImageKnifeOption.test.ets index ffd20b9..6a3acac 100644 --- a/entry/src/ohosTest/ets/test/ImageKnifeOption.test.ets +++ b/entry/src/ohosTest/ets/test/ImageKnifeOption.test.ets @@ -44,7 +44,7 @@ export default function ImageKnifeOptionTest() { imageWidth: 0, imageHeight: 0, } - let ImageKnifeOption: ImageKnifeOption = { + let imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ loadSrc: $r("app.media.rabbit"), onLoadListener: { onLoadFailed: (err) => { @@ -58,10 +58,10 @@ export default function ImageKnifeOptionTest() { return data; }, }, - } - if (ImageKnifeOption.onLoadListener && ImageKnifeOption.onLoadListener.onLoadSuccess && ImageKnifeOption.onLoadListener.onLoadFailed) { - ImageKnifeOption.onLoadListener.onLoadSuccess(a,imageData); - ImageKnifeOption.onLoadListener.onLoadFailed(a); + }) + if (imageKnifeOption.onLoadListener && imageKnifeOption.onLoadListener.onLoadSuccess && imageKnifeOption.onLoadListener.onLoadFailed) { + imageKnifeOption.onLoadListener.onLoadSuccess(a,imageData); + imageKnifeOption.onLoadListener.onLoadFailed(a); } expect(a).assertEqual(b); }); diff --git a/entry/src/ohosTest/ets/test/MemoryLruCache.test.ets b/entry/src/ohosTest/ets/test/MemoryLruCache.test.ets index 98f2514..d0d7302 100644 --- a/entry/src/ohosTest/ets/test/MemoryLruCache.test.ets +++ b/entry/src/ohosTest/ets/test/MemoryLruCache.test.ets @@ -17,7 +17,7 @@ import image from '@ohos.multimedia.image'; import Constants from '../../../main/ets/common/Constants'; -import { MemoryLruCache } from '@ohos/imageknife/src/main/ets/utils/MemoryLruCache'; +import { MemoryLruCache } from '@ohos/imageknife/src/main/ets/cache/MemoryLruCache'; import { ImageKnifeData } from '@ohos/imageknife/src/main/ets/model/ImageKnifeData'; import { IEngineKey, ImageKnifeOption,ImageKnifeRequestSource } from '@ohos/imageknife'; import { DefaultEngineKey } from '@ohos/imageknife/src/main/ets/key/DefaultEngineKey'; @@ -122,9 +122,9 @@ export default function MemoryLruCacheTest() { it('memoryCacheEngineKey', 0, () => { let engineKey: IEngineKey = new DefaultEngineKey() - let imageKnifeOption: ImageKnifeOption = { + let imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ loadSrc:"abc" - } + }) let imageKey = engineKey.generateMemoryKey(imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,imageKnifeOption) let imageAnimatorKey = engineKey.generateMemoryKey(imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,imageKnifeOption,true) expect(imageKey == imageAnimatorKey).assertFalse() diff --git a/entry/src/ohosTest/ets/test/SendableData.test.ets b/entry/src/ohosTest/ets/test/SendableData.test.ets new file mode 100644 index 0000000..e98f65d --- /dev/null +++ b/entry/src/ohosTest/ets/test/SendableData.test.ets @@ -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. + */ +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium' +import { SendableData } from '@ohos/imageknife/src/main/ets/components/imageknife/SendableData' + +export default function SendableDataTest() { + describe('SendableDataTest', ()=> { + // 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('TestPlaceHolderCacheKey', 0, () => { + let value: string = "placeholderRegisterCacheKey"; + let data: SendableData = new SendableData(); + data.setPlaceHolderRegisterCacheKey(value); + expect(data.getPlaceHolderRegisterCacheKey()).assertEqual(value); + }) + it('TestPlaceHolderMemoryCacheKey', 1, () => { + let value: string = "placeholderRegisterMemoryCacheKey"; + let data: SendableData = new SendableData(); + data.setPlaceHolderRegisterMemoryCacheKey(value); + expect(data.getPlaceHolderRegisterMemoryCacheKey()).assertEqual(value); + }) + }) +} \ No newline at end of file diff --git a/entry/src/ohosTest/ets/test/customdatafetchclient.test.ets b/entry/src/ohosTest/ets/test/customdatafetchclient.test.ets new file mode 100644 index 0000000..38109e7 --- /dev/null +++ b/entry/src/ohosTest/ets/test/customdatafetchclient.test.ets @@ -0,0 +1,106 @@ +/* + * 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 { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium' +import { DownloadClient } from '@ohos/imageknife/src/main/ets/components/imageknife/networkmanage/DownloadClient'; +import common from '@ohos.app.ability.common'; +import { GlobalContext } from '../testability/GlobalContext'; +import { CustomDataFetchClient, DataFetchResult, ImageKnifeGlobal, RequestOption } from '@ohos/imageknife'; + +const BASE_COUNT: number = 2000; + +export default function CustomDataFetchClientTest() { + describe('CustomDataFetchClientTest', () => { + // 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('TestIsLocalLoadSrc', 0, () => { + let path = 'invalid path'; + let client = new DownloadClient() + expect(client.isLocalLoadSrc(undefined, path)).assertFalse(); + let context: object | undefined = GlobalContext.getInstance().getObject("hapContext"); + if (context != undefined) { + let loadSrc1 = (context as common.UIAbilityContext).filesDir + 'a.jpg'; + let loadSrc2 = (context as common.UIAbilityContext).cacheDir + 'b.jpg'; + expect(client.isLocalLoadSrc(context, loadSrc1)).assertTrue(); + expect(client.isLocalLoadSrc(context, loadSrc2)).assertTrue(); + } + }) + it('TestLoadData', 1, async () => { + let client = new CustomDataFetchClient(); + let request = new RequestOption(); + request.loadSrc = $r('app.media.icon'); + let error = (await client.loadData(request) as DataFetchResult).error as String; + expect(error).assertEqual('CustomDataFetchClient request or loadSrc error.'); + }) + it('TestLoadData_customGetImage', 2, async () => { + let client = new CustomDataFetchClient(); + let request = new RequestOption(); + request.loadSrc = 'http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg'; + request.customGetImage = (context: Context, src: string) => { + // 这里是模拟的customGetImage逻辑 + return Promise.resolve(new DataFetchResult()); + } + console.log('LXH', 'TestLoadData 2 --1 customGetImage is undefined ?' + (request.customGetImage == undefined)); + let context: object | undefined = GlobalContext.getInstance().getObject("hapContext"); + let result = await client.loadData(request); + if (context != undefined) { + console.log('LXH', 'TestLoadData 2 --2'); + expect(typeof result) + .assertEqual(typeof (await request?.customGetImage(context as common.UIAbilityContext, request.loadSrc))); + } + }) + it('TestLoadData_combineArrayBuffers', 3, () => { + // 创建几个ArrayBuffer作为测试数据 + const arrayBuffer1 = new ArrayBuffer(4); + const uint8Array1 = new Uint8Array(arrayBuffer1); + uint8Array1[0] = 1; + uint8Array1[1] = 2; + uint8Array1[2] = 3; + uint8Array1[3] = 4; + + const arrayBuffer2 = new ArrayBuffer(2); + const uint8Array2 = new Uint8Array(arrayBuffer2); + uint8Array2[0] = 5; + uint8Array2[1] = 6; + let client = new CustomDataFetchClient(); + const combinedArrayBuffer = client.combineArrayBuffers([arrayBuffer1, arrayBuffer2]); + expect(combinedArrayBuffer.byteLength).assertEqual(6); + const combinedUint8Array = new Uint8Array(combinedArrayBuffer); + for (let i = 0; i < 4; i++) { + expect(combinedUint8Array[i]).assertEqual(uint8Array1[i]); + } + for (let i = 0; i < 2; i++) { + expect(combinedUint8Array[i + 4]).assertEqual(uint8Array2[i]); + } + }); + }) +} + diff --git a/entry/src/ohosTest/ets/test/imageknifeOption.test.ets b/entry/src/ohosTest/ets/test/imageknifeOption.test.ets new file mode 100644 index 0000000..6a3acac --- /dev/null +++ b/entry/src/ohosTest/ets/test/imageknifeOption.test.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 { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; +import { ImageKnifeOption,ImageKnifeData } from "@ohos/imageknife" + +export default function ImageKnifeOptionTest() { + describe('ImageKnifeOptionTest',() => { + // 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('onLoadListener', 0, () => { + let a = 'abc'; + let b: string = ''; + let imageData:ImageKnifeData = { + source: "", + imageWidth: 0, + imageHeight: 0, + } + let imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ + loadSrc: $r("app.media.rabbit"), + onLoadListener: { + onLoadFailed: (err) => { + console.error("Load Failed Reason: " + err); + }, + onLoadSuccess: (data,imageknifeData) => { + if(typeof data == 'string') { + return b = data; + } + imageData = imageknifeData + return data; + }, + }, + }) + if (imageKnifeOption.onLoadListener && imageKnifeOption.onLoadListener.onLoadSuccess && imageKnifeOption.onLoadListener.onLoadFailed) { + imageKnifeOption.onLoadListener.onLoadSuccess(a,imageData); + imageKnifeOption.onLoadListener.onLoadFailed(a); + } + expect(a).assertEqual(b); + }); + }); +} \ No newline at end of file diff --git a/entry/src/ohosTest/module.json5 b/entry/src/ohosTest/module.json5 index d0dc5d5..4fc9701 100644 --- a/entry/src/ohosTest/module.json5 +++ b/entry/src/ohosTest/module.json5 @@ -5,9 +5,8 @@ "description": "$string:module_test_desc", "mainElement": "TestAbility", "deviceTypes": [ - "phone", - "tablet", - "2in1" + "default", + "tablet" ], "deliveryWithInstall": true, "installationFree": false, diff --git a/gpu_transform/CHANGELOG.md b/gpu_transform/CHANGELOG.md index 3189513..8898f8d 100644 --- a/gpu_transform/CHANGELOG.md +++ b/gpu_transform/CHANGELOG.md @@ -1,7 +1,11 @@ -## 1.0.3 +## 1.0.4 - 修改门禁编译问题 修改点如下 +- 修改src/main/cpp/boundscheck/CMakeLists.txt文件中的内容 - 修改src/main/cpp/util/DebugLog.h文件中hilog的大小写 +## 1.0.3 +- 安全编译开启Strip和Ftrapv + ## 1.0.2 - 支持x86编译 diff --git a/gpu_transform/build-profile.json5 b/gpu_transform/build-profile.json5 index c3f8f1b..f4b0a30 100644 --- a/gpu_transform/build-profile.json5 +++ b/gpu_transform/build-profile.json5 @@ -3,7 +3,7 @@ "buildOption": { "externalNativeOptions": { "path": "./src/main/cpp/CMakeLists.txt", - "arguments": "", + "arguments": " -DCMAKE_BUILD_TYPE=Release", "abiFilters": [ "armeabi-v7a", "arm64-v8a", diff --git a/gpu_transform/oh-package.json5 b/gpu_transform/oh-package.json5 index 1eb6bf3..1526ae0 100644 --- a/gpu_transform/oh-package.json5 +++ b/gpu_transform/oh-package.json5 @@ -14,7 +14,7 @@ "main": "index.ets", "repository": "https://gitee.com/openharmony-tpc/ImageKnife", "type": "module", - "version": "1.0.3", + "version": "1.0.4", "tags": [ "Tool" ], diff --git a/gpu_transform/src/main/cpp/CMakeLists.txt b/gpu_transform/src/main/cpp/CMakeLists.txt index 6407f87..0751911 100644 --- a/gpu_transform/src/main/cpp/CMakeLists.txt +++ b/gpu_transform/src/main/cpp/CMakeLists.txt @@ -11,8 +11,11 @@ include_directories(${NATIVERENDER_ROOT_PATH} ${NATIVERENDER_ROOT_PATH}/common ${NATIVERENDER_ROOT_PATH}/render ${NATIVERENDER_ROOT_PATH}/constant + ${NATIVERENDER_ROOT_PATH}/boundscheck ) +add_subdirectory(boundscheck) + add_library(nativeGpu SHARED ${NATIVERENDER_ROOT_PATH}/napi/napi_init.cpp ${NATIVERENDER_ROOT_PATH}/render/EGLRender.cpp @@ -30,4 +33,4 @@ find_library ( GLES-lib GLESv3 ) -target_link_libraries(nativeGpu PUBLIC ${hilog-lib} ${EGL-lib} ${GLES-lib} libace_napi.z.so libc++.a) \ No newline at end of file +target_link_libraries(nativeGpu PUBLIC boundscheck ${hilog-lib} ${EGL-lib} ${GLES-lib} libace_napi.z.so -s -ftrapv) \ No newline at end of file diff --git a/gpu_transform/src/main/cpp/boundscheck/CMakeLists.txt b/gpu_transform/src/main/cpp/boundscheck/CMakeLists.txt new file mode 100644 index 0000000..c1bb6a6 --- /dev/null +++ b/gpu_transform/src/main/cpp/boundscheck/CMakeLists.txt @@ -0,0 +1,27 @@ +# the minimum version of CMake. +cmake_minimum_required(VERSION 3.4.1) + +set(can_use_assembler TRUE) +enable_language(ASM) +IF("${OHOS_ARCH}" STREQUAL "arm64-v8a") + SET(ASM_OPTIONS "-x assembler-with-cpp") + SET(CMAKE_ASM_FLAGS "${CFLAGS} ${ASM_OPTIONS} -march=armv8+crypto -D__OHOS__") +ENDIF() + +project(boundscheck) + +set(TAGET_BOUNDSCHECK_SRC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/third_party_bounds_checking_function/src) + +add_library(boundscheck + STATIC + ${TAGET_BOUNDSCHECK_SRC_PATH}/memcpy_s.c + ${TAGET_BOUNDSCHECK_SRC_PATH}/memset_s.c + ${TAGET_BOUNDSCHECK_SRC_PATH}/securecutil.c) + +target_precompile_headers(boundscheck PUBLIC ${CMAKE_SYSROOT}/usr/include/stdint.h) + +include_directories(${TAGET_BOUNDSCHECK_SRC_PATH} + ${CMAKE_CURRENT_SOURCE_DIR}/third_party_bounds_checking_function/include + ) + +target_link_libraries(boundscheck) diff --git a/gpu_transform/src/main/cpp/boundscheck/third_party_bounds_checking_function b/gpu_transform/src/main/cpp/boundscheck/third_party_bounds_checking_function new file mode 160000 index 0000000..a45b3ac --- /dev/null +++ b/gpu_transform/src/main/cpp/boundscheck/third_party_bounds_checking_function @@ -0,0 +1 @@ +Subproject commit a45b3aceed2c0138babc951850445d1cd010ce48 diff --git a/gpu_transform/src/main/cpp/render/EGLRender.cpp b/gpu_transform/src/main/cpp/render/EGLRender.cpp index 0a051de..f0ef9b2 100644 --- a/gpu_transform/src/main/cpp/render/EGLRender.cpp +++ b/gpu_transform/src/main/cpp/render/EGLRender.cpp @@ -535,7 +535,10 @@ void EGLRender::SetImageData(uint8_t *pData, int width, int height) m_RenderImage.height = height; m_RenderImage.format = IMAGE_FORMAT_RGBA; NativeImageUtil::AllocNativeImage(&m_RenderImage); - memcpy(m_RenderImage.ppPlane[0], pData, width * height * DEFAULT_FOUR); + if (memcpy_s(m_RenderImage.ppPlane[0], + width * height * DEFAULT_FOUR, pData, width * height * DEFAULT_FOUR) != EOK) { + return; + } glBindTexture(GL_TEXTURE_2D, m_ImageTextureId); glTexImage2D(GL_TEXTURE_2D, diff --git a/gpu_transform/src/main/cpp/util/NapiUtil.cpp b/gpu_transform/src/main/cpp/util/NapiUtil.cpp index eba879f..271e7b2 100644 --- a/gpu_transform/src/main/cpp/util/NapiUtil.cpp +++ b/gpu_transform/src/main/cpp/util/NapiUtil.cpp @@ -26,6 +26,7 @@ #include #include #include "DebugLog.h" +#include "third_party_bounds_checking_function/include/securec.h" const int32_t MAX_STR_LENGTH = 1024; @@ -41,7 +42,7 @@ void NapiUtil::JsValueToString(const napi_env &env, const napi_value &value, con LOGI("%s nullptr js object to string malloc failed", __func__); return; } - (void) memset(buf.get(), 0, bufLen); + (void) memset_s(buf.get(), bufLen, 0, bufLen); size_t result = 0; napi_get_value_string_utf8(env, value, buf.get(), bufLen, &result); target = buf.get(); diff --git a/gpu_transform/src/main/cpp/util/NativeImage.h b/gpu_transform/src/main/cpp/util/NativeImage.h index d79018d..c97c0f1 100644 --- a/gpu_transform/src/main/cpp/util/NativeImage.h +++ b/gpu_transform/src/main/cpp/util/NativeImage.h @@ -30,6 +30,7 @@ #include #include "DebugLog.h" #include "constant/constant_shape.h" +#include "third_party_bounds_checking_function/include/securec.h" #define IMAGE_FORMAT_RGBA 0x01 #define IMAGE_FORMAT_NV21 0x02 @@ -48,7 +49,7 @@ #define IMAGE_FORMAT_GRAY_EXT "GRAY" #define IMAGE_FORMAT_I444_EXT "I444" #define IMAGE_FORMAT_P010_EXT "P010" // 16bit NV21 - +#define EOK 0 struct NativeImage { int width; @@ -140,7 +141,9 @@ public: if (napi_create_arraybuffer(env, srcLen, &nativePtr, res) != napi_ok || nativePtr == nullptr) { return false; } - memcpy(nativePtr, src, srcLen); + if (memcpy_s(nativePtr, srcLen, src, srcLen) != EOK) { + return false; + } return true; } @@ -149,10 +152,17 @@ public: int totalLength = width * height * DEFAULT_FOUR; int oneLineLength = width * DEFAULT_FOUR; uint8_t* tmp = (uint8_t*)malloc(totalLength); - memcpy(tmp, *buf, totalLength); - memset(*buf, DEFAULT_ZERO, sizeof(uint8_t)*totalLength); + if (memcpy_s(tmp, totalLength, *buf, totalLength) != EOK) { + return; + } + if (memset_s(*buf, sizeof(uint8_t)*totalLength, DEFAULT_ZERO, sizeof(uint8_t)*totalLength) != EOK) { + return; + } for (int i = 0; i < height; i++) { - memcpy(*buf + oneLineLength * i, tmp + totalLength - oneLineLength * (i+1), oneLineLength); + if (memcpy_s(*buf + oneLineLength * i, oneLineLength, + tmp + totalLength - oneLineLength * (i+1), oneLineLength) != EOK) { + break; + } } free(tmp); } diff --git a/hvigor/hvigor-config.json5 b/hvigor/hvigor-config.json5 index 8c56bf6..eb0d70f 100644 --- a/hvigor/hvigor-config.json5 +++ b/hvigor/hvigor-config.json5 @@ -1,6 +1,7 @@ { - "modelVersion": "5.0.0", + "hvigorVersion": "4.0.2", "dependencies": { + "@ohos/hvigor-ohos-plugin": "4.0.2" }, "execution": { // "analyze": "default", /* Define the build analyze mode. Value: [ "default" | "verbose" | false ]. Default: "default" */ @@ -18,4 +19,4 @@ "nodeOptions": { // "maxOldSpaceSize": 4096 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process */ } -} \ No newline at end of file +} diff --git a/hvigor/hvigor-wrapper.js b/hvigor/hvigor-wrapper.js new file mode 100644 index 0000000..26073b8 --- /dev/null +++ b/hvigor/hvigor-wrapper.js @@ -0,0 +1 @@ +"use strict";var u=require("path"),D=require("os"),e=require("fs"),t=require("crypto"),r=require("child_process"),n="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},i={},C={},E=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(C,"__esModule",{value:!0}),C.maxPathLength=C.isMac=C.isLinux=C.isWindows=void 0;const F=E(D),A="Windows_NT",o="Darwin";function a(){return F.default.type()===A}function c(){return F.default.type()===o}C.isWindows=a,C.isLinux=function(){return"Linux"===F.default.type()},C.isMac=c,C.maxPathLength=function(){return c()?1016:a()?259:4095},function(e){var t=n&&n.__createBinding||(Object.create?function(u,D,e,t){void 0===t&&(t=e);var r=Object.getOwnPropertyDescriptor(D,e);r&&!("get"in r?!D.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return D[e]}}),Object.defineProperty(u,t,r)}:function(u,D,e,t){void 0===t&&(t=e),u[t]=D[e]}),r=n&&n.__setModuleDefault||(Object.create?function(u,D){Object.defineProperty(u,"default",{enumerable:!0,value:D})}:function(u,D){u.default=D}),i=n&&n.__importStar||function(u){if(u&&u.__esModule)return u;var D={};if(null!=u)for(var e in u)"default"!==e&&Object.prototype.hasOwnProperty.call(u,e)&&t(D,u,e);return r(D,u),D};Object.defineProperty(e,"__esModule",{value:!0}),e.ENABLE_SIGN_TASK_KEY=e.HVIGOR_CACHE_DIR_KEY=e.WORK_SPACE=e.HVIGOR_PROJECT_WRAPPER_HOME=e.HVIGOR_PROJECT_ROOT_DIR=e.HVIGOR_PROJECT_CACHES_HOME=e.HVIGOR_PNPM_STORE_PATH=e.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH=e.PROJECT_CACHES=e.HVIGOR_WRAPPER_TOOLS_HOME=e.HVIGOR_USER_HOME=e.DEFAULT_PACKAGE_JSON=e.DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME=e.PNPM=e.HVIGOR=e.NPM_TOOL=e.PNPM_TOOL=e.HVIGOR_ENGINE_PACKAGE_NAME=void 0;const E=i(D),F=i(u),A=C;e.HVIGOR_ENGINE_PACKAGE_NAME="@ohos/hvigor",e.PNPM_TOOL=(0,A.isWindows)()?"pnpm.cmd":"pnpm",e.NPM_TOOL=(0,A.isWindows)()?"npm.cmd":"npm",e.HVIGOR="hvigor",e.PNPM="pnpm",e.DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME="hvigor-config.json5",e.DEFAULT_PACKAGE_JSON="package.json",e.HVIGOR_USER_HOME=F.resolve(E.homedir(),".hvigor"),e.HVIGOR_WRAPPER_TOOLS_HOME=F.resolve(e.HVIGOR_USER_HOME,"wrapper","tools"),e.PROJECT_CACHES="project_caches",e.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH=F.resolve(e.HVIGOR_WRAPPER_TOOLS_HOME,"node_modules",".bin",e.PNPM_TOOL),e.HVIGOR_PNPM_STORE_PATH=F.resolve(e.HVIGOR_USER_HOME,"caches"),e.HVIGOR_PROJECT_CACHES_HOME=F.resolve(e.HVIGOR_USER_HOME,e.PROJECT_CACHES),e.HVIGOR_PROJECT_ROOT_DIR=process.cwd(),e.HVIGOR_PROJECT_WRAPPER_HOME=F.resolve(e.HVIGOR_PROJECT_ROOT_DIR,e.HVIGOR),e.WORK_SPACE="workspace",e.HVIGOR_CACHE_DIR_KEY="hvigor.cacheDir",e.ENABLE_SIGN_TASK_KEY="enableSignTask"}(i);var s={},l={};Object.defineProperty(l,"__esModule",{value:!0}),l.logInfoPrintConsole=l.logErrorAndExit=void 0,l.logErrorAndExit=function(u){u instanceof Error?console.error(u.message):console.error(u),process.exit(-1)},l.logInfoPrintConsole=function(u){console.log(u)};var B=n&&n.__createBinding||(Object.create?function(u,D,e,t){void 0===t&&(t=e);var r=Object.getOwnPropertyDescriptor(D,e);r&&!("get"in r?!D.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return D[e]}}),Object.defineProperty(u,t,r)}:function(u,D,e,t){void 0===t&&(t=e),u[t]=D[e]}),d=n&&n.__setModuleDefault||(Object.create?function(u,D){Object.defineProperty(u,"default",{enumerable:!0,value:D})}:function(u,D){u.default=D}),f=n&&n.__importStar||function(u){if(u&&u.__esModule)return u;var D={};if(null!=u)for(var e in u)"default"!==e&&Object.prototype.hasOwnProperty.call(u,e)&&B(D,u,e);return d(D,u),D};Object.defineProperty(s,"__esModule",{value:!0});var _=s.executeBuild=void 0;const O=f(e),p=f(u),h=l;_=s.executeBuild=function(u){const D=p.resolve(u,"node_modules","@ohos","hvigor","bin","hvigor.js");try{const u=O.realpathSync(D);require(u)}catch(e){(0,h.logErrorAndExit)(`Error: ENOENT: no such file ${D},delete ${u} and retry.`)}};var P={},v={};!function(u){var D=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(u,"__esModule",{value:!0}),u.hashFile=u.hash=u.createHash=void 0;const r=D(t),i=D(e);u.createHash=(u="MD5")=>r.default.createHash(u);u.hash=(D,e)=>(0,u.createHash)(e).update(D).digest("hex");u.hashFile=(D,e)=>{if(i.default.existsSync(D))return(0,u.hash)(i.default.readFileSync(D,"utf-8"),e)}}(v);var g={},m={},R={};Object.defineProperty(R,"__esModule",{value:!0}),R.Unicode=void 0;class I{}R.Unicode=I,I.SPACE_SEPARATOR=/[\u1680\u2000-\u200A\u202F\u205F\u3000]/,I.ID_START=/[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]/,I.ID_CONTINUE=/[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u08D4-\u08E1\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u09FC\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9-\u0AFF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C80-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D00-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D54-\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1CD0-\u1CD2\u1CD4-\u1CF9\u1D00-\u1DF9\u1DFB-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C5\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE3E\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC00-\uDC4A\uDC50-\uDC59\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDE00-\uDE3E\uDE47\uDE50-\uDE83\uDE86-\uDE99\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC36\uDC38-\uDC40\uDC50-\uDC59\uDC72-\uDC8F\uDC92-\uDCA7\uDCA9-\uDCB6\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD36\uDD3A\uDD3C\uDD3D\uDD3F-\uDD47\uDD50-\uDD59]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD838[\uDC00-\uDC06\uDC08-\uDC18\uDC1B-\uDC21\uDC23\uDC24\uDC26-\uDC2A]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6\uDD00-\uDD4A\uDD50-\uDD59]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/,Object.defineProperty(m,"__esModule",{value:!0}),m.JudgeUtil=void 0;const y=R;m.JudgeUtil=class{static isIgnoreChar(u){return"string"==typeof u&&("\t"===u||"\v"===u||"\f"===u||" "===u||" "===u||"\ufeff"===u||"\n"===u||"\r"===u||"\u2028"===u||"\u2029"===u)}static isSpaceSeparator(u){return"string"==typeof u&&y.Unicode.SPACE_SEPARATOR.test(u)}static isIdStartChar(u){return"string"==typeof u&&(u>="a"&&u<="z"||u>="A"&&u<="Z"||"$"===u||"_"===u||y.Unicode.ID_START.test(u))}static isIdContinueChar(u){return"string"==typeof u&&(u>="a"&&u<="z"||u>="A"&&u<="Z"||u>="0"&&u<="9"||"$"===u||"_"===u||"‌"===u||"‍"===u||y.Unicode.ID_CONTINUE.test(u))}static isDigitWithoutZero(u){return/[1-9]/.test(u)}static isDigit(u){return"string"==typeof u&&/[0-9]/.test(u)}static isHexDigit(u){return"string"==typeof u&&/[0-9A-Fa-f]/.test(u)}};var N=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(g,"__esModule",{value:!0}),g.parseJsonText=g.parseJsonFile=void 0;const S=N(e),b=N(D),w=N(u),H=m;var x;!function(u){u[u.Char=0]="Char",u[u.EOF=1]="EOF",u[u.Identifier=2]="Identifier"}(x||(x={}));let M,T,G,V,j,J,U="start",L=[],W=0,$=1,K=0,k=!1,z="default",q="'",Z=1;function Y(u,D=!1){T=String(u),U="start",L=[],W=0,$=1,K=0,V=void 0,k=D;do{M=X(),nu[U]()}while("eof"!==M.type);return V}function X(){for(z="default",j="",q="'",Z=1;;){J=Q();const u=Du[z]();if(u)return u}}function Q(){if(T[W])return String.fromCodePoint(T.codePointAt(W))}function uu(){const u=Q();return"\n"===u?($++,K=0):u?K+=u.length:K++,u&&(W+=u.length),u}g.parseJsonFile=function(u,D=!1,e="utf-8"){const t=S.default.readFileSync(w.default.resolve(u),{encoding:e});try{return Y(t,D)}catch(D){if(D instanceof SyntaxError){const e=D.message.split("at");if(2===e.length)throw new Error(`${e[0].trim()}${b.default.EOL}\t at ${u}:${e[1].trim()}`)}throw new Error(`${u} is not in valid JSON/JSON5 format.`)}},g.parseJsonText=Y;const Du={default(){switch(J){case"/":return uu(),void(z="comment");case void 0:return uu(),eu("eof")}if(!H.JudgeUtil.isIgnoreChar(J)&&!H.JudgeUtil.isSpaceSeparator(J))return Du[U]();uu()},start(){z="value"},beforePropertyName(){switch(J){case"$":case"_":return j=uu(),void(z="identifierName");case"\\":return uu(),void(z="identifierNameStartEscape");case"}":return eu("punctuator",uu());case'"':case"'":return q=J,uu(),void(z="string")}if(H.JudgeUtil.isIdStartChar(J))return j+=uu(),void(z="identifierName");throw Fu(x.Char,uu())},afterPropertyName(){if(":"===J)return eu("punctuator",uu());throw Fu(x.Char,uu())},beforePropertyValue(){z="value"},afterPropertyValue(){switch(J){case",":case"}":return eu("punctuator",uu())}throw Fu(x.Char,uu())},beforeArrayValue(){if("]"===J)return eu("punctuator",uu());z="value"},afterArrayValue(){switch(J){case",":case"]":return eu("punctuator",uu())}throw Fu(x.Char,uu())},end(){throw Fu(x.Char,uu())},comment(){switch(J){case"*":return uu(),void(z="multiLineComment");case"/":return uu(),void(z="singleLineComment")}throw Fu(x.Char,uu())},multiLineComment(){switch(J){case"*":return uu(),void(z="multiLineCommentAsterisk");case void 0:throw Fu(x.Char,uu())}uu()},multiLineCommentAsterisk(){switch(J){case"*":return void uu();case"/":return uu(),void(z="default");case void 0:throw Fu(x.Char,uu())}uu(),z="multiLineComment"},singleLineComment(){switch(J){case"\n":case"\r":case"\u2028":case"\u2029":return uu(),void(z="default");case void 0:return uu(),eu("eof")}uu()},value(){switch(J){case"{":case"[":return eu("punctuator",uu());case"n":return uu(),tu("ull"),eu("null",null);case"t":return uu(),tu("rue"),eu("boolean",!0);case"f":return uu(),tu("alse"),eu("boolean",!1);case"-":case"+":return"-"===uu()&&(Z=-1),void(z="numerical");case".":case"0":case"I":case"N":return void(z="numerical");case'"':case"'":return q=J,uu(),j="",void(z="string")}if(void 0===J||!H.JudgeUtil.isDigitWithoutZero(J))throw Fu(x.Char,uu());z="numerical"},numerical(){switch(J){case".":return j=uu(),void(z="decimalPointLeading");case"0":return j=uu(),void(z="zero");case"I":return uu(),tu("nfinity"),eu("numeric",Z*(1/0));case"N":return uu(),tu("aN"),eu("numeric",NaN)}if(void 0!==J&&H.JudgeUtil.isDigitWithoutZero(J))return j=uu(),void(z="decimalInteger");throw Fu(x.Char,uu())},zero(){switch(J){case".":case"e":case"E":return void(z="decimal");case"x":case"X":return j+=uu(),void(z="hexadecimal")}return eu("numeric",0)},decimalInteger(){switch(J){case".":case"e":case"E":return void(z="decimal")}if(!H.JudgeUtil.isDigit(J))return eu("numeric",Z*Number(j));j+=uu()},decimal(){switch(J){case".":j+=uu(),z="decimalFraction";break;case"e":case"E":j+=uu(),z="decimalExponent"}},decimalPointLeading(){if(H.JudgeUtil.isDigit(J))return j+=uu(),void(z="decimalFraction");throw Fu(x.Char,uu())},decimalFraction(){switch(J){case"e":case"E":return j+=uu(),void(z="decimalExponent")}if(!H.JudgeUtil.isDigit(J))return eu("numeric",Z*Number(j));j+=uu()},decimalExponent(){switch(J){case"+":case"-":return j+=uu(),void(z="decimalExponentSign")}if(H.JudgeUtil.isDigit(J))return j+=uu(),void(z="decimalExponentInteger");throw Fu(x.Char,uu())},decimalExponentSign(){if(H.JudgeUtil.isDigit(J))return j+=uu(),void(z="decimalExponentInteger");throw Fu(x.Char,uu())},decimalExponentInteger(){if(!H.JudgeUtil.isDigit(J))return eu("numeric",Z*Number(j));j+=uu()},hexadecimal(){if(H.JudgeUtil.isHexDigit(J))return j+=uu(),void(z="hexadecimalInteger");throw Fu(x.Char,uu())},hexadecimalInteger(){if(!H.JudgeUtil.isHexDigit(J))return eu("numeric",Z*Number(j));j+=uu()},identifierNameStartEscape(){if("u"!==J)throw Fu(x.Char,uu());uu();const u=ru();switch(u){case"$":case"_":break;default:if(!H.JudgeUtil.isIdStartChar(u))throw Fu(x.Identifier)}j+=u,z="identifierName"},identifierName(){switch(J){case"$":case"_":case"‌":case"‍":return void(j+=uu());case"\\":return uu(),void(z="identifierNameEscape")}if(!H.JudgeUtil.isIdContinueChar(J))return eu("identifier",j);j+=uu()},identifierNameEscape(){if("u"!==J)throw Fu(x.Char,uu());uu();const u=ru();switch(u){case"$":case"_":case"‌":case"‍":break;default:if(!H.JudgeUtil.isIdContinueChar(u))throw Fu(x.Identifier)}j+=u,z="identifierName"},string(){switch(J){case"\\":return uu(),void(j+=function(){const u=Q(),D=function(){switch(Q()){case"b":return uu(),"\b";case"f":return uu(),"\f";case"n":return uu(),"\n";case"r":return uu(),"\r";case"t":return uu(),"\t";case"v":return uu(),"\v"}return}();if(D)return D;switch(u){case"0":if(uu(),H.JudgeUtil.isDigit(Q()))throw Fu(x.Char,uu());return"\0";case"x":return uu(),function(){let u="",D=Q();if(!H.JudgeUtil.isHexDigit(D))throw Fu(x.Char,uu());if(u+=uu(),D=Q(),!H.JudgeUtil.isHexDigit(D))throw Fu(x.Char,uu());return u+=uu(),String.fromCodePoint(parseInt(u,16))}();case"u":return uu(),ru();case"\n":case"\u2028":case"\u2029":return uu(),"";case"\r":return uu(),"\n"===Q()&&uu(),""}if(void 0===u||H.JudgeUtil.isDigitWithoutZero(u))throw Fu(x.Char,uu());return uu()}());case'"':case"'":if(J===q){const u=eu("string",j);return uu(),u}return void(j+=uu());case"\n":case"\r":case void 0:throw Fu(x.Char,uu());case"\u2028":case"\u2029":!function(u){console.warn(`JSON5: '${Eu(u)}' in strings is not valid ECMAScript; consider escaping.`)}(J)}j+=uu()}};function eu(u,D){return{type:u,value:D,line:$,column:K}}function tu(u){for(const D of u){if(Q()!==D)throw Fu(x.Char,uu());uu()}}function ru(){let u="",D=4;for(;D-- >0;){const D=Q();if(!H.JudgeUtil.isHexDigit(D))throw Fu(x.Char,uu());u+=uu()}return String.fromCodePoint(parseInt(u,16))}const nu={start(){if("eof"===M.type)throw Fu(x.EOF);iu()},beforePropertyName(){switch(M.type){case"identifier":case"string":return G=M.value,void(U="afterPropertyName");case"punctuator":return void Cu();case"eof":throw Fu(x.EOF)}},afterPropertyName(){if("eof"===M.type)throw Fu(x.EOF);U="beforePropertyValue"},beforePropertyValue(){if("eof"===M.type)throw Fu(x.EOF);iu()},afterPropertyValue(){if("eof"===M.type)throw Fu(x.EOF);switch(M.value){case",":return void(U="beforePropertyName");case"}":Cu()}},beforeArrayValue(){if("eof"===M.type)throw Fu(x.EOF);"punctuator"!==M.type||"]"!==M.value?iu():Cu()},afterArrayValue(){if("eof"===M.type)throw Fu(x.EOF);switch(M.value){case",":return void(U="beforeArrayValue");case"]":Cu()}},end(){}};function iu(){const u=function(){let u;switch(M.type){case"punctuator":switch(M.value){case"{":u={};break;case"[":u=[]}break;case"null":case"boolean":case"numeric":case"string":u=M.value}return u}();if(k&&"object"==typeof u&&(u._line=$,u._column=K),void 0===V)V=u;else{const D=L[L.length-1];Array.isArray(D)?k&&"object"!=typeof u?D.push({value:u,_line:$,_column:K}):D.push(u):D[G]=k&&"object"!=typeof u?{value:u,_line:$,_column:K}:u}!function(u){if(u&&"object"==typeof u)L.push(u),U=Array.isArray(u)?"beforeArrayValue":"beforePropertyName";else{const u=L[L.length-1];U=u?Array.isArray(u)?"afterArrayValue":"afterPropertyValue":"end"}}(u)}function Cu(){L.pop();const u=L[L.length-1];U=u?Array.isArray(u)?"afterArrayValue":"afterPropertyValue":"end"}function Eu(u){const D={"'":"\\'",'"':'\\"',"\\":"\\\\","\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\v":"\\v","\0":"\\0","\u2028":"\\u2028","\u2029":"\\u2029"};if(D[u])return D[u];if(u<" "){const D=u.charCodeAt(0).toString(16);return`\\x${`00${D}`.substring(D.length)}`}return u}function Fu(u,D){let e="";switch(u){case x.Char:e=void 0===D?`JSON5: invalid end of input at ${$}:${K}`:`JSON5: invalid character '${Eu(D)}' at ${$}:${K}`;break;case x.EOF:e=`JSON5: invalid end of input at ${$}:${K}`;break;case x.Identifier:K-=5,e=`JSON5: invalid identifier character at ${$}:${K}`}const t=new Au(e);return t.lineNumber=$,t.columnNumber=K,t}class Au extends SyntaxError{}var ou={},au=n&&n.__createBinding||(Object.create?function(u,D,e,t){void 0===t&&(t=e);var r=Object.getOwnPropertyDescriptor(D,e);r&&!("get"in r?!D.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return D[e]}}),Object.defineProperty(u,t,r)}:function(u,D,e,t){void 0===t&&(t=e),u[t]=D[e]}),cu=n&&n.__setModuleDefault||(Object.create?function(u,D){Object.defineProperty(u,"default",{enumerable:!0,value:D})}:function(u,D){u.default=D}),su=n&&n.__importStar||function(u){if(u&&u.__esModule)return u;var D={};if(null!=u)for(var e in u)"default"!==e&&Object.prototype.hasOwnProperty.call(u,e)&&au(D,u,e);return cu(D,u),D},lu=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(ou,"__esModule",{value:!0}),ou.isFileExists=ou.offlinePluginConversion=ou.executeCommand=ou.getNpmPath=ou.hasNpmPackInPaths=void 0;const Bu=r,du=lu(e),fu=su(u),_u=i,Ou=l;ou.hasNpmPackInPaths=function(u,D){try{return require.resolve(u,{paths:[...D]}),!0}catch(u){return!1}},ou.getNpmPath=function(){const u=process.execPath;return fu.join(fu.dirname(u),_u.NPM_TOOL)},ou.executeCommand=function(u,D,e){0!==(0,Bu.spawnSync)(u,D,e).status&&(0,Ou.logErrorAndExit)(`Error: ${u} ${D} execute failed.See above for details.`)},ou.offlinePluginConversion=function(u,D){return D.startsWith("file:")||D.endsWith(".tgz")?fu.resolve(u,_u.HVIGOR,D.replace("file:","")):D},ou.isFileExists=function(u){return du.default.existsSync(u)&&du.default.statSync(u).isFile()};var pu=n&&n.__createBinding||(Object.create?function(u,D,e,t){void 0===t&&(t=e);var r=Object.getOwnPropertyDescriptor(D,e);r&&!("get"in r?!D.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return D[e]}}),Object.defineProperty(u,t,r)}:function(u,D,e,t){void 0===t&&(t=e),u[t]=D[e]}),hu=n&&n.__setModuleDefault||(Object.create?function(u,D){Object.defineProperty(u,"default",{enumerable:!0,value:D})}:function(u,D){u.default=D}),Pu=n&&n.__importStar||function(u){if(u&&u.__esModule)return u;var D={};if(null!=u)for(var e in u)"default"!==e&&Object.prototype.hasOwnProperty.call(u,e)&&pu(D,u,e);return hu(D,u),D},vu=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(P,"__esModule",{value:!0});var gu=P.initProjectWorkSpace=void 0;const mu=Pu(e),Ru=vu(D),Iu=Pu(u),yu=i,Nu=v,Su=g,bu=l,wu=ou;let Hu,xu,Mu;function Tu(u,D,e){return void 0!==e.dependencies&&(0,wu.offlinePluginConversion)(yu.HVIGOR_PROJECT_ROOT_DIR,D.dependencies[u])===Iu.normalize(e.dependencies[u])}gu=P.initProjectWorkSpace=function(){if(Hu=function(){const u=Iu.resolve(yu.HVIGOR_PROJECT_WRAPPER_HOME,yu.DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME);mu.existsSync(u)||(0,bu.logErrorAndExit)(`Error: Hvigor config file ${u} does not exist.`);return(0,Su.parseJsonFile)(u)}(),Mu=function(u){let D;D=function(u){const D=u.hvigorVersion;if(D.startsWith("file:")||D.endsWith(".tgz"))return!1;const e=u.dependencies,t=Object.getOwnPropertyNames(e);for(const u of t){const D=e[u];if(D.startsWith("file:")||D.endsWith(".tgz"))return!1}if(1===t.length&&"@ohos/hvigor-ohos-plugin"===t[0])return D>"2.5.0";return!1}(u)?function(u){let D=`${yu.HVIGOR_ENGINE_PACKAGE_NAME}@${u.hvigorVersion}`;const e=u.dependencies;if(e){Object.getOwnPropertyNames(e).sort().forEach((u=>{D+=`,${u}@${e[u]}`}))}return(0,Nu.hash)(D)}(u):(0,Nu.hash)(process.cwd());return Iu.resolve(Ru.default.homedir(),".hvigor","project_caches",D)}(Hu),xu=function(){const u=Iu.resolve(Mu,yu.WORK_SPACE,yu.DEFAULT_PACKAGE_JSON);return mu.existsSync(u)?(0,Su.parseJsonFile)(u):{dependencies:{}}}(),function(){const u=Iu.resolve(yu.HVIGOR_USER_HOME,yu.DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME);if(mu.existsSync(u))(0,Su.parseJsonFile)(u)}(),!(0,wu.hasNpmPackInPaths)(yu.HVIGOR_ENGINE_PACKAGE_NAME,[Iu.join(Mu,yu.WORK_SPACE)])||(0,wu.offlinePluginConversion)(yu.HVIGOR_PROJECT_ROOT_DIR,Hu.hvigorVersion)!==xu.dependencies[yu.HVIGOR_ENGINE_PACKAGE_NAME]||!function(){function u(u){const D=null==u?void 0:u.dependencies;return void 0===D?0:Object.getOwnPropertyNames(D).length}const D=u(Hu),e=u(xu);if(D+1!==e)return!1;for(const u in null==Hu?void 0:Hu.dependencies)if(!(0,wu.hasNpmPackInPaths)(u,[Iu.join(Mu,yu.WORK_SPACE)])||!Tu(u,Hu,xu))return!1;return!0}())try{!function(){(0,bu.logInfoPrintConsole)("Hvigor installing...");for(const u in Hu.dependencies)Hu.dependencies[u]&&(Hu.dependencies[u]=(0,wu.offlinePluginConversion)(yu.HVIGOR_PROJECT_ROOT_DIR,Hu.dependencies[u]));const u={dependencies:{...Hu.dependencies}};u.dependencies[yu.HVIGOR_ENGINE_PACKAGE_NAME]=(0,wu.offlinePluginConversion)(yu.HVIGOR_PROJECT_ROOT_DIR,Hu.hvigorVersion);const D=Iu.join(Mu,yu.WORK_SPACE);try{mu.mkdirSync(D,{recursive:!0});const e=Iu.resolve(D,yu.DEFAULT_PACKAGE_JSON);mu.writeFileSync(e,JSON.stringify(u))}catch(u){(0,bu.logErrorAndExit)(u)}(function(){const u=["config","set","store-dir",yu.HVIGOR_PNPM_STORE_PATH],D={cwd:Iu.join(Mu,yu.WORK_SPACE),stdio:["inherit","inherit","inherit"]};(0,wu.executeCommand)(yu.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH,u,D)})(),function(){const u=["install"],D={cwd:Iu.join(Mu,yu.WORK_SPACE),stdio:["inherit","inherit","inherit"]};(0,wu.executeCommand)(yu.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH,u,D)}(),(0,bu.logInfoPrintConsole)("Hvigor install success.")}()}catch(u){!function(){const u=Iu.join(Mu,yu.WORK_SPACE);if((0,bu.logInfoPrintConsole)("Hvigor cleaning..."),!mu.existsSync(u))return;const D=mu.readdirSync(u);if(!D||0===D.length)return;const e=Iu.resolve(Mu,"node_modules","@ohos","hvigor","bin","hvigor.js");mu.existsSync(e)&&(0,wu.executeCommand)(process.argv[0],[e,"--stop-daemon"],{});try{D.forEach((D=>{mu.rmSync(Iu.resolve(u,D),{recursive:!0})}))}catch(D){(0,bu.logErrorAndExit)(`The hvigor build tool cannot be installed. Please manually clear the workspace directory and synchronize the project again.\n\n Workspace Path: ${u}.`)}}()}return Mu};var Gu={};!function(t){var C=n&&n.__createBinding||(Object.create?function(u,D,e,t){void 0===t&&(t=e);var r=Object.getOwnPropertyDescriptor(D,e);r&&!("get"in r?!D.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return D[e]}}),Object.defineProperty(u,t,r)}:function(u,D,e,t){void 0===t&&(t=e),u[t]=D[e]}),E=n&&n.__setModuleDefault||(Object.create?function(u,D){Object.defineProperty(u,"default",{enumerable:!0,value:D})}:function(u,D){u.default=D}),F=n&&n.__importStar||function(u){if(u&&u.__esModule)return u;var D={};if(null!=u)for(var e in u)"default"!==e&&Object.prototype.hasOwnProperty.call(u,e)&&C(D,u,e);return E(D,u),D},A=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(t,"__esModule",{value:!0}),t.executeInstallPnpm=t.isPnpmInstalled=t.environmentHandler=t.checkNpmConifg=t.PNPM_VERSION=void 0;const o=r,a=F(e),c=A(D),s=F(u),B=i,d=l,f=ou;t.PNPM_VERSION="7.30.0",t.checkNpmConifg=function(){const u=s.resolve(B.HVIGOR_PROJECT_ROOT_DIR,".npmrc"),D=s.resolve(c.default.homedir(),".npmrc");if((0,f.isFileExists)(u)||(0,f.isFileExists)(D))return;const e=(0,f.getNpmPath)(),t=(0,o.spawnSync)(e,["config","get","prefix"],{cwd:B.HVIGOR_PROJECT_ROOT_DIR});if(0!==t.status||!t.stdout)return void(0,d.logErrorAndExit)("Error: The hvigor depends on the npmrc file. Configure the npmrc file first.");const r=s.resolve(`${t.stdout}`.replace(/[\r\n]/gi,""),".npmrc");(0,f.isFileExists)(r)||(0,d.logErrorAndExit)("Error: The hvigor depends on the npmrc file. Configure the npmrc file first.")},t.environmentHandler=function(){process.env["npm_config_update-notifier"]="false"},t.isPnpmInstalled=function(){return!!a.existsSync(B.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH)&&(0,f.hasNpmPackInPaths)("pnpm",[B.HVIGOR_WRAPPER_TOOLS_HOME])},t.executeInstallPnpm=function(){(0,d.logInfoPrintConsole)(`Installing pnpm@${t.PNPM_VERSION}...`);const u=(0,f.getNpmPath)();!function(){const u=s.resolve(B.HVIGOR_WRAPPER_TOOLS_HOME,B.DEFAULT_PACKAGE_JSON);try{a.existsSync(B.HVIGOR_WRAPPER_TOOLS_HOME)||a.mkdirSync(B.HVIGOR_WRAPPER_TOOLS_HOME,{recursive:!0});const D={dependencies:{}};D.dependencies[B.PNPM]=t.PNPM_VERSION,a.writeFileSync(u,JSON.stringify(D))}catch(D){(0,d.logErrorAndExit)(`Error: EPERM: operation not permitted,create ${u} failed.`)}}(),(0,f.executeCommand)(u,["install","pnpm"],{cwd:B.HVIGOR_WRAPPER_TOOLS_HOME,stdio:["inherit","inherit","inherit"],env:process.env}),(0,d.logInfoPrintConsole)("Pnpm install success.")}}(Gu),function(){Gu.checkNpmConifg(),Gu.environmentHandler(),Gu.isPnpmInstalled()||Gu.executeInstallPnpm();const D=gu();_(u.join(D,i.WORK_SPACE))}(); \ No newline at end of file diff --git a/hvigorw b/hvigorw new file mode 100644 index 0000000..54aadd2 --- /dev/null +++ b/hvigorw @@ -0,0 +1,48 @@ +#!/bin/bash + +# ---------------------------------------------------------------------------- +# Hvigor startup script, version 1.0.0 +# +# Required ENV vars: +# ------------------ +# NODE_HOME - location of a Node home dir +# or +# Add /usr/local/nodejs/bin to the PATH environment variable +# ---------------------------------------------------------------------------- + +HVIGOR_APP_HOME=$(dirname $(readlink -f $0)) +HVIGOR_WRAPPER_SCRIPT=${HVIGOR_APP_HOME}/hvigor/hvigor-wrapper.js +warn() { + echo "" + echo -e "\033[1;33m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m" +} + +error() { + echo "" + echo -e "\033[1;31m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m" +} + +fail() { + error "$@" + exit 1 +} + +# Determine node to start hvigor wrapper script +if [ -n "${NODE_HOME}" ];then + EXECUTABLE_NODE="${NODE_HOME}/bin/node" + if [ ! -x "$EXECUTABLE_NODE" ];then + fail "ERROR: NODE_HOME is set to an invalid directory,check $NODE_HOME\n\nPlease set NODE_HOME in your environment to the location where your nodejs installed" + fi +else + EXECUTABLE_NODE="node" + which ${EXECUTABLE_NODE} > /dev/null 2>&1 || fail "ERROR: NODE_HOME is not set and not 'node' command found in your path" +fi + +# Check hvigor wrapper script +if [ ! -r "$HVIGOR_WRAPPER_SCRIPT" ];then + fail "ERROR: Couldn't find hvigor/hvigor-wrapper.js in ${HVIGOR_APP_HOME}" +fi + +# start hvigor-wrapper script +exec "${EXECUTABLE_NODE}" \ + "${HVIGOR_WRAPPER_SCRIPT}" "$@" diff --git a/hvigorw.bat b/hvigorw.bat new file mode 100644 index 0000000..29196b4 --- /dev/null +++ b/hvigorw.bat @@ -0,0 +1,57 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Hvigor startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +set WRAPPER_MODULE_PATH=%APP_HOME%\hvigor\hvigor-wrapper.js +set NODE_EXE=node.exe + +goto start + +:start +@rem Find node.exe +if defined NODE_HOME goto findNodeFromNodeHome + +%NODE_EXE% --version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH. +echo. +echo Please set the NODE_HOME variable in your environment to match the +echo location of your NodeJs installation. + +goto fail + +:findNodeFromNodeHome +set NODE_HOME=%NODE_HOME:"=% +set NODE_EXE_PATH=%NODE_HOME%/%NODE_EXE% + +if exist "%NODE_EXE_PATH%" goto execute +echo. +echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH. +echo. +echo Please set the NODE_HOME variable in your environment to match the +echo location of your NodeJs installation. + +goto fail + +:execute +@rem Execute hvigor +"%NODE_EXE%" %WRAPPER_MODULE_PATH% %* + +:fail +exit /b 1 diff --git a/library/index.ets b/library/index.ets index 4576c08..1f67f70 100644 --- a/library/index.ets +++ b/library/index.ets @@ -18,9 +18,9 @@ export { ImageKnifeAnimatorComponent } from './src/main/ets/components/ImageKnif export { ImageKnife } from './src/main/ets/ImageKnife' -export { ImageKnifeOption , AnimatorOption } from './src/main/ets/ImageKnifeOption' +export { ImageKnifeOption , AnimatorOption } from './src/main/ets/model/ImageKnifeOption' -export { ImageKnifeRequest } from './src/main/ets/ImageKnifeRequest' +export { ImageKnifeRequest } from './src/main/ets/model/ImageKnifeRequest' export { FileUtils } from './src/main/ets/utils/FileUtils' diff --git a/library/oh-package.json5 b/library/oh-package.json5 index 67af1d6..ca33846 100644 --- a/library/oh-package.json5 +++ b/library/oh-package.json5 @@ -14,7 +14,7 @@ "main": "index.ets", "repository": "https://gitee.com/openharmony-tpc/ImageKnife", "type": "module", - "version": "3.0.1-rc.2", + "version": "3.1.1-rc.0", "dependencies": { "@ohos/gpu_transform": "^1.0.2" }, diff --git a/library/src/main/ets/ImageKnife.ets b/library/src/main/ets/ImageKnife.ets index d168038..69a6271 100644 --- a/library/src/main/ets/ImageKnife.ets +++ b/library/src/main/ets/ImageKnife.ets @@ -12,14 +12,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ImageKnifeRequest } from './ImageKnifeRequest'; +import { ImageKnifeRequest } from './model/ImageKnifeRequest'; import { CacheStrategy, ImageKnifeData, ImageKnifeRequestSource } from './model/ImageKnifeData'; -import { MemoryLruCache } from './utils/MemoryLruCache'; -import { IMemoryCache } from './utils/IMemoryCache' -import { FileCache } from './utils/FileCache'; +import { MemoryLruCache } from './cache/MemoryLruCache'; +import { IMemoryCache } from './cache/IMemoryCache' +import { FileCache } from './cache/FileCache'; import { ImageKnifeDispatcher } from './ImageKnifeDispatcher'; import { IEngineKey } from './key/IEngineKey'; -import { HeaderOptions, ImageKnifeOption } from './ImageKnifeOption'; +import { HeaderOptions, ImageKnifeOption } from './model/ImageKnifeOption'; import { FileTypeUtil } from './utils/FileTypeUtil'; import { util } from '@kit.ArkTS'; import { image } from '@kit.ImageKit'; diff --git a/library/src/main/ets/ImageKnifeDispatcher.ets b/library/src/main/ets/ImageKnifeDispatcher.ets index 3c2f4fb..fbbb3a8 100644 --- a/library/src/main/ets/ImageKnifeDispatcher.ets +++ b/library/src/main/ets/ImageKnifeDispatcher.ets @@ -12,24 +12,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ImageKnifeRequest, ImageKnifeRequestState } from './ImageKnifeRequest' -import { DefaultJobQueue } from './utils/DefaultJobQueue' -import { IJobQueue } from './utils/IJobQueue' +import { ImageKnifeRequest, ImageKnifeRequestState } from './model/ImageKnifeRequest' +import { DefaultJobQueue } from './queue/DefaultJobQueue' +import { IJobQueue } from './queue/IJobQueue' import List from '@ohos.util.List'; import LightWeightMap from '@ohos.util.LightWeightMap'; import { LogUtil } from './utils/LogUtil'; -import buffer from '@ohos.buffer'; -import { FileCache } from './utils/FileCache'; -import fs from '@ohos.file.fs'; import { ImageKnife } from './ImageKnife'; import { ImageKnifeData, CacheStrategy } from './model/ImageKnifeData'; -import http from '@ohos.net.http'; import image from '@ohos.multimedia.image'; import emitter from '@ohos.events.emitter'; import { Constants } from './utils/Constants'; import taskpool from '@ohos.taskpool'; import { FileTypeUtil } from './utils/FileTypeUtil'; -import util from '@ohos.util'; import { IEngineKey } from './key/IEngineKey'; import { DefaultEngineKey } from './key/DefaultEngineKey'; import { @@ -38,8 +33,9 @@ import { RequestJobResult, RequestJobRequest } from './model/ImageKnifeData' -import { combineArrayBuffers } from './model/utils'; import { BusinessError } from '@kit.BasicServicesKit'; +import { ImageKnifeLoader } from './ImageKnifeLoader' + export class ImageKnifeDispatcher { // 最大并发 @@ -52,7 +48,7 @@ export class ImageKnifeDispatcher { private engineKey: IEngineKey = new DefaultEngineKey(); showFromMemomry(request: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean): boolean { - LogUtil.log("ImageKnife_DataTime_showFromMemomry.start:" + request.imageKnifeOption.loadSrc) + LogUtil.log("ImageKnife_DataTime_showFromMemomry.start:" + request.imageKnifeOption.loadSrc + "requestSource=" + requestSource + " isAnimator=" + isAnimator) let memoryCache: ImageKnifeData | undefined; if ((typeof (request.imageKnifeOption.loadSrc as image.PixelMap).isEditable) == 'boolean') { memoryCache = { @@ -65,13 +61,12 @@ export class ImageKnifeDispatcher { .loadFromMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, request.imageKnifeOption,isAnimator)); } - if (memoryCache !== undefined) { // 画主图 if (request.requestState === ImageKnifeRequestState.PROGRESS) { // 回调请求开始 if (requestSource === ImageKnifeRequestSource.SRC && request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) { - request.imageKnifeOption.onLoadListener?.onLoadStart() + request.imageKnifeOption.onLoadListener.onLoadStart() LogUtil.log("ImageKnife_DataTime_MemoryCache_onLoadStart:" + request.imageKnifeOption.loadSrc) } LogUtil.log("ImageKnife_DataTime_MemoryCache_showPixelMap.start:" + request.imageKnifeOption.loadSrc) @@ -82,23 +77,22 @@ export class ImageKnifeDispatcher { request.requestState = ImageKnifeRequestState.COMPLETE // 回调请求开结束 if (request.imageKnifeOption.onLoadListener?.onLoadSuccess !== undefined) { - request.imageKnifeOption.onLoadListener?.onLoadSuccess(memoryCache.source,memoryCache) + request.imageKnifeOption.onLoadListener.onLoadSuccess(memoryCache.source,memoryCache) LogUtil.log("ImageKnife_DataTime_MemoryCache_onLoadSuccess:" + request.imageKnifeOption.loadSrc) } } else if (requestSource == ImageKnifeRequestSource.ERROR_HOLDER) { request.requestState = ImageKnifeRequestState.ERROR } } - LogUtil.log("ImageKnife_DataTime_showFromMemomry.end_true:" + request.imageKnifeOption.loadSrc) + LogUtil.log("ImageKnife_DataTime_showFromMemomry.end_hasmemory:" + request.imageKnifeOption.loadSrc) return true } - LogUtil.log("ImageKnife_DataTime_showFromMemomry.end_false:" + request.imageKnifeOption.loadSrc) + LogUtil.log("ImageKnife_DataTime_showFromMemomry.end_nomemory:" + request.imageKnifeOption.loadSrc) return false } enqueue(request: ImageKnifeRequest,isAnimator?: boolean): void { - //1.内存有的话直接渲染 if (this.showFromMemomry(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,isAnimator)) { return @@ -157,10 +151,21 @@ export class ImageKnifeDispatcher { isWatchProgress = true } }); - + let src: string | number = "" + let moduleName: string = "" + let resName: string = "" + if((imageSrc as Resource).id != undefined) { + moduleName = (imageSrc as Resource).moduleName + src = (imageSrc as Resource).id + if(src == -1) { + resName = (imageSrc as Resource).params![0] + } + } else if(typeof imageSrc == "string") { + src = imageSrc + } let request: RequestJobRequest = { context: currentRequest.context, - src: imageSrc, + src: src, headers: currentRequest.imageKnifeOption.headerOption, allHeaders: currentRequest.headers, componentWidth:currentRequest.componentWidth, @@ -176,7 +181,9 @@ export class ImageKnifeDispatcher { isWatchProgress: isWatchProgress, memoryKey: memoryKey, fileCacheFolder: ImageKnife.getInstance().getFileCache()?.getCacheFolder(), - isAnimator:isAnimator + isAnimator:isAnimator, + moduleName: moduleName == "" ? undefined : moduleName, + resName: resName == "" ? undefined : resName } if(request.customGetImage == undefined) { @@ -191,9 +198,9 @@ export class ImageKnifeDispatcher { emitter.on(Constants.PROGRESS_EMITTER + memoryKey, (data) => { this.progressCallBack(requestList! , data?.data?.value as number) }); - } + } - LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start:" + currentRequest.imageKnifeOption.loadSrc) + LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(subthread):" + currentRequest.imageKnifeOption.loadSrc) taskpool.execute(task).then((res: Object) => { this.doTaskCallback(res as RequestJobResult | undefined, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator); if (isWatchProgress){ @@ -201,8 +208,9 @@ export class ImageKnifeDispatcher { } LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc) - }).catch((err:BusinessError)=>{ - LogUtil.error("Fail to execute in sub thread src=" + imageSrc + " err=" + err) + }).catch((err: BusinessError) => { + LogUtil.error("Fail to requestJob in sub thread src=" + imageSrc + " err=" + err) + LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc) if (isWatchProgress){ emitter.off(Constants.PROGRESS_EMITTER + memoryKey) } @@ -210,12 +218,14 @@ export class ImageKnifeDispatcher { this.dispatchNextJob(); }) } else { //主线程请求 + LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(mainthread):" + currentRequest.imageKnifeOption.loadSrc) requestJob(request, requestList).then((res: RequestJobResult | undefined) => { this.doTaskCallback(res, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator); LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc) - }).catch((err:BusinessError)=>{ - LogUtil.error("Fail to execute in main thread src=" + imageSrc + " err=" + err) + }).catch((err: BusinessError) => { + LogUtil.error("Fail to requestJob in main thread src=" + imageSrc + " err=" + err) + LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc) this.executingJobMap.remove(memoryKey); this.dispatchNextJob(); }) @@ -244,6 +254,7 @@ export class ImageKnifeDispatcher { } let pixelmap = requestJobResult.pixelMap; if (pixelmap === undefined) { + LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.pixelmap undefined:"+currentRequest.imageKnifeOption.loadSrc) requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => { // 回调请求失败 if (requestWithSource.source === ImageKnifeRequestSource.SRC && @@ -263,6 +274,7 @@ export class ImageKnifeDispatcher { } }); this.executingJobMap.remove(memoryKey); + this.dispatchNextJob(); return; } // 保存文件缓存 @@ -297,8 +309,6 @@ export class ImageKnifeDispatcher { LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveMemoryCache.end:"+currentRequest.imageKnifeOption.loadSrc) } if (requestList !== undefined) { - - // todo 判断request生命周期,已销毁的不需要再绘制 // key相同的request,一起绘制 requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => { if (requestWithSource.request.requestState !== ImageKnifeRequestState.DESTROY) { @@ -326,8 +336,8 @@ export class ImageKnifeDispatcher { } } else { if (requestWithSource.source == ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadCancel) { - // 回调请求成功 - requestWithSource.request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed") + // 回调请求成功 + requestWithSource.request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed") } } }); @@ -346,11 +356,13 @@ export class ImageKnifeDispatcher { while (true) { let request = this.jobQueue.pop() if (request === undefined) { + LogUtil.log("ImageKnife_DataTime_dispatchNextJob.end:no any job") break // 队列已无任务 } else if (request.requestState === ImageKnifeRequestState.PROGRESS) { + LogUtil.log("ImageKnife_DataTime_dispatchNextJob.start executeJob:" + request.imageKnifeOption.loadSrc) this.executeJob(request) - LogUtil.log("ImageKnife_DataTime_dispatchNextJob.end:" + request.imageKnifeOption.loadSrc) + LogUtil.log("ImageKnife_DataTime_dispatchNextJob.end executeJob:" + request.imageKnifeOption.loadSrc) break }else if (request.requestState == ImageKnifeRequestState.DESTROY && request.imageKnifeOption.onLoadListener?.onLoadCancel) { request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed") @@ -381,292 +393,44 @@ export class ImageKnifeDispatcher { */ @Concurrent async function requestJob(request: RequestJobRequest, requestList?: List): Promise { - LogUtil.log("ImageKnife_DataTime_requestJob.start:" + request.src) - let resBuf: ArrayBuffer | undefined - let bufferSize: number = 0 - let loadError: string = ''; + LogUtil.log("ImageKnife_DataTime_requestJob.start:" + request.src + " requestSource=" + request.requestSource) + let src = typeof request.src == "number" ? request.resName != undefined ? request.resName : request.src + "" : request.src + // 生成文件缓存key + let fileKey = request.engineKey.generateFileKey(src, request.signature, request.isAnimator) - class RequestData { - receiveSize: number = 2000 - totalSize: number = 2000 + //获取图片资源 + let resBuf: ArrayBuffer + try { + LogUtil.log("ImageKnife_DataTime_requestJob.getImageArrayBuffer.start:" + request.src) + resBuf = await ImageKnifeLoader.getImageArrayBuffer(request, requestList, fileKey) + LogUtil.log("ImageKnife_DataTime_requestJob.getImageArrayBuffer.end:" + request.src) + } catch (error) { + LogUtil.error("ImageKnife_DataTime_requestJob.end: getImageArrayBuffer error " + request.src + " err=" + error) + return ImageKnifeLoader.makeEmptyResult(error) } - // 生成文件key - let fileKey = request.engineKey.generateFileKey(request.src, request.signature,request.isAnimator) - - // 判断自定义下载 - if (request.customGetImage !== undefined && request.requestSource == ImageKnifeRequestSource.SRC) { - // 先从文件缓存获取 - resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder) - if (resBuf === undefined) { - LogUtil.log("customGetImage customGetImage"); - resBuf = await request.customGetImage(request.context, request.src) - loadError = resBuf == undefined ? "customGetImage loadFile" : loadError - // 保存文件缓存 - if (resBuf !== undefined && request.writeCacheStrategy !== CacheStrategy.Memory) { - let copyBuf = buffer.concat([buffer.from(resBuf)]).buffer; // IDE有bug,不能直接获取resBuf.byteLength - bufferSize = copyBuf.byteLength - FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf , request.fileCacheFolder) - } - } - } - else { - if (typeof request.src === 'string') { - if (request.src.indexOf("http://") == 0 || request.src.indexOf("https://") == 0) { //从网络下载 - // 先从文件缓存获取 - resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder) - if (resBuf === undefined && request.onlyRetrieveFromCache != true) { - LogUtil.log("ImageKnife_DataTime_requestJob_httpRequest.start:"+request.src) - let httpRequest = http.createHttp(); - let progress: number = 0 - let arrayBuffers = new Array() - const headerObj: Record = {} - if (request.headers != undefined) { - request.headers.forEach((value) => { - headerObj[value.key] = value.value - }) - } else if (request.allHeaders.size > 0) { - request.allHeaders.forEach((value, key) => { - headerObj[key] = value - }) - } - httpRequest.on("dataReceive", (data: ArrayBuffer) => { - arrayBuffers.push(data) - }); - - if (request.isWatchProgress) { - httpRequest.on('dataReceiveProgress', (data: RequestData) => { - // 下载进度 - if (data != undefined && (typeof data.receiveSize == 'number') && (typeof data.totalSize == 'number')) { - let percent = Math.round(((data.receiveSize * 1.0) / (data.totalSize * 1.0)) * 100) - if (progress !== percent) { - progress = percent - if (requestList === undefined) { - // 子线程 - emitter.emit(Constants.PROGRESS_EMITTER + request.memoryKey, { data: { "value": progress } }) - }else { - // 主线程请求 - requestList!.forEach((requestWithSource: ImageKnifeRequestWithSource) => { - if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) { - requestWithSource.request.imageKnifeOption.progressListener(progress) - } - }) - } - } - } - }) - } - let promise = httpRequest.requestInStream(request.src, { - header: headerObj, - method: http.RequestMethod.GET, - expectDataType: http.HttpDataType.ARRAY_BUFFER, - connectTimeout: 6000, - readTimeout: 6000, - // usingProtocol:http.HttpProtocol.HTTP1_1 - // header: new Header('application/json') - }); - - await promise.then((data: number) => { - if (data == 200 || data == 204 || data == 201 || data == 206) { - resBuf = combineArrayBuffers(arrayBuffers) - } else { - loadError = "HttpDownloadClient has error, http code =" + JSON.stringify(data) - } - }).catch((err: Error) => { - loadError = err.message; - LogUtil.error("requestInStream ERROR : err = " + JSON.stringify(err)); - }); - LogUtil.log("ImageKnife_DataTime_requestJob_httpRequest.end:"+request.src) - // 保存文件缓存 - if (resBuf !== undefined && request.writeCacheStrategy !== CacheStrategy.Memory) { - LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:"+request.src) - let copyBuf = combineArrayBuffers(arrayBuffers); // IDE有bug,不能直接获取resBuf.byteLength - bufferSize = copyBuf.byteLength - FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf , request.fileCacheFolder) - LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:"+request.src) - } - } - else { - LogUtil.log("success get image from filecache for key = " + fileKey); - loadError = "success get image from filecache for key = " + fileKey; - } - } else if (request.src.startsWith('datashare://') || request.src.startsWith('file://')) { - await fs.open(request.src, fs.OpenMode.READ_ONLY).then(async (file) => { - await fs.stat(file.fd).then(async (stat) =>{ - let buf = new ArrayBuffer(stat.size); - await fs.read(file.fd, buf).then((readLen) => { - resBuf = buf; - fs.closeSync(file.fd); - }).catch((err:BusinessError) => { - loadError = 'LoadDataShareFileClient fs.read err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code; - }) - }).catch((err:BusinessError) => { - loadError = 'LoadDataShareFileClient fs.stat err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code; - }) - }).catch((err:BusinessError) => { - loadError ='LoadDataShareFileClient fs.open err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code; - }) - } else { //从本地文件获取 - try { - let stat = fs.statSync(request.src); - if (stat.size > 0) { - let file = fs.openSync(request.src, fs.OpenMode.READ_ONLY); - resBuf = new ArrayBuffer(stat.size); - fs.readSync(file.fd, resBuf); - fs.closeSync(file); - } - } catch (err) { - if (typeof err == 'string') { - loadError = err; - } else { - loadError = err.message; - } - } - } - } else if ((request.src as Resource).id !== undefined) { //从资源文件获取 - let res = request.src as Resource; - let manager = request.context.createModuleContext(res.moduleName).resourceManager - if (resBuf == undefined && request.onlyRetrieveFromCache != true && request.requestSource == ImageKnifeRequestSource.SRC) { - if(res.id == -1) { - let resName = (res.params![0] as string) - resBuf = (await manager.getMediaByName(resName.substring(10))).buffer as ArrayBuffer - } else { - resBuf = manager.getMediaContentSync(res.id).buffer as ArrayBuffer - } - } else if (resBuf == undefined && request.requestSource != ImageKnifeRequestSource.SRC) { - if(res.id == -1) { - let resName = (res.params![0] as string) - resBuf = (await manager.getMediaByName(resName.substring(10))).buffer as ArrayBuffer - } else { - resBuf = manager.getMediaContentSync(res.id).buffer as ArrayBuffer - } - } - } - } - - - if (resBuf == undefined) { - LogUtil.log("ImageKnife_DataTime_requestJob.end_undefined:"+request.src) - return { - pixelMap: undefined, - bufferSize: 0, - fileKey: '', - loadFail: loadError, - } - } - LogUtil.log("ImageKnife_DataTime_requestJob_createPixelMap.start:"+request.src) - let fileTypeUtil = new FileTypeUtil(); - let typeValue = fileTypeUtil.getFileType(resBuf); + // 获取图片类型 + let typeValue = new FileTypeUtil().getFileType(resBuf); if(typeValue == null) { - return { - pixelMap: undefined, - bufferSize: 0, - fileKey: '', - loadFail: "request is not a valid image source", - } + LogUtil.log("ImageKnife_DataTime_requestJob.end: getFileType is null " + request.src) + return ImageKnifeLoader.makeEmptyResult("request is not a valid image source") } - let imageSource: image.ImageSource = image.createImageSource(resBuf); - let decodingOptions: image.DecodingOptions = { - editable: true, - } - if(request.isAnimator) { - if (typeValue === 'gif' || typeValue === 'webp') { - let pixelMapList: Array = [] - let delayList: Array = [] - await imageSource.createPixelMapList(decodingOptions).then(async (pixelList: Array) => { - //sdk的api接口发生变更:从.getDelayTime() 变为.getDelayTimeList() - await imageSource.getDelayTimeList().then(delayTimes => { - if (pixelList.length > 0) { - for (let i = 0; i < pixelList.length; i++) { - pixelMapList.push(pixelList[i]); - if (i < delayTimes.length) { - delayList.push(delayTimes[i]); - } else { - delayList.push(delayTimes[delayTimes.length - 1]) - } - } - imageSource.release(); - } - }) - }) - return { - pixelMap: "", - bufferSize: bufferSize, - fileKey: fileKey, - type: typeValue, - pixelMapList, - delayList - } - } else { - return { - pixelMap: undefined, - bufferSize: 0, - fileKey: '', - loadFail: "ImageKnifeAnimatorComponent组件仅支持动态图", - } - } - } - let resPixelmap: PixelMap | undefined = undefined - if (typeValue === 'gif' || typeValue === 'webp') { - let frameCount = await imageSource.getFrameCount() - let size = (await imageSource.getImageInfo()).size - if (frameCount == undefined || frameCount == 1) { - } else { - let base64Help = new util.Base64Helper() - let base64str = "data:image/" + typeValue + ";base64," + base64Help.encodeToStringSync(new Uint8Array(resBuf)) - LogUtil.log("ImageKnife_DataTime_requestJob_createPixelMap.end_GIF:" + request.src) - LogUtil.log("ImageKnife_DataTime_requestJob.end_GIF:" + request.src) - return { - pixelMap: base64str, - bufferSize: bufferSize, - fileKey: fileKey, - size: size, - type: typeValue - }; - } - } else if(typeValue == "svg") { - let hValue = Math.round(request.componentHeight); - let wValue = Math.round(request.componentWidth); - let defaultSize: image.Size = { - height: vp2px(hValue), - width: vp2px(wValue) - }; - let opts: image.DecodingOptions = { - editable: true, - desiredSize: defaultSize - }; - await imageSource.createPixelMap(opts) - .then((pixelmap: PixelMap) => { - resPixelmap = pixelmap - imageSource.release() - }) - return { - pixelMap: resPixelmap, - bufferSize: bufferSize, - fileKey: fileKey, - type:typeValue - }; - } - let size = (await imageSource.getImageInfo()).size - await imageSource.createPixelMap(decodingOptions) - .then((pixelmap: PixelMap) => { - resPixelmap = pixelmap - imageSource.release() - }) + // 解析图片 + LogUtil.log("ImageKnife_DataTime_requestJob.parseImage.start:" + request.src) + let result: RequestJobResult = await ImageKnifeLoader.parseImage(resBuf, typeValue, fileKey, request) + LogUtil.log("ImageKnife_DataTime_requestJob.parseImage.end:" + request.src) // 图形变化 - if (request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined) { - resPixelmap = await request.transformation?.transform(request.context, resPixelmap!, request.componentWidth, request.componentHeight); + if (request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined && result?.pixelMap !== undefined && typeof result.pixelMap !== 'string') { + LogUtil.log("ImageKnife_DataTime_requestJob.transform.start:" + request.src) + result.pixelMap = await request.transformation?.transform(request.context, result.pixelMap, request.componentWidth, request.componentHeight); + LogUtil.log("ImageKnife_DataTime_requestJob.transform.end:" + request.src) } - LogUtil.log("ImageKnife_DataTime_requestJob_createPixelMap.end:"+request.src) - LogUtil.log("ImageKnife_DataTime_requestJob.end:"+request.src) - return { - pixelMap: resPixelmap, - bufferSize: bufferSize, - fileKey: fileKey, - size:size, - type:typeValue - }; + + LogUtil.log("ImageKnife_DataTime_requestJob.end:" + request.src) + return result } + + diff --git a/library/src/main/ets/ImageKnifeLoader.ets b/library/src/main/ets/ImageKnifeLoader.ets new file mode 100644 index 0000000..1c14d0c --- /dev/null +++ b/library/src/main/ets/ImageKnifeLoader.ets @@ -0,0 +1,357 @@ +/* + * 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 { + CacheStrategy, + ImageKnifeRequestSource, + ImageKnifeRequestWithSource, RequestJobRequest } from './model/ImageKnifeData'; +import List from '@ohos.util.List' +import { FileCache } from './cache/FileCache'; +import { LogUtil } from './utils/LogUtil'; +import { Constants } from './utils/Constants'; +import http from '@ohos.net.http'; +import { combineArrayBuffers } from './utils/ArrayBufferUtils'; +import { BusinessError } from '@kit.BasicServicesKit'; +import fs from '@ohos.file.fs'; +import emitter from '@ohos.events.emitter'; +import image from '@ohos.multimedia.image'; +import { RequestJobResult } from './model/ImageKnifeData' +import util from '@ohos.util'; + +class RequestData { + receiveSize: number = 2000 + totalSize: number = 2000 +} + +/** + * ImageKnifeDispatcher 抽取出来的方法,因@Concurrent只能import方法,故抽取到另一个类 + */ +export class ImageKnifeLoader { + static async parseImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, + request: RequestJobRequest): Promise { + if(request.isAnimator) { + return ImageKnifeLoader.parseForAnimatorComponent(resBuf ,typeValue ,fileKey, request) + } + + if (typeValue === 'gif' || typeValue === 'webp') { + return ImageKnifeLoader.parseAnimatorImage(resBuf ,typeValue ,fileKey , request) + } else if(typeValue == "svg") { + return ImageKnifeLoader.parseSvgImage(resBuf ,typeValue ,fileKey , request) + } + + return ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request) + } + + static makeEmptyResult(error: string): RequestJobResult{ + return { + pixelMap: undefined, + bufferSize: 0, + fileKey: '', + loadFail: error, + } + } + + static async parseNormalImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, request: RequestJobRequest):Promise { + let resPixelmap: PixelMap | undefined = undefined + let decodingOptions: image.DecodingOptions = { + editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false, + } + let imageSource: image.ImageSource = image.createImageSource(resBuf) + if (imageSource === undefined){ + return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") + } + + let size = (await imageSource.getImageInfo()).size + await imageSource.createPixelMap(decodingOptions) + .then((pixelmap: PixelMap) => { + resPixelmap = pixelmap + imageSource.release() + }).catch((error: BusinessError) => { + imageSource.release() + return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error)) + }) + + return { + pixelMap: resPixelmap, + bufferSize: resBuf.byteLength, + fileKey: fileKey, + size:size, + type:typeValue + }; + } + static async parseSvgImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, + request: RequestJobRequest): Promise { + let resPixelmap: PixelMap | undefined = undefined + let imageSource: image.ImageSource = image.createImageSource(resBuf) + if (imageSource === undefined){ + return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") + } + + let size = (await imageSource.getImageInfo()).size + let scale = size.height / size.width + let hValue = Math.round(request.componentHeight); + let wValue = Math.round(request.componentWidth); + let defaultSize: image.Size = { + height: vp2px(wValue) * scale, + width: vp2px(wValue) + }; + let opts: image.DecodingOptions = { + editable: true, + desiredSize: defaultSize + }; + await imageSource.createPixelMap(opts) + .then((pixelmap: PixelMap) => { + resPixelmap = pixelmap + imageSource.release() + }).catch((error: BusinessError) => { + imageSource.release() + return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error)) + }) + + return { + pixelMap: resPixelmap, + bufferSize: resBuf.byteLength, + fileKey: fileKey, + type:typeValue + }; + } + static async parseAnimatorImage(resBuf: ArrayBuffer, typeValue: string, + fileKey: string,request: RequestJobRequest): Promise { + let imageSource: image.ImageSource = image.createImageSource(resBuf) + if (imageSource === undefined){ + return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") + } + + let frameCount = await imageSource.getFrameCount() + let size = (await imageSource.getImageInfo()).size + imageSource.release() + + if(frameCount == undefined || frameCount == 1) { + } else { + let base64str = "data:image/" + typeValue + ";base64," + new util.Base64Helper().encodeToStringSync(new Uint8Array(resBuf)) + return { + pixelMap: base64str, + bufferSize: resBuf.byteLength, + fileKey: fileKey, + size:size, + type:typeValue + }; + } + return ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request) + } + // 为AnimatorComponent解析动图 + static async parseForAnimatorComponent(resBuf: ArrayBuffer, typeValue: string, fileKey: string,request: RequestJobRequest): Promise { + if (typeValue === 'gif' || typeValue === 'webp') { + let imageSource: image.ImageSource = image.createImageSource(resBuf); + if (imageSource === undefined){ + return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") + } + let decodingOptions: image.DecodingOptions = { + editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false, + } + let pixelMapList: Array = [] + let delayList: Array = [] + await imageSource.createPixelMapList(decodingOptions).then(async (pixelList: Array) => { + //sdk的api接口发生变更:从.getDelayTime() 变为.getDelayTimeList() + await imageSource.getDelayTimeList().then(delayTimes => { + if (pixelList.length > 0) { + for (let i = 0; i < pixelList.length; i++) { + pixelMapList.push(pixelList[i]); + if (i < delayTimes.length) { + delayList.push(delayTimes[i]); + } else { + delayList.push(delayTimes[delayTimes.length - 1]) + } + } + imageSource.release(); + } + }) + }).catch((error: BusinessError) => { + imageSource.release() + return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error)) + }) + return { + pixelMap: "", + bufferSize: resBuf.byteLength, + fileKey: fileKey, + type: typeValue, + pixelMapList, + delayList + } + } else { + return ImageKnifeLoader.makeEmptyResult("ImageKnifeAnimatorComponent组件仅支持动态图") + } + } + + // 获取图片资源 + static async getImageArrayBuffer(request: RequestJobRequest, requestList: List | undefined,fileKey:string): Promise { + let resBuf: ArrayBuffer | undefined + + // 判断自定义下载 + if (request.customGetImage !== undefined && request.requestSource == ImageKnifeRequestSource.SRC && typeof request.src == "string") { + // 先从文件缓存获取 + resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder) + if (resBuf === undefined) { + LogUtil.log("start customGetImage src=" + request.src) + try { + resBuf = await request.customGetImage(request.context, request.src) + LogUtil.log("end customGetImage src=" + request.src) + } catch (err) { + throw new Error('customGetImage loadFile failed! err = ' + err) + } + if (resBuf === undefined) { + throw new Error('customGetImage loadFile failed!') + } + // 保存文件缓存 + if (request.writeCacheStrategy !== CacheStrategy.Memory) { + LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:" + request.src) + FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf, request.fileCacheFolder) + LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:" + request.src) + } + } + } + else { + if (typeof request.src === 'string') { + if (request.src.indexOf("http://") == 0 || request.src.indexOf("https://") == 0) { //从网络下载 + // 先从文件缓存获取 + resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder) + if (resBuf !== undefined){ + LogUtil.log("success get image from filecache for key = " + fileKey + " src = " + request.src) + } + else if (request.onlyRetrieveFromCache != true) { + LogUtil.log("HttpDownloadClient.start:" + request.src) + let httpRequest = http.createHttp(); + let progress: number = 0 + let arrayBuffers = new Array() + const headerObj: Record = {} + if (request.headers != undefined) { + request.headers.forEach((value) => { + headerObj[value.key] = value.value + }) + } else if (request.allHeaders.size > 0) { + request.allHeaders.forEach((value, key) => { + headerObj[key] = value + }) + } + httpRequest.on("dataReceive", (data: ArrayBuffer) => { + arrayBuffers.push(data) + }); + + if (request.isWatchProgress) { + httpRequest.on('dataReceiveProgress', (data: RequestData) => { + // 下载进度 + if (data != undefined && (typeof data.receiveSize == 'number') && (typeof data.totalSize == 'number')) { + let percent = Math.round(((data.receiveSize * 1.0) / (data.totalSize * 1.0)) * 100) + if (progress !== percent) { + progress = percent + if (requestList === undefined) { + // 子线程 + emitter.emit(Constants.PROGRESS_EMITTER + request.memoryKey, { data: { "value": progress } }) + }else { + // 主线程请求 + requestList!.forEach((requestWithSource: ImageKnifeRequestWithSource) => { + if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) { + requestWithSource.request.imageKnifeOption.progressListener(progress) + } + }) + } + } + } + }) + } + let promise = httpRequest.requestInStream(request.src, { + header: headerObj, + method: http.RequestMethod.GET, + expectDataType: http.HttpDataType.ARRAY_BUFFER, + connectTimeout: 60000, + readTimeout: 0, + // usingProtocol:http.HttpProtocol.HTTP1_1 + // header: new Header('application/json') + }); + + await promise.then((data: number) => { + if (data == 200 || data == 206 || data == 204) { + resBuf = combineArrayBuffers(arrayBuffers) + } else { + throw new Error("HttpDownloadClient has error, http code =" + JSON.stringify(data)) + } + }).catch((err: Error) => { + throw new Error("HttpDownloadClient download ERROR : err = " + JSON.stringify(err)) + }); + LogUtil.log("HttpDownloadClient.end:" + request.src) + // 保存文件缓存 + if (resBuf !== undefined && request.writeCacheStrategy !== CacheStrategy.Memory) { + LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:"+request.src) + FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf , request.fileCacheFolder) + LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:"+request.src) + } + } + else { + throw new Error('onlyRetrieveFromCache,do not fetch image src = ' + request.src) + } + } else if (request.src.startsWith('datashare://') || request.src.startsWith('file://')) { + await fs.open(request.src, fs.OpenMode.READ_ONLY).then(async (file) => { + await fs.stat(file.fd).then(async (stat) =>{ + let buf = new ArrayBuffer(stat.size); + await fs.read(file.fd, buf).then((readLen) => { + resBuf = buf; + fs.closeSync(file.fd); + }).catch((err:BusinessError) => { + throw new Error('LoadDataShareFileClient fs.read err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code) + }) + }).catch((err:BusinessError) => { + throw new Error('LoadDataShareFileClient fs.stat err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code) + }) + }).catch((err:BusinessError) => { + throw new Error('LoadDataShareFileClient fs.open err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code) + }) + } else { //从本地文件获取 + try { + let stat = fs.statSync(request.src); + if (stat.size > 0) { + let file = fs.openSync(request.src, fs.OpenMode.READ_ONLY); + resBuf = new ArrayBuffer(stat.size); + fs.readSync(file.fd, resBuf); + fs.closeSync(file); + } + } catch (err) { + throw new Error(err) + } + } + } else if (typeof request.src == "number") { //从资源文件获取 + let manager = request.context.createModuleContext(request.moduleName).resourceManager + if (resBuf == undefined && request.onlyRetrieveFromCache != true && request.requestSource == ImageKnifeRequestSource.SRC) { + if(request.src == -1) { + let resName = request.resName as string + resBuf = (await manager.getMediaByName(resName.substring(10))).buffer as ArrayBuffer + } else { + resBuf = manager.getMediaContentSync(request.src).buffer as ArrayBuffer + } + } else if (resBuf == undefined && request.requestSource != ImageKnifeRequestSource.SRC) { + if(request.src == -1) { + let resName = request.resName as string + resBuf = (await manager.getMediaByName(resName.substring(10))).buffer as ArrayBuffer + } else { + resBuf = manager.getMediaContentSync(request.src).buffer as ArrayBuffer + } + } + } + } + + if (resBuf === undefined){ + throw new Error('getImageArrayBuffer undefined') + } + return resBuf + } +} \ No newline at end of file diff --git a/library/src/main/ets/utils/FileCache.ets b/library/src/main/ets/cache/FileCache.ets similarity index 94% rename from library/src/main/ets/utils/FileCache.ets rename to library/src/main/ets/cache/FileCache.ets index 8c47562..41978b8 100644 --- a/library/src/main/ets/utils/FileCache.ets +++ b/library/src/main/ets/cache/FileCache.ets @@ -13,12 +13,12 @@ * limitations under the License. */ import util from '@ohos.util'; -import { FileUtils } from './FileUtils'; +import { FileUtils } from '../utils/FileUtils'; import fs from '@ohos.file.fs'; -import { LogUtil } from './LogUtil'; +import { LogUtil } from '../utils/LogUtil'; import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5'; - +const INT_MAX = 2147483647 /** * 二级文件缓存 * 主线程通过lruCache管理缓存大小 @@ -34,12 +34,12 @@ export class FileCache { private isInited: boolean = false private context?: Context readonly defaultMaxSize: number = 512; - readonly defaultSize: number = 128; + readonly defaultSize: number = INT_MAX; readonly defaultMaxMemorySize: number = 512 * 1024 * 1024; readonly defaultMemorySize: number = 128 * 1024 * 1024; constructor(context: Context, size: number, memory: number) { - if (size <= 0) { + if (size <= 0 || size > INT_MAX) { size = this.defaultSize } if (memory <= 0 || memory > this.defaultMaxMemorySize) { @@ -232,18 +232,18 @@ export class FileCache { } else if (value != undefined) { this.currentMemory -= value.byteLength - LogUtil.info("FileCache removeMemorySize: " + value.byteLength + " currentMemory:" + this.currentMemory) + LogUtil.debug("FileCache removeMemorySize: " + value.byteLength + " currentMemory:" + this.currentMemory) } } private addMemorySize(value: ArrayBuffer | number): void { if (typeof value == "number") { this.currentMemory += value - LogUtil.info("FileCache addMemorySize: " + value + " currentMemory:" + this.currentMemory) + LogUtil.debug("FileCache addMemorySize: " + value + " currentMemory:" + this.currentMemory) } else if (value != undefined) { this.currentMemory += value.byteLength - LogUtil.info("FileCache addMemorySize: " + value.byteLength + " currentMemory:" + this.currentMemory) + LogUtil.debug("FileCache addMemorySize: " + value.byteLength + " currentMemory:" + this.currentMemory) } } diff --git a/library/src/main/ets/utils/IMemoryCache.ets b/library/src/main/ets/cache/IMemoryCache.ets similarity index 100% rename from library/src/main/ets/utils/IMemoryCache.ets rename to library/src/main/ets/cache/IMemoryCache.ets diff --git a/library/src/main/ets/utils/MemoryLruCache.ets b/library/src/main/ets/cache/MemoryLruCache.ets similarity index 100% rename from library/src/main/ets/utils/MemoryLruCache.ets rename to library/src/main/ets/cache/MemoryLruCache.ets diff --git a/library/src/main/ets/components/ImageKnifeAnimatorComponent.ets b/library/src/main/ets/components/ImageKnifeAnimatorComponent.ets index f3bc678..81a0f85 100644 --- a/library/src/main/ets/components/ImageKnifeAnimatorComponent.ets +++ b/library/src/main/ets/components/ImageKnifeAnimatorComponent.ets @@ -12,8 +12,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { AnimatorOption, ImageKnifeOption } from '../ImageKnifeOption'; -import { ImageKnifeRequest, ImageKnifeRequestState } from '../ImageKnifeRequest'; +import { AnimatorOption, ImageKnifeOption } from '../model/ImageKnifeOption'; +import { ImageKnifeRequest, ImageKnifeRequestState } from '../model/ImageKnifeRequest'; import common from '@ohos.app.ability.common'; import { ImageKnife } from '../ImageKnife'; import { LogUtil } from '../utils/LogUtil'; @@ -79,6 +79,11 @@ export struct ImageKnifeAnimatorComponent { } } }) + .onStart(this.animatorOption.onStart) + .onFinish(this.animatorOption.onFinish) + .onPause(this.animatorOption.onPause) + .onCancel(this.animatorOption.onCancel) + .onRepeat(this.animatorOption.onRepeat) } watchImageKnifeOption() { diff --git a/library/src/main/ets/components/ImageKnifeComponent.ets b/library/src/main/ets/components/ImageKnifeComponent.ets index 57e7432..bc5af04 100644 --- a/library/src/main/ets/components/ImageKnifeComponent.ets +++ b/library/src/main/ets/components/ImageKnifeComponent.ets @@ -12,8 +12,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ImageKnifeOption } from '../ImageKnifeOption'; -import { ImageKnifeRequest, ImageKnifeRequestState } from '../ImageKnifeRequest'; +import { ImageKnifeOption } from '../model/ImageKnifeOption'; +import { ImageKnifeRequest, ImageKnifeRequestState } from '../model/ImageKnifeRequest'; import common from '@ohos.app.ability.common'; import { ImageKnife } from '../ImageKnife'; import { LogUtil } from '../utils/LogUtil'; diff --git a/library/src/main/ets/key/DefaultEngineKey.ets b/library/src/main/ets/key/DefaultEngineKey.ets index 6d43be1..f28024b 100644 --- a/library/src/main/ets/key/DefaultEngineKey.ets +++ b/library/src/main/ets/key/DefaultEngineKey.ets @@ -13,7 +13,7 @@ * limitations under the License. */ import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5'; -import { ImageKnifeOption } from '../ImageKnifeOption'; +import { ImageKnifeOption } from '../model/ImageKnifeOption'; import { IEngineKey } from './IEngineKey'; import { PixelMapTransformation } from '../transform/PixelMapTransformation'; import { ImageKnifeRequestSource } from '../model/ImageKnifeData'; diff --git a/library/src/main/ets/key/IEngineKey.ets b/library/src/main/ets/key/IEngineKey.ets index 54be5bb..3f7a903 100644 --- a/library/src/main/ets/key/IEngineKey.ets +++ b/library/src/main/ets/key/IEngineKey.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ImageKnifeOption } from '../ImageKnifeOption' +import { ImageKnifeOption } from '../model/ImageKnifeOption' import { ImageKnifeRequestSource } from '../model/ImageKnifeData' export interface IEngineKey { diff --git a/library/src/main/ets/model/ImageKnifeData.ets b/library/src/main/ets/model/ImageKnifeData.ets index 79fe5d0..e8a4c2a 100644 --- a/library/src/main/ets/model/ImageKnifeData.ets +++ b/library/src/main/ets/model/ImageKnifeData.ets @@ -12,8 +12,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { HeaderOptions } from '../ImageKnifeOption' -import { ImageKnifeRequest } from '../ImageKnifeRequest' +import { HeaderOptions } from './ImageKnifeOption' +import { ImageKnifeRequest } from './ImageKnifeRequest' import { IEngineKey } from '../key/IEngineKey' import { PixelMapTransformation } from '../transform/PixelMapTransformation' import common from '@ohos.app.ability.common'; @@ -86,7 +86,7 @@ export interface RequestJobResult { */ export interface RequestJobRequest { context: common.UIAbilityContext, - src: string | PixelMap | Resource, + src: string | number, headers?: Array, allHeaders: Map, componentWidth: number, @@ -101,6 +101,8 @@ export interface RequestJobRequest { isWatchProgress: boolean memoryKey: string fileCacheFolder: string, - isAnimator?: boolean + isAnimator?: boolean, + moduleName?:string, + resName?: string } diff --git a/library/src/main/ets/ImageKnifeOption.ets b/library/src/main/ets/model/ImageKnifeOption.ets similarity index 89% rename from library/src/main/ets/ImageKnifeOption.ets rename to library/src/main/ets/model/ImageKnifeOption.ets index 438849e..974b53b 100644 --- a/library/src/main/ets/ImageKnifeOption.ets +++ b/library/src/main/ets/model/ImageKnifeOption.ets @@ -14,8 +14,8 @@ */ import taskpool from '@ohos.taskpool'; import common from '@ohos.app.ability.common' -import { CacheStrategy, ImageKnifeData,EventImage } from './model/ImageKnifeData'; -import { PixelMapTransformation } from './transform/PixelMapTransformation'; +import { CacheStrategy, ImageKnifeData,EventImage } from './ImageKnifeData'; +import { PixelMapTransformation } from '../transform/PixelMapTransformation'; import { drawing } from '@kit.ArkGraphics2D'; export interface HeaderOptions { @@ -31,6 +31,16 @@ export class AnimatorOption { iterations?: number = -1 @Track reverse?: boolean = false + @Track + onStart?:()=>void + @Track + onFinish?:()=>void + @Track + onPause?:()=>void + @Track + onCancel?:()=>void + @Track + onRepeat?:()=>void } @Observed diff --git a/library/src/main/ets/ImageKnifeRequest.ets b/library/src/main/ets/model/ImageKnifeRequest.ets similarity index 97% rename from library/src/main/ets/ImageKnifeRequest.ets rename to library/src/main/ets/model/ImageKnifeRequest.ets index cb2115b..c63f8be 100644 --- a/library/src/main/ets/ImageKnifeRequest.ets +++ b/library/src/main/ets/model/ImageKnifeRequest.ets @@ -14,7 +14,7 @@ */ import { ImageKnifeOption } from './ImageKnifeOption'; import common from '@ohos.app.ability.common'; -import { ImageKnifeRequestSource } from './model/ImageKnifeData'; +import { ImageKnifeRequestSource } from './ImageKnifeData'; export class ImageKnifeRequest { diff --git a/library/src/main/ets/utils/DefaultJobQueue.ets b/library/src/main/ets/queue/DefaultJobQueue.ets similarity index 96% rename from library/src/main/ets/utils/DefaultJobQueue.ets rename to library/src/main/ets/queue/DefaultJobQueue.ets index ac31956..53f3d2a 100644 --- a/library/src/main/ets/utils/DefaultJobQueue.ets +++ b/library/src/main/ets/queue/DefaultJobQueue.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ImageKnifeRequest } from '../ImageKnifeRequest'; +import { ImageKnifeRequest } from '../model/ImageKnifeRequest'; import { IJobQueue } from './IJobQueue' import Queue from '@ohos.util.Queue'; import { taskpool,Stack } from '@kit.ArkTS'; diff --git a/library/src/main/ets/utils/IJobQueue.ets b/library/src/main/ets/queue/IJobQueue.ets similarity index 93% rename from library/src/main/ets/utils/IJobQueue.ets rename to library/src/main/ets/queue/IJobQueue.ets index 0a51ff0..39a3923 100644 --- a/library/src/main/ets/utils/IJobQueue.ets +++ b/library/src/main/ets/queue/IJobQueue.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ImageKnifeRequest } from '../ImageKnifeRequest' +import { ImageKnifeRequest } from '../model/ImageKnifeRequest' export interface IJobQueue { diff --git a/library/src/main/ets/model/utils.ets b/library/src/main/ets/utils/ArrayBufferUtils.ets similarity index 100% rename from library/src/main/ets/model/utils.ets rename to library/src/main/ets/utils/ArrayBufferUtils.ets diff --git a/library/src/main/ets/utils/LogUtil.ets b/library/src/main/ets/utils/LogUtil.ets index 02c2d39..d59f582 100644 --- a/library/src/main/ets/utils/LogUtil.ets +++ b/library/src/main/ets/utils/LogUtil.ets @@ -12,44 +12,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { hilog } from '@kit.PerformanceAnalysisKit'; + export class LogUtil { - public static OFF: number = 1 - public static LOG: number = 2 - public static DEBUG: number = 3 - public static INFO: number = 4 - public static WARN: number = 5 - public static ERROR: number = 6 - public static ALL: number = 7 - public static mLogLevel: number = LogUtil.OFF; - public static TAG: string = "ImageKnife:: "; + public static readonly DOMAIN: number = 0xD002220; + public static readonly TAG: string = "ImageKnife::"; public static debug(message: string, ...args: Object[]) { - if (LogUtil.mLogLevel >= LogUtil.DEBUG) { - console.debug(LogUtil.TAG + message, args) - } + hilog.debug(LogUtil.DOMAIN, LogUtil.TAG, message, args) } public static info(message: string, ...args: Object[]) { - if (LogUtil.mLogLevel >= LogUtil.INFO) { - console.info(LogUtil.TAG + message, args) - } + hilog.info(LogUtil.DOMAIN, LogUtil.TAG, message, args) } public static log(message: string, ...args: Object[]) { - if (LogUtil.mLogLevel >= LogUtil.LOG) { - console.log(LogUtil.TAG + message, args) - } + hilog.debug(LogUtil.DOMAIN, LogUtil.TAG, message, args) } public static warn(message: string, ...args: Object[]) { - if (LogUtil.mLogLevel >= LogUtil.WARN) { - console.warn(LogUtil.TAG + message, args) - } + hilog.warn(LogUtil.DOMAIN, LogUtil.TAG, message, args) } public static error(message: string, ...args: Object[]) { - if (LogUtil.mLogLevel >= LogUtil.ERROR) { - console.error(LogUtil.TAG + message, args) - } + hilog.error(LogUtil.DOMAIN, LogUtil.TAG, message, args) } } \ No newline at end of file diff --git a/library/src/main/ets/utils/Tools.ets b/library/src/main/ets/utils/Tools.ets deleted file mode 100644 index a51faa8..0000000 --- a/library/src/main/ets/utils/Tools.ets +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5' -import util from '@ohos.util' - -export class Tools { - private static keyCache: util.LRUCache = new util.LRUCache(1024) - public static generateMemoryKey(key: string | PixelMap | Resource): string{ - return typeof key == "string"? key : JSON.stringify(key) - } - // 生成唯一的key - public static generateKey(key: string | PixelMap | Resource): string{ - let keyCache = typeof key == "string"? key : JSON.stringify(key) - let result = Tools.keyCache.get(keyCache) - if(result != undefined) { - return result - } else { - result = SparkMD5.hashBinary(keyCache) - Tools.keyCache.put(keyCache,result) - return result - } - } -} \ No newline at end of file diff --git a/oh-package.json5 b/oh-package.json5 index 34e1875..79b1475 100644 --- a/oh-package.json5 +++ b/oh-package.json5 @@ -1,16 +1,11 @@ { - "modelVersion": "5.0.0", - "name": "imageknife", - "version": "1.0.0", - "description": "Please describe the basic information.", - "main": "", - "author": "", - "license": "", - "dependencies": { - "@ohos/gpu_transform": "^1.0.2" - }, + "license": "ISC", "devDependencies": { - "@ohos/hypium": "1.0.16" + "@ohos/hypium": "1.0.6" }, - "dynamicDependencies": {} -} \ No newline at end of file + "name": "imageknife", + "description": "example description", + "repository": {}, + "version": "", + "dependencies": {} +} diff --git a/sharedlibrary/src/main/ets/pages/Index.ets b/sharedlibrary/src/main/ets/pages/Index.ets index ad35007..3bd9a0a 100644 --- a/sharedlibrary/src/main/ets/pages/Index.ets +++ b/sharedlibrary/src/main/ets/pages/Index.ets @@ -21,7 +21,7 @@ export struct IndexComponent { } build() { Column() { - Button("预加载").onClick((event: ClickEvent) => { + Button($r('app.string.Preload')).onClick((event: ClickEvent) => { ImageKnife.getInstance() .preLoadCache('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp') .then((data) => { diff --git a/sharedlibrary/src/main/resources/base/element/string.json b/sharedlibrary/src/main/resources/base/element/string.json index 98e1d8a..dc2fa1f 100644 --- a/sharedlibrary/src/main/resources/base/element/string.json +++ b/sharedlibrary/src/main/resources/base/element/string.json @@ -3,6 +3,10 @@ { "name": "shared_desc", "value": "description" + }, + { + "name": "Preload", + "value": "Preload" } ] } \ No newline at end of file diff --git a/sharedlibrary/src/main/resources/zh_CN/element/string.json b/sharedlibrary/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000..718792d --- /dev/null +++ b/sharedlibrary/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "Preload", + "value": "预加载" + } + ] +} \ No newline at end of file