Pre Merge pull request !391 from zgf/3.x
This commit is contained in:
commit
25e347ea32
|
@ -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
|
12
CHANGELOG.md
12
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
|
||||
|
||||
|
|
17
OAT.xml
17
OAT.xml
|
@ -1,4 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright (c) 2021 Huawei Device Co., Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
This is the configuration file template for OpenHarmony OSS Audit Tool, please copy it to your project root dir and modify it refer to OpenHarmony/tools_oat/README.
|
||||
|
||||
-->
|
||||
<configuration>
|
||||
<oatconfig>
|
||||
<filefilterlist>
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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<ArrayBuffer | undefined> {
|
||||
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<PixelMapTransformation> = new collections.Array<PixelMapTransformation>();
|
||||
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<HeaderOptions> | 设置请求头(可选) |
|
||||
| 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<HeaderOptions> | 全局设置http请求头 |
|
||||
| deleteHeader | key: string | 全局删除http请求头 |
|
||||
| setCustomGetImage | customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined> | 全局设置自定义下载 |
|
||||
| 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属性无法将图片变为圆角
|
|
@ -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",
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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',
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
|
|
|
@ -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<string> = [
|
||||
"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
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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 })
|
||||
})
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
"description": "$string:module_desc",
|
||||
"mainElement": "EntryAbility",
|
||||
"deviceTypes": [
|
||||
"phone",
|
||||
"tablet",
|
||||
"2in1"
|
||||
"default",
|
||||
"tablet"
|
||||
],
|
||||
"deliveryWithInstall": true,
|
||||
"installationFree": false,
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 922 KiB |
Binary file not shown.
|
@ -22,6 +22,7 @@
|
|||
"pages/TestCommonImage",
|
||||
"pages/ImageAnimatorPage",
|
||||
"pages/TestSetCustomImagePage",
|
||||
"pages/TestErrorHolderPage"
|
||||
"pages/TestErrorHolderPage",
|
||||
"pages/TestTaskResourcePage"
|
||||
]
|
||||
}
|
|
@ -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": "测试失败场景请先关闭网络,并保证本地没有此网络图片的缓存"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
})
|
||||
})
|
||||
}
|
|
@ -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]);
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -5,9 +5,8 @@
|
|||
"description": "$string:module_test_desc",
|
||||
"mainElement": "TestAbility",
|
||||
"deviceTypes": [
|
||||
"phone",
|
||||
"tablet",
|
||||
"2in1"
|
||||
"default",
|
||||
"tablet"
|
||||
],
|
||||
"deliveryWithInstall": true,
|
||||
"installationFree": false,
|
||||
|
|
|
@ -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编译
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"buildOption": {
|
||||
"externalNativeOptions": {
|
||||
"path": "./src/main/cpp/CMakeLists.txt",
|
||||
"arguments": "",
|
||||
"arguments": " -DCMAKE_BUILD_TYPE=Release",
|
||||
"abiFilters": [
|
||||
"armeabi-v7a",
|
||||
"arm64-v8a",
|
||||
|
|
|
@ -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"
|
||||
],
|
||||
|
|
|
@ -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)
|
||||
target_link_libraries(nativeGpu PUBLIC boundscheck ${hilog-lib} ${EGL-lib} ${GLES-lib} libace_napi.z.so -s -ftrapv)
|
|
@ -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)
|
|
@ -0,0 +1 @@
|
|||
Subproject commit a45b3aceed2c0138babc951850445d1cd010ce48
|
|
@ -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,
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <string>
|
||||
#include <string.h>
|
||||
#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();
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <string.h>
|
||||
#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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -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}" "$@"
|
|
@ -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
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -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"
|
||||
},
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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<ImageKnifeRequestWithSource>): Promise<RequestJobResult | undefined> {
|
||||
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<ArrayBuffer>()
|
||||
const headerObj: Record<string, object> = {}
|
||||
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<PixelMap> = []
|
||||
let delayList: Array<number> = []
|
||||
await imageSource.createPixelMapList(decodingOptions).then(async (pixelList: Array<PixelMap>) => {
|
||||
//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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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<RequestJobResult> {
|
||||
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<RequestJobResult> {
|
||||
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<RequestJobResult> {
|
||||
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<RequestJobResult> {
|
||||
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<RequestJobResult> {
|
||||
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<PixelMap> = []
|
||||
let delayList: Array<number> = []
|
||||
await imageSource.createPixelMapList(decodingOptions).then(async (pixelList: Array<PixelMap>) => {
|
||||
//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<ImageKnifeRequestWithSource> | undefined,fileKey:string): Promise<ArrayBuffer> {
|
||||
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<ArrayBuffer>()
|
||||
const headerObj: Record<string, object> = {}
|
||||
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
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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() {
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<HeaderOptions>,
|
||||
allHeaders: Map<string, Object>,
|
||||
componentWidth: number,
|
||||
|
@ -101,6 +101,8 @@ export interface RequestJobRequest {
|
|||
isWatchProgress: boolean
|
||||
memoryKey: string
|
||||
fileCacheFolder: string,
|
||||
isAnimator?: boolean
|
||||
isAnimator?: boolean,
|
||||
moduleName?:string,
|
||||
resName?: string
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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 {
|
|
@ -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';
|
|
@ -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 {
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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<string,string> = 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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": {}
|
||||
}
|
||||
"name": "imageknife",
|
||||
"description": "example description",
|
||||
"repository": {},
|
||||
"version": "",
|
||||
"dependencies": {}
|
||||
}
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
{
|
||||
"name": "shared_desc",
|
||||
"value": "description"
|
||||
},
|
||||
{
|
||||
"name": "Preload",
|
||||
"value": "Preload"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "Preload",
|
||||
"value": "预加载"
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue