Pre Merge pull request !351 from zgf/master
122
CHANGELOG.md
|
@ -1,35 +1,107 @@
|
|||
## 2.3.0-rc.2
|
||||
- 加载优先级Priority类型改为taskpool.Priority类型
|
||||
## 3.0.1-rc.2
|
||||
- 修复自定义下载失败无失败回调
|
||||
- 增加全局配置自定义下载接口
|
||||
- 修复主图相同,错误图不同导致只显示一个错误图
|
||||
- heic格式图片文件魔数从第五位开始匹配
|
||||
|
||||
## 3.0.1-rc.1
|
||||
- 新增ImageKnifeAnimatorComponent控制动图组件
|
||||
- 修复部分heif图无法解码
|
||||
|
||||
## 2.3.0-rc.1
|
||||
- 修复file://格式图片无法显示
|
||||
- 修改uuid的生成方式,使用资源loadSrc,宽高以及转换效果的拼接字符串作为入参, 修复同资源图形转换错乱的问题
|
||||
## 3.0.1-rc.0
|
||||
- 文件缓存设置最大缓存数量改为无限制
|
||||
|
||||
## 2.3.0-rc.0
|
||||
- 增加gif图duration的默认值,以及默认播放次数
|
||||
## 3.0.0
|
||||
- 修复图形变换的闪退问题
|
||||
- 自定义下载customGetImage改为仅主图支持
|
||||
- 修改网络请求requestInStream配置优先返回arraybuffer
|
||||
- 新增ColorFilter属性
|
||||
|
||||
## 2.2.0
|
||||
- 修复错误图绘制完后变成占位图
|
||||
- 提供图片加载成功/失败的事件
|
||||
- 修复懒加载在多次点击出现卡死的问题
|
||||
## 3.0.0-rc.9
|
||||
- 修复Resource类型$r(变量无法)加载
|
||||
- 成功回调增加图片格式
|
||||
- Image组件增加onComplete回调
|
||||
- 修复404链接无返回错误信息
|
||||
- onLoadListener增加请求取消回调
|
||||
|
||||
## 3.0.0-rc.8
|
||||
- svg解码单位改为px
|
||||
- 修复预加载接口preLoadCache传ImageKnifeOption失效
|
||||
- 文件缓存初始化接口新增目录参数
|
||||
- 占位图从内存获取提前到判断队列前面
|
||||
- 图片改为不可拖拽
|
||||
- 修复getCacheImage默认内存获取后不返回数据
|
||||
- 成功回调返回GIF图宽高
|
||||
|
||||
## 3.0.0-rc.7
|
||||
- 修复成功回调获取不到宽高
|
||||
- 新增svg图片解码
|
||||
- 新增媒体图片file://格式
|
||||
- 修复头像超过设备高度图片闪动问题-消息列表底部头像闪动问题
|
||||
|
||||
## 3.0.0-rc.6
|
||||
- 支持多种组合变换
|
||||
- 支持全局配置是否在子线程请求加载图片,默认在子线程
|
||||
- 文件缓存初始化增加默认值
|
||||
- 预加载接口新增返回加载错误信息
|
||||
- 加载队列改为使用堆Stack
|
||||
- fileType图片格式新增heic格式
|
||||
|
||||
## 3.0.0-rc.5
|
||||
- 图片加载事件增加请求开始的回调,以及修复有缓存时,没有回调的bug
|
||||
- 修复对已销毁组件不再下发请求的逻辑
|
||||
- 加载图片流程添加日志
|
||||
- 子线程写入文件缓存获取buffer优化
|
||||
- 成功回调增加返回图片分辨率宽高
|
||||
- 内存缓存时将pixelMap进行release释放
|
||||
- 提供清理缓存能力
|
||||
- 修复preLoad接口失效
|
||||
- 修复多线程图片加载出现空白问题
|
||||
|
||||
## 3.0.0-rc.4
|
||||
- 支持hsp多包图片资源
|
||||
- 新增putCache写入缓存接口
|
||||
- 修复入参为pixelMap图片不显示问题
|
||||
- 网络请求减少拼接操作,修复网络加载速度慢
|
||||
- 提供图片加载成功/失败的事件
|
||||
|
||||
## 3.0.0-rc.3
|
||||
- 将请求默认并行从64调整到8,减少对taskpool execute内存消耗
|
||||
- 补充option参数:placeholderObjectFit,errorholderObjectFit分别支持占位图填充效果和错误图填充效果
|
||||
|
||||
## 3.0.0-rc.2
|
||||
- 新增支持使用一个或多个图片变换,如模糊,高亮等
|
||||
|
||||
## 3.0.0-rc.1
|
||||
- 新增从内存或文件缓存获取图片数据接口getCacheImage
|
||||
- 新增图片预加载preLoadCache并返回文件缓存路径
|
||||
- ImageKnifeOption新增writeCacheStrategy存入策略(只存入内存或文件缓存)
|
||||
- ImageKnifeOption新增onlyRetrieveFromCache仅用缓存加载
|
||||
- 新增单个和全局请求头
|
||||
- 补齐自定key特性
|
||||
- 获取组件宽高改用onSizeChange (需要API12)
|
||||
- svg解码宽高单位给位px
|
||||
- 修复复用场景下从内存获取图片后又清空了画布导致图片不显示
|
||||
- 修复复用场景主图比占位图绘制快后下次不显示占位图问题
|
||||
|
||||
## 3.0.0-rc.0
|
||||
- 使用Image组件替换Canvas组件渲染,并重构大部分的实现逻辑,提升渲染性能
|
||||
|
||||
较2.x版本增强点:
|
||||
- 使用Image组件代替Canvas组件渲染
|
||||
- 重构Dispatch分发逻辑,支持控制并发请求数,支持请求排队队列的优先级
|
||||
- 支持通过initMemoryCache自定义策略内存缓存策略和大小。
|
||||
- 支持option自定义实现图片获取/网络下载
|
||||
- 继承Image的能力,支持option传入border,设置边框,圆角
|
||||
- 继承Image的能力,支持option传入objectFit设置图片缩放
|
||||
- 修复发送消息时最近的两条消息头像闪动的问题
|
||||
|
||||
缺失特性
|
||||
- 不支持drawLifeCycle接口,通过canvas自会图片
|
||||
- mainScaleType,border等参数,新版本与系统Image保持一致
|
||||
- gif/webp动图播放与控制
|
||||
- signature自定义key的实现
|
||||
- 支持进行图片变换: 支持图像像素源图片变换效果。
|
||||
- 抗锯齿相关参数
|
||||
|
||||
## 2.2.0-rc.2
|
||||
- ImageKnife支持下采样
|
||||
- ImageKnife支持heic图片修改demo,按钮控制组件是否展示
|
||||
- 修复通过磁盘链接加载图片无法显示
|
||||
- ImageKnife控制可视化区域图片
|
||||
- 修复占位图、错误图、重试图从内存获取之后进入子线程导致内存泄露
|
||||
- ImageKnifeComponent组件key属性改为id属性
|
||||
- 修改header图的存储标志位
|
||||
|
||||
## 2.2.0-rc.1
|
||||
- 修改ImageKnife跳过网络,点击默认,图片没有传入宽高,无显示bug
|
||||
|
@ -283,12 +355,12 @@
|
|||
|
||||
新增
|
||||
|
||||
- 1.onClick事件属性
|
||||
- 1.onClick事件属性
|
||||
|
||||
删除
|
||||
删除
|
||||
|
||||
- 1.size(设置大小)
|
||||
- 2.sizeAnimated 显式动画
|
||||
- 1.size(设置大小)
|
||||
- 2.sizeAnimated 显式动画
|
||||
- 3.backgroundColor背景色
|
||||
- 4.margin 组件外间距 等属性,删除的属性将由通用属性提供支持,可支持在ImageKnifeComponent自定义组件上链式调用
|
||||
## 1.0.4
|
||||
|
|
925
README.md
|
@ -4,630 +4,355 @@
|
|||
|
||||
## 简介
|
||||
|
||||
本项目基于开源库 [Glide](https://github.com/bumptech/glide) 进行OpenHarmony的自研版本:
|
||||
本项目参考开源库 [Glide](https://github.com/bumptech/glide) 进行OpenHarmony的自研版本:
|
||||
|
||||
- 支持内存缓存,使用LRUCache算法,对图片数据进行内存缓存。
|
||||
- 支持磁盘缓存,对于下载图片会保存一份至磁盘当中。
|
||||
- 支持进行图片变换: 支持图像像素源图片变换效果。
|
||||
- 支持用户配置参数使用:(
|
||||
例如:配置是否开启一级内存缓存,配置磁盘缓存策略,配置仅使用缓存加载数据,配置图片变换效果,配置占位图,配置加载失败占位图等)。
|
||||
- 推荐使用ImageKnifeComponent组件配合ImageKnifeOption参数来实现功能。
|
||||
- 支持用户自定义配置实现能力参考ImageKnifeComponent组件中对于入参ImageKnifeOption的处理。
|
||||
- 支持自定义内存缓存策略,支持设置内存缓存的大小(默认LRU策略)。
|
||||
- 支持磁盘二级缓存,对于下载图片会保存一份至磁盘当中。
|
||||
- 支持自定义实现图片获取/网络下载
|
||||
- 支持监听网络下载回调进度
|
||||
- 继承Image的能力,支持option传入border,设置边框,圆角
|
||||
- 继承Image的能力,支持option传入objectFit设置图片缩放,包括objectFit为auto时根据图片自适应高度
|
||||
- 支持通过设置transform缩放图片
|
||||
- 并发请求数量,支持请求排队队列的优先级
|
||||
- 支持生命周期已销毁的图片,不再发起请求
|
||||
- 自定义缓存key
|
||||
- 自定义http网络请求头
|
||||
- 支持writeCacheStrategy控制缓存的存入策略(只存入内存或文件缓存)
|
||||
- 支持preLoadCache预加载图片
|
||||
- 支持onlyRetrieveFromCache仅用缓存加载
|
||||
- 支持使用一个或多个图片变换,如模糊,高亮等
|
||||
|
||||
<img src="screenshot/gif1.gif" width="50%"/>
|
||||
待实现特性
|
||||
|
||||
- gif/webp动图显示与控制
|
||||
- 内存降采样优化,节约内存的占用
|
||||
- 支持自定义图片解码
|
||||
|
||||
注意:3.x版本相对2.x版本做了重大的重构,主要体现在:
|
||||
|
||||
- 使用Image组件代替Canvas组件渲染
|
||||
- 重构Dispatch分发逻辑,支持控制并发请求数,支持请求排队队列的优先级
|
||||
- 支持通过initMemoryCache自定义策略内存缓存策略和大小
|
||||
- 支持option自定义实现图片获取/网络下载
|
||||
|
||||
因此API及能力上,目前有部分差异,主要体现在:
|
||||
|
||||
- 不支持drawLifeCycle接口,通过canvas自会图片
|
||||
- mainScaleType,border等参数,新版本与系统Image保持一致
|
||||
- gif/webp动图播放与控制
|
||||
- 抗锯齿相关参数
|
||||
|
||||
## 下载安装
|
||||
|
||||
```
|
||||
ohpm install @ohos/imageknife
|
||||
|
||||
// 如果需要用文件缓存,需要提前初始化文件缓存
|
||||
await ImageKnife.getInstance().initFileCache(context, 256, 256 * 1024 * 1024)
|
||||
```
|
||||
|
||||
## X86模拟器配置
|
||||
## 使用说明
|
||||
|
||||
[使用模拟器运行应用/服务](https://developer.huawei.com/consumer/cn/deveco-developer-suite/enabling/kit?currentPage=1&pageSize=100)
|
||||
#### 1.显示本地资源图片
|
||||
|
||||
|
||||
## 使用说明
|
||||
|
||||
### 1.依赖配置
|
||||
在entry\src\main\ets\entryability\EntryAbility.ts中做如下配置初始化全局ImageKnife实例:
|
||||
|
||||
```typescript
|
||||
import UIAbility from '@ohos.app.ability.UIAbility';
|
||||
import window from '@ohos.window';
|
||||
import { ImageKnife } from '@ohos/imageknife'
|
||||
|
||||
export default class EntryAbility extends UIAbility {
|
||||
onWindowStageCreate(windowStage: window.WindowStage) {
|
||||
windowStage.loadContent('pages/Index', (err, data) => {
|
||||
});
|
||||
// 初始化全局ImageKnife
|
||||
ImageKnife.with(this.context);
|
||||
// 后续访问ImageKnife请通过:ImageKnifeGlobal.getInstance().getImageKnife()方式
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
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.加载普通图片
|
||||
#### 2.显示本地context files下文件
|
||||
|
||||
接下来我们来写个简单实例看看:
|
||||
|
||||
```extendtypescript
|
||||
import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/imageknife'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct Index {
|
||||
@State message: string = 'Hello World'
|
||||
@State option: ImageKnifeOption = {
|
||||
loadSrc: $r('app.media.icon')
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
ImageKnifeOption: {
|
||||
loadSrc: this.localFile,
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Auto
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
|
||||
build() {
|
||||
Row() {
|
||||
Column() {
|
||||
Text(this.message)
|
||||
.fontSize(50)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
ImageKnifeComponent({ imageKnifeOption: this.option })
|
||||
.width(300)
|
||||
.height(300)
|
||||
}.width('100%')
|
||||
}.height('100%')
|
||||
#### 3.显示网络图片
|
||||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
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)
|
||||
```
|
||||
|
||||
非常简单,仅需定义一个ImageKnifeOption数据对象,然后在你需要的UI位置,加入ImageKnifeComponent自定义组件就可以加载出一张图像了。
|
||||
#### 4.自定义下载图片
|
||||
|
||||
### 3.加载SVG图片
|
||||
|
||||
加载svg其实和普通流程没有区别,只要将 `loadSrc: $r('app.media.jpgSample'),` `改成一张 loadSrc: $r('app.media.svgSample'),`
|
||||
svg类型图片即可。
|
||||
|
||||
注:SVG文件需添加xml声明,应以"<?xml"开头,并且SVG标签需设置width, height。
|
||||
|
||||
|
||||
### 4.加载GIF图片
|
||||
|
||||
加载GIF其实和普通流程也没有区别只要将 `loadSrc: $r('app.media.jpgSample'),` `改成一张 loadSrc: $r('app.media.gifSample'),`
|
||||
GIF图片即可。
|
||||
|
||||
#### 4.1加载GIF图片
|
||||
|
||||
更改ImageKnifeOption对象的autoPlay(可选autoPlay = true为开始播放,autoPlay = false为暂停播放)
|
||||
|
||||
### 5.自定义Key
|
||||
因为通常改变标识符比较困难或者根本不可能,所以ImageKnife也提供了 签名 API 来混合(你可以控制的)额外数据到你的缓存键中。
|
||||
签名(signature)适用于媒体内容,也适用于你可以自行维护的一些版本元数据。
|
||||
|
||||
将签名传入加载请求
|
||||
```extendtypescript
|
||||
imageKnifeOption = {
|
||||
loadSrc: 'https://aahyhy.oss-cn-beijing.aliyuncs.com/blue.jpg',
|
||||
signature: new ObjectKey(new Date().getTime().toString())
|
||||
}
|
||||
```
|
||||
详细样例请参考SignatureTestPage文件
|
||||
|
||||
代码示例
|
||||
|
||||
### 6.自定义请求头规格
|
||||
设置全局header并且设置request的header时,当key不同时全局和request并行,当key相同时request的header覆盖全局的header
|
||||
|
||||
### 7.自定义网络栈加载图片
|
||||
7.1 自定义网络栈加载单个图片,在imageKnifeNextOption中添加customGetImage标签,然后完善custom函数的逻辑即可,
|
||||
```
|
||||
ImageKnifeNextComponent({
|
||||
imageKnifeNextOption: {
|
||||
loadSrc: 'http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg',
|
||||
placeholderSrc: $r('app.media.icon_loading'),
|
||||
errorholderSrc: $r('app.media.icon_failed'),
|
||||
customGetImage: custom
|
||||
ImageKnifeComponent({
|
||||
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): Promise<ArrayBuffer | undefined> {
|
||||
let result: DataFetchResult = new DataFetchResult();
|
||||
result.data = arraybuffer; //此处替换成自己网络获取的ArrayBuffer的逻辑
|
||||
return result;
|
||||
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
|
||||
}
|
||||
```
|
||||
7.2 自定义网络栈加载全部图片
|
||||
```
|
||||
1.先执行ImageKnifeGlobal.getInstance().getImageKnife()?.replaceDataFetch(new CustomDataFetchClient()); 替换网络栈
|
||||
2.在CustomDataFetchClient这个类中也通过下面的逻辑替换成自己网络获取的ArrayBuffer的逻辑
|
||||
let result: DataFetchResult = new DataFetchResult();
|
||||
result.data = arraybuffer; //此处替换成自己网络获取的ArrayBuffer的逻辑
|
||||
return result;
|
||||
```
|
||||
7.3 取消自定义网络栈加载全部图片
|
||||
```
|
||||
如果用户执行了自定义网络加载全部图片,后面又不想自定义网络栈加载全部图片了,可以通过下面的方式恢复
|
||||
ImageKnifeGlobal.getInstance().getImageKnife()?.replaceDataFetch(new CustomDataFetchClient());
|
||||
```
|
||||
|
||||
### 8.监听图片加载成功与失败
|
||||
#### 5.监听网络下载进度
|
||||
|
||||
```
|
||||
ImageKnifeNextComponent({
|
||||
imageKnifeNextOption: {
|
||||
loadSrc: 'http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg',
|
||||
onLoadListener: {
|
||||
console.log('Load Successful: ' + data);
|
||||
return data;
|
||||
},
|
||||
onLoadFailed: (err) => {
|
||||
console.error('Load Failed Reason: ' + err);
|
||||
}
|
||||
ImageKnifeComponent({
|
||||
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,设置边框,圆角
|
||||
|
||||
如果简单的加载一张图像无法满足需求,我们可以看看ImageKnifeOption这个类提供了哪些扩展能力。
|
||||
```
|
||||
ImageKnifeComponent({ ImageKnifeOption:
|
||||
{
|
||||
loadSrc: $r("app.media.rabbit"),
|
||||
border: {radius:50}
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
|
||||
#### 7.支持option图片变换
|
||||
|
||||
```
|
||||
ImageKnifeComponent({ 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({
|
||||
{
|
||||
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:
|
||||
{
|
||||
loadSrc: $r('app.media.pngSample'),
|
||||
objectFit: ImageFit.Cover,
|
||||
border: { radius: 150 }
|
||||
}
|
||||
}).width(300)
|
||||
.height(300)
|
||||
```
|
||||
|
||||
圆形裁剪带边框变换示例
|
||||
|
||||
```
|
||||
ImageKnifeComponent({ ImageKnifeOption:
|
||||
{
|
||||
loadSrc: $r('app.media.pngSample'),
|
||||
objectFit: ImageFit.Cover,
|
||||
border: { radius: 150, color: Color.Red, width: 5 }
|
||||
}
|
||||
}).width(300)
|
||||
.height(300)
|
||||
```
|
||||
|
||||
对比度滤波变换示例
|
||||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: $r('app.media.pngSample')
|
||||
}
|
||||
}).width(300)
|
||||
.height(300)
|
||||
.contrast(12)
|
||||
```
|
||||
|
||||
旋转变换示例
|
||||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: $r('app.media.pngSample')
|
||||
}
|
||||
}).width(300)
|
||||
.height(300)
|
||||
.rotate({angle:90})
|
||||
.backgroundColor(Color.Pink)
|
||||
```
|
||||
|
||||
#### 8.监听图片加载成功与失败
|
||||
|
||||
```
|
||||
ImageKnifeComponent({ 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
|
||||
设置是否同步加载图片,默认是异步加载。建议加载尺寸较小的本地图片时将syncLoad设为true,因为耗时较短,在主线程上执行即可
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption:{
|
||||
loadSrc:$r("app.media.pngSample"),
|
||||
placeholderSrc:$r("app.media.loading")
|
||||
},syncLoad:true
|
||||
})
|
||||
```
|
||||
#### 10.ImageKnifeAnimatorComponent 示例
|
||||
```
|
||||
ImageKnifeAnimatorComponent({
|
||||
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})
|
||||
```
|
||||
## 接口说明
|
||||
### ImageKnife组件
|
||||
| 组件名称 | 入参内容 | 功能简介 |
|
||||
|-----------------------------|---------------------------------|--------|
|
||||
| ImageKnifeComponent | ImageKnifeOption | 图片显示组件 |
|
||||
| ImageKnifeAnimatorComponent | ImageKnifeOption、AnimatorOption | 动图控制组件 |
|
||||
|
||||
### AnimatorOption参数列表
|
||||
| 参数名称 | 入参内容 | 功能简介 |
|
||||
|-----------------------|-------------------------------------------------------|----------|
|
||||
| state | AnimationStatus | 播放状态(可选) |
|
||||
| iterations | number | 播放次数(可选) |
|
||||
| reverse | boolean | 播放顺序(可选) |
|
||||
|
||||
### ImageKnifeOption参数列表
|
||||
|
||||
| 参数名称 | 入参内容 | 功能简介 |
|
||||
|------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------|
|
||||
| loadSrc | string\ | PixelMap\ |Resource | 图片数据源 |
|
||||
| mainScaleType | ScaleType | 设置主图展示样式(可选) |
|
||||
| strategy | DiskStrategy | 设置磁盘缓存策略(可选) |
|
||||
| dontAnimateFlag | boolean | gif加载展示一帧(可选) |
|
||||
| placeholderSrc | string\ (占位图不支持gif图且不支持网络下载功能) | PixelMap\ |Resource | 占位图数据源 |
|
||||
| placeholderScaleType | ScaleType | 设置占位图展示样式(可选) |
|
||||
| errorholderSrc | PixelMap\ | Resource | 错误占位图数据源 |
|
||||
| errorholderSrcScaleType | ScaleType | 设置失败占位图展示样式(可选) |
|
||||
| retryholderSrc | PixelMap\ | Resource | 重试占位图数据源 |
|
||||
| retryholderScaleType | ScaleType | 设置重试占位图展示样式(可选) |
|
||||
| fallbackSrc | PixelMap\ | Resource | 后备回调符数据源 |
|
||||
| thumbSizeMultiplier | number 范围(0,1] | 设置缩略图占比(可选) |
|
||||
| thumbSizeDelay | number | 设置缩略图展示时间(可选) |
|
||||
| thumbSizeMultiplierScaleType | ScaleType | 设置缩略图展示样式(可选) |
|
||||
| displayProgress | boolean | 设置是否展示下载进度条(可选) |
|
||||
| canRetryClick | boolean | 设置重试图层是否点击重试(可选) |
|
||||
| onlyRetrieveFromCache | boolean | 仅使用缓存加载数据(可选) |
|
||||
| isCacheable | boolean | 是否开启一级内存缓存(可选) |
|
||||
| gif | {<br/> // 返回一周期动画gif消耗的时间<br/> loopFinish?: (loopTime?) => void<br/> // gif播放速率相关<br/> speedFactory?: number<br/> // 直接展示gif第几帧数据<br/> seekTo?: number<br/> playTimes?: number<br/> } | GIF播放控制能力(可选) |
|
||||
| transformation | BaseTransform<PixelMap> | 单个变换(可选) |
|
||||
| transformations | Array<BaseTransform<PixelMap>> | 多个变换(可选) |
|
||||
| allCacheInfoCallback | IAllCacheInfoCallback | 输出缓存相关内容和信息(可选) |
|
||||
| signature | ObjectKey | 自定key(可选) |
|
||||
| **drawLifeCycle** | **IDrawLifeCycle** | **用户自定义实现绘制方案(可选)** |
|
||||
| imageSmoothingEnabled | boolean | 抗锯齿是否开启属性配置,设置为false时,imageSmoothingQuality失效 |
|
||||
| imageSmoothingQuality | AntiAliasing | 抗锯齿属性配置 |
|
||||
| autoPlay | boolean | GIF播放暂停控制(可选) |
|
||||
| customGetImage | (Context, string) | 设置是否使用应用自定义的方式加载图片(可选) |
|
||||
| onLoadListener | onLoadSuccess: (data: string | PixelMap | Resource | undefined) => void;onLoadFailed: (err: string) => void; | 监听图片加载成功/失败 |
|
||||
| 参数名称 | 入参内容 | 功能简介 |
|
||||
|-----------------------|-------------------------------------------------------|-----------------|
|
||||
| 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| 监听图片加载成功与失败 |
|
||||
|
||||
其他参数只需要在ImageKnifeOption对象上按需添加即可。
|
||||
### ImageKnife接口
|
||||
|
||||
这里我们着重讲一下**自定义实现绘制方案**。为了增强绘制扩展能力,目前ImageKnifeComponent使用了Canvas的渲染能力作为基础。在此之上为了抽象组件绘制表达。我将图像的状态使用了
|
||||
**IDrawLifeCycle绘制生命周期进行表达**,
|
||||
| 参数名称 | 入参内容 | 功能简介 |
|
||||
|------------------|-------------------------------------------------------------------------------------------------------|---------------|
|
||||
| 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) |
|
||||
|
||||
<img src="screenshot/png1.png" width="100%"/>
|
||||
|
||||
ImageKnifeComponent内部,责任链实现。 用户参数设置->全局参数设置->自定义组件内部设置
|
||||
|
||||
采用责任链的好处是,用户可以通过自定义绘制,重新绘制图层。如果不想绘制也可以通过预制回调获取绘制流程信息。
|
||||
|
||||
<img src="screenshot/png2.png" width="70%"/>
|
||||
|
||||
### 场景1:默认的展示不满足需求,需要加个圆角效果。
|
||||
|
||||
代码如下:
|
||||
|
||||
```typescript
|
||||
import { ImageKnifeComponent } from '@ohos/imageknife'
|
||||
import { ImageKnifeOption } from '@ohos/imageknife'
|
||||
import { ImageKnifeDrawFactory } from '@ohos/imageknife'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct Index {
|
||||
@State imageKnifeOption1: ImageKnifeOption = {
|
||||
// 加载一张本地的jpg资源(必选)
|
||||
loadSrc: $r('app.media.jpgSample'),
|
||||
// 占位图使用本地资源icon_loading(可选)
|
||||
placeholderSrc: $r('app.media.icon_loading'),
|
||||
// 失败占位图使用本地资源icon_failed(可选)
|
||||
errorholderSrc: $r('app.media.icon_failed'),
|
||||
// 绘制圆角30,边框5,边框"#ff00ff".用户自定义绘制(可选)
|
||||
drawLifeCycle:ImageKnifeDrawFactory.createRoundLifeCycle(5,"#ff00ff",30)
|
||||
};
|
||||
|
||||
build(){
|
||||
Scroll() {
|
||||
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
|
||||
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 })
|
||||
.width(300)
|
||||
.height(300)
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
## 下载安装GPUImage依赖
|
||||
方法一:在Terminal窗口中,执行如下命令安装三方包,DevEco Studio会自动在工程的oh-package.json5中自动添加三方包依赖。
|
||||
```
|
||||
ohpm install @ohos/gpu_transform
|
||||
```
|
||||
方法二: 在工程的oh-package.json5中设置三方包依赖,配置示例如下:
|
||||
```
|
||||
"dependencies": {
|
||||
"@ohos/gpu_transform": "^1.0.2"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`ImageKnifeDrawFactory.createRoundLifeCycle(5,"#ff00ff",30)`
|
||||
我们深入查看源码可以发现,实际上是对IDrawLifeCycle接口的部分实现,这里我介绍一下IDrawLifeCycle。
|
||||
|
||||
*
|
||||
*IDrawLifeCycle的返回值代表事件是否被消费,如果被消费接下来组件内部就不会处理,如果没被消费就会传递到下一个使用者。目前消费流程(用户自定义->
|
||||
全局配置定义->组件内部默认定义)**
|
||||
|
||||
所以我们在当数据是一张PixelMap的时候(目前jpg png bmp webp
|
||||
svg返回的都是PixelMap,gif返回GIFFrame数组),我们返回了true。消费了事件,代表这个绘制流程用户自定义完成。
|
||||
|
||||
<img src="screenshot/gif2.gif" width="50%"/>
|
||||
|
||||
由于IDrawLifeCycle实现较为冗长,我们封装了ImageKnifeDrawFactory工厂,提供了网络下载百分比效果、圆角、椭圆添加边框等能力。下面我们就再看看使用工厂封装之后的场景代码。
|
||||
|
||||
### 场景2: 网络下载百分比效果展示
|
||||
|
||||
当进行加载网络图片时,可能需要展示网络下载百分比动画。但是默认的动画又不能满足需求,这个时候我们就需要自定义网络下载百分比效果。代码如下:
|
||||
|
||||
```typescript
|
||||
import UIAbility from '@ohos.app.ability.UIAbility';
|
||||
import window from '@ohos.window';
|
||||
import { ImageKnifeGlobal,ImageKnife,ImageKnifeDrawFactory,LogUtil } from '@ohos/imageknife'
|
||||
import abilityAccessCtrl,{Permissions} from '@ohos.abilityAccessCtrl';
|
||||
export default class EntryAbility extends UIAbility {
|
||||
onWindowStageCreate(windowStage: window.WindowStage) {
|
||||
//.. 删除不必要代码
|
||||
windowStage.loadContent('pages/index', (err, data) => {
|
||||
});
|
||||
// 初始化ImageKnifeGlobal和ImageKnife
|
||||
ImageKnife.with(this.context);
|
||||
// 全局配置网络加载进度条 使用ImageKnifeGlobal.getInstance().getImageKnife()访问ImageKnife
|
||||
ImageKnifeGlobal.getInstance().getImageKnife().setDefaultLifeCycle(ImageKnifeDrawFactory.createProgressLifeCycle("#10a5ff", 0.5))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这里大家可能会问,为什么会将这个IDrawLifeCycle放在AbilityStage里面实现?
|
||||
|
||||
这是因为网络下载百分比进度很多时候都是全局通用,如果有需要全局配置的自定义展示方案。推荐在AbilityStage里面,往ImageKnife的setDefaultLifeCycle函数中注入,即可将ImageKnifeComponent中的默认绘制方案替换。
|
||||
|
||||
在这里我们实现的效果如下图所示。
|
||||
|
||||
<img src="screenshot/gif3.gif" width="50%"/>
|
||||
|
||||
## 高级用法
|
||||
|
||||
以上简单使用和进阶使用都是经过一层自定义组件封装之后形成的,RequestOption封装成了ImageKnifeOption,绘制部分封装成了自定义组件ImageKnifeComponent。
|
||||
|
||||
如果用户其实并不关心绘制部分,或者说想用自己的通用方案对自定义组件ImageKnifeComponent重构都是可以的。
|
||||
|
||||
下面我们会着重指导用户如何复用图片加载逻辑,重构自定义组件ImageKnifeComponent。
|
||||
|
||||
首先我们先看看RequestOption构建的内容,如下所示:
|
||||
|
||||
### 数据加载
|
||||
|
||||
#### RequestOption构建:
|
||||
|
||||
请查阅下文接口内容:[RequestOption接口方法](#requestoption用户配置参数)
|
||||
|
||||
了解了RequestOption的参数内容后,我们可以参考ImageKnifeComponent组件代码进行分析。
|
||||
|
||||
**从`imageKnifeExecute()`函数入口,首先我们需要构建一个RequestOption对象,`let request = new RequestOption()`,
|
||||
接下来就是按需配置request对象的内容,最后使用 `ImageKnifeGlobal.getInstance().getImageKnife()?.call(request)`发送request执行任务即可。**
|
||||
|
||||
是不是很简单,而其实最重要的内容是就是: **按需配置request对象的内容** 为了更好理解,我举例说明一下:
|
||||
|
||||
#### 场景一: 简单加载一张图片
|
||||
|
||||
```
|
||||
let request = new RequestOption();
|
||||
// (必传)
|
||||
request.load("图片url")
|
||||
// (可选 整个request监听回调)
|
||||
.addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => {
|
||||
// data 是ImageKnifeData对象
|
||||
if(data.isPixelMap()){
|
||||
// 这样就获取到了目标PixelMap
|
||||
let pixelmap = data.drawPixleMap.imagePixelMap;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
|
||||
let compSize:Size = {
|
||||
width: this.currentWidth,
|
||||
height:this.currentHeight
|
||||
}
|
||||
// (必传)这里setImageViewSize函数必传组件大小,因为涉及到图片变换效果都需要适配图像源和组件大小
|
||||
request.setImageViewSize(compSize)
|
||||
// 最后使用ImageKnife的call函数调用request即可
|
||||
let imageKnife:ImageKnife|undefined = ImageKnifeGlobal.getInstance().getImageKnife();
|
||||
if(imageKnife != undefined){
|
||||
imageKnife.call(request)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**其他场景,可以按需加载**
|
||||
|
||||
比如我需要配置 **占位图** 只需要 在request对象创建好之后,调用 **placeholder** 函数即可
|
||||
|
||||
```
|
||||
request.placeholder(this.imageKnifeOption.placeholderSrc, (data) => {
|
||||
console.log('request.placeholder callback')
|
||||
this.displayPlaceholder(data)
|
||||
})
|
||||
```
|
||||
|
||||
再比如 我对缓存配置有要求,我要禁用内存缓存,调用 **skipMemoryCache** 函数即可
|
||||
|
||||
```
|
||||
request.skipMemoryCache(true)
|
||||
```
|
||||
|
||||
这里只是简单介绍部分使用,更多的内容请参考 **按需加载** 原则,并且可以参考ImageKnifeComponent源码或者根据文档自行探索实现。
|
||||
|
||||
## 接口说明
|
||||
|
||||
### RequestOption用户配置参数
|
||||
|
||||
| 方法名 | 入参 | 接口描述 |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------ | -------------------------------------------------------- |
|
||||
| load(src: string \| PixelMap \|Resource) | src:string\|PixelMap\|Resource | 用户加载图片源 |
|
||||
| setImageViewSize(imageSize: { width: number, height: number }) | imageSize:{width: number, height: number } | 传入显示图片组件的大小,变换的时候需要作为参考 |
|
||||
| diskCacheStrategy(strategy: DiskStrategy) | strategy:DiskStrategy | 配置磁盘缓存策略 NONE SOURCE RESULT ALL AUTOMATIC |
|
||||
| placeholder(src: string \| PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData>) | src: string\|PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData> | 占位图,占位图回调数据ImageKnifeData |
|
||||
| errorholder(src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData>) | src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData> | 错误占位图,错误占位图回调数据ImageKnifeData |
|
||||
| retryholder(src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData>) | src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData> | 重试占位图,重试占位图回调数据ImageKnifeData |
|
||||
| fallback(src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData>) | src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData> | 重试占位图,重试占位图回调数据ImageKnifeData |
|
||||
| addListener(func: AsyncCallback<ImageKnifeData>) | func: AsyncCallback<ImageKnifeData> | 配置整个监听回调,数据正常加载返回,加载失败返回错误信息 |
|
||||
| thumbnail(sizeMultiplier:number, func?: AsyncSuccess<ImageKnifeData>) | sizeMultiplier:number, func?: AsyncSuccess<ImageKnifeData> | 设置缩略图比例,缩略图返回后,加载并展示缩略图 |
|
||||
| addProgressListener(func?: AsyncSuccess<number>) | func?: AsyncSuccess<number> | 设置网络下载百分比监听,返回数据加载百分比数值 |
|
||||
| addAllCacheInfoCallback(func: IAllCacheInfoCallback) | func: IAllCacheInfoCallback | 设置获取所有缓存信息监听 |
|
||||
| skipMemoryCache(skip: boolean) | skip: boolean | 配置是否跳过内存缓存 |
|
||||
| retrieveDataFromCache(flag: boolean) | flag: boolean | 配置仅从缓存中加载数据 |
|
||||
| signature | ObjectKey | 自定义key |
|
||||
|
||||
同时支持[图片变换相关](#图片变换相关)接口。
|
||||
|
||||
### ImageKnife 启动器/门面类
|
||||
|
||||
| 方法名 | 入参 | 接口描述 |
|
||||
|----------------------------------| ---------------------- | ------------------------------------------------------------ |
|
||||
| call(request: RequestOption) | request: RequestOption | 根据用户配置参数具体执行加载流程 |
|
||||
| preload(request: RequestOption) | request: RequestOption | 根据用户配置参数具体执行预加载流程 |
|
||||
| pauseRequests() | | 全局暂停请求 |
|
||||
| resumeRequests() | | 全局恢复暂停 |
|
||||
| isUrlExist(url, cacheType, size) | url, CacheType, Size | 判断图片是否在 缓存和磁盘中存在,如果入参是缓存,需要传入值图片大小,参数 CacheType, Size(可选) |
|
||||
| setMaxRequests(count: number) | count | 设置请求的最大并发数量 |
|
||||
| removeAllMemoryCache() | | 清除全部内存缓存 |
|
||||
| removeAllFileCache() | | 清除全部磁盘缓存 |
|
||||
| removeMemoryCache(url: string) | url: string | 清除指定内存缓存 |
|
||||
| removeFileCache(url: string) | url: string | 清除指定磁盘缓存 |
|
||||
| getMemoryCacheKey(url: string) | url: string | 获取指定图片内存缓存key |
|
||||
| getDiskCacheKey(url: string) | url: string | 获取指定图片磁盘缓存key |
|
||||
|
||||
### 缓存策略相关
|
||||
|
||||
| 使用方法 | 类型 | 策略描述 |
|
||||
|--------------------------------------------|-----------|----------------------|
|
||||
| request.diskCacheStrategy(new ALL()) | ALL | 表示既缓存原始图片,也缓存转换过后的图片 |
|
||||
| request.diskCacheStrategy(new AUTOMATIC()) | AUTOMATIC | 表示尝试对本地和远程图片使用适合的策略 |
|
||||
| request.diskCacheStrategy(new DATA()) | DATA | 表示只缓存原始图片 |
|
||||
| request.diskCacheStrategy(new NONE()) | NONE | 表示不缓存任何内容 |
|
||||
| request.diskCacheStrategy(new RESOURCE()) | RESOURCE | 表示只缓存转换过后的图片 |
|
||||
|
||||
### AntiAliasing类型展示效果
|
||||
|
||||
| 使用方法 | 类型 | 策略描述 |
|
||||
|-------------------------|--------|-------------|
|
||||
| AntiAliasing.FIT_HIGH | String | 图像抗锯齿设置为高画质 |
|
||||
| AntiAliasing.FIT_MEDIUM | String | 图像抗锯齿设置为中画质 |
|
||||
| AntiAliasing.FIT_LOW | String | 图像抗锯齿设置为低画质 |
|
||||
|
||||
### CacheType类型展示效果
|
||||
|
||||
| 使用方法 | 类型 | 策略描述 |
|
||||
|-------------------------|-----|-----------------------------------|
|
||||
| CacheType.Default| int | 默认值,先从内存获取,无值则从磁盘获取 |
|
||||
| CacheType.Cache| int | 缓存 |
|
||||
| CacheType.Disk | int | 磁盘 |
|
||||
|
||||
### ScaleType类型展示效果
|
||||
|
||||
| 使用方法 | 类型 | 策略描述 |
|
||||
|-------------------------|-----|-----------------------------------|
|
||||
| ScaleType.FIT_START | int | 图像位于用户设置组件左上角显示,图像会缩放至全部展示 |
|
||||
| ScaleType.FIT_END | int | 图像位于用户设置组件右下角显示,图像会缩放至全部展示 |
|
||||
| ScaleType.FIT_CENTER | int | 图像位于用户设置组件居中,图像会缩放至全部展示 |
|
||||
| ScaleType.CENTER | int | 图像居中展示,不缩放 |
|
||||
| ScaleType.CENTER_CROP | int | 图像的宽高长度,短的部分缩放至组件大小,超出的全部裁剪 |
|
||||
| ScaleType.FIT_XY | int | 图像拉伸至组件大小 |
|
||||
| ScaleType.CENTER_INSIDE | int | 如果图像大于组件则执行FIT_CENTER,小于组件则CENTER |
|
||||
| ScaleType.NONE | int | 如果不想适配,直接展示原图大小 |
|
||||
| ScaleType.AUTO_HEIGHT | int | 设置宽的时候,图片高度自适应 |
|
||||
| ScaleType.AUTO_WIDTH | int | 设置高的时候,图片宽度自适应 |
|
||||
| ScaleType.AUTO | int | 没有设置宽和高,图片按照自身宽高显示 |
|
||||
|
||||
### 图片变换相关
|
||||
|
||||
| 使用方法 | 类型 | 相关描述 |
|
||||
|--------------------------------|------------------------------------|--------------------------------|
|
||||
| request.centerCrop() | CenterCrop | 可以根据图片文件,目标显示大小,进行对应centerCrop |
|
||||
| request.centerInside() | CenterInside | 可以根据图片文件,目标显示大小,进行对应centerInside |
|
||||
| request.fitCenter() | FitCenter | 可以根据图片文件,目标显示大小,进行对应fitCenter |
|
||||
| request.blur() | BlurTransformation | 模糊处理(图片分辨率较大建议传递第二个参数将图片进行缩小) |
|
||||
| request.brightnessFilter() | BrightnessFilterTransformation | 亮度滤波器 |
|
||||
| request.contrastFilter() | ContrastFilterTransformation | 对比度滤波器 |
|
||||
| request.cropCircle() | CropCircleTransformation | 圆形剪裁显示 |
|
||||
| request.cropCircleWithBorder() | CropCircleWithBorderTransformation | 圆环展示 |
|
||||
| request.cropSquare() | CropSquareTransformation | 正方形剪裁 |
|
||||
| request.crop() | CropTransformation | 自定义矩形剪裁 |
|
||||
| request.grayscale() | GrayscaleTransformation | 灰度级转换 |
|
||||
| request.invertFilter() | InvertFilterTransformation | 反转滤波器 |
|
||||
| request.pixelationFilter() | PixelationFilterTransformation | 像素化滤波器 |
|
||||
| request.rotateImage() | RotateImageTransformation | 图片旋转 |
|
||||
| request.roundedCorners() | RoundedCornersTransformation | 圆角剪裁 |
|
||||
| request.sepiaFilter() | SepiaFilterTransformation | 乌墨色滤波器 |
|
||||
| request.sketchFilter() | SketchFilterTransformation | 素描滤波器 |
|
||||
| request.mask() | MaskTransformation | 遮罩 |
|
||||
| request.swirlFilter() | SwirlFilterTransformation | 扭曲滤波器 |
|
||||
| request.kuwaharaFilter() | KuwaharaFilterTransform | 桑原滤波器 |
|
||||
| request.toonFilter() | ToonFilterTransform | 动画滤波器 |
|
||||
| request.vignetteFilter() | VignetteFilterTransform | 装饰滤波器 |
|
||||
| request.downsampleOf() | BaseDownsampling | 下采样 |
|
||||
|
||||
<img src="screenshot/gif4.gif" width="50%"/>
|
||||
|
||||
### setLruCacheSize
|
||||
|
||||
setLruCacheSize(size: number,memory:number): void
|
||||
|
||||
设置图片文件缓存的大小上限,size单位为张数,memory单位为字节,提升再次加载同源图片的加载速度,特别是对网络图源会有较明显提升。
|
||||
如果不设置则默认为100张,100MB。缓存采用内置的LRU策略。
|
||||
size为0则代表不限制缓存张数,memory为0则代表不限制缓存大小。
|
||||
建议根据应用实际需求,设置合理缓存上限,数字过大可能导致内存占用过高,可能导致OOM异常。
|
||||
|
||||
**参数:**
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
| -------- | -------- | -------- |-------------------------|
|
||||
| size | number | 是 | 图片文件的缓存张数,单位为张。只支持正整数,0 |
|
||||
| memory | number | 是 | 图片文件的缓存大小,单位为字节。只支持正数,0 |
|
||||
|
||||
**示例:**
|
||||
```ts
|
||||
//EntryAbility.ets
|
||||
import { InitImageKnife } from '...imageknife'
|
||||
export default class EntryAbility extends UIAbility {
|
||||
onWindowStageCreate(windowStage: window.WindowStage) {
|
||||
InitImageKnife.init(this.context);
|
||||
let imageKnife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife()
|
||||
if (imageKnife != undefined) {
|
||||
//设置全局内存缓存大小张数
|
||||
imageKnife.setLruCacheSize(100, 100 * 1204 * 1024)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Queue
|
||||
|
||||
| 方法名 | 入参 | 接口描述 |
|
||||
| ----------------------------------- | ----------------------- | ------------------------------ |
|
||||
| getQueueLength(): number | | 获取队列总长度 |
|
||||
| add(request: RequestOption) | request:RequestOption | 在队列尾部插入元素 |
|
||||
| pop(): RequestOption | undefined | | 删除队列头元素并返回该删除元素 |
|
||||
|
||||
## 约束与限制
|
||||
|
||||
在下述版本验证通过:
|
||||
DevEco Studio 4.1(4.1.3.520)--SDK:API11( 4.1.0.63)
|
||||
DevEco Studio 4.1(4.1.3.418)--SDK:API11( 4.1.0.56)
|
||||
DevEco Studio 4.1(4.1.3.322)--SDK:API11( 4.1.0.36)
|
||||
DevEco Studio 4.0(4.0.3.700)--SDK:API10( 4.0.10.15)
|
||||
|
||||
HSP场景适配:
|
||||
|
||||
在使用ImageKnifeComponent进行加载图片时, 提供的ImageKnifeOption配置类新增了可选参数context, 在HSP场景下需要传入正确的context, 才能保证三方库后续正确获取Resource资源。
|
||||
|
||||
在使用RquestOption进行加载图片时, 提供的RquestOption配置类新增了接口`setModuleContext(moduleCtx:common.UIAbilityContext)`, 在HSP场景下需要传入正确的context, 才能保证三方库后续正确获取Resource资源。
|
||||
|
||||
非HSP场景不影响原功能, ImageKnifeOption配置类新增的可选参数context可以不传, RquestOption配置类新增的接口可以不调用。
|
||||
|
||||
注意:
|
||||
|
||||
基于性能优化的原因,2.1.2-rc.13及以后版本引用了API12 Sendable接口,至此以后的版本只支持API12。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
/library/src/
|
||||
- main/ets/components
|
||||
- cache # 缓存相关内容
|
||||
- diskstrategy # 缓存策略
|
||||
- key # 缓存key生成策略
|
||||
- Base64.ets # Base64算法
|
||||
- CustomMap.ets # 自定义Map封装
|
||||
- DiskCacheEntry.ets # 磁盘缓存entry
|
||||
- DiskLruCache.ets # 磁盘LRU缓存策略
|
||||
- FileReader.ets # 文件读取相关
|
||||
- FileUtils.ets # 文件工具类
|
||||
- LruCache.ets # 内存LRU缓存策略
|
||||
- Md5.ets # MD5算法
|
||||
|
||||
- imageknife # imageknife主要内容
|
||||
- compress # 压缩相关
|
||||
- constants # 常量相关
|
||||
- Downsampling # 下采样相关
|
||||
- entry # 部分数据结构
|
||||
- holder # 占位图相关解析
|
||||
- interface # 接口相关
|
||||
- networkmanage # 网络相关
|
||||
- pngj # pngj相关
|
||||
- requestmanage # imageknife请求相关
|
||||
- resourcemanage # 本地资源解析相关
|
||||
- transform # 图片变换相关
|
||||
- utils # 工具类相关
|
||||
- ImageKnife.ets # imageknife门面,app持久化类
|
||||
- ImageKnifeData.ets # 数据封装
|
||||
- ImageKnifeComponent.ets # 自定义控件封装
|
||||
- ImageKnifeDrawFactory.ets # IDrawLifeCycle用户自定义实现
|
||||
- ImageKnifeOption.ets # 用户传参数封装
|
||||
- RequestOption.ets # 用户设置参数封装
|
||||
|
||||
/entry/src/
|
||||
- main/ets
|
||||
- entryability
|
||||
- CustomEngineKeyImpl.ets
|
||||
- EntryAbility.ts
|
||||
- pages # 测试page页面列表
|
||||
- basicTestFeatureAbilityPage.ets # 测试列表加载
|
||||
- basicTestFileIOPage.ets # 测试fileio
|
||||
- basicTestMediaImage.ets # 测试媒体image
|
||||
- basicTestResourceManagerPage.ets # 测试本地资源解析
|
||||
- compressPage.ets # 压缩页面
|
||||
- cropImagePage2.ets # 手势裁剪页面
|
||||
- DownsamplingPage.ets # 图片下采样测试
|
||||
- frescoImageTestCasePage.ets # 测试属性动画组件切换
|
||||
- frescoRetryTestCasePage.ets # 测试ImageKnifeComponent加载失败重试
|
||||
- svgTestCasePage.ets # 测试svg解析页面
|
||||
- imageknifeTestCaseIndex.ets # 测试用例页面入口
|
||||
- index.ets # 程序入口页面
|
||||
- loadNetworkTestCasePage.ets # 网络加载测试
|
||||
- loadResourceTestCasePage.ets # 本地加载测试
|
||||
- showErrorholderTestCasePage.ets # 加载失败占位图测试
|
||||
- SignatureTestPage.ets # 自定义key测试
|
||||
- storageTestDiskLruCache.ets # 磁盘缓存测试
|
||||
- storageTestLruCache.ets # 内存缓存测试
|
||||
- testAllCacheInfoPage.ets # 所有缓存信息获取测试
|
||||
- testCustomDataFetchClientWithPage # 测试图片下载使用自定义的网络栈
|
||||
- testImageKnifeAutoHeightPage.ets # 图片高度自适应测试
|
||||
- testImageKnifeAutoWidthPage.ets # 图片宽度自适应测试
|
||||
- testImageKnifeAutoPage.ets # 图片宽高自适应测试
|
||||
- testImageKnifeOptionChangedPage.ets # 数据切换测试
|
||||
- testImageKnifeOptionChangedPage2.ets # 数据切换测试,部分变换
|
||||
- testImageKnifeOptionChangedPage3.ets # 数据切换测试,组件动画
|
||||
- testImageKnifeOptionChangedPage4.ets # 数据切换测试,内容动画
|
||||
- testImageKnifeOptionChangedPage5.ets # 数据切换测试,ImageKnifeDrawFactory封装圆角圆环边框等
|
||||
- testPreloadPage.ets # 预加载测试
|
||||
- transformPixelMapPage.ets # 所有类型变换测试
|
||||
- testSingleFrameGifPage.ets # 单帧gif加载测试
|
||||
- TestStopPlayingGifPage # gif播放暂停测试
|
||||
- TestImageKnifeNetPlaceholder # 缓存获取string类型占位图以及后备回调符测试
|
||||
|
||||
- OptionTestPage.ets # 图片缓存测试
|
||||
- testManyGifLoadWithPage # 测试gif加载页面
|
||||
- testImageKnifeCache # 测试图片是否在缓存或者磁盘中
|
||||
-workers
|
||||
- upngWorkerTestCase.ets # png子线程解析
|
||||
- upngWorkerDepend.ts # png子线程解析具体执行
|
||||
```
|
||||
在下述版本验证通过:
|
||||
DevEco Studio 5.0 Canary3(5.0.3.221)--SDK:API12
|
||||
|
||||
## 贡献代码
|
||||
|
||||
|
@ -640,47 +365,5 @@ HSP场景适配:
|
|||
|
||||
## 遗留问题
|
||||
|
||||
1.目前svg和gif动图不支持变换效果。
|
||||
|
||||
## 补充说明
|
||||
### SVG标签说明
|
||||
从API version 10开始支持SVG标签, 使用版本为(SVG)1.1,SVG文件需添加xml声明,应以"<?xml"开头,并且SVG标签需设置width, height。
|
||||
当前支持的标签列表有:
|
||||
- a
|
||||
- circla
|
||||
- clipPath
|
||||
- defs
|
||||
- ellipse
|
||||
- feBlend
|
||||
- feColorMatrix
|
||||
- feComposite
|
||||
- feDiffuseLighting
|
||||
- feDisplacementMap
|
||||
- feDistantLight
|
||||
- feFlood
|
||||
- feGaussianBlur
|
||||
- feImage
|
||||
- feMorphology
|
||||
- feOffset
|
||||
- fePointLight
|
||||
- feSpecularLighting
|
||||
- feSpotLight
|
||||
- feTurbulence
|
||||
- filter
|
||||
- g
|
||||
- image
|
||||
- line
|
||||
- linearGradient
|
||||
- mask
|
||||
- path
|
||||
- pattern
|
||||
- polygon
|
||||
- polyline
|
||||
- radialGradient
|
||||
- rect
|
||||
- stop
|
||||
- svg
|
||||
- text
|
||||
- textPath
|
||||
- tspan
|
||||
- use
|
||||
- ImageKnifeAnimator组件无法设置ImageFit属性
|
||||
- ImageKnifeAnimator组件设置border属性无法将图片变为圆角
|
|
@ -49,18 +49,6 @@
|
|||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sharedlibrary2",
|
||||
"srcPath": "./sharedlibrary2",
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"applyToProducts": [
|
||||
"default"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
/node_modules
|
||||
/oh_modules
|
||||
/.preview
|
||||
/build
|
||||
/oh_modules/
|
||||
/oh-package-lock.json5
|
||||
/.cxx
|
||||
/.test
|
|
@ -1,15 +1,28 @@
|
|||
{
|
||||
"apiType": 'stageMode',
|
||||
"apiType": "stageMode",
|
||||
"buildOption": {
|
||||
"sourceOption": {
|
||||
"workers": [
|
||||
"./src/main/ets/workers/upngWorkerTestCase.ets"
|
||||
]
|
||||
"arkOptions": {
|
||||
// "apPath": "./modules.ap" /* Profile used for profile-guided optimization (PGO), a compiler optimization technique to improve app runtime performance. */
|
||||
}
|
||||
},
|
||||
"buildOptionSet": [
|
||||
{
|
||||
"name": "release",
|
||||
"arkOptions": {
|
||||
"obfuscation": {
|
||||
"ruleOptions": {
|
||||
"enable": true,
|
||||
"files": [
|
||||
"./obfuscation-rules.txt"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"name": "ohosTest",
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
|
||||
|
||||
export default {
|
||||
system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
|
||||
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
# Define project specific obfuscation rules here.
|
||||
# You can include the obfuscation configuration files in the current module's build-profile.json5.
|
||||
#
|
||||
# For more details, see
|
||||
# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md
|
||||
|
||||
# Obfuscation options:
|
||||
# -disable-obfuscation: disable all obfuscations
|
||||
# -enable-property-obfuscation: obfuscate the property names
|
||||
# -enable-toplevel-obfuscation: obfuscate the names in the global scope
|
||||
# -compact: remove unnecessary blank spaces and all line feeds
|
||||
# -remove-log: remove all console.* statements
|
||||
# -print-namecache: print the name cache that contains the mapping from the old names to new names
|
||||
# -apply-namecache: reuse the given cache file
|
||||
|
||||
# Keep options:
|
||||
# -keep-property-name: specifies property names that you want to keep
|
||||
# -keep-global-name: specifies names that you want to keep in the global scope
|
|
@ -1,14 +1,13 @@
|
|||
{
|
||||
"license": "Apache License 2.0",
|
||||
"devDependencies": {},
|
||||
"name": "entry",
|
||||
"description": "example description",
|
||||
"repository": {},
|
||||
"version": "2.2.0-rc.3",
|
||||
"version": "1.0.0",
|
||||
"description": "Please describe the basic information.",
|
||||
"main": "",
|
||||
"author": "",
|
||||
"license": "",
|
||||
"dependencies": {
|
||||
"@ohos/libraryimageknife": "file:../sharedlibrary",
|
||||
"@ohos/sharedlibrary2": "file:../sharedlibrary2",
|
||||
"@ohos/disklrucache": "^2.0.2-rc.0",
|
||||
"@ohos/imageknife": "file:../library"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +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.
|
||||
*/
|
||||
export default class Constants {
|
||||
static readonly TAG: string = "MyImageKnifeTest: "
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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 { IEngineKey, ImageKnifeOption, PixelMapTransformation,SparkMD5 ,ImageKnifeRequestSource} from '@ohos/libraryimageknife';
|
||||
|
||||
//全局自定义key demo
|
||||
@Sendable
|
||||
export class CustomEngineKeyImpl implements IEngineKey {
|
||||
// 生成内存缓存key
|
||||
generateMemoryKey(loadSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,
|
||||
imageKnifeOption: ImageKnifeOption,isAnimator?: boolean, width?: number, height?: number): string {
|
||||
let key = ""
|
||||
if(imageKnifeOption.signature == "aaa" && typeof loadSrc == "string") {
|
||||
let num = loadSrc.indexOf("?")
|
||||
let src = loadSrc.substring(0,num)
|
||||
key = "loadSrc=" + src
|
||||
} else {
|
||||
key = (isAnimator == true ? "Animator=" : "loadSrc==") + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";"
|
||||
}
|
||||
if (requestSource === ImageKnifeRequestSource.SRC) {
|
||||
if (imageKnifeOption.signature !== undefined && imageKnifeOption.signature !== "") {
|
||||
key += "signature=" + imageKnifeOption.signature + ";"
|
||||
}
|
||||
if (imageKnifeOption.transformation) {
|
||||
key += "transformation=" + this.getTransformation(imageKnifeOption.transformation) + ";"
|
||||
}
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
// 生成文件缓存key
|
||||
generateFileKey(loadSrc: string | PixelMap | Resource, signature?: string,isAnimator?: boolean): string {
|
||||
let src = ""
|
||||
if(signature == "aaa" && typeof loadSrc == "string") {
|
||||
let num = loadSrc.indexOf("?")
|
||||
let key = loadSrc.substring(0,num)
|
||||
src = "loadSrc=" + key
|
||||
} else {
|
||||
src = (isAnimator == true ? "Animator=" : "loadSrc==") + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";"
|
||||
}
|
||||
if (signature !== undefined && signature !== "") {
|
||||
src += "signature=" + signature + ";"
|
||||
}
|
||||
return SparkMD5.hashBinary(src)
|
||||
}
|
||||
|
||||
private getTransformation(transformation: PixelMapTransformation): string {
|
||||
return transformation.getName()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export class GlobalContext {
|
||||
private constructor() {
|
||||
}
|
||||
|
||||
private static instance: GlobalContext;
|
||||
private _objects = new Map<string, Object>();
|
||||
|
||||
public static getContext(): GlobalContext {
|
||||
if (!GlobalContext.instance) {
|
||||
GlobalContext.instance = new GlobalContext();
|
||||
}
|
||||
return GlobalContext.instance;
|
||||
}
|
||||
|
||||
getObject(value: string): Object | undefined {
|
||||
return this._objects.get(value);
|
||||
}
|
||||
|
||||
setObject(key: string, objectClass: Object): void {
|
||||
this._objects.set(key, objectClass);
|
||||
}
|
||||
}
|
|
@ -1,27 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* 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,
|
||||
* 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 UIAbility from '@ohos.app.ability.UIAbility';
|
||||
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
|
||||
import hilog from '@ohos.hilog';
|
||||
import UIAbility from '@ohos.app.ability.UIAbility';
|
||||
import Want from '@ohos.app.ability.Want';
|
||||
import window from '@ohos.window';
|
||||
import { InitImageKnife, ImageKnifeGlobal, ImageKnife, ImageKnifeDrawFactory, LogUtil } from '@ohos/libraryimageknife'
|
||||
import { CustomEngineKeyImpl } from './CustomEngineKeyImpl'
|
||||
import { ImageKnife, InitImageKnife, LogUtil } from '@ohos/libraryimageknife';
|
||||
import { CustomEngineKeyImpl } from '../common/CustomEngineKeyImpl';
|
||||
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
|
||||
import { BusinessError } from '@ohos.base'
|
||||
|
||||
export default class EntryAbility extends UIAbility {
|
||||
onWindowStageCreate(windowStage: window.WindowStage) {
|
||||
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
|
||||
}
|
||||
|
||||
onDestroy(): void {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
|
||||
}
|
||||
|
||||
async onWindowStageCreate(windowStage: window.WindowStage): Promise<void> {
|
||||
// Main window is created, set main page for this ability
|
||||
// let list: Array<Permissions> = ['ohos.permission.READ_IMAGEVIDEO', 'ohos.permission.WRITE_IMAGEVIDEO'];
|
||||
// let permissionRequestResult: Object;
|
||||
|
@ -35,25 +45,37 @@ export default class EntryAbility extends UIAbility {
|
|||
// }
|
||||
// })
|
||||
|
||||
windowStage.loadContent('pages/index', (err: BusinessError, data: void) => {
|
||||
});
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
|
||||
|
||||
InitImageKnife.init(this.context);
|
||||
|
||||
let imageKnife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife()
|
||||
if (imageKnife != undefined) {
|
||||
// 全局配置网络加载进度条
|
||||
imageKnife
|
||||
.setDefaultLifeCycle(ImageKnifeDrawFactory.createProgressLifeCycle("#10a5ff", 0.5))
|
||||
// 全局配置缓存key
|
||||
imageKnife.setEngineKeyImpl(new CustomEngineKeyImpl())
|
||||
// 设置全局内存缓存大小张数
|
||||
imageKnife.setLruCacheSize(100, 100 * 1204 * 1024)
|
||||
// 全局配置请求头
|
||||
imageKnife.addHeader('refer', "http://1.94.37.200:7070/AntiTheftChain/downloadImage");
|
||||
imageKnife.deleteHeader('refer');
|
||||
}
|
||||
// 开启ImageKnife所有级别日志开关
|
||||
LogUtil.mLogLevel = LogUtil.ALL
|
||||
// 初始化ImageKnife的文件缓存
|
||||
await InitImageKnife.init(this.context)
|
||||
ImageKnife.getInstance().setEngineKeyImpl(new CustomEngineKeyImpl())
|
||||
// 全局配置请求头
|
||||
ImageKnife.getInstance().addHeader('refer', "http://1.94.37.200:7070/AntiTheftChain/downloadImage");
|
||||
ImageKnife.getInstance().deleteHeader('refer');
|
||||
|
||||
windowStage.loadContent('pages/Index', (err, data) => {
|
||||
if (err.code) {
|
||||
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
|
||||
return;
|
||||
}
|
||||
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
|
||||
});
|
||||
}
|
||||
|
||||
onWindowStageDestroy(): void {
|
||||
// Main window is destroyed, release UI related resources
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
|
||||
}
|
||||
|
||||
onForeground(): void {
|
||||
// Ability has brought to foreground
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
|
||||
}
|
||||
|
||||
onBackground(): void {
|
||||
// Ability has back to background
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
import { AnimatorOption, ImageKnifeAnimatorComponent } from "@ohos/libraryimageknife"
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct ImageAnimatorPage {
|
||||
@State animatorOption: AnimatorOption = {
|
||||
state: AnimationStatus.Running,
|
||||
iterations: -1
|
||||
}
|
||||
build() {
|
||||
Column(){
|
||||
Flex(){
|
||||
Button("播放").onClick(()=>{
|
||||
this.animatorOption.state = AnimationStatus.Running
|
||||
})
|
||||
Button("暂停").onClick(()=>{
|
||||
this.animatorOption.state = AnimationStatus.Paused
|
||||
})
|
||||
Button("停止").onClick(()=>{
|
||||
this.animatorOption.state = AnimationStatus.Stopped
|
||||
})
|
||||
Button("无限循环").onClick(()=>{
|
||||
this.animatorOption.iterations = -1
|
||||
})
|
||||
Button("播放一次").onClick(()=>{
|
||||
this.animatorOption.iterations = 1
|
||||
})
|
||||
Button("播放两次").onClick(()=>{
|
||||
this.animatorOption.iterations = 2
|
||||
})
|
||||
}
|
||||
ImageKnifeAnimatorComponent({
|
||||
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})
|
||||
}.width("100%").height("100%")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,432 @@
|
|||
/*
|
||||
* 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 {
|
||||
BlurTransformation,
|
||||
BrightnessTransformation,
|
||||
CropSquareTransformation,
|
||||
CropTransformation,
|
||||
GrayScaleTransformation,
|
||||
ImageKnifeComponent,
|
||||
ImageKnifeOption,
|
||||
InvertTransformation,
|
||||
KuwaharaTransformation,
|
||||
MaskTransformation,
|
||||
MultiTransTransformation,
|
||||
PixelationTransformation,
|
||||
PixelMapTransformation,
|
||||
SepiaTransformation,
|
||||
SketchTransformation,
|
||||
SwirlTransformation,
|
||||
ToonTransformation,
|
||||
VignetterTransformation
|
||||
} from '@ohos/libraryimageknife';
|
||||
import { collections } from '@kit.ArkTS'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct ImageTransformation {
|
||||
@State imageKnifeOption: ImageKnifeOption = {
|
||||
loadSrc: $r('app.media.pngSample'),
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Contain
|
||||
}
|
||||
@State isRound: boolean = false;
|
||||
@State isContrast: boolean = false;
|
||||
@State isRotate: boolean = false;
|
||||
isBlur: boolean = false
|
||||
isBrightness: boolean = false
|
||||
isGrayScale: boolean = false;
|
||||
isInvert: boolean = false;
|
||||
isToon: boolean = false;
|
||||
isCropCircle: boolean = false;
|
||||
isCropCircleWithBorder: boolean = false;
|
||||
isKuwahara: boolean = false;
|
||||
isPixelation: boolean = false;
|
||||
isSketch: boolean = false;
|
||||
isSwirl: boolean = false;
|
||||
isVignetter: boolean = false;
|
||||
isCropSquare: boolean = false;
|
||||
isCropTop: boolean = false;
|
||||
isCropCenter: boolean = false;
|
||||
isCropBottom: boolean = false;
|
||||
isMask: boolean = false;
|
||||
isSepia: boolean = false;
|
||||
|
||||
build() {
|
||||
Scroll() {
|
||||
Column() {
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox1', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isBlur = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('模糊效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox2', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isBrightness = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('高亮效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox3', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isGrayScale = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('灰化效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox4', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isInvert = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('反转效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox5', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isToon = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('动画滤镜效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox6', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isCropCircle = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('裁剪圆形效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox7', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isCropCircleWithBorder = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('裁剪圆形带边框效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox8', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isContrast = value;
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('对比度效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox9', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isSepia = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('乌墨色滤波效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox10', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isRotate = value;
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('旋转效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox11', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isRound = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('圆角效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox12', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isKuwahara = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('桑原滤波效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox13', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isPixelation = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('像素化滤波效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox14', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isSketch = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('素描滤波效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox15', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isSwirl = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('扭曲滤波效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox16', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isVignetter = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('装饰滤波效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox17', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isCropSquare = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('正方形裁剪效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox18', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isCropTop = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('上方裁剪效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox19', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isCropCenter = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('中间裁剪效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox20', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isCropBottom = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('底下裁剪效果').fontSize(20)
|
||||
}
|
||||
|
||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||
Checkbox({ name: 'checkbox21', group: 'checkboxGroup' })
|
||||
.selectedColor(0x39a2db)
|
||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||
.onChange((value: boolean) => {
|
||||
this.isMask = value;
|
||||
this.updateImageKnifeOption();
|
||||
})
|
||||
.width(30)
|
||||
.height(30)
|
||||
Text('遮罩效果').fontSize(20)
|
||||
}
|
||||
|
||||
if (this.isContrast) {
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: this.imageKnifeOption
|
||||
})
|
||||
.width(300)
|
||||
.height(300)
|
||||
.rotate({ angle: this.isRotate ? 90 : 0 })
|
||||
.contrast(12)
|
||||
.backgroundColor(Color.Pink)
|
||||
} else {
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: this.imageKnifeOption
|
||||
}).width(300)
|
||||
.height(300)
|
||||
.rotate({ angle: this.isRotate ? 90 : 0 })
|
||||
.backgroundColor(Color.Pink)
|
||||
}
|
||||
}
|
||||
}
|
||||
.height('100%')
|
||||
.width('100%')
|
||||
}
|
||||
|
||||
updateImageKnifeOption() {
|
||||
let transformations: collections.Array<PixelMapTransformation> = new collections.Array<PixelMapTransformation>()
|
||||
if (this.isBlur) {
|
||||
transformations.push(new BlurTransformation(5));
|
||||
}
|
||||
if (this.isBrightness) {
|
||||
transformations.push(new BrightnessTransformation(0.2));
|
||||
}
|
||||
if (this.isGrayScale) {
|
||||
transformations.push(new GrayScaleTransformation());
|
||||
}
|
||||
if (this.isInvert) {
|
||||
transformations.push(new InvertTransformation());
|
||||
}
|
||||
if (this.isToon) {
|
||||
transformations.push(new ToonTransformation(0.3, 10.0));
|
||||
}
|
||||
if (this.isKuwahara) {
|
||||
transformations.push(new KuwaharaTransformation(10));
|
||||
}
|
||||
if (this.isPixelation) {
|
||||
transformations.push(new PixelationTransformation(5.0));
|
||||
}
|
||||
if (this.isSketch) {
|
||||
transformations.push(new SketchTransformation());
|
||||
}
|
||||
if (this.isSwirl) {
|
||||
transformations.push(new SwirlTransformation(200, 1.0, [0.5, 0.5]));
|
||||
}
|
||||
if (this.isVignetter) {
|
||||
transformations.push(new VignetterTransformation([0.5, 0.5], [0.0, 0.0, 0.0], [0.3, 0.75]));
|
||||
}
|
||||
if (this.isCropSquare) {
|
||||
transformations.push(new CropSquareTransformation());
|
||||
}
|
||||
if (this.isCropTop) {
|
||||
transformations.push(new CropTransformation(25, 25, 0));
|
||||
}
|
||||
if (this.isCropCenter) {
|
||||
transformations.push(new CropTransformation(25, 25, 1));
|
||||
}
|
||||
if (this.isCropBottom) {
|
||||
transformations.push(new CropTransformation(25, 25, 2));
|
||||
}
|
||||
if (this.isSepia) {
|
||||
transformations.push(new SepiaTransformation());
|
||||
}
|
||||
if (this.isMask) {
|
||||
transformations.push(new MaskTransformation($r('app.media.mask_starfish')));
|
||||
}
|
||||
this.imageKnifeOption = {
|
||||
loadSrc: $r('app.media.pngSample'),
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Contain,
|
||||
border: { radius: this.isRound ? { topLeft: 50, bottomRight: 50 } : 0 },
|
||||
transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined
|
||||
}
|
||||
if (this.isCropCircle) {
|
||||
this.imageKnifeOption.objectFit = ImageFit.Cover;
|
||||
this.imageKnifeOption.border = { radius: 150 };
|
||||
}
|
||||
if (this.isCropCircleWithBorder) {
|
||||
this.imageKnifeOption.objectFit = ImageFit.Cover;
|
||||
this.imageKnifeOption.border = { radius: 150, color: Color.Red, width: 5 };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife';
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct ListPage {
|
||||
|
||||
private data: string[] = []
|
||||
@State ImageKnifeOption: ImageKnifeOption = { loadSrc: $r('app.media.startIcon')}
|
||||
|
||||
|
||||
aboutToAppear(): void {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
this.data.push(i.toString())
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
Row() {
|
||||
List({ space: 10 }) {
|
||||
ForEach(this.data, (item: string) => {
|
||||
ImageKnifeComponent({ imageKnifeOption: this.ImageKnifeOption }).height(200).width(200)
|
||||
}, (item: string) => item)
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
.height('100%')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeComponent, ImageKnifeOption } from "@ohos/libraryimageknife"
|
||||
import matrix4 from '@ohos.matrix4'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct LoadStatePage {
|
||||
|
||||
starTime:number = new Date().getTime()
|
||||
|
||||
@State ImageKnifeOption: ImageKnifeOption = {
|
||||
loadSrc: $r("app.media.rabbit"),
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Contain,
|
||||
onLoadListener: {
|
||||
onLoadFailed: (err) => {
|
||||
console.error("Load Failed Reason: " + err);
|
||||
},
|
||||
onLoadSuccess: (data) => {
|
||||
return data;
|
||||
},
|
||||
},
|
||||
border: { radius: 50 }
|
||||
}
|
||||
@State imageKnifeOption1: ImageKnifeOption = {
|
||||
loadSrc: $r('app.media.startIcon')
|
||||
}
|
||||
@State message: string = ""
|
||||
@State currentWidth: number = 200
|
||||
@State currentHeight: number = 200
|
||||
@State typeValue: string = ""
|
||||
build() {
|
||||
Column() {
|
||||
Text('测试失败场景请先关闭网络,并保证本地没有此网络图片的缓存')
|
||||
.margin({ top: 20 })
|
||||
Row() {
|
||||
Button('测试失败/成功场景')
|
||||
.onClick(() => {
|
||||
this.ImageKnifeOption = {
|
||||
loadSrc: "https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Contain,
|
||||
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");
|
||||
this.currentWidth = imageData.imageWidth!
|
||||
this.currentHeight = imageData.imageHeight!
|
||||
this.typeValue = imageData.type!
|
||||
return data;
|
||||
},
|
||||
},
|
||||
border: { radius: 50 },
|
||||
onComplete:(event)=>{
|
||||
console.error("Load onComplete width:"+event?.width , " height:"+event?.height , " componentWidth:"+event?.componentWidth," componentHeight:" + event?.componentHeight);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
.margin({ top: 20 })
|
||||
Text(this.typeValue)
|
||||
ImageKnifeComponent({ imageKnifeOption: this.ImageKnifeOption }).height(this.currentHeight).width(this.currentWidth)
|
||||
.margin({ top: 20 })
|
||||
Button("自定义下载失败").onClick(()=>{
|
||||
this.imageKnifeOption1 = {
|
||||
loadSrc: "abc",
|
||||
placeholderSrc:$r('app.media.loading'),
|
||||
errorholderSrc:$r('app.media.failed'),
|
||||
customGetImage:custom,
|
||||
onLoadListener: {
|
||||
onLoadFailed:(err)=>{
|
||||
this.message = "err:" + err
|
||||
}
|
||||
}
|
||||
}
|
||||
}).margin({ top: 20 })
|
||||
Text(this.message).fontSize(20).margin({ top: 20 })
|
||||
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).height(this.currentHeight).width(this.currentWidth)
|
||||
.margin({ top: 20 })
|
||||
}
|
||||
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
}
|
||||
|
||||
}
|
||||
// 自定义下载方法
|
||||
@Concurrent
|
||||
async function custom(context: Context, src: string | PixelMap | Resource): Promise<ArrayBuffer | undefined> {
|
||||
console.info("ImageKnife:: custom download:" + src)
|
||||
// 举例写死从本地文件读取,也可以自己请求网络图片
|
||||
return undefined
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeComponent } from '@ohos/libraryimageknife'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct LongImagePage {
|
||||
|
||||
build() {
|
||||
Scroll() {
|
||||
|
||||
// Image("https://wx2.sinaimg.cn/mw690/006HyQKGgy1hnqp08dw09j30u04twu0x.jpg").objectFit(ImageFit.Auto).height(300)
|
||||
|
||||
// Image($r("app.media.aaa")).objectFit(ImageFit.Auto).width(200)
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc:"https://wx2.sinaimg.cn/mw690/006HyQKGgy1hnqp08dw09j30u04twu0x.jpg",
|
||||
//src:$r("app.media.aaa"),
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.failed"),
|
||||
objectFit: ImageFit.Auto
|
||||
}
|
||||
})
|
||||
}
|
||||
.height('100%') .width('100%')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnife, ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct ObjectFitPage {
|
||||
@State imageKnifeOption: ImageKnifeOption = {
|
||||
loadSrc: $r("app.media.app_icon"),
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Fill
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
|
||||
Button("主图Fill拉伸填充").onClick(()=>{
|
||||
this.imageKnifeOption = {
|
||||
loadSrc: $r("app.media.app_icon"),
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Fill
|
||||
}
|
||||
})
|
||||
|
||||
Button("占位图Contain保持比例填充").margin({top:10}).onClick(async () => {
|
||||
ImageKnife.getInstance().removeAllMemoryCache()
|
||||
await ImageKnife.getInstance().removeAllFileCache()
|
||||
|
||||
this.imageKnifeOption = {
|
||||
loadSrc: "https://wx2.sinaimg.cn/mw690/006HyQKGgy1hnqp08dw09j30u04twu0x.jpg",
|
||||
placeholderSrc: $r("app.media.app_icon"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Fill,
|
||||
placeholderObjectFit: ImageFit.Contain
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Button("错误图None不变化").margin({top:10}).onClick(() => {
|
||||
this.imageKnifeOption = {
|
||||
loadSrc: "http://xxxxx",
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Fill,
|
||||
errorholderObjectFit: ImageFit.None
|
||||
}
|
||||
})
|
||||
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: this.imageKnifeOption
|
||||
}).width(300).height(200).border({width:1}).margin({top:50})
|
||||
|
||||
}
|
||||
.height('100%')
|
||||
.width('100%')
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
* 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
|
||||
|
@ -12,9 +12,8 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife';
|
||||
|
||||
import { ImageKnifeComponent, ImageKnifeOption, NONE, DiskStrategy } from '@ohos/libraryimageknife'
|
||||
import { ObjectKey } from '@ohos/libraryimageknife';
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
|
@ -22,43 +21,39 @@ struct SignatureTestPage {
|
|||
@State imageKnifeOption1: ImageKnifeOption =
|
||||
{
|
||||
loadSrc: $r('app.media.icon'),
|
||||
placeholderSrc: $r('app.media.icon_loading'),
|
||||
errorholderSrc: $r('app.media.icon_failed'),
|
||||
placeholderSrc:$r("app.media.loading"),
|
||||
};
|
||||
@State imageKnifeOption2: ImageKnifeOption =
|
||||
{
|
||||
loadSrc: $r('app.media.icon'),
|
||||
placeholderSrc: $r('app.media.icon_loading'),
|
||||
errorholderSrc: $r('app.media.icon_failed')
|
||||
placeholderSrc:$r("app.media.loading"),
|
||||
};
|
||||
|
||||
build() {
|
||||
Scroll() {
|
||||
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
|
||||
|
||||
Text("Signature固定为 1").fontSize(15)
|
||||
Text("key固定为 1").fontSize(15)
|
||||
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
|
||||
Button("加载")
|
||||
.onClick(() => {
|
||||
this.imageKnifeOption1 = {
|
||||
loadSrc: 'https://img-blog.csdn.net/20140514114029140',
|
||||
placeholderSrc: $r('app.media.icon_loading'),
|
||||
errorholderSrc: $r('app.media.icon_failed'),
|
||||
signature: new ObjectKey("1")
|
||||
placeholderSrc:$r("app.media.loading"),
|
||||
signature: "1"
|
||||
}
|
||||
}).margin({ top: 5, left: 3 })
|
||||
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).width(300).height(300)
|
||||
}.width('100%').backgroundColor(Color.Pink)
|
||||
|
||||
Text("设置Signature,每次为时间戳").fontSize(15)
|
||||
Text("key每次变化:时间戳").fontSize(15)
|
||||
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
|
||||
Button("加载")
|
||||
.onClick(() => {
|
||||
this.imageKnifeOption2 = {
|
||||
loadSrc: 'https://img-blog.csdn.net/20140514114029140',
|
||||
placeholderSrc: $r('app.media.icon_loading'),
|
||||
errorholderSrc: $r('app.media.icon_failed'),
|
||||
signature: new ObjectKey(new Date().getTime().toString())
|
||||
placeholderSrc:$r("app.media.loading"),
|
||||
signature: new Date().getTime().toString()
|
||||
}
|
||||
}).margin({ top: 5, left: 3 })
|
||||
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption2 }).width(300).height(300)
|
||||
|
@ -71,7 +66,7 @@ struct SignatureTestPage {
|
|||
}
|
||||
|
||||
aboutToAppear() {
|
||||
console.log("唯一标识页面:" + new ObjectKey(new Date().getTime().toString()).getKey())
|
||||
console.log("唯一标识页面:" + new Date().getTime().toString())
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* 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,BlurTransformation } from '@ohos/libraryimageknife';
|
||||
import fs from '@ohos.file.fs';
|
||||
import image from '@ohos.multimedia.image';
|
||||
import { common2D, drawing } from '@kit.ArkGraphics2D';
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct SingleImage {
|
||||
resource: string = "app.media.svgSample"
|
||||
scroller: Scroller = new Scroller;
|
||||
localFile: string = getContext(this).filesDir + "/icon.png"
|
||||
@State pixelMap:PixelMap | undefined = undefined;
|
||||
@State DrawingColorFilter: ColorFilter | undefined = undefined
|
||||
private color: common2D.Color = { alpha: 255, red: 255, green: 0, blue: 0 };
|
||||
aboutToAppear(): void {
|
||||
// 拷贝本地文件
|
||||
let icon: Uint8Array = getContext(this).resourceManager.getMediaContentSync($r("app.media.startIcon"));
|
||||
let file = fs.openSync(this.localFile, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
|
||||
fs.writeSync(file.fd, icon.buffer);
|
||||
fs.fsyncSync(file.fd);
|
||||
fs.closeSync(file);
|
||||
this.changePic(getContext().resourceManager.getMediaContentSync( $r("app.media.aaa"))
|
||||
.buffer as ArrayBuffer);
|
||||
|
||||
|
||||
}
|
||||
|
||||
build() {
|
||||
Scroll(this.scroller) {
|
||||
Column() {
|
||||
Text("本地资源svg图片")
|
||||
.fontSize(30)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: $r("app.media.svgSample"),
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.failed"),
|
||||
objectFit: ImageFit.Contain
|
||||
}
|
||||
}).width(100).height(100)
|
||||
.onClick(()=>{
|
||||
this.DrawingColorFilter = drawing.ColorFilter.createBlendModeColorFilter(this.color, drawing.BlendMode.SRC_IN);
|
||||
})
|
||||
Text("本地context files下文件")
|
||||
.fontSize(30)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: this.localFile,
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.failed"),
|
||||
objectFit: ImageFit.Contain
|
||||
}
|
||||
}).width(100).height(100)
|
||||
Text("网络图片")
|
||||
.fontSize(30)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.failed"),
|
||||
objectFit: ImageFit.Contain,
|
||||
progressListener:(progress:number)=>{console.info("ImageKnife:: call back progress = " + progress)}
|
||||
}
|
||||
}).width(100).height(100)
|
||||
Text("自定义下载")
|
||||
.fontSize(30)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: "https://file.atomgit.com/uploads/user/1704857786989_8994.jpeg",
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.failed"),
|
||||
objectFit: ImageFit.Contain,
|
||||
customGetImage: custom,
|
||||
transformation: new BlurTransformation(10)
|
||||
}
|
||||
}).width(100).height(100)
|
||||
Text("pixelMap加载图片")
|
||||
.fontSize(30)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: this.pixelMap!,
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.failed"),
|
||||
objectFit: ImageFit.Contain,
|
||||
}
|
||||
}).width(100).height(100)
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
.height('100%')
|
||||
}
|
||||
|
||||
changePic(buffer: ArrayBuffer){
|
||||
let imageSource: image.ImageSource = image.createImageSource(buffer);
|
||||
if (imageSource) {
|
||||
let decodingOptions: image.DecodingOptions = {
|
||||
editable: true,
|
||||
}
|
||||
imageSource.createPixelMap(decodingOptions,(err,pixelMap)=>{
|
||||
this.pixelMap = pixelMap;
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 自定义下载方法
|
||||
@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.startIcon").id).buffer as ArrayBuffer
|
||||
}
|
||||
|
|
@ -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 { ImageKnifeComponent } from '@ohos/libraryimageknife';
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct TestCommonImage {
|
||||
private data: Array<string> = []
|
||||
aboutToAppear(): void {
|
||||
for (let index = 0; index < 30; index++) {
|
||||
this.data.push(`https://img-blog.csdn.net/20140514114029140?${index}`)
|
||||
}
|
||||
}
|
||||
build() {
|
||||
Column() {
|
||||
WaterFlow() {
|
||||
ForEach(this.data,(item: string)=>{
|
||||
FlowItem() {
|
||||
Column(){
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: item,
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.failed"),
|
||||
objectFit: ImageFit.Contain,
|
||||
signature: "aaa"
|
||||
}
|
||||
}).width("50%").height(200)
|
||||
}
|
||||
}.height(200)
|
||||
.backgroundColor("#95efd2")
|
||||
},(item: string) => item)
|
||||
}.columnsTemplate("1fr 1fr")
|
||||
.columnsGap(10)
|
||||
.rowsGap(5)
|
||||
.backgroundColor(0xFAEEE0)
|
||||
.width("100%").height("100%")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct TestErrorHolderPage {
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Text("ImageKnifeComponent1").fontSize(20)
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: "abc",
|
||||
errorholderSrc:$r('app.media.failed')
|
||||
}
|
||||
}).width(200).height(200)
|
||||
Text("ImageKnifeComponent2").fontSize(20)
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: "abc",
|
||||
errorholderSrc:$r('app.media.startIcon')
|
||||
}
|
||||
}).width(200).height(200)
|
||||
Text("ImageKnifeComponent2").fontSize(20)
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: "abc",
|
||||
errorholderSrc:$r('app.media.mask_starfish')
|
||||
}
|
||||
}).width(200).height(200)
|
||||
}
|
||||
.height('100%') .width('100%')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeComponent,ImageKnifeOption } from '@ohos/libraryimageknife'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct TestPrefetchToFileCachePage {
|
||||
@State imageKnifeOption: ImageKnifeOption = {
|
||||
loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
|
||||
placeholderSrc:$r('app.media.loading'),
|
||||
headerOption:[
|
||||
{
|
||||
key:"abc",
|
||||
value:"单个"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: this.imageKnifeOption
|
||||
}).width(300).height(300)
|
||||
}
|
||||
.height('100%') .width('100%')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 { IndexComponent } from "@ohos/libraryimageknife"
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct TestHspPreLoadImage {
|
||||
build() {
|
||||
Column() {
|
||||
IndexComponent()
|
||||
}.width("100%").height('100%')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* 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'
|
||||
|
||||
@Observed
|
||||
export class MsgModel {
|
||||
id: string
|
||||
cId: string
|
||||
body: string
|
||||
status: number
|
||||
|
||||
constructor(id: string, body: string, cId?: string) {
|
||||
this.id = id
|
||||
this.body = body
|
||||
this.status = -1
|
||||
this.cId = cId || ''
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Reusable
|
||||
@Component
|
||||
export struct MsgItem {
|
||||
count: number = 0
|
||||
private data: Array<string> = [
|
||||
"http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg",
|
||||
"http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg",
|
||||
"http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg",
|
||||
"http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg",
|
||||
"http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg",
|
||||
"http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg",
|
||||
"http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg",
|
||||
"http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg",
|
||||
"http://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg",
|
||||
"http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg",
|
||||
"http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg",
|
||||
"http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg",
|
||||
"http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg",
|
||||
"http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg",
|
||||
"http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg",
|
||||
"http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
|
||||
]
|
||||
build(){
|
||||
if (this.count % 2 == 0 && this.count <6){
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption:{
|
||||
loadSrc:$r("app.media.startIcon"),
|
||||
placeholderSrc:$r("app.media.loading")
|
||||
},syncLoad:true
|
||||
})
|
||||
}else if (this.count > 6 && this.count - 6 < this.data.length){
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption:{
|
||||
loadSrc:this.data[this.count - 6],
|
||||
placeholderSrc:$r("app.media.loading")
|
||||
},syncLoad:true
|
||||
})
|
||||
}else {
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption:{
|
||||
loadSrc:$r("app.media.pngSample"),
|
||||
placeholderSrc:$r("app.media.loading")
|
||||
},syncLoad:true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct ImageTestPage {
|
||||
count : number = 0
|
||||
rCount: number = 0
|
||||
scroller: Scroller = new Scroller()
|
||||
@State list: MsgModel[] = []
|
||||
@State imageSize: number =100
|
||||
handAdd(){
|
||||
this.count++
|
||||
const msgItem = new MsgModel('add_id'+this.count, 'addBody'+this.count,'cId'+ this.count)
|
||||
this.list.push(msgItem)
|
||||
setTimeout(()=> {
|
||||
msgItem.status = 1
|
||||
},3000)
|
||||
this.scroller.scrollEdge(Edge.Bottom)
|
||||
}
|
||||
|
||||
build(){
|
||||
Column(){
|
||||
Row(){
|
||||
Button("addItem").onClick(()=> {
|
||||
this.handAdd()
|
||||
})
|
||||
Button("remove").onClick(()=> {
|
||||
this.list.splice(0,1)
|
||||
})
|
||||
}
|
||||
Row(){
|
||||
Text("点击尺寸加50")
|
||||
.onClick(()=> {
|
||||
this.imageSize = this.imageSize + 50
|
||||
})
|
||||
.width('50%').backgroundColor(0x88ff0000).textAlign(TextAlign.Center).height(50)
|
||||
Text("点击尺寸减50")
|
||||
.onClick(()=> {
|
||||
this.imageSize = Math.max(this.imageSize - 50, 0)
|
||||
})
|
||||
.width('50%').backgroundColor(0x88ff0000).textAlign(TextAlign.Center).height(50)
|
||||
}.height(50).width('100%')
|
||||
|
||||
List({space: 20, scroller: this.scroller }) {
|
||||
ForEach(this.list, (item: MsgModel)=> {
|
||||
ListItem(){
|
||||
MsgItem({count : this.count}).width(this.imageSize).height(this.imageSize);
|
||||
}
|
||||
},(item:MsgModel)=> item.id)
|
||||
}.width('100%').height('auto').layoutWeight(1)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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, ImageKnife, ImageKnifeOption, CacheStrategy } from '@ohos/libraryimageknife'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct TestIsUrlExist {
|
||||
@State imageKnifeOption: ImageKnifeOption = {
|
||||
loadSrc: $r('app.media.startIcon'),
|
||||
placeholderSrc: $r('app.media.loading'),
|
||||
errorholderSrc:$r('app.media.failed')
|
||||
}
|
||||
@State source: PixelMap | string | Resource = $r("app.media.startIcon")
|
||||
@State source1: PixelMap | string | Resource = $r("app.media.startIcon")
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Flex() {
|
||||
Button("预加载gif图").onClick(() => {
|
||||
this.imageKnifeOption.loadSrc =
|
||||
"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658"
|
||||
})
|
||||
Button("内存缓存获取gif").onClick(() => {
|
||||
ImageKnife.getInstance()
|
||||
.getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
|
||||
CacheStrategy.Memory)
|
||||
.then((data) => {
|
||||
this.source = data !== undefined ? data.source : $r("app.media.startIcon")
|
||||
})
|
||||
})
|
||||
Button("文件缓存获取gif").onClick(() => {
|
||||
ImageKnife.getInstance()
|
||||
.getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
|
||||
CacheStrategy.File)
|
||||
.then((data) => {
|
||||
this.source1 = data !== undefined ? data.source : $r("app.media.startIcon")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Flex() {
|
||||
Button("预加载静态图").onClick(() => {
|
||||
this.imageKnifeOption.loadSrc =
|
||||
'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp'
|
||||
})
|
||||
Button("内存缓存获取").onClick(() => {
|
||||
ImageKnife.getInstance()
|
||||
.getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
|
||||
CacheStrategy.Memory)
|
||||
.then((data) => {
|
||||
this.source = data!.source
|
||||
})
|
||||
})
|
||||
Button("文件缓存获取").onClick(() => {
|
||||
ImageKnife.getInstance()
|
||||
.getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
|
||||
CacheStrategy.File)
|
||||
.then((data) => {
|
||||
this.source1 = data!.source
|
||||
})
|
||||
})
|
||||
}.margin({ top: 10 })
|
||||
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: this.imageKnifeOption
|
||||
}).width(200).height(200).margin({ top: 10 })
|
||||
Image(this.source).margin({ top: 10 })
|
||||
.width(200).height(200)
|
||||
Image(this.source1).margin({ top: 10 })
|
||||
.width(200).height(200)
|
||||
}
|
||||
.height('100%').width('100%')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeComponent,ImageKnife,ImageKnifeOption } from '@ohos/libraryimageknife'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct TestPrefetchToFileCachePage {
|
||||
@State imageKnifeOption: ImageKnifeOption = {
|
||||
loadSrc:$r('app.media.startIcon'),
|
||||
placeholderSrc:$r('app.media.loading'),
|
||||
errorholderSrc:$r('app.media.failed')
|
||||
}
|
||||
async preload(url:string) {
|
||||
let fileCachePath = await ImageKnife.getInstance().preLoadCache(url)
|
||||
console.log("preload-fileCachePath=="+ fileCachePath)
|
||||
}
|
||||
async preload1(url:string) {
|
||||
let fileCachePath = await ImageKnife.getInstance().preLoadCache({ loadSrc: url })
|
||||
console.log("preload-fileCachePath1=="+ fileCachePath)
|
||||
}
|
||||
build() {
|
||||
Column() {
|
||||
Button("url预加载图片到文件缓存").margin({top:10}).onClick(async ()=>{
|
||||
await this.preload("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658")
|
||||
})
|
||||
Button("option预加载图片到文件缓存").margin({top:10}).onClick(async ()=>{
|
||||
await this.preload1("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658")
|
||||
})
|
||||
Button("加载图片(预加载后可断网加载)").margin({top:10}).onClick(()=>{
|
||||
this.imageKnifeOption.loadSrc = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658"
|
||||
})
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: this.imageKnifeOption
|
||||
}).width(300).height(300).margin({top:30})
|
||||
}
|
||||
.height('100%') .width('100%')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeComponent, ImageKnife, ImageKnifeOption, CacheStrategy } from '@ohos/libraryimageknife'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct TestRemoveCache {
|
||||
@State imageKnifeOption: ImageKnifeOption = {
|
||||
loadSrc: $r('app.media.startIcon'),
|
||||
placeholderSrc: $r('app.media.loading'),
|
||||
errorholderSrc:$r('app.media.failed')
|
||||
}
|
||||
@State source: PixelMap | string | Resource = $r("app.media.startIcon");
|
||||
@State source1: PixelMap | string | Resource = $r("app.media.startIcon");
|
||||
@State url: string = '';
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Flex() {
|
||||
Button("预加载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(() => {
|
||||
ImageKnife.getInstance()
|
||||
.getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
|
||||
CacheStrategy.Memory)
|
||||
.then((data) => {
|
||||
this.source = data !== undefined ? data.source : $r("app.media.startIcon");
|
||||
})
|
||||
})
|
||||
.margin({left:10})
|
||||
Button("文件缓存获取gif").onClick(() => {
|
||||
ImageKnife.getInstance()
|
||||
.getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
|
||||
CacheStrategy.File)
|
||||
.then((data) => {
|
||||
this.source1 = data !== undefined ? data.source : $r("app.media.startIcon");
|
||||
})
|
||||
})
|
||||
.margin({left:10})
|
||||
}
|
||||
|
||||
Flex() {
|
||||
Button("预加载静态图").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(() => {
|
||||
ImageKnife.getInstance()
|
||||
.getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
|
||||
CacheStrategy.Memory)
|
||||
.then((data) => {
|
||||
this.source = data!.source;
|
||||
})
|
||||
})
|
||||
.margin({left:10})
|
||||
Button("文件缓存获取").onClick(() => {
|
||||
ImageKnife.getInstance()
|
||||
.getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
|
||||
CacheStrategy.File)
|
||||
.then((data) => {
|
||||
this.source1 = data!.source;
|
||||
})
|
||||
})
|
||||
.margin({left:10})
|
||||
}.margin({ top: 10 })
|
||||
|
||||
Flex() {
|
||||
Button("删除全部缓存").onClick(() => {
|
||||
ImageKnife.getInstance()
|
||||
.removeAllMemoryCache()
|
||||
ImageKnife.getInstance()
|
||||
.removeAllFileCache()
|
||||
})
|
||||
.margin({left:5})
|
||||
Button("删除全部内存缓存").onClick(() => {
|
||||
ImageKnife.getInstance()
|
||||
.removeAllMemoryCache()
|
||||
})
|
||||
.margin({left:5})
|
||||
Button("删除全部文件缓存").onClick(() => {
|
||||
ImageKnife.getInstance()
|
||||
.removeAllFileCache()
|
||||
})
|
||||
.margin({left:5})
|
||||
}.margin({ top: 10 })
|
||||
|
||||
Flex() {
|
||||
Button("删除自定义内存缓存").onClick(() => {
|
||||
ImageKnife.getInstance()
|
||||
.removeMemoryCache(this.url)
|
||||
})
|
||||
.margin({left:20})
|
||||
Button("删除自定义文件缓存").onClick(() => {
|
||||
ImageKnife.getInstance()
|
||||
.removeFileCache(this.url)
|
||||
})
|
||||
.margin({left:20})
|
||||
}.margin({ top: 10 })
|
||||
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: this.imageKnifeOption
|
||||
}).width(200).height(200).margin({ top: 10 })
|
||||
Image(this.source).margin({ top: 10 })
|
||||
.width(200).height(200)
|
||||
Image(this.source1).margin({ top: 10 })
|
||||
.width(200).height(200)
|
||||
}
|
||||
.height('100%').width('100%')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeComponent, ImageKnife, ImageKnifeOption } from '@ohos/libraryimageknife'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct TestSetCustomImagePage {
|
||||
@State imageKnifeOption: ImageKnifeOption = {
|
||||
loadSrc: $r('app.media.startIcon'),
|
||||
placeholderSrc: $r('app.media.loading')
|
||||
}
|
||||
aboutToAppear(): void {
|
||||
ImageKnife.getInstance().setCustomGetImage(custom)
|
||||
}
|
||||
aboutToDisappear(): void {
|
||||
ImageKnife.getInstance().setCustomGetImage()
|
||||
}
|
||||
build() {
|
||||
Column() {
|
||||
Button("自定义下载a").onClick(()=>{
|
||||
this.imageKnifeOption = {
|
||||
loadSrc: "aaa",
|
||||
placeholderSrc: $r('app.media.loading')
|
||||
}
|
||||
})
|
||||
Button("自定义下载b").onClick(()=>{
|
||||
this.imageKnifeOption = {
|
||||
loadSrc: "bbb",
|
||||
placeholderSrc: $r('app.media.loading')
|
||||
}
|
||||
})
|
||||
Button("自定义下载c").onClick(()=>{
|
||||
this.imageKnifeOption = {
|
||||
loadSrc: "ccc",
|
||||
placeholderSrc: $r('app.media.loading')
|
||||
}
|
||||
})
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: this.imageKnifeOption
|
||||
}).width(300)
|
||||
.height(300)
|
||||
}
|
||||
.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.pngSample").id).buffer as ArrayBuffer
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeComponent,CacheStrategy,ImageKnifeOption } from '@ohos/libraryimageknife'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct TestWriteCacheStage {
|
||||
@State imageKnifeOption1: ImageKnifeOption = {
|
||||
loadSrc:$r('app.media.startIcon'),
|
||||
placeholderSrc:$r('app.media.loading'),
|
||||
errorholderSrc:$r('app.media.failed')
|
||||
}
|
||||
@State imageKnifeOption2: ImageKnifeOption = {
|
||||
loadSrc:$r('app.media.startIcon'),
|
||||
placeholderSrc:$r('app.media.loading'),
|
||||
errorholderSrc:$r('app.media.failed')
|
||||
}
|
||||
@State imageKnifeOption3: ImageKnifeOption = {
|
||||
loadSrc:$r('app.media.startIcon'),
|
||||
placeholderSrc:$r('app.media.loading'),
|
||||
errorholderSrc:$r('app.media.failed')
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Button("写入内存文件缓存").margin({top:10}).onClick(async ()=>{
|
||||
this.imageKnifeOption1 = {
|
||||
loadSrc:'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
|
||||
placeholderSrc:$r('app.media.loading'),
|
||||
errorholderSrc:$r('app.media.failed'),
|
||||
writeCacheStrategy:CacheStrategy.Default
|
||||
}
|
||||
})
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: this.imageKnifeOption1
|
||||
}).width(200).height(200).margin({top:10})
|
||||
Button("写入内存缓存").margin({top:10}).onClick(async ()=>{
|
||||
this.imageKnifeOption2 = {
|
||||
loadSrc:"https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB",
|
||||
placeholderSrc:$r('app.media.loading'),
|
||||
errorholderSrc:$r('app.media.failed'),
|
||||
writeCacheStrategy:CacheStrategy.Memory
|
||||
}
|
||||
})
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: this.imageKnifeOption2
|
||||
}).width(200).height(200).margin({top:10})
|
||||
Button("写入文件缓存").margin({top:10}).onClick(async ()=>{
|
||||
this.imageKnifeOption3 = {
|
||||
loadSrc:'https://img-blog.csdn.net/20140514114029140',
|
||||
placeholderSrc:$r('app.media.loading'),
|
||||
errorholderSrc:$r('app.media.failed'),
|
||||
writeCacheStrategy:CacheStrategy.File
|
||||
}
|
||||
})
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: this.imageKnifeOption3
|
||||
}).width(200).height(200).margin({top:10})
|
||||
}
|
||||
.height('100%') .width('100%')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeComponent, ImageKnifeOption } from "@ohos/libraryimageknife"
|
||||
import matrix4 from '@ohos.matrix4'
|
||||
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct TransformPage {
|
||||
private custom_scale:number = 1
|
||||
@State matrix1:object = matrix4.identity().scale({ x: 1, y: 1 })
|
||||
@State ImageKnifeOption: ImageKnifeOption = {
|
||||
loadSrc: $r("app.media.rabbit"),
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Contain,
|
||||
border: { radius: 50 }
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
ImageKnifeComponent({ imageKnifeOption: this.ImageKnifeOption }).height(200).width(200)
|
||||
.transform(this.matrix1)
|
||||
// Image($r('app.media.rabbit')).objectFit(ImageFit.Contain).height(200).width(200).transform(this.matrix1)
|
||||
Button("放大").onClick(()=>{
|
||||
this.custom_scale = this.custom_scale * 2
|
||||
this.matrix1 = matrix4.identity().scale({ x: this.custom_scale, y: this.custom_scale })
|
||||
})
|
||||
|
||||
Button("缩小").onClick(()=>{
|
||||
this.custom_scale = this.custom_scale / 2
|
||||
this.matrix1 = matrix4.identity().scale({ x: this.custom_scale, y: this.custom_scale })
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
|
||||
.height('100%')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife'
|
||||
|
||||
// const logger = new imUtils.logger.IMLogger('Avatar')
|
||||
|
||||
class MyImageOption extends ImageKnifeOption {
|
||||
account?: string
|
||||
}
|
||||
|
||||
@Component
|
||||
export struct UserAvatar {
|
||||
@Prop @Watch('userInfoUpdate') userInfo: string = ""
|
||||
// @Prop userInfo: string = ""
|
||||
imgSize: number = 100
|
||||
radius: number = 12
|
||||
borderSize: number = 0
|
||||
imgSizes: number = 1
|
||||
@State ImageKnifeOption: ImageKnifeOption = new ImageKnifeOption()
|
||||
@StorageProp('WeLink_Mob_fontSize_multiple') @Watch('updateImgSize') WeLink_Mob_fontSize_multiple: number = 0
|
||||
scalable: boolean = true;
|
||||
@State calcImgSize: number = 100
|
||||
|
||||
aboutToAppear(): void {
|
||||
this.userInfoUpdate()
|
||||
this.setImageSize()
|
||||
}
|
||||
|
||||
setImageSize() {
|
||||
if (!this.scalable) {
|
||||
this.calcImgSize = this.imgSize
|
||||
} else if (this.WeLink_Mob_fontSize_multiple < 0.9) {
|
||||
this.calcImgSize = this.imgSize * 0.9
|
||||
} else if (this.WeLink_Mob_fontSize_multiple > 1.6) {
|
||||
this.calcImgSize = this.imgSize * 1.6
|
||||
} else {
|
||||
this.calcImgSize = this.imgSize * this.WeLink_Mob_fontSize_multiple
|
||||
}
|
||||
}
|
||||
|
||||
updateImgSize() {
|
||||
this.setImageSize()
|
||||
}
|
||||
|
||||
aboutToReuse(param: ESObject) {
|
||||
this.userInfoUpdate()
|
||||
}
|
||||
|
||||
userInfoUpdate() {
|
||||
// if (uri === 'userInfo' && this.imageKnifeOption.account !== this.userInfo.contactId) return;
|
||||
// // logger.info(`userInfoUpdate uri=${uri} oldAcc=${this.imageKnifeOption.loadSrc} nowAcc=${this.userInfo.externalHeadUrl}`)
|
||||
// if (this.userInfo.externalHeadUrl === this.imageKnifeOption.loadSrc && this.userInfo.infoUpdateTime.getTime()
|
||||
// .toString() === this.imageKnifeOption?.signature?.getKey()) return;
|
||||
this.ImageKnifeOption = {
|
||||
//TODO:写死loadSRC,场景:变更组件大小,所有图片不显示
|
||||
loadSrc: this.userInfo,
|
||||
placeholderSrc: $r('app.media.loading'),
|
||||
errorholderSrc: $r('app.media.failed'),
|
||||
border: { radius:20,width:5,color:$r('app.color.start_window_background') },
|
||||
objectFit:ImageFit.Contain
|
||||
// signature: new ObjectKey(this.userInfo.infoUpdateTime.getTime().toString())
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
Row() {
|
||||
// Image(this.imageKnifeOption.loadSrc)
|
||||
|
||||
ImageKnifeComponent({ imageKnifeOption: this.ImageKnifeOption })
|
||||
.borderRadius(this.radius)
|
||||
.clip(true)
|
||||
.width(this.calcImgSize)
|
||||
.height(this.calcImgSize)
|
||||
.backgroundColor(Color.Pink)
|
||||
|
||||
|
||||
|
||||
// Image(this.userInfo)
|
||||
// Text((this.imageKnifeOption.loadSrc as string).split('/')[8])
|
||||
// .position({ x: 0, y: 0 })
|
||||
// .zIndex(9)
|
||||
// .fontSize(12)
|
||||
// .fontColor('#ff0000')
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* 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 { UserAvatar } from './User'
|
||||
|
||||
class CommonDataSource <T> implements IDataSource {
|
||||
private dataArray: T[] = []
|
||||
private listeners: DataChangeListener[] = []
|
||||
|
||||
constructor(element: []) {
|
||||
this.dataArray = element
|
||||
}
|
||||
|
||||
public getData(index: number) {
|
||||
return this.dataArray[index]
|
||||
}
|
||||
|
||||
public totalCount(): number {
|
||||
return this.dataArray.length
|
||||
}
|
||||
|
||||
public addData(index: number, data: T[]): void {
|
||||
this.dataArray = this.dataArray.concat(data)
|
||||
this.notifyDataAdd(index)
|
||||
}
|
||||
|
||||
unregisterDataChangeListener(listener: DataChangeListener): void {
|
||||
const pos = this.listeners.indexOf(listener);
|
||||
if (pos >= 0) {
|
||||
this.listeners.splice(pos, 1);
|
||||
}
|
||||
}
|
||||
|
||||
registerDataChangeListener(listener: DataChangeListener): void {
|
||||
if (this.listeners.indexOf(listener) < 0) {
|
||||
this.listeners.push(listener)
|
||||
}
|
||||
}
|
||||
|
||||
notifyDataAdd(index: number): void {
|
||||
this.listeners.forEach((listener: DataChangeListener) => {
|
||||
listener.onDataAdd(index)
|
||||
})
|
||||
}
|
||||
}
|
||||
@Entry
|
||||
@Component
|
||||
struct Index {
|
||||
@State hotCommendList:CommonDataSource<string> = new CommonDataSource<string>([])
|
||||
private data:string[] = [
|
||||
"http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg",
|
||||
"http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg",
|
||||
"http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg",
|
||||
"http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg",
|
||||
"http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg",
|
||||
"http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg",
|
||||
"http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg",
|
||||
"http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg",
|
||||
"http://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg",
|
||||
"http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg",
|
||||
"http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg",
|
||||
"http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg",
|
||||
"http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg",
|
||||
"http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg",
|
||||
"http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg",
|
||||
"http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
|
||||
"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',
|
||||
]
|
||||
aboutToAppear(): void {
|
||||
this.hotCommendList.addData(this.hotCommendList.totalCount(),this.data)
|
||||
AppStorage.set("WeLink_Mob_fontSize_multiple",1)
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Button("bigger").onClick(()=>{
|
||||
AppStorage.set("WeLink_Mob_fontSize_multiple",1.6)
|
||||
})
|
||||
Button("small").onClick(()=>{
|
||||
AppStorage.set("WeLink_Mob_fontSize_multiple",0.8)
|
||||
})
|
||||
List(){
|
||||
LazyForEach(this.hotCommendList,(item:string)=>{
|
||||
ListItem(){
|
||||
ReuseImage({
|
||||
userInfo:item
|
||||
}).width("100%").height("100%").backgroundColor(Color.Yellow)
|
||||
}.width(200).height(200).margin({bottom:5})
|
||||
})
|
||||
}
|
||||
// .cachedCount(20)
|
||||
.width("100%")
|
||||
.height("100%")
|
||||
.backgroundColor(0xFAEEE0)
|
||||
}.width('100%').height("100%")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Reusable
|
||||
@Component
|
||||
struct ReuseImage {
|
||||
@State userInfo:string = ""
|
||||
aboutToReuse(params: ESObject): void {
|
||||
this.userInfo = params.userInfo
|
||||
}
|
||||
|
||||
build() {
|
||||
Column(){
|
||||
UserAvatar({
|
||||
userInfo:this.userInfo
|
||||
})
|
||||
}.width("100%").height("100%")
|
||||
}
|
||||
}
|
|
@ -24,8 +24,8 @@ struct DataShareUriLoadPage {
|
|||
{
|
||||
loadSrc: $r('app.media.icon'),
|
||||
|
||||
placeholderSrc: $r('app.media.icon_loading'),
|
||||
errorholderSrc: $r('app.media.icon_failed')
|
||||
placeholderSrc: $r('app.media.loading'),
|
||||
errorholderSrc: $r('app.media.failed')
|
||||
};
|
||||
|
||||
|
||||
|
@ -45,7 +45,7 @@ struct DataShareUriLoadPage {
|
|||
uris = photoSelectResult.photoUris;
|
||||
this.imageKnifeOption1 = {
|
||||
loadSrc: uris[0],
|
||||
placeholderSrc:$r('app.media.icon_loading')
|
||||
placeholderSrc:$r('app.media.loading')
|
||||
}
|
||||
}).margin({ top: 5, left: 3 })
|
||||
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).width(300).height(300)
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import router from '@ohos.router';
|
||||
import {
|
||||
ImageKnifeComponent,
|
||||
ImageKnifeOption,
|
||||
ImageKnifeGlobal,
|
||||
ImageKnife,
|
||||
HeaderOptions
|
||||
} from '@ohos/libraryimageknife'
|
||||
|
||||
import { ObjectKey } from '@ohos/libraryimageknife';
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct IndexFunctionDemo {
|
||||
@State headerOptions1: HeaderOptions = {
|
||||
key: "refer",
|
||||
value: "http://1.94.37.200:7070/AntiTheftChain/downloadImage"
|
||||
};
|
||||
@State imageKnifeOption1: ImageKnifeOption =
|
||||
{
|
||||
loadSrc: $r('app.media.icon'),
|
||||
placeholderSrc: $r('app.media.icon_loading'),
|
||||
errorholderSrc: $r('app.media.icon_failed'),
|
||||
headerOption: [this.headerOptions1]
|
||||
};
|
||||
@State imageKnifeOption2: ImageKnifeOption =
|
||||
{
|
||||
loadSrc: $r('app.media.icon'),
|
||||
placeholderSrc: $r('app.media.icon_loading'),
|
||||
errorholderSrc: $r('app.media.icon_failed'),
|
||||
headerOption: [this.headerOptions1]
|
||||
};
|
||||
build() {
|
||||
Scroll() {
|
||||
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
|
||||
Text("简单示例1:加载一张本地png图片").fontSize(15)
|
||||
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
|
||||
Button("加载PNG")
|
||||
.onClick(() => {
|
||||
this.imageKnifeOption1 = {
|
||||
loadSrc: $r('app.media.pngSample'),
|
||||
placeholderSrc: $r('app.media.icon_loading'),
|
||||
errorholderSrc: $r('app.media.icon_failed'),
|
||||
signature: new ObjectKey('ccccccc')
|
||||
}
|
||||
}).margin({ top: 5, left: 3 })
|
||||
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).width(300).height(300)
|
||||
}.width('100%').backgroundColor(Color.Pink)
|
||||
|
||||
Text("简单示例2:加载一张网络gif图片").fontSize(15)
|
||||
Text("gif解析在子线程,请在页面构建后创建worker,注入imageknife").fontSize(15)
|
||||
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
|
||||
Button("加载GIF")
|
||||
.onClick(() => {
|
||||
this.imageKnifeOption2 = {
|
||||
loadSrc: 'https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658',
|
||||
placeholderSrc: $r('app.media.icon_loading'),
|
||||
errorholderSrc: $r('app.media.icon_failed'),
|
||||
displayProgress:true,
|
||||
}
|
||||
}).margin({ top: 5, left: 3 })
|
||||
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption2 }).width(300).height(300)
|
||||
}.width('100%').backgroundColor(Color.Pink)
|
||||
|
||||
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
|
||||
Button("ImageKnife测试目录页面")
|
||||
.onClick(() => {
|
||||
console.log("pages/imageknifeTestCaseIndex 页面跳转")
|
||||
router.pushUrl({ url: "pages/imageknifeTestCaseIndex" });
|
||||
}).margin({ top: 15 })
|
||||
}.width('100%').height(60).backgroundColor(Color.Pink)
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
}
|
||||
|
||||
aboutToAppear() {
|
||||
|
||||
}
|
||||
aboutToDisappear(){
|
||||
|
||||
}
|
||||
|
||||
onBackPress() {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
import {ImageKnifeComponent, ScaleType} from '@ohos/libraryimageknife'
|
||||
import {ImageKnifeOption} from '@ohos/libraryimageknife'
|
||||
import {ImageKnifeGlobal} from '@ohos/libraryimageknife'
|
||||
import {RotateImageTransformation} from '@ohos/libraryimageknife'
|
||||
import {Material} from './model/Material'
|
||||
import {TestDataSource} from './model/TestDataSource'
|
||||
import {DiskLruCache} from '@ohos/disklrucache'
|
||||
import ArkWorker from '@ohos.worker'
|
||||
import Prompt from '@system.prompt'
|
||||
@Entry
|
||||
@Component
|
||||
struct ManyPhotoShowPage {
|
||||
private data: TestDataSource = new TestDataSource();
|
||||
|
||||
private elementScroller: Scroller = new Scroller()
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
|
||||
List({ space: 20, scroller: this.elementScroller }) {
|
||||
LazyForEach(this.data, (item: Material, index) => {
|
||||
ListItem() {
|
||||
Column() {
|
||||
Stack({ alignContent: Alignment.BottomEnd }) {
|
||||
// 滤镜图片
|
||||
ImageKnifeComponent({ imageKnifeOption: {
|
||||
loadSrc: item.thumbnail,
|
||||
mainScaleType: ScaleType.FIT_XY,
|
||||
} })
|
||||
}
|
||||
.width(56).height(56)
|
||||
//滤镜标题
|
||||
Text(item.name)
|
||||
.fontSize(10)
|
||||
.maxLines(1)
|
||||
.fontColor(Color.White)
|
||||
.textAlign(TextAlign.Center)
|
||||
.layoutWeight(1)
|
||||
.width('100%')
|
||||
.backgroundColor(Color.Orange)
|
||||
}
|
||||
.width(56)
|
||||
.height(72)
|
||||
.clip(true)
|
||||
.borderRadius(4)
|
||||
}
|
||||
}, (item: Material) => item.material_id)
|
||||
}
|
||||
.listDirection(Axis.Horizontal)
|
||||
.width('100%')
|
||||
.height(72)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -2,33 +2,26 @@
|
|||
"module": {
|
||||
"name": "entry",
|
||||
"type": "entry",
|
||||
|
||||
"description": "$string:entry_desc",
|
||||
"mainElement": "MainAbility",
|
||||
"description": "$string:module_desc",
|
||||
"mainElement": "EntryAbility",
|
||||
"deviceTypes": [
|
||||
"default",
|
||||
"tablet"
|
||||
"phone",
|
||||
"tablet",
|
||||
"2in1"
|
||||
],
|
||||
"deliveryWithInstall": true,
|
||||
"installationFree": false,
|
||||
"pages": "$profile:main_pages",
|
||||
"metadata": [
|
||||
{
|
||||
"name": "ArkTSPartialUpdate",
|
||||
"value": "true"
|
||||
}
|
||||
],
|
||||
"uiSyntax": "ets",
|
||||
"abilities": [
|
||||
{
|
||||
"name": "MainAbility",
|
||||
"name": "EntryAbility",
|
||||
"srcEntry": "./ets/entryability/EntryAbility.ets",
|
||||
"description": "$string:MainAbility_desc",
|
||||
"description": "$string:EntryAbility_desc",
|
||||
"icon": "$media:icon",
|
||||
"label": "$string:MainAbility_label",
|
||||
"startWindowIcon": "$media:icon",
|
||||
"startWindowBackground": "$color:test_color",
|
||||
"visible": true,
|
||||
"label": "$string:EntryAbility_label",
|
||||
"startWindowIcon": "$media:startIcon",
|
||||
"startWindowBackground": "$color:start_window_background",
|
||||
"exported": true,
|
||||
"skills": [
|
||||
{
|
||||
"entities": [
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"color": [
|
||||
{
|
||||
"name": "test_color",
|
||||
"value": "#3d2564"
|
||||
"name": "start_window_background",
|
||||
"value": "#FFFFFF"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,125 +1,24 @@
|
|||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "entry_desc",
|
||||
"name": "module_desc",
|
||||
"value": "module description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_desc",
|
||||
"value": "description"
|
||||
},
|
||||
{
|
||||
"name": "MainAbility_desc",
|
||||
"value": "description"
|
||||
},
|
||||
{
|
||||
"name": "MainAbility_label",
|
||||
"value": "ImageKnife"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "ImageKnife_OHOS",
|
||||
"value": "ImageKnife_OHOS"
|
||||
},
|
||||
{
|
||||
"name": "mainability_description",
|
||||
"value": "ETS_Empty Ability"
|
||||
},
|
||||
{
|
||||
"name": "left_top_corner",
|
||||
"value": "左上角"
|
||||
},
|
||||
{
|
||||
"name": "r_top_corner",
|
||||
"value": "右上角"
|
||||
},
|
||||
{
|
||||
"name": "left_bottom_corner",
|
||||
"value": "左下角"
|
||||
},
|
||||
{
|
||||
"name": "r_bottom_corner",
|
||||
"value": "右下角"
|
||||
},
|
||||
{
|
||||
"name": "trans_circle",
|
||||
"value": "裁剪-圆"
|
||||
},
|
||||
{
|
||||
"name": "trans_circle_border",
|
||||
"value": "裁剪-圆环"
|
||||
},
|
||||
{
|
||||
"name": "trans_rotate",
|
||||
"value": "旋转"
|
||||
},
|
||||
{
|
||||
"name": "trans_square",
|
||||
"value": "正方形裁剪"
|
||||
},
|
||||
{
|
||||
"name": "trans_clip_top",
|
||||
"value": "上方裁剪"
|
||||
},
|
||||
{
|
||||
"name": "trans_clip_center",
|
||||
"value": "中间裁剪"
|
||||
},
|
||||
{
|
||||
"name": "trans_clip_bottom",
|
||||
"value": "底下裁剪"
|
||||
},
|
||||
{
|
||||
"name": "resource_image_compress",
|
||||
"value": "资源图片压缩"
|
||||
},
|
||||
{
|
||||
"name": "file_image_compress",
|
||||
"value": "本地文件图片压缩"
|
||||
},
|
||||
{
|
||||
"name": "image_transform",
|
||||
"value": "图片变换"
|
||||
},
|
||||
{
|
||||
"name": "image_compress",
|
||||
"value": "图片压缩"
|
||||
},
|
||||
{
|
||||
"name": "image_grayscale",
|
||||
"value": "灰度处理"
|
||||
},
|
||||
{
|
||||
"name": "image_Brightness",
|
||||
"value": "亮度处理"
|
||||
},
|
||||
{
|
||||
"name": "image_Contrast",
|
||||
"value": "对比度处理"
|
||||
},
|
||||
{
|
||||
"name": "image_Invert",
|
||||
"value": "反转处理"
|
||||
},
|
||||
{
|
||||
"name": "image_Sepia",
|
||||
"value": "黑褐色处理"
|
||||
},
|
||||
{
|
||||
"name": "image_Sketch",
|
||||
"value": "素描处理"
|
||||
},
|
||||
{
|
||||
"name": "image_blur",
|
||||
"value": "模糊处理"
|
||||
},
|
||||
{
|
||||
"name": "image_pixel",
|
||||
"value": "马赛克处理"
|
||||
},
|
||||
{
|
||||
"name": "app_permission_READ_IMAGEVIDEO",
|
||||
"value": "获取读媒体资源权限"
|
||||
"name": "EntryAbility_label",
|
||||
"value": "label"
|
||||
},
|
||||
{
|
||||
"name": "app_permission_WRITE_IMAGEVIDEO",
|
||||
"value": "获取写入媒体资源权限"
|
||||
},
|
||||
{
|
||||
"name": "app_permission_READ_IMAGEVIDEO",
|
||||
"value": "获取读媒体资源权限"
|
||||
}
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 580 KiB |
After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.9 MiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 4.2 KiB |
|
@ -1,67 +1,27 @@
|
|||
{
|
||||
"src": [
|
||||
"pages/index",
|
||||
"pages/CacheRuleChangedPage",
|
||||
"pages/frescoRetryTestCasePage",
|
||||
"pages/basicTestFeatureAbilityPage",
|
||||
"pages/basicTestFileIOPage",
|
||||
"pages/basicTestMediaImage",
|
||||
"pages/basicTestResourceManagerPage",
|
||||
"pages/storageTestLruCache",
|
||||
"pages/pngjTestCasePage",
|
||||
"pages/showErrorholderTestCasePage",
|
||||
"pages/transformPixelMapPage",
|
||||
"pages/transformsPage",
|
||||
"pages/testPreloadPage",
|
||||
"pages/testDiskPreLoadPage",
|
||||
"pages/testImageKnifeOptionChangedPage",
|
||||
"pages/testImageKnifeOptionChangedPage2",
|
||||
"pages/testImageKnifeOptionChangedPage3",
|
||||
"pages/testImageKnifeOptionChangedPage4",
|
||||
"pages/testImageKnifeOptionChangedPage5",
|
||||
"pages/testGifPlayTimesPage",
|
||||
"pages/compressPage",
|
||||
"pages/testAllCacheInfoPage",
|
||||
"pages/cropImagePage2",
|
||||
"pages/svgTestCasePage",
|
||||
"pages/imageknifeTestCaseIndex",
|
||||
"pages/dataShareUriLoadPage",
|
||||
"pages/manyPhotoShowPage",
|
||||
"pages/photosPausedResumedPage",
|
||||
"pages/photosPausedResumedPage2",
|
||||
"pages/tempUrlTestPage",
|
||||
"pages/drawFactoryTestPage",
|
||||
"pages/testSingleFrameGifPage",
|
||||
"pages/OptionTestPage",
|
||||
"pages/Index",
|
||||
"pages/ListPage",
|
||||
"pages/SingleImage",
|
||||
"pages/ManyPhotoShowPage",
|
||||
"pages/LongImagePage",
|
||||
"pages/TransformPage",
|
||||
"pages/UserPage",
|
||||
"pages/TestImageFlash",
|
||||
"pages/SignatureTestPage",
|
||||
"pages/hspCacheTestPage",
|
||||
"pages/multiHspTestPage",
|
||||
"pages/testManyNetImageLoadWithPage",
|
||||
"pages/testManyNetImageLoadWithPage2",
|
||||
"pages/testManyGifLoadWithPage",
|
||||
"pages/testImageAntiAliasingWithPage",
|
||||
"pages/testImageKnifeRouter1",
|
||||
"pages/testImageKnifeRouter2",
|
||||
"pages/RequestOptionLoadImage",
|
||||
"pages/testImageKnifeHttpRequestHeader",
|
||||
"pages/testImageKnifeHttpRequestHeader1",
|
||||
"pages/testImageKnifeAutoPage",
|
||||
"pages/testImageKnifeAutoWidthPage",
|
||||
"pages/testImageKnifeAutoHeightPage",
|
||||
"pages/testPriorityComponent",
|
||||
"pages/testVisiblePage",
|
||||
"pages/testReusePhotoPage",
|
||||
"pages/testImageKnifeCache",
|
||||
"pages/webpImageTestPage",
|
||||
"pages/testStopPlayingGifPage",
|
||||
"pages/testImageKnifeDataFetch",
|
||||
"pages/testImageKnifeHeic",
|
||||
"pages/testImageKnifeNetPlaceholder",
|
||||
"pages/testCustomDataFetchClientWithPage",
|
||||
"pages/testReuseAblePages",
|
||||
"pages/downsamplingPage",
|
||||
"pages/testImageKnifeLoadState",
|
||||
"pages/testImageKnifeRemoveCache",
|
||||
"pages/TestDurationAndPlayTimesPage"
|
||||
"pages/TestPrefetchToFileCache",
|
||||
"pages/TestIsUrlExist",
|
||||
"pages/TestHeader",
|
||||
"pages/ImageTransformation",
|
||||
"pages/ObjectFitPage",
|
||||
"pages/TestWriteCacheStage",
|
||||
"pages/LoadStatePage",
|
||||
"pages/TestHspPreLoadImage",
|
||||
"pages/TestRemoveCache",
|
||||
"pages/dataShareUriLoadPage",
|
||||
"pages/TestCommonImage",
|
||||
"pages/ImageAnimatorPage",
|
||||
"pages/TestSetCustomImagePage",
|
||||
"pages/TestErrorHolderPage"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "module_desc",
|
||||
"value": "module description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_desc",
|
||||
"value": "description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_label",
|
||||
"value": "label"
|
||||
},
|
||||
{
|
||||
"name": "app_permission_WRITE_IMAGEVIDEO",
|
||||
"value": "获取写入媒体资源权限"
|
||||
},
|
||||
{
|
||||
"name": "app_permission_READ_IMAGEVIDEO",
|
||||
"value": "获取读媒体资源权限"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "module_desc",
|
||||
"value": "模块描述"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_desc",
|
||||
"value": "description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_label",
|
||||
"value": "label"
|
||||
},
|
||||
{
|
||||
"name": "app_permission_WRITE_IMAGEVIDEO",
|
||||
"value": "获取写入媒体资源权限"
|
||||
},
|
||||
{
|
||||
"name": "app_permission_READ_IMAGEVIDEO",
|
||||
"value": "获取读媒体资源权限"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -12,60 +12,76 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { describe, it, expect } from '@ohos/hypium';
|
||||
import { ImageKnife, ImageKnifeGlobal, RequestOption } from '@ohos/imageknife/Index';
|
||||
import { DefaultJobQueue } from '@ohos/imageknife/src/main/ets/components/imageknife/utils/DefaultJobQueue';
|
||||
import { IJobQueue } from '@ohos/imageknife/src/main/ets/components/imageknife/utils/IJobQueue';
|
||||
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 taskpool from '@ohos.taskpool';
|
||||
import common from '@ohos.app.ability.common';
|
||||
import { fitter} from '@ohos/imageknife';
|
||||
|
||||
|
||||
export default function DefaultJobQueueTest() {
|
||||
|
||||
describe('DefaultJobQueueTest', () => {
|
||||
it('testJob', 0, () => {
|
||||
let job: IJobQueue = new DefaultJobQueue();
|
||||
job.add(makeRequest("medium1", getContext() as common.UIAbilityContext));
|
||||
job.add(makeRequest("medium2", getContext() as common.UIAbilityContext, taskpool.Priority.MEDIUM));
|
||||
job.add(makeRequest("medium3", getContext() as common.UIAbilityContext));
|
||||
job.add(makeRequest("low1", getContext() as common.UIAbilityContext, taskpool.Priority.LOW));
|
||||
job.add(makeRequest("high1", getContext() as common.UIAbilityContext, taskpool.Priority.HIGH));
|
||||
job.add(makeRequest("low2", getContext() as common.UIAbilityContext, taskpool.Priority.LOW));
|
||||
job.add(makeRequest("medium4", getContext() as common.UIAbilityContext));
|
||||
|
||||
expect(job.getQueueLength()).assertEqual(7);
|
||||
expect(job.pop()!.loadSrc).assertEqual("high1");
|
||||
expect(job.pop()!.loadSrc).assertEqual("medium1");
|
||||
expect(job.pop()!.loadSrc).assertEqual("medium2");
|
||||
expect(job.pop()!.loadSrc).assertEqual("medium3");
|
||||
expect(job.pop()!.loadSrc).assertEqual("medium4");
|
||||
expect(job.pop()!.loadSrc).assertEqual("low1");
|
||||
expect(job.pop()!.loadSrc).assertEqual("low2");
|
||||
expect(job.pop()).assertEqual(undefined);
|
||||
expect(job.getQueueLength()).assertEqual(0);
|
||||
// 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('testJob', 0, async () => {
|
||||
let job: IJobQueue = new DefaultJobQueue()
|
||||
job.add(makeRequest("medium1", getContext() as common.UIAbilityContext))
|
||||
job.add(makeRequest("medium2", getContext() as common.UIAbilityContext, taskpool.Priority.MEDIUM))
|
||||
job.add(makeRequest("medium3", getContext() as common.UIAbilityContext))
|
||||
job.add(makeRequest("low1", getContext() as common.UIAbilityContext, taskpool.Priority.LOW))
|
||||
job.add(makeRequest("high1", getContext() as common.UIAbilityContext, taskpool.Priority.HIGH))
|
||||
job.add(makeRequest("low2", getContext() as common.UIAbilityContext, taskpool.Priority.LOW))
|
||||
job.add(makeRequest("medium4", getContext() as common.UIAbilityContext))
|
||||
|
||||
expect(job.getQueueLength()).assertEqual(7)
|
||||
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("high1")
|
||||
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium4")
|
||||
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium3")
|
||||
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium2")
|
||||
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium1")
|
||||
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("low2")
|
||||
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("low1")
|
||||
expect(job.pop()).assertEqual(undefined)
|
||||
expect(job.getQueueLength()).assertEqual(0)
|
||||
|
||||
});
|
||||
|
||||
it("testMaxRequests", 1, () => {
|
||||
let imageKnife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife();
|
||||
if (imageKnife) {
|
||||
expect(imageKnife.maxRequests).assertEqual(64);
|
||||
imageKnife.setMaxRequests(10);
|
||||
expect(imageKnife.maxRequests).assertEqual(10);
|
||||
};
|
||||
})
|
||||
it("downsampleOf", 1, () => {
|
||||
let request: RequestOption = new RequestOption()
|
||||
if (request) {
|
||||
let requests = request.downsampleOf(new fitter())
|
||||
expect(requests.downsampType.getName()=='FitCenter').assertTrue()
|
||||
};
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function makeRequest(src: string, context: common.UIAbilityContext, priority: taskpool.Priority = taskpool.Priority.MEDIUM): RequestOption {
|
||||
let request: RequestOption = new RequestOption()
|
||||
request.loadSrc = src;
|
||||
request.priority = priority;
|
||||
request.moduleContext = context;
|
||||
return request;
|
||||
function makeRequest(src: string, context: common.UIAbilityContext, priority?: taskpool.Priority): ImageKnifeRequest {
|
||||
let option: ImageKnifeOption = {
|
||||
loadSrc: src,
|
||||
priority: priority
|
||||
}
|
||||
return new ImageKnifeRequest(
|
||||
option,
|
||||
context,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
{
|
||||
showPixelMap: async (version: number,pixelMap: PixelMap | string) => {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* 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 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 { IEngineKey, ImageKnifeOption } from '@ohos/imageknife';
|
||||
import { DefaultEngineKey } from '@ohos/imageknife/src/main/ets/key/DefaultEngineKey';
|
||||
|
||||
|
||||
export default function FileLruCacheTest() {
|
||||
|
||||
describe('FileLruCacheTest', () => {
|
||||
// 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.
|
||||
});
|
||||
|
||||
// 测试基础put,get以及size功能
|
||||
it('assertFileSizeAllInMainThread', 0, async () => {
|
||||
const buf: ArrayBuffer = new ArrayBuffer(1024 * 1024);
|
||||
console.info(Constants.TAG + buf.byteLength)
|
||||
console.info(Constants.TAG + GlobalContext.getContext().getObject("cacheDir"))
|
||||
|
||||
let fileCache: FileCache = new FileCache(GlobalContext.getContext()
|
||||
.getObject("context") as Context, 5, 3 * 1024 * 1024)
|
||||
await fileCache.initFileCache()
|
||||
|
||||
fileCache.put("aaa", buf)
|
||||
await sleep(1000)
|
||||
fileCache.put("bbb", buf)
|
||||
await sleep(1000)
|
||||
fileCache.put("ccc", buf)
|
||||
expect(fileCache.size()).assertEqual(3)
|
||||
console.info(Constants.TAG + fileCache.currentMemory + "")
|
||||
fileCache.get("aaa")
|
||||
await sleep(1000)
|
||||
fileCache.put("ddd", buf)
|
||||
await sleep(1000)
|
||||
console.info(Constants.TAG + fileCache.currentMemory + "")
|
||||
expect(fileCache.size()).assertEqual(3)
|
||||
console.info(Constants.TAG + fileCache.get("aaa")?.byteLength)
|
||||
expect(fileCache.get("ddd")?.byteLength).assertEqual(buf.byteLength)
|
||||
await sleep(1000)
|
||||
expect(fileCache.get("aaa")?.byteLength).assertEqual(buf.byteLength)
|
||||
await sleep(1000)
|
||||
expect(fileCache.get("ccc")?.byteLength).assertEqual(buf.byteLength)
|
||||
await sleep(1000)
|
||||
expect(fileCache.get("bbb")).assertUndefined()
|
||||
|
||||
|
||||
// 模拟第二次启动后重新加载缓存
|
||||
let fileCache2: FileCache = new FileCache(GlobalContext.getContext()
|
||||
.getObject("context") as Context, 5, 3 * 1024 * 1024)
|
||||
await fileCache2.initFileCache()
|
||||
expect(fileCache2.size()).assertEqual(3)
|
||||
expect(fileCache2.get("ddd")?.byteLength).assertEqual(buf.byteLength)
|
||||
expect(fileCache2.get("aaa")?.byteLength).assertEqual(buf.byteLength)
|
||||
expect(fileCache2.get("ccc")?.byteLength).assertEqual(buf.byteLength)
|
||||
|
||||
});
|
||||
|
||||
it('assertFileSizeAllInSubThread', 0, async () => {
|
||||
const buf: ArrayBuffer = new ArrayBuffer(1024 * 1024);
|
||||
console.info(Constants.TAG + buf.byteLength)
|
||||
console.info(Constants.TAG + GlobalContext.getContext().getObject("cacheDir"))
|
||||
|
||||
let fileCache: FileCache = new FileCache(GlobalContext.getContext()
|
||||
.getObject("context") as Context, 5, 3 * 1024 * 1024)
|
||||
await fileCache.initFileCache()
|
||||
|
||||
fileCache.put("aaa", buf)
|
||||
|
||||
let task: taskpool.Task = new taskpool.Task(getFile, "bbb", GlobalContext.getContext()
|
||||
.getObject("context") as Context);
|
||||
let res: ArrayBuffer | undefined = await taskpool.execute(task) as (ArrayBuffer | undefined)
|
||||
if (res !== undefined) {
|
||||
fileCache.putWithoutWriteFile("bbb", res)
|
||||
}
|
||||
|
||||
task = new taskpool.Task(getFile, "aaa", GlobalContext.getContext()
|
||||
.getObject("context") as Context);
|
||||
res = await taskpool.execute(task) as (ArrayBuffer | undefined)
|
||||
if (res !== undefined) {
|
||||
fileCache.putWithoutWriteFile("aaa", res)
|
||||
}
|
||||
|
||||
fileCache.put("ddd", buf)
|
||||
expect(fileCache.size()).assertEqual(3)
|
||||
expect(fileCache.currentMemory).assertEqual(3 * 1024 * 1024)
|
||||
expect(fileCache.get("bbb")?.byteLength).assertEqual(1024 * 1024)
|
||||
expect(fileCache.get("aaa")?.byteLength).assertEqual(1024 * 1024)
|
||||
expect(fileCache.get("ddd")?.byteLength).assertEqual(1024 * 1024)
|
||||
|
||||
|
||||
task = new taskpool.Task(getFile, "eee", GlobalContext.getContext()
|
||||
.getObject("context") as Context);
|
||||
|
||||
res = await taskpool.execute(task) as (ArrayBuffer | undefined)
|
||||
if (res !== undefined) {
|
||||
fileCache.putWithoutWriteFile("eee", res)
|
||||
}
|
||||
expect(fileCache.size()).assertEqual(3)
|
||||
expect(fileCache.currentMemory).assertEqual(3 * 1024 * 1024)
|
||||
expect(fileCache.get("bbb")).assertEqual(undefined)
|
||||
expect(fileCache.get("aaa")?.byteLength).assertEqual(1024 * 1024)
|
||||
expect(fileCache.get("ddd")?.byteLength).assertEqual(1024 * 1024)
|
||||
|
||||
});
|
||||
|
||||
|
||||
it('test', 0, async () => {
|
||||
const buf: ArrayBuffer = new ArrayBuffer(1024 * 1024);
|
||||
console.info(Constants.TAG + buf.byteLength)
|
||||
console.info(Constants.TAG + GlobalContext.getContext().getObject("cacheDir"))
|
||||
|
||||
let fileCache: FileCache = new FileCache(GlobalContext.getContext()
|
||||
.getObject("context") as Context, 5, 3 * 1024 * 1024)
|
||||
await fileCache.initFileCache()
|
||||
|
||||
console.info(Constants.TAG + JSON.stringify("xxxxx"))
|
||||
fileCache.put(JSON.stringify("xxxxx"),buf)
|
||||
expect(fileCache.get(JSON.stringify("xxxxx"))?.byteLength).assertEqual(1024 * 1024)
|
||||
});
|
||||
it('fileCacheEngineKey', 0, () => {
|
||||
let engineKey: IEngineKey = new DefaultEngineKey()
|
||||
let imageKnifeOption: ImageKnifeOption = {
|
||||
loadSrc:"abc"
|
||||
}
|
||||
let imageKey = engineKey.generateFileKey(imageKnifeOption.loadSrc,"")
|
||||
let imageAnimatorKey = engineKey.generateFileKey(imageKnifeOption.loadSrc,"",true)
|
||||
expect(imageKey == imageAnimatorKey).assertFalse()
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
@Concurrent
|
||||
async function getFile(key: string, context: Context): Promise<ArrayBuffer | undefined> {
|
||||
// 读取文件缓存
|
||||
let buf = FileCache.getFileCacheByFile(context, key)
|
||||
|
||||
if (buf !== undefined) {
|
||||
return buf
|
||||
}
|
||||
|
||||
buf = new ArrayBuffer(1024 * 1024)
|
||||
// 写文件缓存
|
||||
FileCache.saveFileCacheOnlyFile(context, key, buf)
|
||||
return buf;
|
||||
}
|
|
@ -1,39 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* 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,
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import abilityTest from './Ability.test'
|
||||
import lruCacheTest from './lrucache.test'
|
||||
import CustomDataFetchClientTest from './customdatafetchclient.test'
|
||||
import LogUtilTest from './logutil.test'
|
||||
import Transfrom from './transfrom.test'
|
||||
import RequestOptionTest from './requestoption.test'
|
||||
import ImageKnifeTest from './imageknife.test'
|
||||
import DiskLruCacheTest from './diskLruCache.test'
|
||||
import SendableDataTest from './SendableData.test'
|
||||
import DefaultJobQueueTest from './DefaultJobQueueTest.test';
|
||||
import ImageKnifeOptionTest from './imageknifeOption.test';
|
||||
import FileLruCacheTest from './FileLruCache.test';
|
||||
import ImageKnifeOptionTest from './ImageKnifeOption.test';
|
||||
import MemoryLruCacheTest from './MemoryLruCache.test';
|
||||
import ImageKnifeTest from './ImageKnife.test';
|
||||
import Transform from './transform.test';
|
||||
|
||||
export default function testsuite() {
|
||||
abilityTest()
|
||||
lruCacheTest()
|
||||
DiskLruCacheTest()
|
||||
LogUtilTest()
|
||||
Transfrom()
|
||||
RequestOptionTest()
|
||||
ImageKnifeTest();
|
||||
SendableDataTest();
|
||||
MemoryLruCacheTest();
|
||||
FileLruCacheTest();
|
||||
DefaultJobQueueTest();
|
||||
CustomDataFetchClientTest();
|
||||
ImageKnifeOptionTest();
|
||||
ImageKnifeTest();
|
||||
Transform();
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* 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 image from '@ohos.multimedia.image';
|
||||
|
||||
|
||||
import Constants from '../../../main/ets/common/Constants';
|
||||
import { MemoryLruCache } from '@ohos/imageknife/src/main/ets/utils/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';
|
||||
|
||||
|
||||
export default function MemoryLruCacheTest() {
|
||||
|
||||
describe('MemoryLruCacheTest', () => {
|
||||
// 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.
|
||||
});
|
||||
|
||||
// 测试基础put,get以及size功能
|
||||
it('assertBasicFunction', 0, async () => {
|
||||
let memoryCache: MemoryLruCache = new MemoryLruCache(3, 3 * 1024 * 1024);
|
||||
|
||||
let data: ImageKnifeData = await getNewImageKnifeData(96)
|
||||
memoryCache.put("aaa", data)
|
||||
memoryCache.put("bbb", data)
|
||||
memoryCache.put("ccc", data)
|
||||
expect(memoryCache.size()).assertEqual(3)
|
||||
expect(memoryCache.get("aaa")).assertEqual(data)
|
||||
expect(memoryCache.get("bbb")).assertEqual(data)
|
||||
expect(memoryCache.get("ccc")).assertEqual(data)
|
||||
expect(memoryCache.size()).assertEqual(3)
|
||||
|
||||
memoryCache.remove("ccc")
|
||||
memoryCache.remove("ddd")
|
||||
expect(memoryCache.size()).assertEqual(2)
|
||||
|
||||
memoryCache.removeAll()
|
||||
expect(memoryCache.size()).assertEqual(0)
|
||||
});
|
||||
|
||||
|
||||
// 测试内存缓存size的lru功能
|
||||
it('assertSizeLruFuction', 0, async () => {
|
||||
let memoryCache: MemoryLruCache = new MemoryLruCache(3, 3 * 1024 * 1024);
|
||||
|
||||
let data1: ImageKnifeData = await getNewImageKnifeData(96)
|
||||
let data2: ImageKnifeData = await getNewImageKnifeData(106)
|
||||
let data3: ImageKnifeData = await getNewImageKnifeData(116)
|
||||
let data4: ImageKnifeData = await getNewImageKnifeData(126)
|
||||
let data5: ImageKnifeData = await getNewImageKnifeData(136)
|
||||
memoryCache.put("aaa", data1)
|
||||
memoryCache.put("bbb", data2)
|
||||
memoryCache.put("ccc", data3)
|
||||
memoryCache.put("ddd", data4)
|
||||
|
||||
expect(memoryCache.get("aaa")).assertUndefined()
|
||||
expect(memoryCache.get("bbb")).assertEqual(data2)
|
||||
memoryCache.put("eee", data5)
|
||||
expect(memoryCache.get("ccc")).assertUndefined()
|
||||
expect(memoryCache.get("bbb")).assertEqual(data2)
|
||||
expect(memoryCache.get("ddd")).assertEqual(data4)
|
||||
expect(memoryCache.get("eee")).assertEqual(data5)
|
||||
});
|
||||
|
||||
// 测试内存缓存memorySize的lru功能
|
||||
it('assertMemorySizeLruFuction', 0, async () => {
|
||||
let memoryCache: MemoryLruCache = new MemoryLruCache(3, 2 * 1024 * 1024);
|
||||
|
||||
const color: ArrayBuffer = new ArrayBuffer(1024 * 1024); //96为需要创建的像素buffer大小,取值为:height * width *4
|
||||
let opts: image.InitializationOptions = {
|
||||
editable: true, pixelFormat: 3, size: {
|
||||
height: 512, width: 512
|
||||
}
|
||||
}
|
||||
let pixelmap: PixelMap = await image.createPixelMap(color, opts)
|
||||
console.info(Constants.TAG + pixelmap.getPixelBytesNumber())
|
||||
let data: ImageKnifeData = {
|
||||
source: pixelmap,
|
||||
imageWidth: 5,
|
||||
imageHeight: 5
|
||||
}
|
||||
|
||||
memoryCache.put("aaa", data)
|
||||
memoryCache.put("bbb", data)
|
||||
memoryCache.get("aaa")
|
||||
memoryCache.put("ccc", data)
|
||||
expect(memoryCache.size()).assertEqual(2)
|
||||
expect(memoryCache.get("bbb")).assertUndefined()
|
||||
expect(memoryCache.get("aaa")).assertEqual(data)
|
||||
expect(memoryCache.get("ccc")).assertEqual(data)
|
||||
});
|
||||
|
||||
it('memoryCacheEngineKey', 0, () => {
|
||||
let engineKey: IEngineKey = new DefaultEngineKey()
|
||||
let imageKnifeOption: 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()
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
async function getNewImageKnifeData(num:number): Promise<ImageKnifeData> {
|
||||
const color: ArrayBuffer = new ArrayBuffer(num); //96为需要创建的像素buffer大小,取值为:height * width *4
|
||||
let opts: image.InitializationOptions = {
|
||||
editable: true, pixelFormat: 3, size: {
|
||||
height: 4, width: 6
|
||||
}
|
||||
}
|
||||
let pixelmap: PixelMap = await image.createPixelMap(color, opts)
|
||||
|
||||
let data: ImageKnifeData = {
|
||||
source: pixelmap,
|
||||
imageWidth: 5,
|
||||
imageHeight: 5
|
||||
}
|
||||
return data
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import hilog from '@ohos.hilog';
|
||||
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'
|
||||
import { DiskLruCache, ImageKnife,ImageKnifeDrawFactory,ImageKnifeGlobal,LruCache} from '@ohos/imageknife';
|
||||
import { common } from '@kit.AbilityKit';
|
||||
import { GlobalContext } from '../testability/GlobalContext';
|
||||
|
||||
const BASE_COUNT: number = 2000;
|
||||
|
||||
export default function ImageKnifeTest() {
|
||||
describe('ImageKnifeTest', ()=> {
|
||||
// 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('TestGlobalImageKnife',0, ()=> {
|
||||
let context:Object|undefined = ImageKnifeGlobal.getInstance().getHapContext();
|
||||
if(context != undefined) {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
ImageKnife.with(context);
|
||||
}
|
||||
endTime(startTime, 'TestGlobalImageKnife');
|
||||
let global: ImageKnifeGlobal = ImageKnife.with(context)
|
||||
expect(global.getImageKnife()).not().assertUndefined()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
it('TestGlobalDefaultLifeCycle',1, ()=> {
|
||||
let imageKnife:ImageKnife|undefined = ImageKnifeGlobal.getInstance().getImageKnife()
|
||||
if(imageKnife != undefined){
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
imageKnife.setDefaultLifeCycle(ImageKnifeDrawFactory.createProgressLifeCycle("#10a5ff", 0.5))
|
||||
}
|
||||
endTime(startTime, 'setDefaultLifeCycle');
|
||||
let startTime1 = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
imageKnife.getDefaultLifeCycle();
|
||||
}
|
||||
endTime(startTime1, 'getDefaultLifeCycle');
|
||||
imageKnife.setDefaultLifeCycle(ImageKnifeDrawFactory.createProgressLifeCycle("#10a5ff", 0.5))
|
||||
let globalLifeCycle = imageKnife.getDefaultLifeCycle();
|
||||
expect(globalLifeCycle).not().assertUndefined()
|
||||
}
|
||||
|
||||
})
|
||||
it('TestRemoveAllMemoryCache',2,()=>{
|
||||
let imageKnife:ImageKnife|undefined = ImageKnifeGlobal.getInstance().getImageKnife();
|
||||
imageKnife?.removeAllMemoryCache();
|
||||
let a = imageKnife?.getMemoryCache();
|
||||
expect(a).assertEqual(undefined);
|
||||
})
|
||||
it('TestRemoveAllFileCache',3,()=>{
|
||||
let imageKnife:ImageKnife|undefined = ImageKnifeGlobal.getInstance().getImageKnife();
|
||||
imageKnife?.removeAllFileCache();
|
||||
let a = imageKnife?.getDiskMemoryCache();
|
||||
expect(a).assertEqual(undefined);
|
||||
})
|
||||
it('TestRemoveMemoryCache',4,()=>{
|
||||
let memoryCache = new LruCache<string, string>(5);
|
||||
memoryCache.put("1","1");
|
||||
memoryCache.remove("1");
|
||||
let result = memoryCache.get("1");
|
||||
expect(result).assertEqual(undefined);
|
||||
})
|
||||
it('TestRemoveFileCache',5,()=>{
|
||||
let context: object | undefined = GlobalContext.getInstance().getObject("hapContext");
|
||||
let disLruCache: DiskLruCache = DiskLruCache.create(context as common.UIAbilityContext, 1024);
|
||||
disLruCache.set('test', "Hello World Simple Example.");
|
||||
disLruCache.deleteCacheDataByKey('test');
|
||||
let a = disLruCache.get('test');
|
||||
expect(a).assertEqual(undefined);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function endTime(startTime: number, tag: string) {
|
||||
let endTime: number = new Date().getTime();
|
||||
let averageTime = ((endTime - startTime) * 1000 / BASE_COUNT)
|
||||
console.info(tag + " startTime: " + endTime)
|
||||
console.info(tag + " endTime: " + endTime)
|
||||
console.log(tag + " averageTime: " + averageTime + "μs");
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* 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 {
|
||||
BlurTransformation,
|
||||
BrightnessTransformation,
|
||||
CropCircleTransformation,
|
||||
CropCircleWithBorderTransformation,
|
||||
CropSquareTransformation,
|
||||
CropTransformation,
|
||||
GrayScaleTransformation,
|
||||
InvertTransformation,
|
||||
KuwaharaTransformation,
|
||||
MaskTransformation,
|
||||
PixelationTransformation,
|
||||
SepiaTransformation,
|
||||
SketchTransformation,
|
||||
SwirlTransformation,
|
||||
ToonTransformation,
|
||||
VignetterTransformation
|
||||
} from '@ohos/imageknife'
|
||||
|
||||
const BASE_COUNT: number = 1000;
|
||||
|
||||
export default function Transform() {
|
||||
describe('Transform', () => {
|
||||
// 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('TestBlurTransformation', 0, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new BlurTransformation(15);
|
||||
}
|
||||
endTime(startTime, 'TestBlurTransformation');
|
||||
let blur = new BlurTransformation(15);
|
||||
expect(blur.getName()).assertEqual('BlurTransformation;radius:15');
|
||||
})
|
||||
it('TestBrightnessTransformation', 1, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new BrightnessTransformation(20);
|
||||
}
|
||||
endTime(startTime, 'BrightnessTransformation');
|
||||
let bright = new BrightnessTransformation(20);
|
||||
expect(bright.getName()).assertEqual("BrightnessTransformation;bright:20");
|
||||
})
|
||||
it('TestCropCircleTransformation', 3, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new CropCircleTransformation();
|
||||
}
|
||||
endTime(startTime, 'TestCropCircleTransformation');
|
||||
let cropCircle = new CropCircleTransformation();
|
||||
expect(cropCircle.getName()).assertContain("CropCircleTransformation");
|
||||
expect(cropCircle.getName()).assertContain(";mCenterX:");
|
||||
expect(cropCircle.getName()).assertContain(";mCenterY:");
|
||||
expect(cropCircle.getName()).assertContain(";mRadius:");
|
||||
})
|
||||
it('TestCropCircleWithBorderTransformation', 4, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new CropCircleWithBorderTransformation(10, {
|
||||
r_color: 100, g_color: 100, b_color: 100
|
||||
});
|
||||
}
|
||||
endTime(startTime, 'TestCropCircleWithBorderTransformation');
|
||||
let CropCircleWithBorder = new CropCircleWithBorderTransformation(10, {
|
||||
r_color: 100, g_color: 100, b_color: 100
|
||||
});
|
||||
expect(CropCircleWithBorder.getName()).assertContain("CropCircleWithBorderTransformation")
|
||||
expect(CropCircleWithBorder.getName()).assertContain(";mCenterX:");
|
||||
expect(CropCircleWithBorder.getName()).assertContain(";mCenterY:");
|
||||
expect(CropCircleWithBorder.getName()).assertContain(";mRadius:");
|
||||
expect(CropCircleWithBorder.getName()).assertContain(";mBorderSize:");
|
||||
expect(CropCircleWithBorder.getName()).assertContain(";mRColor:");
|
||||
expect(CropCircleWithBorder.getName()).assertContain(";mGColor:");
|
||||
expect(CropCircleWithBorder.getName()).assertContain(";mBColor:");
|
||||
})
|
||||
it('TestCropSquareTransformation', 5, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new CropSquareTransformation();
|
||||
}
|
||||
endTime(startTime, 'TestCropSquareTransformation');
|
||||
let CropSquare = new CropSquareTransformation();
|
||||
expect(CropSquare.getName()).assertContain("CropSquareTransformation");
|
||||
})
|
||||
it('TestCropTransformation', 6, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new CropTransformation(10, 10, 1);
|
||||
}
|
||||
endTime(startTime, 'TestCropTransformation');
|
||||
let crop = new CropTransformation(10, 10, 1);
|
||||
expect(crop.getName()).assertContain("CropTransformation" + ";mWidth:10" + ";mHeight:10" + ";mCropType:1")
|
||||
})
|
||||
it('TestGrayScaleTransformation', 7, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new GrayScaleTransformation();
|
||||
}
|
||||
endTime(startTime, 'GrayScaleTransformation');
|
||||
let grayscale = new GrayScaleTransformation();
|
||||
expect(grayscale.getName()).assertContain("GrayScaleTransformation")
|
||||
})
|
||||
it('TestInvertTransformation', 8, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new InvertTransformation();
|
||||
}
|
||||
endTime(startTime, 'TestInvertFilterTransformation');
|
||||
let invert = new InvertTransformation();
|
||||
expect(invert.getName()).assertContain("InvertTransformation");
|
||||
})
|
||||
it('TestPixelationTransformation', 9, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new PixelationTransformation();
|
||||
}
|
||||
endTime(startTime, 'TestPixelationTransformation');
|
||||
let pixelation = new PixelationTransformation();
|
||||
expect(pixelation.getName()).assertContain("PixelationTransformation");
|
||||
})
|
||||
it('TestSepiaTransformation', 12, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new SepiaTransformation();
|
||||
}
|
||||
endTime(startTime, 'SepiaTransformation');
|
||||
let speia = new SepiaTransformation();
|
||||
expect(speia.getName()).assertContain("SepiaTransformation");
|
||||
})
|
||||
it('TestSketchTransformation', 13, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new SketchTransformation();
|
||||
}
|
||||
endTime(startTime, 'TestSketchTransformation');
|
||||
let Sketch = new SketchTransformation();
|
||||
expect(Sketch.getName()).assertContain("SketchTransformation");
|
||||
})
|
||||
it('TestMaskTransformation', 14, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new MaskTransformation($r('app.media.icon'));
|
||||
}
|
||||
endTime(startTime, 'TestMaskTransformation');
|
||||
let mask = new MaskTransformation($r('app.media.icon'));
|
||||
expect(mask.getName()).assertContain("MaskTransformation");
|
||||
})
|
||||
it('TestSwirlTransformation', 15, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new SwirlTransformation(10, 180, [10, 10]);
|
||||
}
|
||||
endTime(startTime, 'TestSwirlTransformation');
|
||||
let swirl = new SwirlTransformation(10, 180, [10, 10]);
|
||||
expect(swirl.getName()).assertContain("SwirlTransformation");
|
||||
})
|
||||
it('TestKuwaharaTransformation', 16, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new KuwaharaTransformation(10);
|
||||
}
|
||||
endTime(startTime, 'TestKuwaharaTransformation');
|
||||
let kuwahara = new KuwaharaTransformation(10);
|
||||
expect(kuwahara.getName()).assertContain("KuwaharaTransformation;radius:10");
|
||||
})
|
||||
it('TestToonTransformation', 17, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new ToonTransformation(10);
|
||||
}
|
||||
endTime(startTime, 'TestToonTransformation');
|
||||
let toon = new ToonTransformation(10);
|
||||
expect(toon.getName()).assertContain("ToonTransformation;threshold:10");
|
||||
})
|
||||
it('TestVignetterTransformation', 18, () => {
|
||||
let startTime = new Date().getTime();
|
||||
for (let index = 0; index < BASE_COUNT; index++) {
|
||||
new VignetterTransformation([0.5, 0.5], [0.0, 0.0, 0.0], [0.3, 0.75]);
|
||||
}
|
||||
endTime(startTime, 'TestVignetterTransformation');
|
||||
let vignette = new VignetterTransformation([0.5, 0.5], [0.0, 0.0, 0.0], [0.3, 0.75]);
|
||||
expect(vignette.getName()).assertContain("VignetterTransformation");
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function endTime(startTime: number, tag: string) {
|
||||
let endTime: number = new Date().getTime();
|
||||
let averageTime = ((endTime - startTime) * 1000 / BASE_COUNT);
|
||||
console.info(tag + " startTime: " + endTime);
|
||||
console.info(tag + " endTime: " + endTime);
|
||||
console.log(tag + " averageTime: " + averageTime + "μs");
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* 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,
|
||||
* 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.
|
||||
|
@ -18,46 +18,50 @@ import hilog from '@ohos.hilog';
|
|||
import { Hypium } from '@ohos/hypium';
|
||||
import testsuite from '../test/List.test';
|
||||
import window from '@ohos.window';
|
||||
import {ImageKnife,ImageKnifeDrawFactory,ImageKnifeGlobal} from '@ohos/libraryimageknife'
|
||||
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
|
||||
import Want from '@ohos.app.ability.Want';
|
||||
import { BusinessError } from '@ohos.base'
|
||||
import {GlobalContext } from './GlobalContext'
|
||||
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
|
||||
import { GlobalContext } from '../../../main/ets/common/GlobalContext';
|
||||
|
||||
export default class TestAbility extends UIAbility {
|
||||
onCreate(want: Want, param: AbilityConstant.LaunchParam) {
|
||||
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate');
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? '');
|
||||
let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator;
|
||||
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
|
||||
let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs;
|
||||
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments();
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!');
|
||||
Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
|
||||
}
|
||||
|
||||
let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator
|
||||
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
|
||||
let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs
|
||||
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
|
||||
onDestroy() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy');
|
||||
}
|
||||
|
||||
Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite)
|
||||
// 初始化xts的ImageKnife
|
||||
ImageKnife.with(this.context.createModuleContext("entry_test"));
|
||||
GlobalContext.getInstance().setObject("hapContext",this.context.createModuleContext("entry_test"));
|
||||
GlobalContext.getInstance().setObject("filesDir",this.context.createModuleContext("entry_test").filesDir);
|
||||
}
|
||||
onWindowStageCreate(windowStage: window.WindowStage) {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate');
|
||||
GlobalContext.getContext().setObject("context", this.context);
|
||||
GlobalContext.getContext().setObject("cacheDir", this.context.cacheDir);
|
||||
windowStage.loadContent('testability/pages/Index', (err, data) => {
|
||||
if (err.code) {
|
||||
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
|
||||
return;
|
||||
}
|
||||
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s',
|
||||
JSON.stringify(data) ?? '');
|
||||
});
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
onWindowStageDestroy() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy');
|
||||
}
|
||||
|
||||
}
|
||||
onForeground() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground');
|
||||
}
|
||||
|
||||
onWindowStageCreate(windowStage: window.WindowStage) {
|
||||
|
||||
windowStage.loadContent('testability/pages/Index', (err:BusinessError, data:void) => {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
onWindowStageDestroy() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy');
|
||||
}
|
||||
|
||||
onForeground() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground');
|
||||
}
|
||||
|
||||
onBackground() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground');
|
||||
}
|
||||
onBackground() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground');
|
||||
}
|
||||
}
|
|
@ -1,50 +1,31 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* 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,
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import hilog from '@ohos.hilog';
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct Index {
|
||||
@State message: string = 'Hello World';
|
||||
|
||||
aboutToAppear() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility index aboutToAppear');
|
||||
build() {
|
||||
Row() {
|
||||
Column() {
|
||||
Text(this.message)
|
||||
.fontSize(50)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
.height('100%')
|
||||
}
|
||||
|
||||
@State message: string = 'Hello World'
|
||||
build() {
|
||||
Row() {
|
||||
Column() {
|
||||
Text(this.message)
|
||||
.fontSize(50)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
Button() {
|
||||
Text('next page')
|
||||
.fontSize(20)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
}.type(ButtonType.Capsule)
|
||||
.margin({
|
||||
top: 20
|
||||
})
|
||||
.backgroundColor('#0D9FFB')
|
||||
.width('35%')
|
||||
.height('5%')
|
||||
.onClick(()=>{
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
.height('100%')
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import hilog from '@ohos.hilog';
|
||||
import TestRunner from '@ohos.application.testRunner';
|
||||
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
|
||||
import Want from '@ohos.app.ability.Want';
|
||||
|
||||
let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator | undefined = undefined
|
||||
let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs | undefined = undefined
|
||||
|
||||
async function onAbilityCreateCallback() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback');
|
||||
}
|
||||
|
||||
async function addAbilityMonitorCallback(err : Error) {
|
||||
hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? '');
|
||||
}
|
||||
|
||||
export default class OpenHarmonyTestRunner implements TestRunner {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
onPrepare() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare ');
|
||||
}
|
||||
|
||||
async onRun() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run');
|
||||
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
|
||||
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
|
||||
const bundleName = abilityDelegatorArguments.bundleName;
|
||||
const testAbilityName = 'TestAbility';
|
||||
const moduleName = abilityDelegatorArguments.parameters['-m'];
|
||||
let lMonitor: AbilityDelegatorRegistry.AbilityMonitor = {
|
||||
abilityName: testAbilityName,
|
||||
onAbilityCreate: onAbilityCreateCallback,
|
||||
moduleName: moduleName
|
||||
};
|
||||
abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
|
||||
const want: Want = {
|
||||
bundleName: bundleName,
|
||||
abilityName: testAbilityName,
|
||||
moduleName: moduleName
|
||||
};
|
||||
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
|
||||
abilityDelegator.startAbility(want, (err, data) => {
|
||||
hilog.info(0x0000, 'testTag', 'startAbility : err : %{public}s', JSON.stringify(err) ?? '');
|
||||
hilog.info(0x0000, 'testTag', 'startAbility : data : %{public}s',JSON.stringify(data) ?? '');
|
||||
})
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end');
|
||||
}
|
||||
}
|
|
@ -2,19 +2,16 @@
|
|||
"module": {
|
||||
"name": "entry_test",
|
||||
"type": "feature",
|
||||
"srcEntry": "./ets/testability/TestAbility.ets",
|
||||
"description": "$string:module_test_desc",
|
||||
"mainElement": "TestAbility",
|
||||
"deviceTypes": ["default"],
|
||||
"deviceTypes": [
|
||||
"phone",
|
||||
"tablet",
|
||||
"2in1"
|
||||
],
|
||||
"deliveryWithInstall": true,
|
||||
"installationFree": false,
|
||||
"pages": "$profile:test_pages",
|
||||
"metadata": [
|
||||
{
|
||||
"name": "ArkTSPartialUpdate",
|
||||
"value": "true"
|
||||
}
|
||||
],
|
||||
"abilities": [
|
||||
{
|
||||
"name": "TestAbility",
|
||||
|
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 2.0 KiB |
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"src": [
|
||||
"testability/pages/index"
|
||||
"testability/pages/Index"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/node_modules
|
||||
/oh_modules
|
||||
/.preview
|
||||
/build
|
||||
/oh_modules/
|
||||
/oh-package-lock.json5
|
||||
/.cxx
|
||||
/.test
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export default class BuildProfile {
|
||||
static readonly HAR_VERSION = '3.0.0-rc.0';
|
||||
static readonly BUILD_MODE_NAME = 'debug';
|
||||
static readonly DEBUG = true;
|
||||
}
|
|
@ -1,5 +1,28 @@
|
|||
{
|
||||
"apiType": "stageMode",
|
||||
"buildOption": {
|
||||
}
|
||||
},
|
||||
"buildOptionSet": [
|
||||
{
|
||||
"name": "release",
|
||||
"arkOptions": {
|
||||
"obfuscation": {
|
||||
"ruleOptions": {
|
||||
"enable": true,
|
||||
"files": [
|
||||
"./obfuscation-rules.txt"
|
||||
]
|
||||
},
|
||||
"consumerFiles": [
|
||||
"./consumer-rules.txt"
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
|
||||
module.exports = require('@ohos/hvigor-ohos-plugin').harTasks
|
||||
import { harTasks } from '@ohos/hvigor-ohos-plugin';
|
||||
|
||||
export default {
|
||||
system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
|
||||
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
* 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
|
||||
* 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,
|
||||
|
@ -12,127 +12,58 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { ImageKnifeComponent } from './src/main/ets/components/ImageKnifeComponent'
|
||||
|
||||
export { ImageKnifeAnimatorComponent } from './src/main/ets/components/ImageKnifeAnimatorComponent'
|
||||
|
||||
/**
|
||||
* cache
|
||||
*/
|
||||
export { ImageKnife } from './src/main/ets/ImageKnife'
|
||||
|
||||
export { FileUtils } from './src/main/ets/components/cache/FileUtils'
|
||||
export { Base64 } from './src/main/ets/components/cache/Base64'
|
||||
export { LruCache } from './src/main/ets/components/cache/LruCache'
|
||||
export { DiskLruCache } from './src/main/ets/components/cache/DiskLruCache'
|
||||
export { DiskCacheEntry } from './src/main/ets/components/cache/DiskCacheEntry'
|
||||
export { DiskStrategy } from './src/main/ets/components/cache/diskstrategy/DiskStrategy'
|
||||
export { ALL } from './src/main/ets/components/cache/diskstrategy/enum/ALL'
|
||||
export { AUTOMATIC } from './src/main/ets/components/cache/diskstrategy/enum/AUTOMATIC'
|
||||
export { DATA } from './src/main/ets/components/cache/diskstrategy/enum/DATA'
|
||||
export { NONE } from './src/main/ets/components/cache/diskstrategy/enum/NONE'
|
||||
export { RESOURCE } from './src/main/ets/components/cache/diskstrategy/enum/RESOURCE'
|
||||
export { EngineKeyInterface } from './src/main/ets/components/cache/key/EngineKeyInterface'
|
||||
export { EngineKeyFactories } from './src/main/ets/components/cache/key/EngineKeyFactories'
|
||||
export { DataFetchResult } from './src/main/ets/components/imageknife/networkmanage/DataFetchResult'
|
||||
export { ImageKnifeOption , AnimatorOption } from './src/main/ets/ImageKnifeOption'
|
||||
|
||||
/**
|
||||
* compress
|
||||
*/
|
||||
export { CompressBuilder } from './src/main/ets/components/imageknife/compress/CompressBuilder'
|
||||
export { OnCompressListener } from './src/main/ets/components/imageknife/compress/listener/OnCompressListener'
|
||||
export { OnRenameListener } from './src/main/ets/components/imageknife/compress/listener/OnRenameListener'
|
||||
export { CompressDataListener } from './src/main/ets/components/imageknife/compress/listener/CompressDataListener'
|
||||
export { CompressionPredicate } from './src/main/ets/components/imageknife/compress/listener/CompressionPredicate'
|
||||
export { CompressAdapter } from './src/main/ets/components/imageknife/compress/provider/CompressAdapter'
|
||||
export { CompressProvider } from './src/main/ets/components/imageknife/compress/provider/CompressProvider'
|
||||
export { DataStringPathProvider } from './src/main/ets/components/imageknife/compress/provider/DataStringPathProvider'
|
||||
export { RecourseProvider } from './src/main/ets/components/imageknife/compress/provider/RecourseProvider'
|
||||
export { ImageKnifeRequest } from './src/main/ets/ImageKnifeRequest'
|
||||
|
||||
/**
|
||||
* crop
|
||||
*/
|
||||
export { FileUtils } from './src/main/ets/utils/FileUtils'
|
||||
|
||||
export { CropImage } from './src/main/ets/components/imageknife/crop/CropImage'
|
||||
export { CropOptions } from './src/main/ets/components/imageknife/crop/CropOptions'
|
||||
export { PixelMapCrop,Options } from './src/main/ets/components/imageknife/crop/PixelMapCrop'
|
||||
export { CropCallback } from './src/main/ets/components/imageknife/crop/CropCallback'
|
||||
export { LogUtil } from './src/main/ets/utils/LogUtil'
|
||||
|
||||
/**
|
||||
* transform
|
||||
*/
|
||||
export { BaseTransform } from './src/main/ets/components/imageknife/transform/BaseTransform'
|
||||
export { BlurTransformation } from './src/main/ets/components/imageknife/transform/BlurTransformation'
|
||||
export { BrightnessFilterTransformation } from './src/main/ets/components/imageknife/transform/BrightnessFilterTransformation'
|
||||
export { ContrastFilterTransformation } from './src/main/ets/components/imageknife/transform/ContrastFilterTransformation'
|
||||
export { CropCircleTransformation } from './src/main/ets/components/imageknife/transform/CropCircleTransformation'
|
||||
export { CropCircleWithBorderTransformation,rgbColor } from './src/main/ets/components/imageknife/transform/CropCircleWithBorderTransformation'
|
||||
export { CropSquareTransformation } from './src/main/ets/components/imageknife/transform/CropSquareTransformation'
|
||||
export { CropTransformation,CropType } from './src/main/ets/components/imageknife/transform/CropTransformation'
|
||||
export { GrayscaleTransformation } from './src/main/ets/components/imageknife/transform/GrayscaleTransformation'
|
||||
export { InvertFilterTransformation } from './src/main/ets/components/imageknife/transform/InvertFilterTransformation'
|
||||
export { PixelationFilterTransformation } from './src/main/ets/components/imageknife/transform/PixelationFilterTransformation'
|
||||
export { RotateImageTransformation } from './src/main/ets/components/imageknife/transform/RotateImageTransformation'
|
||||
export { RoundedCornersTransformation,RoundCorner } from './src/main/ets/components/imageknife/transform/RoundedCornersTransformation'
|
||||
export { SepiaFilterTransformation } from './src/main/ets/components/imageknife/transform/SepiaFilterTransformation'
|
||||
export { SketchFilterTransformation } from './src/main/ets/components/imageknife/transform/SketchFilterTransformation'
|
||||
export { MaskTransformation } from './src/main/ets/components/imageknife/transform/MaskTransformation'
|
||||
export { SwirlFilterTransformation } from './src/main/ets/components/imageknife/transform/SwirlFilterTransformation'
|
||||
export { KuwaharaFilterTransform } from './src/main/ets/components/imageknife/transform/KuwaharaFilterTransform'
|
||||
export { ToonFilterTransform } from './src/main/ets/components/imageknife/transform/ToonFilterTransform'
|
||||
export { VignetteFilterTransform } from './src/main/ets/components/imageknife/transform/VignetteFilterTransform'
|
||||
export { TransformUtils } from './src/main/ets/components/imageknife/transform/TransformUtils'
|
||||
export { TransformType } from './src/main/ets/components/imageknife/transform/TransformType'
|
||||
export { CenterCrop } from './src/main/ets/components/imageknife/transform/pixelmap/CenterCrop'
|
||||
export { CenterInside } from './src/main/ets/components/imageknife/transform/pixelmap/CenterInside'
|
||||
export { FitCenter } from './src/main/ets/components/imageknife/transform/pixelmap/FitCenter'
|
||||
export { IEngineKey } from './src/main/ets/key/IEngineKey'
|
||||
|
||||
/**
|
||||
* pngj
|
||||
*/
|
||||
export { Pngj } from './src/main/ets/components/imageknife/pngj/Pngj'
|
||||
export {handler} from './PngWork'
|
||||
export { UPNG } from './src/main/ets/components/3rd_party/upng/UPNG'
|
||||
export { ImageKnifeData , CacheStrategy , ImageKnifeRequestSource} from "./src/main/ets/model/ImageKnifeData"
|
||||
|
||||
export { PixelMapTransformation } from './src/main/ets/transform/PixelMapTransformation'
|
||||
|
||||
export { MultiTransTransformation } from './src/main/ets/transform/MultiTransTransformation'
|
||||
|
||||
/**
|
||||
* ImageKnife
|
||||
*/
|
||||
export { ImageKnife } from './src/main/ets/components/imageknife/ImageKnife'
|
||||
export { ImageKnifeGlobal } from './src/main/ets/components/imageknife/ImageKnifeGlobal'
|
||||
export { ObjectKey } from './src/main/ets/components/imageknife/ObjectKey'
|
||||
export {RequestOption,Size,DetachFromLayout,CacheType} from './src/main/ets/components/imageknife/RequestOption'
|
||||
export { ImageKnifeComponent, ScaleType, ScaleTypeHelper, AntiAliasing} from './src/main/ets/components/imageknife/ImageKnifeComponent'
|
||||
export { ImageKnifeDrawFactory } from './src/main/ets/components/imageknife/ImageKnifeDrawFactory'
|
||||
export {ImageKnifeOption,CropCircleWithBorder,Crop,GifOptions,TransformOptions,HeaderOptions} from './src/main/ets/components/imageknife/ImageKnifeOption'
|
||||
export { ImageKnifeData } from './src/main/ets/components/imageknife/ImageKnifeData'
|
||||
export {IAllCacheInfoCallback,AllCacheInfo,ResourceCacheInfo,MemoryCacheInfo,DataCacheInfo} from './src/main/ets/components/imageknife/interface/IAllCacheInfoCallback'
|
||||
export {IParseImage} from './src/main/ets/components/imageknife/interface/IParseImage'
|
||||
export {IDataFetch} from './src/main/ets/components/imageknife/networkmanage/IDataFetch'
|
||||
export {ICache} from './src/main/ets/components/imageknife/requestmanage/ICache'
|
||||
export { FileTypeUtil } from './src/main/ets/components/imageknife/utils/FileTypeUtil'
|
||||
export { ParseImageUtil } from './src/main/ets/components/imageknife/utils/ParseImageUtil'
|
||||
export { DownloadClient } from './src/main/ets/components/imageknife/networkmanage/DownloadClient';
|
||||
export { CustomDataFetchClient } from './src/main/ets/components/imageknife/networkmanage/CustomDataFetchClient';
|
||||
export { BrightnessTransformation } from './src/main/ets/transform/BrightnessTransformation'
|
||||
|
||||
/**
|
||||
* svg parse
|
||||
*/
|
||||
export { SVGParseImpl } from './src/main/ets/components/imageknife/utils/svg/SVGParseImpl'
|
||||
export { BlurTransformation } from './src/main/ets/transform/BlurTransformation'
|
||||
|
||||
/**
|
||||
* gif parse
|
||||
*/
|
||||
export { GIFParseImpl } from './src/main/ets/components/imageknife/utils/gif/GIFParseImpl'
|
||||
export { GIFFrame } from './src/main/ets/components/imageknife/utils/gif/GIFFrame'
|
||||
export { SparkMD5 } from "./src/main/ets/3rd_party/sparkmd5/spark-md5"
|
||||
|
||||
export { GrayScaleTransformation } from './src/main/ets/transform/GrayScaleTransformation'
|
||||
|
||||
// 自定义组件新增
|
||||
// 自定义组件绘制生命周期
|
||||
export { IDrawLifeCycle } from './src/main/ets/components/imageknife/interface/IDrawLifeCycle'
|
||||
export { InvertTransformation } from './src/main/ets/transform/InvertTransformation'
|
||||
|
||||
// 日志管理
|
||||
export { LogUtil } from './src/main/ets/components/imageknife/utils/LogUtil'
|
||||
export { ToonTransformation } from './src/main/ets/transform/ToonTransformation'
|
||||
|
||||
/*下采样*/
|
||||
export {Downsampler} from './src/main/ets/components/imageknife/downsampling/Downsampler'
|
||||
export { CropCircleTransformation } from './src/main/ets/transform/CropCircleTransformation'
|
||||
|
||||
export {DownsampleNone as sampleNone, FitCenter as fitter} from './src/main/ets/components/imageknife/downsampling/DownsampleStartegy'
|
||||
export { CropCircleWithBorderTransformation } from './src/main/ets/transform/CropCircleWithBorderTransformation'
|
||||
|
||||
export { KuwaharaTransformation } from './src/main/ets/transform/KuwaharaTransformation'
|
||||
|
||||
export { PixelationTransformation } from './src/main/ets/transform/PixelationTransformation'
|
||||
|
||||
export { SketchTransformation } from './src/main/ets/transform/SketchTransformation'
|
||||
|
||||
export { SwirlTransformation } from './src/main/ets/transform/SwirlTransformation'
|
||||
|
||||
export { VignetterTransformation } from './src/main/ets/transform/VignetterTransformation'
|
||||
|
||||
export { CropSquareTransformation } from './src/main/ets/transform/CropSquareTransformation'
|
||||
|
||||
export { CropTransformation } from './src/main/ets/transform/CropTransformation'
|
||||
|
||||
export { MaskTransformation } from './src/main/ets/transform/MaskTransformation'
|
||||
|
||||
export { SepiaTransformation } from './src/main/ets/transform/SepiaTransformation'
|
|
@ -0,0 +1,18 @@
|
|||
# Define project specific obfuscation rules here.
|
||||
# You can include the obfuscation configuration files in the current module's build-profile.json5.
|
||||
#
|
||||
# For more details, see
|
||||
# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md
|
||||
|
||||
# Obfuscation options:
|
||||
# -disable-obfuscation: disable all obfuscations
|
||||
# -enable-property-obfuscation: obfuscate the property names
|
||||
# -enable-toplevel-obfuscation: obfuscate the names in the global scope
|
||||
# -compact: remove unnecessary blank spaces and all line feeds
|
||||
# -remove-log: remove all console.* statements
|
||||
# -print-namecache: print the name cache that contains the mapping from the old names to new names
|
||||
# -apply-namecache: reuse the given cache file
|
||||
|
||||
# Keep options:
|
||||
# -keep-property-name: specifies property names that you want to keep
|
||||
# -keep-global-name: specifies names that you want to keep in the global scope
|
|
@ -14,10 +14,9 @@
|
|||
"main": "index.ets",
|
||||
"repository": "https://gitee.com/openharmony-tpc/ImageKnife",
|
||||
"type": "module",
|
||||
"version": "2.3.0-rc.2",
|
||||
"version": "3.0.1-rc.2",
|
||||
"dependencies": {
|
||||
"pako": "^2.1.0",
|
||||
"@ohos/gpu_transform": "^1.0.0"
|
||||
"@ohos/gpu_transform": "^1.0.2"
|
||||
},
|
||||
"tags": [
|
||||
"ImageCache",
|
||||
|
|
|
@ -0,0 +1,741 @@
|
|||
import buffer from '@ohos.buffer';
|
||||
|
||||
/*
|
||||
* Fastest md5 implementation around (JKM md5).
|
||||
* Credits: Joseph Myers
|
||||
*
|
||||
* @see http://www.myersdaily.org/joseph/javascript/md5-text.html
|
||||
* @see http://jsperf.com/md5-shootout/7
|
||||
*/
|
||||
|
||||
/* this function is much faster,
|
||||
so if possible we use it. Some IEs
|
||||
are the only ones I know of that
|
||||
need the idiotic second function,
|
||||
generated by an if clause. */
|
||||
var add32 = function (a, b) {
|
||||
return (a + b) & 0xFFFFFFFF;
|
||||
},
|
||||
hex_chr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
|
||||
|
||||
|
||||
function cmn(q, a, b, x, s, t) {
|
||||
a = add32(add32(a, q), add32(x, t));
|
||||
return add32((a << s) | (a >>> (32 - s)), b);
|
||||
}
|
||||
|
||||
function md5cycle(x, k) {
|
||||
var a = x[0],
|
||||
b = x[1],
|
||||
c = x[2],
|
||||
d = x[3];
|
||||
|
||||
a += (b & c | ~b & d) + k[0] - 680876936 | 0;
|
||||
a = (a << 7 | a >>> 25) + b | 0;
|
||||
d += (a & b | ~a & c) + k[1] - 389564586 | 0;
|
||||
d = (d << 12 | d >>> 20) + a | 0;
|
||||
c += (d & a | ~d & b) + k[2] + 606105819 | 0;
|
||||
c = (c << 17 | c >>> 15) + d | 0;
|
||||
b += (c & d | ~c & a) + k[3] - 1044525330 | 0;
|
||||
b = (b << 22 | b >>> 10) + c | 0;
|
||||
a += (b & c | ~b & d) + k[4] - 176418897 | 0;
|
||||
a = (a << 7 | a >>> 25) + b | 0;
|
||||
d += (a & b | ~a & c) + k[5] + 1200080426 | 0;
|
||||
d = (d << 12 | d >>> 20) + a | 0;
|
||||
c += (d & a | ~d & b) + k[6] - 1473231341 | 0;
|
||||
c = (c << 17 | c >>> 15) + d | 0;
|
||||
b += (c & d | ~c & a) + k[7] - 45705983 | 0;
|
||||
b = (b << 22 | b >>> 10) + c | 0;
|
||||
a += (b & c | ~b & d) + k[8] + 1770035416 | 0;
|
||||
a = (a << 7 | a >>> 25) + b | 0;
|
||||
d += (a & b | ~a & c) + k[9] - 1958414417 | 0;
|
||||
d = (d << 12 | d >>> 20) + a | 0;
|
||||
c += (d & a | ~d & b) + k[10] - 42063 | 0;
|
||||
c = (c << 17 | c >>> 15) + d | 0;
|
||||
b += (c & d | ~c & a) + k[11] - 1990404162 | 0;
|
||||
b = (b << 22 | b >>> 10) + c | 0;
|
||||
a += (b & c | ~b & d) + k[12] + 1804603682 | 0;
|
||||
a = (a << 7 | a >>> 25) + b | 0;
|
||||
d += (a & b | ~a & c) + k[13] - 40341101 | 0;
|
||||
d = (d << 12 | d >>> 20) + a | 0;
|
||||
c += (d & a | ~d & b) + k[14] - 1502002290 | 0;
|
||||
c = (c << 17 | c >>> 15) + d | 0;
|
||||
b += (c & d | ~c & a) + k[15] + 1236535329 | 0;
|
||||
b = (b << 22 | b >>> 10) + c | 0;
|
||||
|
||||
a += (b & d | c & ~d) + k[1] - 165796510 | 0;
|
||||
a = (a << 5 | a >>> 27) + b | 0;
|
||||
d += (a & c | b & ~c) + k[6] - 1069501632 | 0;
|
||||
d = (d << 9 | d >>> 23) + a | 0;
|
||||
c += (d & b | a & ~b) + k[11] + 643717713 | 0;
|
||||
c = (c << 14 | c >>> 18) + d | 0;
|
||||
b += (c & a | d & ~a) + k[0] - 373897302 | 0;
|
||||
b = (b << 20 | b >>> 12) + c | 0;
|
||||
a += (b & d | c & ~d) + k[5] - 701558691 | 0;
|
||||
a = (a << 5 | a >>> 27) + b | 0;
|
||||
d += (a & c | b & ~c) + k[10] + 38016083 | 0;
|
||||
d = (d << 9 | d >>> 23) + a | 0;
|
||||
c += (d & b | a & ~b) + k[15] - 660478335 | 0;
|
||||
c = (c << 14 | c >>> 18) + d | 0;
|
||||
b += (c & a | d & ~a) + k[4] - 405537848 | 0;
|
||||
b = (b << 20 | b >>> 12) + c | 0;
|
||||
a += (b & d | c & ~d) + k[9] + 568446438 | 0;
|
||||
a = (a << 5 | a >>> 27) + b | 0;
|
||||
d += (a & c | b & ~c) + k[14] - 1019803690 | 0;
|
||||
d = (d << 9 | d >>> 23) + a | 0;
|
||||
c += (d & b | a & ~b) + k[3] - 187363961 | 0;
|
||||
c = (c << 14 | c >>> 18) + d | 0;
|
||||
b += (c & a | d & ~a) + k[8] + 1163531501 | 0;
|
||||
b = (b << 20 | b >>> 12) + c | 0;
|
||||
a += (b & d | c & ~d) + k[13] - 1444681467 | 0;
|
||||
a = (a << 5 | a >>> 27) + b | 0;
|
||||
d += (a & c | b & ~c) + k[2] - 51403784 | 0;
|
||||
d = (d << 9 | d >>> 23) + a | 0;
|
||||
c += (d & b | a & ~b) + k[7] + 1735328473 | 0;
|
||||
c = (c << 14 | c >>> 18) + d | 0;
|
||||
b += (c & a | d & ~a) + k[12] - 1926607734 | 0;
|
||||
b = (b << 20 | b >>> 12) + c | 0;
|
||||
|
||||
a += (b ^ c ^ d) + k[5] - 378558 | 0;
|
||||
a = (a << 4 | a >>> 28) + b | 0;
|
||||
d += (a ^ b ^ c) + k[8] - 2022574463 | 0;
|
||||
d = (d << 11 | d >>> 21) + a | 0;
|
||||
c += (d ^ a ^ b) + k[11] + 1839030562 | 0;
|
||||
c = (c << 16 | c >>> 16) + d | 0;
|
||||
b += (c ^ d ^ a) + k[14] - 35309556 | 0;
|
||||
b = (b << 23 | b >>> 9) + c | 0;
|
||||
a += (b ^ c ^ d) + k[1] - 1530992060 | 0;
|
||||
a = (a << 4 | a >>> 28) + b | 0;
|
||||
d += (a ^ b ^ c) + k[4] + 1272893353 | 0;
|
||||
d = (d << 11 | d >>> 21) + a | 0;
|
||||
c += (d ^ a ^ b) + k[7] - 155497632 | 0;
|
||||
c = (c << 16 | c >>> 16) + d | 0;
|
||||
b += (c ^ d ^ a) + k[10] - 1094730640 | 0;
|
||||
b = (b << 23 | b >>> 9) + c | 0;
|
||||
a += (b ^ c ^ d) + k[13] + 681279174 | 0;
|
||||
a = (a << 4 | a >>> 28) + b | 0;
|
||||
d += (a ^ b ^ c) + k[0] - 358537222 | 0;
|
||||
d = (d << 11 | d >>> 21) + a | 0;
|
||||
c += (d ^ a ^ b) + k[3] - 722521979 | 0;
|
||||
c = (c << 16 | c >>> 16) + d | 0;
|
||||
b += (c ^ d ^ a) + k[6] + 76029189 | 0;
|
||||
b = (b << 23 | b >>> 9) + c | 0;
|
||||
a += (b ^ c ^ d) + k[9] - 640364487 | 0;
|
||||
a = (a << 4 | a >>> 28) + b | 0;
|
||||
d += (a ^ b ^ c) + k[12] - 421815835 | 0;
|
||||
d = (d << 11 | d >>> 21) + a | 0;
|
||||
c += (d ^ a ^ b) + k[15] + 530742520 | 0;
|
||||
c = (c << 16 | c >>> 16) + d | 0;
|
||||
b += (c ^ d ^ a) + k[2] - 995338651 | 0;
|
||||
b = (b << 23 | b >>> 9) + c | 0;
|
||||
|
||||
a += (c ^ (b | ~d)) + k[0] - 198630844 | 0;
|
||||
a = (a << 6 | a >>> 26) + b | 0;
|
||||
d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0;
|
||||
d = (d << 10 | d >>> 22) + a | 0;
|
||||
c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0;
|
||||
c = (c << 15 | c >>> 17) + d | 0;
|
||||
b += (d ^ (c | ~a)) + k[5] - 57434055 | 0;
|
||||
b = (b << 21 | b >>> 11) + c | 0;
|
||||
a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0;
|
||||
a = (a << 6 | a >>> 26) + b | 0;
|
||||
d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0;
|
||||
d = (d << 10 | d >>> 22) + a | 0;
|
||||
c += (a ^ (d | ~b)) + k[10] - 1051523 | 0;
|
||||
c = (c << 15 | c >>> 17) + d | 0;
|
||||
b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0;
|
||||
b = (b << 21 | b >>> 11) + c | 0;
|
||||
a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0;
|
||||
a = (a << 6 | a >>> 26) + b | 0;
|
||||
d += (b ^ (a | ~c)) + k[15] - 30611744 | 0;
|
||||
d = (d << 10 | d >>> 22) + a | 0;
|
||||
c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0;
|
||||
c = (c << 15 | c >>> 17) + d | 0;
|
||||
b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0;
|
||||
b = (b << 21 | b >>> 11) + c | 0;
|
||||
a += (c ^ (b | ~d)) + k[4] - 145523070 | 0;
|
||||
a = (a << 6 | a >>> 26) + b | 0;
|
||||
d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0;
|
||||
d = (d << 10 | d >>> 22) + a | 0;
|
||||
c += (a ^ (d | ~b)) + k[2] + 718787259 | 0;
|
||||
c = (c << 15 | c >>> 17) + d | 0;
|
||||
b += (d ^ (c | ~a)) + k[9] - 343485551 | 0;
|
||||
b = (b << 21 | b >>> 11) + c | 0;
|
||||
|
||||
x[0] = a + x[0] | 0;
|
||||
x[1] = b + x[1] | 0;
|
||||
x[2] = c + x[2] | 0;
|
||||
x[3] = d + x[3] | 0;
|
||||
}
|
||||
|
||||
function md5blk(s) {
|
||||
var md5blks = [],
|
||||
i; /* Andy King said do it this way. */
|
||||
|
||||
for (i = 0; i < 64; i += 4) {
|
||||
md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
|
||||
}
|
||||
return md5blks;
|
||||
}
|
||||
|
||||
function md5blk_array(a) {
|
||||
var md5blks = [],
|
||||
i; /* Andy King said do it this way. */
|
||||
|
||||
for (i = 0; i < 64; i += 4) {
|
||||
md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);
|
||||
}
|
||||
return md5blks;
|
||||
}
|
||||
|
||||
function md51(s) {
|
||||
var n = s.length,
|
||||
state = [1732584193, -271733879, -1732584194, 271733878],
|
||||
i,
|
||||
length,
|
||||
tail,
|
||||
tmp,
|
||||
lo,
|
||||
hi;
|
||||
|
||||
for (i = 64; i <= n; i += 64) {
|
||||
md5cycle(state, md5blk(s.substring(i - 64, i)));
|
||||
}
|
||||
s = s.substring(i - 64);
|
||||
length = s.length;
|
||||
tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
for (i = 0; i < length; i += 1) {
|
||||
tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
|
||||
}
|
||||
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
|
||||
if (i > 55) {
|
||||
md5cycle(state, tail);
|
||||
for (i = 0; i < 16; i += 1) {
|
||||
tail[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Beware that the final length might not fit in 32 bits so we take care of that
|
||||
tmp = n * 8;
|
||||
tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
|
||||
lo = parseInt(tmp[2], 16);
|
||||
hi = parseInt(tmp[1], 16) || 0;
|
||||
|
||||
tail[14] = lo;
|
||||
tail[15] = hi;
|
||||
|
||||
md5cycle(state, tail);
|
||||
return state;
|
||||
}
|
||||
|
||||
function md51_array(a) {
|
||||
var n = a.length,
|
||||
state = [1732584193, -271733879, -1732584194, 271733878],
|
||||
i,
|
||||
length,
|
||||
tail,
|
||||
tmp,
|
||||
lo,
|
||||
hi;
|
||||
|
||||
for (i = 64; i <= n; i += 64) {
|
||||
md5cycle(state, md5blk_array(a.subarray(i - 64, i)));
|
||||
}
|
||||
|
||||
// Not sure if it is a bug, however IE10 will always produce a sub array of length 1
|
||||
// containing the last element of the parent array if the sub array specified starts
|
||||
// beyond the length of the parent array - weird.
|
||||
// https://connect.microsoft.com/IE/feedback/details/771452/typed-array-subarray-issue
|
||||
a = (i - 64) < n ? a.subarray(i - 64) : new Uint8Array(0);
|
||||
|
||||
length = a.length;
|
||||
tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
for (i = 0; i < length; i += 1) {
|
||||
tail[i >> 2] |= a[i] << ((i % 4) << 3);
|
||||
}
|
||||
|
||||
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
|
||||
if (i > 55) {
|
||||
md5cycle(state, tail);
|
||||
for (i = 0; i < 16; i += 1) {
|
||||
tail[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Beware that the final length might not fit in 32 bits so we take care of that
|
||||
tmp = n * 8;
|
||||
tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
|
||||
lo = parseInt(tmp[2], 16);
|
||||
hi = parseInt(tmp[1], 16) || 0;
|
||||
|
||||
tail[14] = lo;
|
||||
tail[15] = hi;
|
||||
|
||||
md5cycle(state, tail);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
function rhex(n) {
|
||||
var s = '',
|
||||
j;
|
||||
for (j = 0; j < 4; j += 1) {
|
||||
s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function hex(x) {
|
||||
var i;
|
||||
for (i = 0; i < x.length; i += 1) {
|
||||
x[i] = rhex(x[i]);
|
||||
}
|
||||
return x.join('');
|
||||
}
|
||||
|
||||
// In some cases the fast add32 function cannot be used..
|
||||
if (hex(md51('hello')) !== '5d41402abc4b2a76b9719d911017c592') {
|
||||
add32 = function (x, y) {
|
||||
var lsw = (x & 0xFFFF) + (y & 0xFFFF),
|
||||
msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
||||
return (msw << 16) | (lsw & 0xFFFF);
|
||||
};
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
|
||||
/**
|
||||
* ArrayBuffer slice polyfill.
|
||||
*
|
||||
* @see https://github.com/ttaubert/node-arraybuffer-slice
|
||||
*/
|
||||
|
||||
if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {
|
||||
(function () {
|
||||
|
||||
function clamp(val, length) {
|
||||
val = (val | 0) || 0;
|
||||
|
||||
if (val < 0) {
|
||||
return Math.max(val + length, 0);
|
||||
}
|
||||
|
||||
return Math.min(val, length);
|
||||
}
|
||||
|
||||
ArrayBuffer.prototype.slice = function (from, to) {
|
||||
var length = this.byteLength,
|
||||
begin = clamp(from, length),
|
||||
end = length,
|
||||
num,
|
||||
target,
|
||||
targetArray,
|
||||
sourceArray;
|
||||
|
||||
if (to !== undefined) {
|
||||
end = clamp(to, length);
|
||||
}
|
||||
|
||||
if (begin > end) {
|
||||
return new ArrayBuffer(0);
|
||||
}
|
||||
|
||||
num = end - begin;
|
||||
target = new ArrayBuffer(num);
|
||||
targetArray = new Uint8Array(target);
|
||||
|
||||
sourceArray = new Uint8Array(this, begin, num);
|
||||
targetArray.set(sourceArray);
|
||||
|
||||
return target;
|
||||
};
|
||||
})();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
|
||||
/**
|
||||
* Helpers.
|
||||
*/
|
||||
|
||||
function toUtf8(str) {
|
||||
if (/[\u0080-\uFFFF]/.test(str)) {
|
||||
// 源码是str = unescape(encodeURIComponent(str));这里的API并不对等
|
||||
buffer.from(str).toString("utf-8")
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function utf8Str2ArrayBuffer(str, returnUInt8Array) {
|
||||
var length = str.length,
|
||||
buff = new ArrayBuffer(length),
|
||||
arr = new Uint8Array(buff),
|
||||
i;
|
||||
|
||||
for (i = 0; i < length; i += 1) {
|
||||
arr[i] = str.charCodeAt(i);
|
||||
}
|
||||
|
||||
return returnUInt8Array ? arr : buff;
|
||||
}
|
||||
|
||||
function arrayBuffer2Utf8Str(buff) {
|
||||
return String.fromCharCode.apply(null, new Uint8Array(buff));
|
||||
}
|
||||
|
||||
function concatenateArrayBuffers(first, second, returnUInt8Array) {
|
||||
var result = new Uint8Array(first.byteLength + second.byteLength);
|
||||
|
||||
result.set(new Uint8Array(first));
|
||||
result.set(new Uint8Array(second), first.byteLength);
|
||||
|
||||
return returnUInt8Array ? result : result.buffer;
|
||||
}
|
||||
|
||||
function hexToBinaryString(hex) {
|
||||
var bytes = [],
|
||||
length = hex.length,
|
||||
x;
|
||||
|
||||
for (x = 0; x < length - 1; x += 2) {
|
||||
bytes.push(parseInt(hex.substr(x, 2), 16));
|
||||
}
|
||||
|
||||
return String.fromCharCode.apply(String, bytes);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
|
||||
/**
|
||||
* SparkMD5 OOP implementation.
|
||||
*
|
||||
* Use this class to perform an incremental md5, otherwise use the
|
||||
* static methods instead.
|
||||
*/
|
||||
|
||||
function SparkMD5() {
|
||||
// call reset to init the instance
|
||||
this.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a string.
|
||||
* A conversion will be applied if an utf8 string is detected.
|
||||
*
|
||||
* @param {String} str The string to be appended
|
||||
*
|
||||
* @return {SparkMD5} The instance itself
|
||||
*/
|
||||
SparkMD5.prototype.append = function (str) {
|
||||
// Converts the string to utf8 bytes if necessary
|
||||
// Then append as binary
|
||||
this.appendBinary(toUtf8(str));
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Appends a binary string.
|
||||
*
|
||||
* @param {String} contents The binary string to be appended
|
||||
*
|
||||
* @return {SparkMD5} The instance itself
|
||||
*/
|
||||
SparkMD5.prototype.appendBinary = function (contents) {
|
||||
this._buff += contents;
|
||||
this._length += contents.length;
|
||||
|
||||
var length = this._buff.length,
|
||||
i;
|
||||
|
||||
for (i = 64; i <= length; i += 64) {
|
||||
md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i)));
|
||||
}
|
||||
|
||||
this._buff = this._buff.substring(i - 64);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Finishes the incremental computation, reseting the internal state and
|
||||
* returning the result.
|
||||
*
|
||||
* @param {Boolean} raw True to get the raw string, false to get the hex string
|
||||
*
|
||||
* @return {String} The result
|
||||
*/
|
||||
SparkMD5.prototype.end = function (raw) {
|
||||
var buff = this._buff,
|
||||
length = buff.length,
|
||||
i,
|
||||
tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
ret;
|
||||
|
||||
for (i = 0; i < length; i += 1) {
|
||||
tail[i >> 2] |= buff.charCodeAt(i) << ((i % 4) << 3);
|
||||
}
|
||||
|
||||
this._finish(tail, length);
|
||||
ret = hex(this._hash);
|
||||
|
||||
if (raw) {
|
||||
ret = hexToBinaryString(ret);
|
||||
}
|
||||
|
||||
this.reset();
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resets the internal state of the computation.
|
||||
*
|
||||
* @return {SparkMD5} The instance itself
|
||||
*/
|
||||
SparkMD5.prototype.reset = function () {
|
||||
this._buff = '';
|
||||
this._length = 0;
|
||||
this._hash = [1732584193, -271733879, -1732584194, 271733878];
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the internal state of the computation.
|
||||
*
|
||||
* @return {Object} The state
|
||||
*/
|
||||
SparkMD5.prototype.getState = function () {
|
||||
return {
|
||||
buff: this._buff,
|
||||
length: this._length,
|
||||
hash: this._hash.slice()
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the internal state of the computation.
|
||||
*
|
||||
* @param {Object} state The state
|
||||
*
|
||||
* @return {SparkMD5} The instance itself
|
||||
*/
|
||||
SparkMD5.prototype.setState = function (state) {
|
||||
this._buff = state.buff;
|
||||
this._length = state.length;
|
||||
this._hash = state.hash;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Releases memory used by the incremental buffer and other additional
|
||||
* resources. If you plan to use the instance again, use reset instead.
|
||||
*/
|
||||
SparkMD5.prototype.destroy = function () {
|
||||
delete this._hash;
|
||||
delete this._buff;
|
||||
delete this._length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Finish the final calculation based on the tail.
|
||||
*
|
||||
* @param {Array} tail The tail (will be modified)
|
||||
* @param {Number} length The length of the remaining buffer
|
||||
*/
|
||||
SparkMD5.prototype._finish = function (tail, length) {
|
||||
var i = length,
|
||||
tmp,
|
||||
lo,
|
||||
hi;
|
||||
|
||||
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
|
||||
if (i > 55) {
|
||||
md5cycle(this._hash, tail);
|
||||
for (i = 0; i < 16; i += 1) {
|
||||
tail[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Do the final computation based on the tail and length
|
||||
// Beware that the final length may not fit in 32 bits so we take care of that
|
||||
tmp = this._length * 8;
|
||||
tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
|
||||
lo = parseInt(tmp[2], 16);
|
||||
hi = parseInt(tmp[1], 16) || 0;
|
||||
|
||||
tail[14] = lo;
|
||||
tail[15] = hi;
|
||||
md5cycle(this._hash, tail);
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs the md5 hash on a string.
|
||||
* A conversion will be applied if utf8 string is detected.
|
||||
*
|
||||
* @param {String} str The string
|
||||
* @param {Boolean} [raw] True to get the raw string, false to get the hex string
|
||||
*
|
||||
* @return {String} The result
|
||||
*/
|
||||
SparkMD5.hash = function (str, raw) {
|
||||
// Converts the string to utf8 bytes if necessary
|
||||
// Then compute it using the binary function
|
||||
return SparkMD5.hashBinary(toUtf8(str), raw);
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs the md5 hash on a binary string.
|
||||
*
|
||||
* @param {String} content The binary string
|
||||
* @param {Boolean} [raw] True to get the raw string, false to get the hex string
|
||||
*
|
||||
* @return {String} The result
|
||||
*/
|
||||
SparkMD5.hashBinary = function (content, raw) {
|
||||
var hash = md51(content),
|
||||
ret = hex(hash);
|
||||
|
||||
return raw ? hexToBinaryString(ret) : ret;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------
|
||||
|
||||
/**
|
||||
* SparkMD5 OOP implementation for array buffers.
|
||||
*
|
||||
* Use this class to perform an incremental md5 ONLY for array buffers.
|
||||
*/
|
||||
SparkMD5.ArrayBuffer = function () {
|
||||
// call reset to init the instance
|
||||
this.reset();
|
||||
};
|
||||
|
||||
/**
|
||||
* Appends an array buffer.
|
||||
*
|
||||
* @param {ArrayBuffer} arr The array to be appended
|
||||
*
|
||||
* @return {SparkMD5.ArrayBuffer} The instance itself
|
||||
*/
|
||||
SparkMD5.ArrayBuffer.prototype.append = function (arr) {
|
||||
// @ts-ignore
|
||||
var buff = concatenateArrayBuffers(this._buff.buffer, arr, true),
|
||||
// @ts-ignore
|
||||
length = buff.length,
|
||||
i;
|
||||
|
||||
// @ts-ignore
|
||||
this._length += arr.byteLength;
|
||||
|
||||
for (i = 64; i <= length; i += 64) {
|
||||
// @ts-ignore
|
||||
md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i)));
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
this._buff = (i - 64) < length ? new Uint8Array(buff.buffer.slice(i - 64)) : new Uint8Array(0);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Finishes the incremental computation, reseting the internal state and
|
||||
* returning the result.
|
||||
*
|
||||
* @param {Boolean} raw True to get the raw string, false to get the hex string
|
||||
*
|
||||
* @return {String} The result
|
||||
*/
|
||||
SparkMD5.ArrayBuffer.prototype.end = function (raw) {
|
||||
// @ts-ignore
|
||||
var buff = this._buff,
|
||||
length = buff.length,
|
||||
tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
i,
|
||||
ret;
|
||||
|
||||
for (i = 0; i < length; i += 1) {
|
||||
tail[i >> 2] |= buff[i] << ((i % 4) << 3);
|
||||
}
|
||||
|
||||
this._finish(tail, length);
|
||||
// @ts-ignore
|
||||
ret = hex(this._hash);
|
||||
|
||||
if (raw) {
|
||||
ret = hexToBinaryString(ret);
|
||||
}
|
||||
|
||||
this.reset();
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resets the internal state of the computation.
|
||||
*
|
||||
* @return {SparkMD5.ArrayBuffer} The instance itself
|
||||
*/
|
||||
SparkMD5.ArrayBuffer.prototype.reset = function () {
|
||||
// @ts-ignore
|
||||
this._buff = new Uint8Array(0);
|
||||
// @ts-ignore
|
||||
this._length = 0;
|
||||
// @ts-ignore
|
||||
this._hash = [1732584193, -271733879, -1732584194, 271733878];
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the internal state of the computation.
|
||||
*
|
||||
* @return {Object} The state
|
||||
*/
|
||||
SparkMD5.ArrayBuffer.prototype.getState = function () {
|
||||
var state = SparkMD5.prototype.getState.call(this);
|
||||
|
||||
// Convert buffer to a string
|
||||
state.buff = arrayBuffer2Utf8Str(state.buff);
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the internal state of the computation.
|
||||
*
|
||||
* @param {Object} state The state
|
||||
*
|
||||
* @return {SparkMD5.ArrayBuffer} The instance itself
|
||||
*/
|
||||
SparkMD5.ArrayBuffer.prototype.setState = function (state) {
|
||||
// Convert string to buffer
|
||||
state.buff = utf8Str2ArrayBuffer(state.buff, true);
|
||||
|
||||
return SparkMD5.prototype.setState.call(this, state);
|
||||
};
|
||||
|
||||
SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;
|
||||
|
||||
SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;
|
||||
|
||||
/**
|
||||
* Performs the md5 hash on an array buffer.
|
||||
*
|
||||
* @param {ArrayBuffer} arr The array buffer
|
||||
* @param {Boolean} [raw] True to get the raw string, false to get the hex one
|
||||
*
|
||||
* @return {String} The result
|
||||
*/
|
||||
SparkMD5.ArrayBuffer.hash = function (arr, raw) {
|
||||
var hash = md51_array(new Uint8Array(arr)),
|
||||
ret = hex(hash);
|
||||
|
||||
return raw ? hexToBinaryString(ret) : ret;
|
||||
};
|
||||
|
||||
export { SparkMD5 }
|
||||
|
|
@ -0,0 +1,393 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeRequest } from './ImageKnifeRequest';
|
||||
import { CacheStrategy, ImageKnifeData, ImageKnifeRequestSource } from './model/ImageKnifeData';
|
||||
import { MemoryLruCache } from './utils/MemoryLruCache';
|
||||
import { IMemoryCache } from './utils/IMemoryCache'
|
||||
import { FileCache } from './utils/FileCache';
|
||||
import { ImageKnifeDispatcher } from './ImageKnifeDispatcher';
|
||||
import { IEngineKey } from './key/IEngineKey';
|
||||
import { HeaderOptions, ImageKnifeOption } from './ImageKnifeOption';
|
||||
import { FileTypeUtil } from './utils/FileTypeUtil';
|
||||
import { util } from '@kit.ArkTS';
|
||||
import { image } from '@kit.ImageKit';
|
||||
import { common } from '@kit.AbilityKit';
|
||||
import { LogUtil } from './utils/LogUtil';
|
||||
|
||||
|
||||
export class ImageKnife {
|
||||
private static instance: ImageKnife;
|
||||
// 内存缓存
|
||||
private memoryCache: IMemoryCache = new MemoryLruCache(256, 128 * 1024 * 1024);
|
||||
// 文件缓存
|
||||
private fileCache?: FileCache
|
||||
private dispatcher: ImageKnifeDispatcher = new ImageKnifeDispatcher()
|
||||
// 配置全局是否在子线程加载图片请求
|
||||
private _isRequestInSubThread: boolean = true;
|
||||
//定义全局网络请求header map
|
||||
headerMap: Map<string, Object> = new Map<string, Object>();
|
||||
customGetImage: ((context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>) | undefined = undefined
|
||||
public static getInstance(): ImageKnife {
|
||||
if (!ImageKnife.instance) {
|
||||
ImageKnife.instance = new ImageKnife();
|
||||
}
|
||||
return ImageKnife.instance;
|
||||
}
|
||||
|
||||
private constructor() {
|
||||
}
|
||||
|
||||
public set isRequestInSubThread(value: boolean) {
|
||||
this._isRequestInSubThread = value;
|
||||
}
|
||||
|
||||
public get isRequestInSubThread(): boolean {
|
||||
return this._isRequestInSubThread;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化文件缓存个数,大小,以及路径
|
||||
* @param context 上下文
|
||||
* @param size 缓存数量
|
||||
* @param memory 内存大小
|
||||
* @param path 文件目录
|
||||
*/
|
||||
async initFileCache(context: Context, size: number = 256, memory: number = 256 * 1024 * 1024,path?: string) {
|
||||
this.fileCache = new FileCache(context, size, memory)
|
||||
if ( path != undefined ) {
|
||||
await this.fileCache.initFileCache(path)
|
||||
} else {
|
||||
await this.fileCache.initFileCache()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件缓存是否已完成初始化
|
||||
* @returns 是否初始化
|
||||
*/
|
||||
public isFileCacheInit(): boolean {
|
||||
return this.fileCache === undefined ? false : this.fileCache.isFileCacheInit()
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局添加单个请求头header
|
||||
* @param key 请求头属性
|
||||
* @param value 请求头值
|
||||
*/
|
||||
addHeader(key: string, value: Object) {
|
||||
this.headerMap.set(key, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局设置请求头header
|
||||
* @param options 请求头数组
|
||||
*/
|
||||
serHeaderOptions(options: Array<HeaderOptions>) {
|
||||
options.forEach((value) => {
|
||||
this.headerMap.set(value.key, value.value)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除单个请求头header
|
||||
* @param key 请求头属性
|
||||
*/
|
||||
deleteHeader(key: string) {
|
||||
this.headerMap.delete(key)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置自定义的内存缓存
|
||||
* @param newMemoryCache 自定义内存缓存
|
||||
*/
|
||||
initMemoryCache(newMemoryCache: IMemoryCache): void {
|
||||
this.memoryCache = newMemoryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有内存缓存
|
||||
*/
|
||||
removeAllMemoryCache(): void {
|
||||
this.memoryCache.removeAll()
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除指定内存缓存
|
||||
* @param url 待清除的url路径或ImageKnifeOption
|
||||
*/
|
||||
removeMemoryCache(url: string | ImageKnifeOption) {
|
||||
let imageKnifeOption = new ImageKnifeOption();
|
||||
if (typeof url == 'string') {
|
||||
imageKnifeOption.loadSrc = url;
|
||||
} else {
|
||||
imageKnifeOption = url;
|
||||
}
|
||||
let key = this.getEngineKeyImpl().generateMemoryKey(imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC, imageKnifeOption);
|
||||
this.memoryCache.remove(key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 预加载图片到文件缓存
|
||||
* @param loadSrc 图片地址url
|
||||
* @returns 返回文件缓存路径
|
||||
*/
|
||||
preLoadCache(loadSrc: string | ImageKnifeOption): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let imageKnifeOption = new ImageKnifeOption()
|
||||
if (typeof loadSrc == "string") {
|
||||
imageKnifeOption.loadSrc = loadSrc
|
||||
} else {
|
||||
imageKnifeOption = loadSrc;
|
||||
}
|
||||
LogUtil.log("ImageKnife_DataTime_preLoadCache-imageKnifeOption:"+loadSrc)
|
||||
let fileKey = this.getEngineKeyImpl().generateFileKey(imageKnifeOption.loadSrc, imageKnifeOption.signature)
|
||||
let cachePath = ImageKnife.getInstance().getFileCache().getFileToPath(fileKey)
|
||||
if (cachePath == null || cachePath == "" || cachePath == undefined) {
|
||||
imageKnifeOption.onLoadListener = {
|
||||
onLoadSuccess(){
|
||||
resolve(ImageKnife.getInstance().getFileCache().getFileToPath(fileKey))
|
||||
},
|
||||
onLoadFailed(err) {
|
||||
reject(err)
|
||||
}
|
||||
}
|
||||
let request = new ImageKnifeRequest(
|
||||
imageKnifeOption,
|
||||
imageKnifeOption.context !== undefined ? imageKnifeOption.context : getContext(this) as common.UIAbilityContext,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
{
|
||||
showPixelMap(version: number, pixelMap: PixelMap | string) {
|
||||
}
|
||||
}
|
||||
)
|
||||
this.execute(request)
|
||||
} else {
|
||||
resolve(cachePath)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 从内存或文件缓存中获取图片数据
|
||||
* @param url 图片地址url
|
||||
* @param cacheType 缓存策略
|
||||
* @returns 图片数据
|
||||
* @param signature key自定义信息
|
||||
*/
|
||||
getCacheImage(loadSrc: string,
|
||||
cacheType: CacheStrategy = CacheStrategy.Default, signature?: string): Promise<ImageKnifeData | undefined> {
|
||||
let option: ImageKnifeOption = {
|
||||
loadSrc: loadSrc,
|
||||
signature:signature
|
||||
}
|
||||
let engineKeyImpl: IEngineKey = this.getEngineKeyImpl();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (cacheType == CacheStrategy.Memory) {
|
||||
resolve(this.readMemoryCache(loadSrc, option, engineKeyImpl))
|
||||
} else if (cacheType == CacheStrategy.File) {
|
||||
this.readFileCache(loadSrc, engineKeyImpl, resolve)
|
||||
} else {
|
||||
let data = this.readMemoryCache(loadSrc, option, engineKeyImpl)
|
||||
data == undefined ? this.readFileCache(loadSrc, engineKeyImpl, resolve) : resolve(data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载缓存(用于外部已获取pixelmap,需要加入imageknife缓存的场景)
|
||||
* @param url 图片地址url
|
||||
* @param pixelMap 图片
|
||||
* @param cacheType 缓存策略
|
||||
* @param signature key自定义信息
|
||||
*/
|
||||
putCacheImage(url: string, pixelMap: PixelMap, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string) {
|
||||
let memoryKey = this.getEngineKeyImpl()
|
||||
.generateMemoryKey(url, ImageKnifeRequestSource.SRC, { loadSrc: url, signature: signature });
|
||||
let fileKey = this.getEngineKeyImpl().generateFileKey(url, signature);
|
||||
let imageKnifeData: ImageKnifeData = { source: pixelMap, imageWidth: 0, imageHeight: 0 };
|
||||
switch (cacheType) {
|
||||
case CacheStrategy.Default:
|
||||
this.saveMemoryCache(memoryKey, imageKnifeData);
|
||||
this.saveFileCache(fileKey, this.pixelMapToArrayBuffer(pixelMap));
|
||||
break;
|
||||
case CacheStrategy.File:
|
||||
this.saveFileCache(fileKey, this.pixelMapToArrayBuffer(pixelMap));
|
||||
break
|
||||
case CacheStrategy.Memory:
|
||||
this.saveMemoryCache(memoryKey, imageKnifeData);
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有文件缓存
|
||||
* @returns
|
||||
*/
|
||||
async removeAllFileCache(): Promise<void> {
|
||||
if (this.fileCache !== undefined) {
|
||||
await this.fileCache.removeAll()
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 清除指定文件缓存
|
||||
* */
|
||||
removeFileCache(url: string | ImageKnifeOption) {
|
||||
let imageKnifeOption: ImageKnifeOption;
|
||||
if (url instanceof ImageKnifeOption) {
|
||||
imageKnifeOption = url;
|
||||
} else {
|
||||
imageKnifeOption = {
|
||||
loadSrc: url
|
||||
};
|
||||
}
|
||||
let key = this.getEngineKeyImpl().generateFileKey(imageKnifeOption.loadSrc, imageKnifeOption.signature);
|
||||
if (this.fileCache !== undefined) {
|
||||
this.fileCache.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置taskpool默认并发数量
|
||||
* @param concurrency 默认并发数量,默认为8
|
||||
*/
|
||||
setMaxRequests(concurrency: number): void {
|
||||
this.dispatcher.setMaxRequests(concurrency)
|
||||
}
|
||||
|
||||
getFileCacheByFile(context: Context, key: string): ArrayBuffer | undefined {
|
||||
if (this.fileCache !== undefined) {
|
||||
return FileCache.getFileCacheByFile(context, key)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
loadFromMemoryCache(key: string): ImageKnifeData | undefined {
|
||||
if (key !== "") {
|
||||
return this.memoryCache.get(key)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
saveMemoryCache(key: string, data: ImageKnifeData): void {
|
||||
if (key !== "") {
|
||||
this.memoryCache.put(key, data)
|
||||
}
|
||||
}
|
||||
|
||||
loadFromFileCache(key: string): ArrayBuffer | undefined {
|
||||
return this.fileCache?.get(key)
|
||||
}
|
||||
|
||||
saveFileCache(key: string, data: ArrayBuffer): void {
|
||||
this.fileCache?.put(key, data)
|
||||
}
|
||||
|
||||
getFileCache(): FileCache {
|
||||
return this.fileCache as FileCache
|
||||
}
|
||||
|
||||
|
||||
private pixelMapToArrayBuffer(pixelMap: PixelMap): ArrayBuffer {
|
||||
let imageInfo = pixelMap.getImageInfoSync();
|
||||
let readBuffer: ArrayBuffer = new ArrayBuffer(imageInfo.size.height * imageInfo.size.width * 4);
|
||||
pixelMap.readPixelsToBufferSync(readBuffer);
|
||||
return readBuffer
|
||||
|
||||
}
|
||||
|
||||
private readMemoryCache(loadSrc: string, option: ImageKnifeOption, engineKey: IEngineKey): ImageKnifeData | undefined {
|
||||
let memoryKey = engineKey.generateMemoryKey(loadSrc, ImageKnifeRequestSource.SRC, option)
|
||||
return ImageKnife.getInstance()
|
||||
.loadFromMemoryCache(memoryKey)
|
||||
}
|
||||
|
||||
private readFileCache(loadSrc: string, engineKey: IEngineKey, onComplete: (data: ImageKnifeData | undefined) => void) {
|
||||
let keys = engineKey.generateFileKey(loadSrc)
|
||||
let buffer = ImageKnife.getInstance().loadFromFileCache(keys)
|
||||
if (buffer != undefined) {
|
||||
let fileTypeUtil = new FileTypeUtil();
|
||||
let typeValue = fileTypeUtil.getFileType(buffer);
|
||||
if (typeValue === 'gif' || typeValue === 'webp') {
|
||||
let base64Help = new util.Base64Helper()
|
||||
|
||||
let base64str = "data:image/" + typeValue + ";base64," + base64Help.encodeToStringSync(new Uint8Array(buffer))
|
||||
onComplete({
|
||||
source: base64str,
|
||||
imageWidth: 0,
|
||||
imageHeight: 0
|
||||
})
|
||||
}
|
||||
|
||||
let imageSource: image.ImageSource = image.createImageSource(buffer);
|
||||
let decodingOptions: image.DecodingOptions = {
|
||||
editable: true,
|
||||
}
|
||||
|
||||
imageSource.createPixelMap(decodingOptions)
|
||||
.then((pixelmap: PixelMap) => {
|
||||
onComplete({
|
||||
source: pixelmap,
|
||||
imageWidth: 0,
|
||||
imageHeight: 0
|
||||
})
|
||||
imageSource.release()
|
||||
})
|
||||
} else {
|
||||
onComplete(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
saveWithoutWriteFile(key: string, bufferSize: number): void {
|
||||
this.fileCache?.putWithoutWriteFile(key, bufferSize)
|
||||
}
|
||||
|
||||
saveFileCacheOnlyFile(context: Context, key: string, value: ArrayBuffer): boolean {
|
||||
if (this.fileCache !== undefined) {
|
||||
return FileCache.saveFileCacheOnlyFile(context, key, value)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
async execute(request: ImageKnifeRequest,isAnimator?: boolean): Promise<void> {
|
||||
LogUtil.log("ImageKnife_DataTime_execute.start:"+request.imageKnifeOption.loadSrc)
|
||||
if (this.headerMap.size > 0) {
|
||||
request.addHeaderMap(this.headerMap)
|
||||
}
|
||||
this.dispatcher.enqueue(request,isAnimator)
|
||||
LogUtil.log("ImageKnife_DataTime_execute.end:"+request.imageKnifeOption.loadSrc)
|
||||
}
|
||||
|
||||
setEngineKeyImpl(impl: IEngineKey): void {
|
||||
this.dispatcher.setEngineKeyImpl(impl);
|
||||
}
|
||||
|
||||
getEngineKeyImpl(): IEngineKey {
|
||||
return this.dispatcher.getEngineKeyImpl();
|
||||
}
|
||||
/**
|
||||
* 全局设置自定义下载
|
||||
* @param customGetImage 自定义请求函数
|
||||
*/
|
||||
setCustomGetImage(customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>) {
|
||||
this.customGetImage = customGetImage
|
||||
}
|
||||
getCustomGetImage(): undefined | ((context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>){
|
||||
return this.customGetImage
|
||||
}
|
||||
}
|
|
@ -0,0 +1,668 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeRequest, ImageKnifeRequestState } from './ImageKnifeRequest'
|
||||
import { DefaultJobQueue } from './utils/DefaultJobQueue'
|
||||
import { IJobQueue } from './utils/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 {
|
||||
ImageKnifeRequestWithSource,
|
||||
ImageKnifeRequestSource,
|
||||
RequestJobResult,
|
||||
RequestJobRequest
|
||||
} from './model/ImageKnifeData'
|
||||
import { combineArrayBuffers } from './model/utils';
|
||||
import { BusinessError } from '@kit.BasicServicesKit';
|
||||
|
||||
export class ImageKnifeDispatcher {
|
||||
// 最大并发
|
||||
private maxRequests: number = 8
|
||||
// 排队队列
|
||||
private jobQueue: IJobQueue = new DefaultJobQueue()
|
||||
// 执行中的请求
|
||||
executingJobMap: LightWeightMap<string, List<ImageKnifeRequestWithSource>> = new LightWeightMap();
|
||||
// 开发者可配置全局缓存
|
||||
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)
|
||||
let memoryCache: ImageKnifeData | undefined;
|
||||
if ((typeof (request.imageKnifeOption.loadSrc as image.PixelMap).isEditable) == 'boolean') {
|
||||
memoryCache = {
|
||||
source: request.imageKnifeOption.loadSrc as image.PixelMap,
|
||||
imageWidth: 0,
|
||||
imageHeight: 0,
|
||||
}
|
||||
} else {
|
||||
memoryCache = ImageKnife.getInstance()
|
||||
.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()
|
||||
LogUtil.log("ImageKnife_DataTime_MemoryCache_onLoadStart:" + request.imageKnifeOption.loadSrc)
|
||||
}
|
||||
LogUtil.log("ImageKnife_DataTime_MemoryCache_showPixelMap.start:" + request.imageKnifeOption.loadSrc)
|
||||
request.ImageKnifeRequestCallback?.showPixelMap(request.componentVersion, memoryCache.source, requestSource,memoryCache.imageAnimator)
|
||||
LogUtil.log("ImageKnife_DataTime_MemoryCache_showPixelMap.end:" + request.imageKnifeOption.loadSrc)
|
||||
|
||||
if (requestSource == ImageKnifeRequestSource.SRC) {
|
||||
request.requestState = ImageKnifeRequestState.COMPLETE
|
||||
// 回调请求开结束
|
||||
if (request.imageKnifeOption.onLoadListener?.onLoadSuccess !== undefined) {
|
||||
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)
|
||||
return true
|
||||
}
|
||||
LogUtil.log("ImageKnife_DataTime_showFromMemomry.end_false:" + request.imageKnifeOption.loadSrc)
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
enqueue(request: ImageKnifeRequest,isAnimator?: boolean): void {
|
||||
|
||||
//1.内存有的话直接渲染
|
||||
if (this.showFromMemomry(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,isAnimator)) {
|
||||
return
|
||||
}
|
||||
// 2.内存获取占位图
|
||||
if (request.imageKnifeOption.placeholderSrc !== undefined) {
|
||||
if (this.showFromMemomry(request, request.imageKnifeOption.placeholderSrc, ImageKnifeRequestSource.PLACE_HOLDER)) {
|
||||
request.drawPlayHolderSuccess = true
|
||||
}
|
||||
}
|
||||
//3.判断是否要排队
|
||||
if (this.executingJobMap.length > this.maxRequests) {
|
||||
this.jobQueue.add(request)
|
||||
return
|
||||
}
|
||||
this.executeJob(request,isAnimator)
|
||||
}
|
||||
|
||||
executeJob(request: ImageKnifeRequest,isAnimator?: boolean): void {
|
||||
LogUtil.log("ImageKnife_DataTime_executeJob.start:" + request.imageKnifeOption.loadSrc)
|
||||
// 加载占位符
|
||||
if (request.imageKnifeOption.placeholderSrc !== undefined && request.drawPlayHolderSuccess == false) {
|
||||
this.getAndShowImage(request, request.imageKnifeOption.placeholderSrc, ImageKnifeRequestSource.PLACE_HOLDER)
|
||||
}
|
||||
|
||||
// 加载主图
|
||||
this.getAndShowImage(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,isAnimator)
|
||||
LogUtil.log("ImageKnife_DataTime_executeJob.end:" + request.imageKnifeOption.loadSrc)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取和显示图片
|
||||
*/
|
||||
getAndShowImage(currentRequest: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean): void {
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage.start:" + currentRequest.imageKnifeOption.loadSrc)
|
||||
let memoryKey: string = this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,isAnimator)
|
||||
let requestList: List<ImageKnifeRequestWithSource> | undefined = this.executingJobMap.get(memoryKey)
|
||||
if (requestList == undefined) {
|
||||
requestList = new List()
|
||||
requestList.add({ request: currentRequest, source: requestSource })
|
||||
this.executingJobMap.set(memoryKey, requestList)
|
||||
} else {
|
||||
requestList.add({ request: currentRequest, source: requestSource })
|
||||
return
|
||||
}
|
||||
|
||||
let isWatchProgress : boolean = false
|
||||
|
||||
// 回调请求开始
|
||||
requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
|
||||
if (requestWithSource.source === ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) {
|
||||
requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart()
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadStart:" + currentRequest.imageKnifeOption.loadSrc)
|
||||
}
|
||||
if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) {
|
||||
isWatchProgress = true
|
||||
}
|
||||
});
|
||||
|
||||
let request: RequestJobRequest = {
|
||||
context: currentRequest.context,
|
||||
src: imageSrc,
|
||||
headers: currentRequest.imageKnifeOption.headerOption,
|
||||
allHeaders: currentRequest.headers,
|
||||
componentWidth:currentRequest.componentWidth,
|
||||
componentHeight:currentRequest.componentHeight,
|
||||
customGetImage: currentRequest.imageKnifeOption.customGetImage,
|
||||
onlyRetrieveFromCache: currentRequest.imageKnifeOption.onlyRetrieveFromCache,
|
||||
transformation: currentRequest.imageKnifeOption.transformation,
|
||||
writeCacheStrategy: ImageKnife.getInstance()
|
||||
.isFileCacheInit() ? currentRequest.imageKnifeOption.writeCacheStrategy : CacheStrategy.Memory, // 未初始化文件缓存时,不写文件缓存
|
||||
engineKey: this.engineKey,
|
||||
signature: currentRequest.imageKnifeOption.signature,
|
||||
requestSource: requestSource,
|
||||
isWatchProgress: isWatchProgress,
|
||||
memoryKey: memoryKey,
|
||||
fileCacheFolder: ImageKnife.getInstance().getFileCache().getCacheFolder(),
|
||||
isAnimator:isAnimator
|
||||
}
|
||||
|
||||
if(request.customGetImage == undefined) {
|
||||
request.customGetImage = ImageKnife.getInstance().getCustomGetImage()
|
||||
}
|
||||
if (ImageKnife.getInstance().isRequestInSubThread){
|
||||
// 启动线程下载和解码主图
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_Task.start:" + currentRequest.imageKnifeOption.loadSrc)
|
||||
let task = new taskpool.Task(requestJob, request)
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_Task.end:" + currentRequest.imageKnifeOption.loadSrc)
|
||||
if (isWatchProgress){
|
||||
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)
|
||||
taskpool.execute(task).then((res: Object) => {
|
||||
this.doTaskCallback(res as RequestJobResult | undefined, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator);
|
||||
if (isWatchProgress){
|
||||
emitter.off(Constants.PROGRESS_EMITTER + memoryKey)
|
||||
}
|
||||
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)
|
||||
if (isWatchProgress){
|
||||
emitter.off(Constants.PROGRESS_EMITTER + memoryKey)
|
||||
}
|
||||
this.executingJobMap.remove(memoryKey);
|
||||
this.dispatchNextJob();
|
||||
})
|
||||
} else { //主线程请求
|
||||
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)
|
||||
this.executingJobMap.remove(memoryKey);
|
||||
this.dispatchNextJob();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 回调下载进度
|
||||
* @param requestList 请求列表
|
||||
* @param data 进度
|
||||
*/
|
||||
private progressCallBack(requestList:List<ImageKnifeRequestWithSource>, data: number) {
|
||||
for (let i = 0; i < requestList.length; i++) {
|
||||
let requestWithSource:ImageKnifeRequestWithSource = requestList[i]
|
||||
if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) {
|
||||
requestWithSource.request.imageKnifeOption.progressListener(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private doTaskCallback(requestJobResult: RequestJobResult | undefined, requestList: List<ImageKnifeRequestWithSource> ,
|
||||
currentRequest: ImageKnifeRequest, memoryKey: string, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean):void {
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.start:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
if (requestJobResult === undefined){
|
||||
return
|
||||
}
|
||||
let pixelmap = requestJobResult.pixelMap;
|
||||
if (pixelmap === undefined) {
|
||||
requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
|
||||
// 回调请求失败
|
||||
if (requestWithSource.source === ImageKnifeRequestSource.SRC &&
|
||||
requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadFailed !== undefined &&
|
||||
requestJobResult.loadFail) {
|
||||
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadFailed(requestJobResult.loadFail);
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadFailed:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
}
|
||||
if (requestWithSource.source === ImageKnifeRequestSource.SRC &&
|
||||
requestWithSource.request.imageKnifeOption.errorholderSrc !== undefined) {
|
||||
|
||||
if (this.showFromMemomry(requestWithSource.request, requestWithSource.request.imageKnifeOption.errorholderSrc,
|
||||
ImageKnifeRequestSource.ERROR_HOLDER) === false) {
|
||||
this.getAndShowImage(requestWithSource.request, requestWithSource.request.imageKnifeOption.errorholderSrc,
|
||||
ImageKnifeRequestSource.ERROR_HOLDER);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.executingJobMap.remove(memoryKey);
|
||||
return;
|
||||
}
|
||||
// 保存文件缓存
|
||||
if (requestJobResult.bufferSize > 0 && currentRequest.imageKnifeOption.writeCacheStrategy !== CacheStrategy.Memory) {
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveWithoutWriteFile.start:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
ImageKnife.getInstance().saveWithoutWriteFile(requestJobResult.fileKey, requestJobResult.bufferSize);
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveWithoutWriteFile.end:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
}
|
||||
|
||||
let ImageKnifeData: ImageKnifeData = {
|
||||
source: pixelmap!,
|
||||
imageWidth: requestJobResult.size == undefined ? 0 : requestJobResult.size.width,
|
||||
imageHeight: requestJobResult.size == undefined ? 0 : requestJobResult.size.height,
|
||||
type:requestJobResult.type
|
||||
};
|
||||
if(requestJobResult.pixelMapList != undefined) {
|
||||
let imageAnimator: Array<ImageFrameInfo> = []
|
||||
requestJobResult.pixelMapList.forEach((item,index)=>{
|
||||
imageAnimator.push({
|
||||
src:requestJobResult.pixelMapList![index],
|
||||
duration:requestJobResult.delayList![index]
|
||||
})
|
||||
})
|
||||
ImageKnifeData.imageAnimator = imageAnimator
|
||||
}
|
||||
// 保存内存缓存
|
||||
if (currentRequest.imageKnifeOption.writeCacheStrategy !== CacheStrategy.File) {
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveMemoryCache.start:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
ImageKnife.getInstance()
|
||||
.saveMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,isAnimator),
|
||||
ImageKnifeData);
|
||||
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) {
|
||||
// 画主图
|
||||
if (requestWithSource.source === ImageKnifeRequestSource.SRC ||
|
||||
requestWithSource.source === ImageKnifeRequestSource.ERROR_HOLDER
|
||||
|| (requestWithSource.source === ImageKnifeRequestSource.PLACE_HOLDER &&
|
||||
requestWithSource.request.requestState === ImageKnifeRequestState.PROGRESS)) {
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.start:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
requestWithSource.request.ImageKnifeRequestCallback.showPixelMap(requestWithSource.request.componentVersion,
|
||||
ImageKnifeData.source, requestWithSource.source,ImageKnifeData.imageAnimator);
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.end:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
}
|
||||
|
||||
if (requestWithSource.source == ImageKnifeRequestSource.SRC) {
|
||||
requestWithSource.request.requestState = ImageKnifeRequestState.COMPLETE;
|
||||
if (requestWithSource.request.imageKnifeOption.onLoadListener &&
|
||||
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess) {
|
||||
// 回调请求成功
|
||||
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess(ImageKnifeData.source,ImageKnifeData);
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadSuccess:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
}
|
||||
} else if (requestWithSource.source == ImageKnifeRequestSource.ERROR_HOLDER) {
|
||||
requestWithSource.request.requestState = ImageKnifeRequestState.ERROR;
|
||||
}
|
||||
} else {
|
||||
if (requestWithSource.source == ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadCancel) {
|
||||
// 回调请求成功
|
||||
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed")
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.executingJobMap.remove(memoryKey);
|
||||
this.dispatchNextJob();
|
||||
} else {
|
||||
LogUtil.log("error: no requestlist need to draw for key = " + memoryKey);
|
||||
}
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.end:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
}
|
||||
|
||||
|
||||
dispatchNextJob() {
|
||||
LogUtil.log("ImageKnife_DataTime_dispatchNextJob.start")
|
||||
while (true) {
|
||||
let request = this.jobQueue.pop()
|
||||
if (request === undefined) {
|
||||
break // 队列已无任务
|
||||
}
|
||||
else if (request.requestState === ImageKnifeRequestState.PROGRESS) {
|
||||
this.executeJob(request)
|
||||
LogUtil.log("ImageKnife_DataTime_dispatchNextJob.end:" + request.imageKnifeOption.loadSrc)
|
||||
break
|
||||
}else if (request.requestState == ImageKnifeRequestState.DESTROY && request.imageKnifeOption.onLoadListener?.onLoadCancel) {
|
||||
request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setMaxRequests(concurrency: number): void {
|
||||
if (concurrency > 0) {
|
||||
this.maxRequests = concurrency
|
||||
}
|
||||
}
|
||||
|
||||
setEngineKeyImpl(impl: IEngineKey): void {
|
||||
this.engineKey = impl;
|
||||
}
|
||||
|
||||
getEngineKeyImpl(): IEngineKey {
|
||||
return this.engineKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过taskpool 二级缓存,下载/读取本地文件,编解码
|
||||
* @param context
|
||||
* @param src
|
||||
* @returns
|
||||
*/
|
||||
@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 = '';
|
||||
|
||||
class RequestData {
|
||||
receiveSize: number = 2000
|
||||
totalSize: number = 2000
|
||||
}
|
||||
|
||||
// 生成文件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) {
|
||||
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.close(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);
|
||||
if(typeValue == null) {
|
||||
return {
|
||||
pixelMap: undefined,
|
||||
bufferSize: 0,
|
||||
fileKey: '',
|
||||
loadFail: "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 size = (await imageSource.getImageInfo()).size
|
||||
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()
|
||||
})
|
||||
|
||||
// 图形变化
|
||||
if (request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined) {
|
||||
resPixelmap = await request.transformation?.transform(request.context, resPixelmap!, request.componentWidth, request.componentHeight);
|
||||
}
|
||||
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
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
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 { drawing } from '@kit.ArkGraphics2D';
|
||||
|
||||
export interface HeaderOptions {
|
||||
key: string;
|
||||
value: Object;
|
||||
}
|
||||
|
||||
@Observed
|
||||
export class AnimatorOption {
|
||||
@Track
|
||||
state?: AnimationStatus = AnimationStatus.Running
|
||||
@Track
|
||||
iterations?: number = -1
|
||||
@Track
|
||||
reverse?: boolean = false
|
||||
}
|
||||
|
||||
@Observed
|
||||
export class ImageKnifeOption {
|
||||
// 主图资源
|
||||
loadSrc: string | PixelMap | Resource = "";
|
||||
// 占位图
|
||||
placeholderSrc?: string | PixelMap | Resource;
|
||||
// 失败占位图
|
||||
errorholderSrc?: string | PixelMap | Resource;
|
||||
headerOption?: Array<HeaderOptions>;
|
||||
// 自定义缓存关键字
|
||||
signature?: string;
|
||||
// 主图填充效果
|
||||
objectFit?: ImageFit
|
||||
// 占位图填充效果
|
||||
placeholderObjectFit?: ImageFit
|
||||
// 错误图填充效果
|
||||
errorholderObjectFit?: ImageFit
|
||||
customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>
|
||||
border?: BorderOptions
|
||||
// 缓存策略
|
||||
writeCacheStrategy?: CacheStrategy
|
||||
// 仅使用缓存加载数据
|
||||
onlyRetrieveFromCache?: boolean = false;
|
||||
priority?: taskpool.Priority = taskpool.Priority.LOW
|
||||
context?: common.UIAbilityContext;
|
||||
progressListener?: (progress: number) => void;
|
||||
transformation?: PixelMapTransformation
|
||||
onLoadListener?: OnLoadCallBack | undefined;
|
||||
onComplete?:(event:EventImage | undefined) => void
|
||||
drawingColorFilter?: ColorFilter | drawing.ColorFilter
|
||||
constructor() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求回调
|
||||
*/
|
||||
export interface OnLoadCallBack {
|
||||
// 请求开始
|
||||
onLoadStart?: () => void;
|
||||
|
||||
// 请求成功
|
||||
onLoadSuccess?: (data: string | PixelMap | undefined, imageKnifeData: ImageKnifeData) => void;
|
||||
|
||||
// 请求结束
|
||||
onLoadFailed?: (err: string) => void;
|
||||
// 请求取消
|
||||
onLoadCancel?: (reason: string) => void;
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeOption } from './ImageKnifeOption';
|
||||
import common from '@ohos.app.ability.common';
|
||||
import { ImageKnifeRequestSource } from './model/ImageKnifeData';
|
||||
|
||||
|
||||
export class ImageKnifeRequest {
|
||||
requestState: ImageKnifeRequestState = ImageKnifeRequestState.PROGRESS
|
||||
componentWidth: number = 0
|
||||
componentHeight: number = 0
|
||||
drawPlayHolderSuccess: boolean = false
|
||||
imageKnifeOption: ImageKnifeOption
|
||||
context: common.UIAbilityContext
|
||||
ImageKnifeRequestCallback: ImageKnifeRequestCallback
|
||||
componentVersion: number = 0
|
||||
headers: Map<string,Object> = new Map<string,Object>()
|
||||
constructor(option: ImageKnifeOption,
|
||||
uIAbilityContext: common.UIAbilityContext,
|
||||
width: number,
|
||||
height: number,
|
||||
version: number,
|
||||
ImageKnifeRequestCallback: ImageKnifeRequestCallback) {
|
||||
this.imageKnifeOption = option
|
||||
this.context = uIAbilityContext
|
||||
this.componentWidth = width
|
||||
this.componentHeight = height
|
||||
this.componentVersion = version
|
||||
this.ImageKnifeRequestCallback = ImageKnifeRequestCallback
|
||||
}
|
||||
// RequestOption调用header对于的方法
|
||||
addHeader(key: string, value: Object) {
|
||||
this.headers.set(key, value);
|
||||
}
|
||||
|
||||
// 全局调用header对应的方法,包含RequestOption的形式
|
||||
addHeaderMap(map: Map<string, Object>) {
|
||||
map.forEach((value, key) => {
|
||||
if (!this.headers.has(key)) {
|
||||
this.addHeader(key, value);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export enum ImageKnifeRequestState {
|
||||
PROGRESS,
|
||||
COMPLETE,
|
||||
ERROR,
|
||||
DESTROY
|
||||
}
|
||||
|
||||
|
||||
export interface ImageKnifeRequestCallback {
|
||||
showPixelMap: (version: number, pixelMap: PixelMap | string , requestSource: ImageKnifeRequestSource,imageAnimator?: Array<ImageFrameInfo>) => void;
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* 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, ImageKnifeOption } from '../ImageKnifeOption';
|
||||
import { ImageKnifeRequest, ImageKnifeRequestState } from '../ImageKnifeRequest';
|
||||
import common from '@ohos.app.ability.common';
|
||||
import { ImageKnife } from '../ImageKnife';
|
||||
import { LogUtil } from '../utils/LogUtil';
|
||||
import { ImageKnifeRequestSource } from '../model/ImageKnifeData';
|
||||
|
||||
@Component
|
||||
export struct ImageKnifeAnimatorComponent {
|
||||
@Watch('watchImageKnifeOption') @ObjectLink imageKnifeOption: ImageKnifeOption;
|
||||
@Watch('watchAnimatorOption') @State animatorOption: AnimatorOption = new AnimatorOption();
|
||||
@State pixelMap: PixelMap | string | undefined = undefined
|
||||
@State imageAnimator: Array<ImageFrameInfo> | undefined = undefined
|
||||
@State state: AnimationStatus = AnimationStatus.Running
|
||||
@State iterations: number = -1
|
||||
@State reverse: boolean = false
|
||||
@State adaptiveWidth: Length = '100%'
|
||||
@State adaptiveHeight: Length = '100%'
|
||||
@State objectFit: ImageFit = ImageFit.Contain
|
||||
private request: ImageKnifeRequest | undefined
|
||||
private lastWidth: number = 0
|
||||
private lastHeight: number = 0
|
||||
private currentWidth: number = 0
|
||||
private currentHeight: number = 0
|
||||
private componentVersion: number = 0
|
||||
private currentContext: common.UIAbilityContext | undefined = undefined
|
||||
|
||||
aboutToAppear(): void {
|
||||
this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
|
||||
}
|
||||
|
||||
aboutToDisappear(): void {
|
||||
if (this.request !== undefined) {
|
||||
this.request.requestState = ImageKnifeRequestState.DESTROY
|
||||
this.request = undefined
|
||||
}
|
||||
}
|
||||
|
||||
aboutToRecycle() {
|
||||
if (this.request !== undefined) {
|
||||
this.request.requestState = ImageKnifeRequestState.DESTROY
|
||||
this.request = undefined
|
||||
}
|
||||
this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
|
||||
}
|
||||
|
||||
build() {
|
||||
ImageAnimator()
|
||||
.images(this.imageAnimator)
|
||||
.width(this.adaptiveWidth)
|
||||
.height(this.adaptiveHeight)
|
||||
.border(this.imageKnifeOption.border)
|
||||
.state(this.state)
|
||||
.iterations(this.iterations)
|
||||
.reverse(this.reverse)
|
||||
.onSizeChange((oldValue:SizeOptions, newValue:SizeOptions) => {
|
||||
this.currentWidth = newValue.width as number
|
||||
this.currentHeight = newValue.height as number
|
||||
this.lastWidth = oldValue.width as number
|
||||
this.lastHeight = oldValue.height as number
|
||||
if (this.currentWidth <= 0 || this.currentHeight <= 0) {
|
||||
// 存在宽或者高为0,此次重回无意义,无需进行request请求
|
||||
} else {
|
||||
// 前提:宽高值均有效,值>0. 条件1:当前宽高与上一次宽高不同 条件2:当前是第一次绘制
|
||||
if (this.currentHeight != this.lastHeight || this.currentWidth != this.lastWidth) {
|
||||
LogUtil.log("execute request:width=" + this.currentWidth + " height= " + this.currentHeight)
|
||||
ImageKnife.getInstance().execute(this.getRequest(this.currentWidth, this.currentHeight),true)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
watchAnimatorOption(){
|
||||
if(this.animatorOption.state != undefined) {
|
||||
this.state = this.animatorOption.state
|
||||
}
|
||||
if(this.animatorOption.iterations != undefined) {
|
||||
this.iterations = this.animatorOption.iterations
|
||||
}
|
||||
if(this.animatorOption.reverse != undefined) {
|
||||
this.reverse = this.animatorOption.reverse
|
||||
}
|
||||
}
|
||||
|
||||
watchImageKnifeOption() {
|
||||
if (this.request !== undefined) {
|
||||
this.request.requestState = ImageKnifeRequestState.DESTROY
|
||||
}
|
||||
this.request = undefined
|
||||
this.componentVersion++
|
||||
ImageKnife.getInstance().execute(this.getRequest(this.currentWidth, this.currentHeight),true)
|
||||
}
|
||||
|
||||
getCurrentContext(): common.UIAbilityContext {
|
||||
if (this.currentContext == undefined) {
|
||||
this.currentContext = getContext(this) as common.UIAbilityContext
|
||||
}
|
||||
return this.currentContext
|
||||
}
|
||||
|
||||
getRequest(width: number, height: number): ImageKnifeRequest {
|
||||
if (this.request == undefined) {
|
||||
this.request = new ImageKnifeRequest(
|
||||
this.imageKnifeOption,
|
||||
this.imageKnifeOption.context !== undefined ? this.imageKnifeOption.context : this.getCurrentContext(),
|
||||
width,
|
||||
height,
|
||||
this.componentVersion,
|
||||
{
|
||||
showPixelMap: async (version: number, pixelMap: PixelMap | string, requestSource: ImageKnifeRequestSource,imageAnimator?: Array<ImageFrameInfo>) => {
|
||||
if (version !== this.componentVersion) {
|
||||
return //针对reuse场景,不显示历史图片
|
||||
}
|
||||
if (imageAnimator != undefined) {
|
||||
this.imageAnimator = imageAnimator
|
||||
} else {
|
||||
this.imageAnimator = [
|
||||
{
|
||||
src: pixelMap
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
if (requestSource == ImageKnifeRequestSource.SRC) {
|
||||
this.objectFit =
|
||||
this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
|
||||
} else if (requestSource == ImageKnifeRequestSource.PLACE_HOLDER) {
|
||||
this.objectFit =
|
||||
this.imageKnifeOption.placeholderObjectFit === undefined ? (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : this.imageKnifeOption.placeholderObjectFit
|
||||
} else {
|
||||
this.objectFit =
|
||||
this.imageKnifeOption.errorholderObjectFit === undefined ? (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : this.imageKnifeOption.errorholderObjectFit
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return this.request
|
||||
}
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeOption } from '../ImageKnifeOption';
|
||||
import { ImageKnifeRequest, ImageKnifeRequestState } from '../ImageKnifeRequest';
|
||||
import common from '@ohos.app.ability.common';
|
||||
import { ImageKnife } from '../ImageKnife';
|
||||
import { LogUtil } from '../utils/LogUtil';
|
||||
import { ImageKnifeData, ImageKnifeRequestSource } from '../model/ImageKnifeData';
|
||||
import { IEngineKey } from '../key/IEngineKey';
|
||||
import { DefaultEngineKey } from '../key/DefaultEngineKey';
|
||||
|
||||
@Component
|
||||
export struct ImageKnifeComponent {
|
||||
@Watch('watchImageKnifeOption') @ObjectLink imageKnifeOption: ImageKnifeOption;
|
||||
@State pixelMap: PixelMap | string | undefined = undefined
|
||||
@State syncLoad: boolean = false
|
||||
@State adaptiveWidth: Length = '100%'
|
||||
@State adaptiveHeight: Length = '100%'
|
||||
@State objectFit: ImageFit = ImageFit.Contain
|
||||
private request: ImageKnifeRequest | undefined
|
||||
private lastWidth: number = 0
|
||||
private lastHeight: number = 0
|
||||
private currentWidth: number = 0
|
||||
private currentHeight: number = 0
|
||||
private componentVersion: number = 0
|
||||
private currentContext: common.UIAbilityContext | undefined = undefined
|
||||
|
||||
aboutToAppear(): void {
|
||||
//闪动问题失效,注释相应代码后续修复
|
||||
if(this.syncLoad) {
|
||||
let engineKey: IEngineKey = new DefaultEngineKey();
|
||||
let memoryCacheSrc: ImageKnifeData | undefined = ImageKnife.getInstance()
|
||||
.loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,this.imageKnifeOption))
|
||||
if (memoryCacheSrc !== undefined){
|
||||
LogUtil.log("aboutToAppear load from memory cache for key = "+ engineKey.generateMemoryKey(this.imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,this.imageKnifeOption))
|
||||
//画主图
|
||||
this.pixelMap = memoryCacheSrc.source;
|
||||
}else {
|
||||
let memoryCachePlace: ImageKnifeData | undefined = ImageKnife.getInstance()
|
||||
.loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.placeholderSrc!,ImageKnifeRequestSource.PLACE_HOLDER,this.imageKnifeOption))
|
||||
if (memoryCachePlace !== undefined){
|
||||
LogUtil.log("aboutToAppear load from memory cache for key = "+ engineKey.generateMemoryKey(this.imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,this.imageKnifeOption))
|
||||
//画主图
|
||||
this.pixelMap = memoryCachePlace.source;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
|
||||
}
|
||||
|
||||
aboutToDisappear(): void {
|
||||
if (this.request !== undefined) {
|
||||
this.request.requestState = ImageKnifeRequestState.DESTROY
|
||||
this.request = undefined
|
||||
}
|
||||
}
|
||||
|
||||
aboutToRecycle() {
|
||||
if (this.request !== undefined) {
|
||||
this.request.requestState = ImageKnifeRequestState.DESTROY
|
||||
this.request = undefined
|
||||
}
|
||||
this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
|
||||
}
|
||||
|
||||
build() {
|
||||
Image(this.pixelMap)
|
||||
.colorFilter(this.imageKnifeOption.drawingColorFilter)
|
||||
.objectFit(this.objectFit)
|
||||
.width(this.adaptiveWidth)
|
||||
.height(this.adaptiveHeight)
|
||||
.border(this.imageKnifeOption.border)
|
||||
.syncLoad(this.syncLoad)
|
||||
.draggable(false)
|
||||
.onComplete(this.imageKnifeOption.onComplete)
|
||||
.onSizeChange((oldValue:SizeOptions, newValue:SizeOptions) => {
|
||||
this.currentWidth = newValue.width as number
|
||||
this.currentHeight = newValue.height as number
|
||||
this.lastWidth = oldValue.width as number
|
||||
this.lastHeight = oldValue.height as number
|
||||
if (this.currentWidth <= 0 || this.currentHeight <= 0) {
|
||||
// 存在宽或者高为0,此次重回无意义,无需进行request请求
|
||||
} else {
|
||||
// 前提:宽高值均有效,值>0. 条件1:当前宽高与上一次宽高不同 条件2:当前是第一次绘制
|
||||
if (this.currentHeight != this.lastHeight || this.currentWidth != this.lastWidth) {
|
||||
LogUtil.log("execute request:width=" + this.currentWidth + " height= " + this.currentHeight)
|
||||
ImageKnife.getInstance().execute(this.getRequest(this.currentWidth, this.currentHeight))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
watchImageKnifeOption() {
|
||||
if (this.request !== undefined) {
|
||||
this.request.requestState = ImageKnifeRequestState.DESTROY
|
||||
}
|
||||
this.request = undefined
|
||||
this.componentVersion++
|
||||
ImageKnife.getInstance().execute(this.getRequest(this.currentWidth, this.currentHeight))
|
||||
}
|
||||
|
||||
getCurrentContext(): common.UIAbilityContext {
|
||||
if (this.currentContext == undefined) {
|
||||
this.currentContext = getContext(this) as common.UIAbilityContext
|
||||
}
|
||||
return this.currentContext
|
||||
}
|
||||
|
||||
getRequest(width: number, height: number): ImageKnifeRequest {
|
||||
if (this.request == undefined) {
|
||||
this.request = new ImageKnifeRequest(
|
||||
this.imageKnifeOption,
|
||||
this.imageKnifeOption.context !== undefined ? this.imageKnifeOption.context : this.getCurrentContext(),
|
||||
width,
|
||||
height,
|
||||
this.componentVersion,
|
||||
{
|
||||
showPixelMap: async (version: number, pixelMap: PixelMap | string, requestSource: ImageKnifeRequestSource) => {
|
||||
if (version !== this.componentVersion) {
|
||||
return //针对reuse场景,不显示历史图片
|
||||
}
|
||||
this.pixelMap = pixelMap
|
||||
if (typeof this.pixelMap !== 'string') {
|
||||
if (this.imageKnifeOption.objectFit === ImageFit.Auto) {
|
||||
let info = await this.pixelMap.getImageInfo()
|
||||
|
||||
this.adaptiveWidth = this.currentWidth
|
||||
this.adaptiveHeight = info.size.height * this.currentWidth / info.size.width
|
||||
|
||||
// if (this.currentWidth / this.currentHeight > info.size.width / info.size.height) {
|
||||
// this.adaptiveWidth = this.currentWidth
|
||||
// this.adaptiveHeight = info.size.height * this.currentWidth / this.currentHeight
|
||||
// }
|
||||
// else {
|
||||
// this.adaptiveWidth = info.size.width * this.currentWidth / this.currentHeight
|
||||
// this.adaptiveHeight = this.currentHeight
|
||||
// }
|
||||
}
|
||||
} else {
|
||||
//console.info("KKKKKKKKKKK:" + pixelMap)
|
||||
}
|
||||
|
||||
if (requestSource == ImageKnifeRequestSource.SRC) {
|
||||
this.objectFit =
|
||||
this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
|
||||
} else if (requestSource == ImageKnifeRequestSource.PLACE_HOLDER) {
|
||||
this.objectFit =
|
||||
this.imageKnifeOption.placeholderObjectFit === undefined ? (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : this.imageKnifeOption.placeholderObjectFit
|
||||
} else {
|
||||
this.objectFit =
|
||||
this.imageKnifeOption.errorholderObjectFit === undefined ? (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : this.imageKnifeOption.errorholderObjectFit
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return this.request
|
||||
}
|
||||
}
|
||||
|
||||
interface KeyCanvas {
|
||||
keyId: string
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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 { ImageKnifeOption } from '../ImageKnifeOption';
|
||||
import { IEngineKey } from './IEngineKey';
|
||||
import { PixelMapTransformation } from '../transform/PixelMapTransformation';
|
||||
import { ImageKnifeRequestSource } from '../model/ImageKnifeData';
|
||||
|
||||
@Sendable
|
||||
export class DefaultEngineKey implements IEngineKey {
|
||||
// 生成内存缓存key
|
||||
generateMemoryKey(loadSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,
|
||||
imageKnifeOption: ImageKnifeOption,isAnimator?: boolean, width?: number, height?: number): string {
|
||||
let key = (isAnimator == true ? "Animator=" : "loadSrc==") + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";"
|
||||
if (requestSource === ImageKnifeRequestSource.SRC) {
|
||||
if (imageKnifeOption.signature !== undefined && imageKnifeOption.signature !== "") {
|
||||
key += "signature=" + imageKnifeOption.signature + ";"
|
||||
}
|
||||
if (imageKnifeOption.transformation) {
|
||||
key += "transformation=" + this.getTransformation(imageKnifeOption.transformation) + ";"
|
||||
}
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
// 生成文件缓存key
|
||||
generateFileKey(loadSrc: string | PixelMap | Resource, signature?: string,isAnimator?: boolean): string {
|
||||
let src = (isAnimator == true ? "Animator=" : "loadSrc==") + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";"
|
||||
if (signature !== undefined && signature !== "") {
|
||||
src += "signature=" + signature + ";"
|
||||
}
|
||||
return SparkMD5.hashBinary(src)
|
||||
}
|
||||
|
||||
private getTransformation(transformation: PixelMapTransformation): string {
|
||||
return transformation.getName()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeOption } from '../ImageKnifeOption'
|
||||
import { ImageKnifeRequestSource } from '../model/ImageKnifeData'
|
||||
|
||||
export interface IEngineKey {
|
||||
// 生成内存缓存key
|
||||
generateMemoryKey(loadSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,
|
||||
imageKnifeOption: ImageKnifeOption,isAnimator?: boolean, width?: number, height?: number): string
|
||||
|
||||
// 生成文件缓存key
|
||||
generateFileKey(loadSrc: string | PixelMap | Resource, signature?: string,isAnimator?: boolean): string
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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 { HeaderOptions } from '../ImageKnifeOption'
|
||||
import { ImageKnifeRequest } from '../ImageKnifeRequest'
|
||||
import { IEngineKey } from '../key/IEngineKey'
|
||||
import { PixelMapTransformation } from '../transform/PixelMapTransformation'
|
||||
import common from '@ohos.app.ability.common';
|
||||
import { Size } from '@kit.ArkUI'
|
||||
|
||||
export interface ImageKnifeData {
|
||||
source: PixelMap | string,
|
||||
imageWidth: number,
|
||||
imageHeight: number,
|
||||
type?:string,
|
||||
imageAnimator?: Array<ImageFrameInfo>
|
||||
}
|
||||
/**
|
||||
* onComplete成功回调
|
||||
*/
|
||||
export interface EventImage {
|
||||
width: number;
|
||||
height: number;
|
||||
componentWidth: number;
|
||||
componentHeight: number;
|
||||
loadingStatus: number;
|
||||
contentWidth: number;
|
||||
contentHeight: number;
|
||||
contentOffsetX: number;
|
||||
contentOffsetY: number;
|
||||
}
|
||||
/**
|
||||
* 缓存策略
|
||||
*/
|
||||
export enum CacheStrategy {
|
||||
// 默认-写入/读取内存和文件缓存
|
||||
Default = 0,
|
||||
// 只写入/读取内存缓存
|
||||
Memory = 1,
|
||||
// 只写入/读取文件缓存
|
||||
File = 2
|
||||
}
|
||||
|
||||
/**
|
||||
* 区分是src,placehodler,还是error_holder
|
||||
*/
|
||||
export enum ImageKnifeRequestSource {
|
||||
SRC,
|
||||
PLACE_HOLDER,
|
||||
ERROR_HOLDER
|
||||
}
|
||||
|
||||
|
||||
export interface ImageKnifeRequestWithSource {
|
||||
request: ImageKnifeRequest
|
||||
source: ImageKnifeRequestSource
|
||||
}
|
||||
|
||||
/**
|
||||
* request子线程处理时的返回
|
||||
*/
|
||||
export interface RequestJobResult {
|
||||
pixelMap: PixelMap | string | undefined
|
||||
bufferSize: number
|
||||
fileKey: string
|
||||
loadFail?: string,
|
||||
size?:Size,
|
||||
type?: string,
|
||||
pixelMapList?:Array<PixelMap>,
|
||||
delayList?: Array<number>
|
||||
}
|
||||
|
||||
/**
|
||||
* request子线程处理时的请求参数
|
||||
*/
|
||||
export interface RequestJobRequest {
|
||||
context: common.UIAbilityContext,
|
||||
src: string | PixelMap | Resource,
|
||||
headers?: Array<HeaderOptions>,
|
||||
allHeaders: Map<string, Object>,
|
||||
componentWidth: number,
|
||||
componentHeight: number,
|
||||
customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>,
|
||||
onlyRetrieveFromCache?: boolean
|
||||
requestSource: ImageKnifeRequestSource
|
||||
transformation?: PixelMapTransformation
|
||||
writeCacheStrategy?: CacheStrategy
|
||||
signature?: string
|
||||
engineKey: IEngineKey
|
||||
isWatchProgress: boolean
|
||||
memoryKey: string
|
||||
fileCacheFolder: string,
|
||||
isAnimator?: boolean
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export function combineArrayBuffers(arrayBuffers: ArrayBuffer[]): ArrayBuffer {
|
||||
// 计算多个ArrayBuffer的总字节大小
|
||||
let totalByteLength = 0;
|
||||
for (const arrayBuffer of arrayBuffers) {
|
||||
totalByteLength += arrayBuffer.byteLength;
|
||||
}
|
||||
|
||||
// 创建一个新的ArrayBuffer
|
||||
const combinedArrayBuffer = new ArrayBuffer(totalByteLength);
|
||||
|
||||
// 创建一个Uint8Array来操作新的ArrayBuffer
|
||||
const combinedUint8Array = new Uint8Array(combinedArrayBuffer);
|
||||
|
||||
// 依次复制每个ArrayBuffer的内容到新的ArrayBuffer中
|
||||
let offset = 0;
|
||||
for (const arrayBuffer of arrayBuffers) {
|
||||
const sourceUint8Array = new Uint8Array(arrayBuffer);
|
||||
combinedUint8Array.set(sourceUint8Array, offset);
|
||||
offset += sourceUint8Array.length;
|
||||
}
|
||||
|
||||
return combinedArrayBuffer;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 图片变换接口
|
||||
*/
|
||||
export interface BaseTransformation<T> {
|
||||
|
||||
transform(context: Context, toTransform: T, width: number, height: number): Promise<T>;
|
||||
|
||||
getName(): string
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import effectKit from '@ohos.effectKit';
|
||||
|
||||
/**
|
||||
* 图片变换:模糊效果
|
||||
*/
|
||||
@Sendable
|
||||
export class BlurTransformation extends PixelMapTransformation {
|
||||
private radius: number // 模糊半径,单位是像素。模糊效果与所设置的值成正比,值越大效果越明显。
|
||||
|
||||
constructor(radius: number) {
|
||||
super()
|
||||
this.radius = radius
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.constructor.name + ';radius:' + this.radius;
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
let headFilter = effectKit.createEffect(toTransform);
|
||||
if (headFilter != null) {
|
||||
return await headFilter.blur(this.radius).getEffectPixelMap()
|
||||
}
|
||||
return toTransform
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import effectKit from '@ohos.effectKit';
|
||||
|
||||
/**
|
||||
* 图片变换:高亮效果
|
||||
*/
|
||||
@Sendable
|
||||
export class BrightnessTransformation extends PixelMapTransformation {
|
||||
private bright: number // 高亮程度,取值范围在0-1之间,取值为0时图像保持不变。
|
||||
|
||||
constructor(bright: number) {
|
||||
super()
|
||||
this.bright = bright
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.constructor.name + ';bright:' + this.bright;
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
let headFilter = effectKit.createEffect(toTransform);
|
||||
if (headFilter != null) {
|
||||
return await headFilter.brightness(this.bright).getEffectPixelMap()
|
||||
}
|
||||
return toTransform
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import { Size } from '@kit.ArkUI';
|
||||
import { image } from '@kit.ImageKit';
|
||||
|
||||
/**
|
||||
* 图片变换:圆形裁剪效果
|
||||
*/
|
||||
@Sendable
|
||||
export class CropCircleTransformation extends PixelMapTransformation {
|
||||
private mCenterX: number = 0;
|
||||
private mCenterY: number = 0;
|
||||
private mRadius: number = 0;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.constructor.name + ';mCenterX:' + this.mCenterX + ';mCenterY:' + this.mCenterY + ';mRadius:' + this.mRadius;
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
return await this.transformCircle(toTransform);
|
||||
}
|
||||
|
||||
private async transformCircle(data: PixelMap): Promise<PixelMap> {
|
||||
let imageInfo: image.ImageInfo = await data.getImageInfo();
|
||||
let size: Size = {
|
||||
width: imageInfo.size.width,
|
||||
height: imageInfo.size.height
|
||||
};
|
||||
if (!size) {
|
||||
console.error("CropCircleTransformation The image size does not exist.");
|
||||
return data;
|
||||
}
|
||||
let height: number = size.height;
|
||||
let width: number = size.width;
|
||||
this.mRadius = 0;
|
||||
if (width > height) {
|
||||
this.mRadius = height / 2;
|
||||
} else {
|
||||
this.mRadius = width / 2;
|
||||
}
|
||||
this.mCenterX = width / 2;
|
||||
this.mCenterY = height / 2;
|
||||
|
||||
let bufferData: ArrayBuffer = new ArrayBuffer(data.getPixelBytesNumber());
|
||||
await data.readPixelsToBuffer(bufferData);
|
||||
|
||||
let dataArray = new Uint8Array(bufferData);
|
||||
|
||||
for (let h = 0; h <= height; h++) {
|
||||
for (let w = 0; w <= width; w++) {
|
||||
if (this.isContainsCircle(w, h)) {
|
||||
continue;
|
||||
}
|
||||
// 针对的点
|
||||
let index = (h * width + w) * 4;
|
||||
dataArray[index] = 0;
|
||||
dataArray[index+1] = 0;
|
||||
dataArray[index+2] = 0;
|
||||
dataArray[index+3] = 0;
|
||||
}
|
||||
}
|
||||
await data.writeBufferToPixels(bufferData);
|
||||
return data;
|
||||
}
|
||||
|
||||
isContainsCircle(x: number, y: number): boolean {
|
||||
let a = Math.pow((this.mCenterX - x), 2);
|
||||
let b = Math.pow((this.mCenterY - y), 2);
|
||||
let c = Math.sqrt((a + b));
|
||||
return c <= this.mRadius;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* 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 { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import { Size } from '@kit.ArkUI';
|
||||
import { image } from '@kit.ImageKit';
|
||||
|
||||
export interface rgbColor {
|
||||
r_color: number,
|
||||
g_color: number,
|
||||
b_color: number,
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片变换:圆环裁剪效果
|
||||
*/
|
||||
@Sendable
|
||||
export class CropCircleWithBorderTransformation extends PixelMapTransformation {
|
||||
private mBorderSize: number = 5;
|
||||
private mCenterX: number = 0;
|
||||
private mCenterY: number = 0;
|
||||
private mRadius: number = 0;
|
||||
private mRColor: number = 0;
|
||||
private mGColor: number = 0;
|
||||
private mBColor: number = 0;
|
||||
|
||||
constructor(borderSize: number, value: rgbColor) {
|
||||
super();
|
||||
this.mRColor = value.g_color;
|
||||
this.mGColor = value.g_color;
|
||||
this.mBColor = value.b_color;
|
||||
this.mBorderSize = borderSize;
|
||||
}
|
||||
|
||||
getConstructorParams() {
|
||||
return JSON.stringify([this.mBorderSize, {
|
||||
r_color: this.mRColor,
|
||||
g_color: this.mGColor,
|
||||
b_color: this.mBColor
|
||||
}]);
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.constructor.name + ';mBorderSize:' + this.mBorderSize + ';mCenterX:' + this.mCenterX + ';mCenterY:'
|
||||
+ this.mCenterY + ';mRadius:' + this.mRadius + ';mRColor:' + this.mRColor + ';mGColor:' + this.mGColor + ';mBColor:' + this.mBColor;
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
return await this.transformPixelMap(toTransform);
|
||||
}
|
||||
|
||||
private async transformPixelMap(pixelMap: PixelMap): Promise<PixelMap> {
|
||||
let imageInfo: image.ImageInfo = await pixelMap.getImageInfo();
|
||||
let size: Size = {
|
||||
width: imageInfo.size.width,
|
||||
height: imageInfo.size.height
|
||||
};
|
||||
if (!size) {
|
||||
console.error("CropCircleWithBorderTransformation The image size does not exist.");
|
||||
return pixelMap;
|
||||
}
|
||||
let height: number = size.height;
|
||||
let width: number = size.width;
|
||||
this.mRadius = 0;
|
||||
if (width > height) {
|
||||
this.mRadius = height / 2;
|
||||
} else {
|
||||
this.mRadius = width / 2;
|
||||
}
|
||||
this.mCenterX = width / 2;
|
||||
this.mCenterY = height / 2;
|
||||
|
||||
|
||||
let bufferData = new ArrayBuffer(pixelMap.getPixelBytesNumber());
|
||||
await pixelMap.readPixelsToBuffer(bufferData);
|
||||
|
||||
let dataArray = new Uint8Array(bufferData);
|
||||
|
||||
for (let h = 0; h <= height; h++) {
|
||||
for (let w = 0; w <= width; w++) {
|
||||
// 不在大圆之内的设置透明
|
||||
// 在大圆与小圆之间的 设置rgb值
|
||||
// 小圆之内的不变
|
||||
let isSmallCircle: boolean = this.isContainsSmallCircle(w, h);
|
||||
let isBigCircle: boolean = this.isContainsCircle(w, h);
|
||||
if (isSmallCircle) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let index = (h * width + w) * 4;
|
||||
if (!isBigCircle) {
|
||||
// 设置透明
|
||||
dataArray[index] = 0;
|
||||
dataArray[index+1] = 0;
|
||||
dataArray[index+2] = 0;
|
||||
dataArray[index+3] = 0;
|
||||
} else {
|
||||
// 设置broke
|
||||
dataArray[index] = this.mRColor;
|
||||
dataArray[index+1] = this.mGColor;
|
||||
dataArray[index+2] = this.mBColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
await pixelMap.writeBufferToPixels(bufferData);
|
||||
return pixelMap;
|
||||
}
|
||||
|
||||
isContainsCircle(x: number, y: number): boolean {
|
||||
let a: number = Math.pow((this.mCenterX - x), 2);
|
||||
let b: number = Math.pow((this.mCenterY - y), 2);
|
||||
let c: number = Math.sqrt((a + b));
|
||||
return c <= this.mRadius;
|
||||
}
|
||||
|
||||
isContainsSmallCircle(x: number, y: number): boolean {
|
||||
let a: number = Math.pow((this.mCenterX - x), 2);
|
||||
let b: number = Math.pow((this.mCenterY - y), 2);
|
||||
let c: number = Math.sqrt((a + b));
|
||||
return c <= (this.mRadius - this.mBorderSize);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import { Size } from '@kit.ArkUI';
|
||||
import { image } from '@kit.ImageKit';
|
||||
|
||||
/**
|
||||
* 图片变换:正方形裁剪效果
|
||||
*/
|
||||
@Sendable
|
||||
export class CropSquareTransformation extends PixelMapTransformation {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||
let size: Size = {
|
||||
width: imageInfo.size.width,
|
||||
height: imageInfo.size.height
|
||||
};
|
||||
if (!size) {
|
||||
console.error("CropSquareTransformation The image size does not exist.");
|
||||
return toTransform;
|
||||
}
|
||||
let pixelMapWidth: number = size.width;
|
||||
let pixelMapHeight: number = size.height;
|
||||
let targetSize: number = pixelMapWidth > pixelMapHeight ? pixelMapHeight : pixelMapWidth;
|
||||
let region: image.Region = {
|
||||
size: { width: targetSize, height: targetSize },
|
||||
x: pixelMapWidth / 2 - targetSize / 2,
|
||||
y: pixelMapHeight / 2 - targetSize / 2
|
||||
};
|
||||
await toTransform.crop(region);
|
||||
return toTransform;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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 { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import { Size } from '@kit.ArkUI';
|
||||
import { image } from '@kit.ImageKit';
|
||||
|
||||
/**
|
||||
* 图片变换:自定义裁剪效果
|
||||
*/
|
||||
@Sendable
|
||||
export class CropTransformation extends PixelMapTransformation {
|
||||
private mWidth: number = 0;
|
||||
private mHeight: number = 0;
|
||||
private mCropType: number = 0;
|
||||
|
||||
constructor(width: number, height: number, cropType: number) {
|
||||
super();
|
||||
this.mWidth = width;
|
||||
this.mHeight = height;
|
||||
this.mCropType = cropType;
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.constructor.name + ";mWidth:" + this.mWidth + ";mHeight:" + this.mHeight + ";mCropType:" + this.mCropType;
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||
let size: Size = {
|
||||
width: imageInfo.size.width,
|
||||
height: imageInfo.size.height
|
||||
};
|
||||
if (!size) {
|
||||
console.error("CropTransformation The image size does not exist.");
|
||||
return toTransform;
|
||||
}
|
||||
let pixelMapWidth: number = size.width;
|
||||
let pixelMapHeight: number = size.height;
|
||||
this.mWidth = this.mWidth == 0 ? pixelMapWidth : this.mWidth;
|
||||
this.mHeight = this.mHeight == 0 ? pixelMapHeight : this.mHeight;
|
||||
let scaleX: number = this.mWidth / pixelMapWidth;
|
||||
let scaleY: number = this.mHeight / pixelMapHeight;
|
||||
let scale: number = Math.max(scaleX, scaleY);
|
||||
let scaledWidth: number = scale * pixelMapWidth;
|
||||
let scaledHeight: number = scale * pixelMapHeight;
|
||||
let left: number = (this.mWidth - scaledWidth) / 2;
|
||||
let top: number = Math.abs(this.getTop(pixelMapHeight));
|
||||
let region: image.Region = {
|
||||
size: {
|
||||
width: scaledWidth > pixelMapWidth ? pixelMapWidth : scaledWidth,
|
||||
height: scaledHeight > pixelMapHeight ? pixelMapHeight : scaledHeight
|
||||
},
|
||||
x: left < 0 ? 0 : left,
|
||||
y: top < 0 ? 0 : top
|
||||
};
|
||||
toTransform.cropSync(region);
|
||||
return toTransform;
|
||||
}
|
||||
|
||||
private getTop(scaledHeight: number): number {
|
||||
switch (this.mCropType) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return (this.mHeight - scaledHeight) / 2;
|
||||
case 2:
|
||||
return this.mHeight - scaledHeight;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import { effectKit } from '@kit.ArkGraphics2D';
|
||||
|
||||
/**
|
||||
* 图片变换:灰化效果
|
||||
*/
|
||||
@Sendable
|
||||
export class GrayScaleTransformation extends PixelMapTransformation {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
let headFilter = effectKit.createEffect(toTransform);
|
||||
if (headFilter != null) {
|
||||
return await headFilter.grayscale().getEffectPixelMap();
|
||||
}
|
||||
return toTransform;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import { effectKit } from '@kit.ArkGraphics2D';
|
||||
|
||||
/**
|
||||
* 图片变换:反转效果
|
||||
*/
|
||||
@Sendable
|
||||
export class InvertTransformation extends PixelMapTransformation {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
let headFilter = effectKit.createEffect(toTransform);
|
||||
if (headFilter != null) {
|
||||
return await headFilter.invert().getEffectPixelMap();
|
||||
}
|
||||
return toTransform;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { GPUImageKuwaharaFilter } from '@ohos/gpu_transform';
|
||||
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import { image } from '@kit.ImageKit';
|
||||
|
||||
/**
|
||||
* 图片变换:桑原滤波效果
|
||||
*/
|
||||
@Sendable
|
||||
export class KuwaharaTransformation extends PixelMapTransformation {
|
||||
private radius: number;
|
||||
|
||||
constructor(radius: number) {
|
||||
super();
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.constructor.name + ';radius:' + this.radius;
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||
if (!imageInfo.size) {
|
||||
console.error("KuwaharaTransformation The image size does not exist.");
|
||||
return toTransform;
|
||||
}
|
||||
return await this.kuwaharaGpu(toTransform, imageInfo.size.width, imageInfo.size.height);
|
||||
}
|
||||
|
||||
private async kuwaharaGpu(bitmap: PixelMap, targetWidth: number, targetHeight: number): Promise<PixelMap> {
|
||||
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||
await bitmap.readPixelsToBuffer(bufferData);
|
||||
let filter = new GPUImageKuwaharaFilter();
|
||||
filter.setImageData(bufferData, targetWidth, targetHeight);
|
||||
filter.setRadius(this.radius);
|
||||
let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight);
|
||||
await bitmap.writeBufferToPixels(buf);
|
||||
return bitmap;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* 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 { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import { Size } from '@kit.ArkUI';
|
||||
import { image } from '@kit.ImageKit';
|
||||
import { resourceManager } from '@kit.LocalizationKit';
|
||||
import { CalculatePixelUtils } from '../utils/CalculatePixelUtils';
|
||||
import { ColorUtils } from '../utils/ColorUtils';
|
||||
import { PixelEntry } from './entry/PixelEntry';
|
||||
|
||||
/**
|
||||
* 图片变换:遮罩效果
|
||||
*/
|
||||
@Sendable
|
||||
export class MaskTransformation extends PixelMapTransformation {
|
||||
private mResourceId: number;
|
||||
private mResourceModuleName: string;
|
||||
|
||||
constructor(resource: Resource) {
|
||||
super();
|
||||
this.mResourceId = resource.id;
|
||||
this.mResourceModuleName = resource.moduleName;
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.constructor.name + ';resourceId:' + this.mResourceId + ';resourceModuleName:' + this.mResourceModuleName;
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
let imageInfo = await toTransform.getImageInfo();
|
||||
let size: Size = {
|
||||
width: imageInfo.size.width,
|
||||
height: imageInfo.size.height
|
||||
};
|
||||
if (!size) {
|
||||
console.error("MaskTransformation The image size does not exist.");
|
||||
return toTransform;
|
||||
}
|
||||
let pixelMapWidth: number = size.width;
|
||||
let pixelMapHeight: number = size.height;
|
||||
let targetWidth: number = width;
|
||||
let targetHeight: number = height;
|
||||
if (pixelMapWidth > targetWidth && pixelMapHeight > targetHeight) {
|
||||
let scale = Math.max(targetWidth / pixelMapWidth, targetHeight / pixelMapHeight);
|
||||
await toTransform.scale(scale, scale);
|
||||
return await this.openInternal(context, toTransform, scale * pixelMapWidth, scale * pixelMapHeight);
|
||||
}
|
||||
return await this.openInternal(context, toTransform, size.width, size.height);
|
||||
}
|
||||
|
||||
private async openInternal(context: Context, bitmap: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
if (context == undefined) {
|
||||
console.error("MaskTransformation openInternal the context is undefined.");
|
||||
return bitmap;
|
||||
}
|
||||
let moduleContext = context.createModuleContext(this.mResourceModuleName);
|
||||
if (moduleContext == undefined) {
|
||||
console.error("MaskTransformation openInternal the moduleContext is undefined.");
|
||||
return bitmap;
|
||||
}
|
||||
let resourceManager = moduleContext.resourceManager as resourceManager.ResourceManager;
|
||||
if (resourceManager == undefined) {
|
||||
console.error("MaskTransformation openInternal the resourceManager is undefined.");
|
||||
return bitmap;
|
||||
}
|
||||
let array: Uint8Array = await resourceManager.getMediaContent(this.mResourceId);
|
||||
let buffer = array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset);
|
||||
let imageSource: image.ImageSource = image.createImageSource(buffer);
|
||||
let options: image.DecodingOptions = {
|
||||
editable: true,
|
||||
desiredSize: {
|
||||
width: width,
|
||||
height: height
|
||||
}
|
||||
};
|
||||
let maskBitmap: PixelMap = await imageSource.createPixelMap(options);
|
||||
return await this.mask(bitmap, maskBitmap);
|
||||
}
|
||||
|
||||
async mask(bitmap: PixelMap, maskBitmap: PixelMap): Promise<PixelMap> {
|
||||
let imageInfo = await bitmap.getImageInfo();
|
||||
let size: Size = {
|
||||
width: imageInfo.size.width,
|
||||
height: imageInfo.size.height
|
||||
};
|
||||
if (!size) {
|
||||
console.error("MaskTransformation mask the image size does not exist.");
|
||||
return bitmap;
|
||||
}
|
||||
let width = size.width;
|
||||
let height = size.height;
|
||||
let rgbData = CalculatePixelUtils.createInt2DArray(height, width);
|
||||
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||
await bitmap.readPixelsToBuffer(bufferData);
|
||||
let dataArray = new Uint8Array(bufferData);
|
||||
let ph = 0;
|
||||
let pw = 0;
|
||||
for (let index = 0; index < dataArray.length; index += 4) {
|
||||
const r = dataArray[index];
|
||||
const g = dataArray[index+1];
|
||||
const b = dataArray[index+2];
|
||||
const f = dataArray[index+3];
|
||||
let entry = new PixelEntry();
|
||||
entry.a = 0;
|
||||
entry.b = b;
|
||||
entry.g = g;
|
||||
entry.r = r;
|
||||
entry.f = f;
|
||||
entry.pixel = ColorUtils.rgb(entry.r, entry.g, entry.b);
|
||||
rgbData[ph][pw] = ColorUtils.rgb(entry.r, entry.g, entry.b);
|
||||
if (pw == width - 1) {
|
||||
pw = 0;
|
||||
ph++;
|
||||
} else {
|
||||
pw++;
|
||||
}
|
||||
}
|
||||
let imageInfoMask = await maskBitmap.getImageInfo();
|
||||
let sizeMask: Size = {
|
||||
width: imageInfoMask.size.width,
|
||||
height: imageInfoMask.size.height
|
||||
};
|
||||
if (!sizeMask) {
|
||||
console.error("MaskTransformation mask the sizeMask size does not exist.");
|
||||
return bitmap;
|
||||
}
|
||||
let widthMask = sizeMask.width;
|
||||
let heightMask = sizeMask.height;
|
||||
let rgbDataMask = CalculatePixelUtils.createInt2DArray(heightMask, widthMask);
|
||||
let pixEntry: Array<PixelEntry> = new Array();
|
||||
let bufferDataM = new ArrayBuffer(maskBitmap.getPixelBytesNumber());
|
||||
await maskBitmap.readPixelsToBuffer(bufferDataM);
|
||||
let dataArrayM = new Uint8Array(bufferDataM);
|
||||
let phM = 0;
|
||||
let pwM = 0;
|
||||
for (let index = 0; index < dataArrayM.length; index += 4) {
|
||||
const r = dataArrayM[index];
|
||||
const g = dataArrayM[index+1];
|
||||
const b = dataArrayM[index+2];
|
||||
const f = dataArrayM[index+3];
|
||||
let entry = new PixelEntry();
|
||||
entry.a = 0;
|
||||
entry.b = b;
|
||||
entry.g = g;
|
||||
entry.r = r;
|
||||
entry.f = f;
|
||||
entry.pixel = ColorUtils.rgb(entry.r, entry.g, entry.b);
|
||||
pixEntry.push(entry);
|
||||
if (entry.r == 0 && entry.g == 0 && entry.b == 0) {
|
||||
rgbDataMask[phM][pwM] = rgbData[phM][pwM];
|
||||
} else {
|
||||
rgbDataMask[phM][pwM] = ColorUtils.rgb(entry.r, entry.g, entry.b);
|
||||
}
|
||||
if (pwM == widthMask - 1) {
|
||||
pwM = 0;
|
||||
phM++;
|
||||
} else {
|
||||
pwM++;
|
||||
}
|
||||
}
|
||||
let bufferNewData = new ArrayBuffer(maskBitmap.getPixelBytesNumber());
|
||||
let dataNewArray = new Uint8Array(bufferNewData);
|
||||
let index = 0;
|
||||
let mh = 0;
|
||||
let nw = 0;
|
||||
for (let i = 0; i < dataNewArray.length; i += 4) {
|
||||
let pixel1 = rgbDataMask[mh][nw];
|
||||
if (nw == widthMask - 1) {
|
||||
nw = 0;
|
||||
mh++;
|
||||
} else {
|
||||
nw++;
|
||||
}
|
||||
let pR = ColorUtils.red(pixel1);
|
||||
let pG = ColorUtils.green(pixel1);
|
||||
let pB = ColorUtils.blue(pixel1);
|
||||
dataNewArray[i] = pR;
|
||||
dataNewArray[i+1] = pG;
|
||||
dataNewArray[i+2] = pB;
|
||||
dataNewArray[i+3] = pixEntry[index].f;
|
||||
index++;
|
||||
}
|
||||
await maskBitmap.writeBufferToPixels(bufferNewData);
|
||||
return maskBitmap;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import { collections } from '@kit.ArkTS';
|
||||
|
||||
/**
|
||||
* 多个图片变换
|
||||
*/
|
||||
@Sendable
|
||||
export class MultiTransTransformation extends PixelMapTransformation {
|
||||
private transformations: collections.Array<PixelMapTransformation>
|
||||
|
||||
constructor(transformations: collections.Array<PixelMapTransformation>) {
|
||||
super()
|
||||
this.transformations = transformations
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
let res = toTransform
|
||||
for (let i = 0; i < this.transformations.length; i++) {
|
||||
res = await this.transformations[i].transform(context, res, width, height)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
let res: string = ""
|
||||
this.transformations.forEach((transformation) => {
|
||||
res += transformation.getName() + "&"
|
||||
})
|
||||
return res
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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 { BaseTransformation } from './BaseTransformation';
|
||||
|
||||
/**
|
||||
* 基于PixelMap的图片变换
|
||||
*/
|
||||
@Sendable
|
||||
export abstract class PixelMapTransformation implements BaseTransformation<PixelMap>{
|
||||
transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.constructor.name
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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 { GPUImagePixelationFilter } from '@ohos/gpu_transform';
|
||||
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import { image } from '@kit.ImageKit';
|
||||
|
||||
/**
|
||||
* Applies a Pixelation effect to the image.
|
||||
* The pixel with a default of 10.0.
|
||||
*/
|
||||
@Sendable
|
||||
export class PixelationTransformation extends PixelMapTransformation {
|
||||
private mPixel: number = 10.0;
|
||||
|
||||
constructor(pixel?: number) {
|
||||
super();
|
||||
if (pixel) {
|
||||
this.mPixel = pixel;
|
||||
}
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.constructor.name + ';pixel:' + this.mPixel;
|
||||
}
|
||||
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||
if (!imageInfo.size) {
|
||||
console.error("PixelationTransformation The image size does not exist.");
|
||||
return toTransform;
|
||||
}
|
||||
return await this.pixelGPU(toTransform, imageInfo.size.width, imageInfo.size.height);
|
||||
}
|
||||
|
||||
private async pixelGPU(bitmap: PixelMap, targetWidth: number, targetHeight: number): Promise<PixelMap> {
|
||||
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||
await bitmap.readPixelsToBuffer(bufferData);
|
||||
let filter = new GPUImagePixelationFilter();
|
||||
filter.setImageData(bufferData, targetWidth, targetHeight);
|
||||
filter.setPixel(this.mPixel);
|
||||
let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight);
|
||||
await bitmap.writeBufferToPixels(buf);
|
||||
return bitmap;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 { GPUImageSepiaToneFilter } from '@ohos/gpu_transform';
|
||||
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import { image } from '@kit.ImageKit';
|
||||
|
||||
/**
|
||||
* 图片变换:乌墨色滤波效果
|
||||
*/
|
||||
@Sendable
|
||||
export class SepiaTransformation extends PixelMapTransformation {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||
if (!imageInfo.size) {
|
||||
console.error("SepiaTransformation The image size does not exist.");
|
||||
return toTransform;
|
||||
}
|
||||
return await this.sepiaGPU(toTransform, imageInfo.size.width, imageInfo.size.height);
|
||||
}
|
||||
|
||||
private async sepiaGPU(bitmap: PixelMap, targetWidth: number, targetHeight: number): Promise<PixelMap> {
|
||||
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||
await bitmap.readPixelsToBuffer(bufferData);
|
||||
let filter = new GPUImageSepiaToneFilter();
|
||||
filter.setImageData(bufferData, targetWidth, targetHeight);
|
||||
let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight);
|
||||
await bitmap.writeBufferToPixels(buf);
|
||||
return bitmap;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 { GPUImageSketchFilter } from '@ohos/gpu_transform';
|
||||
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import { image } from '@kit.ImageKit';
|
||||
|
||||
/**
|
||||
* 图片变换:素描效果
|
||||
*/
|
||||
@Sendable
|
||||
export class SketchTransformation extends PixelMapTransformation {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||
if (!imageInfo.size) {
|
||||
console.error("SketchTransformation The image size does not exist.");
|
||||
return toTransform;
|
||||
}
|
||||
return await this.sketchGPU(toTransform, imageInfo.size.width, imageInfo.size.height);
|
||||
}
|
||||
|
||||
private async sketchGPU(bitmap: PixelMap, targetWidth: number, targetHeight: number): Promise<PixelMap> {
|
||||
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||
await bitmap.readPixelsToBuffer(bufferData);
|
||||
let filter = new GPUImageSketchFilter();
|
||||
filter.setImageData(bufferData, targetWidth, targetHeight);
|
||||
let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight);
|
||||
await bitmap.writeBufferToPixels(buf);
|
||||
return bitmap;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { GPUImageSwirlFilter } from '@ohos/gpu_transform';
|
||||
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import { image } from '@kit.ImageKit';
|
||||
|
||||
/**
|
||||
* 图片变换:扭曲效果
|
||||
*/
|
||||
@Sendable
|
||||
export class SwirlTransformation extends PixelMapTransformation {
|
||||
// degree:值越大范围越大
|
||||
private mDegree: number = 0;
|
||||
// 取值范围 0.0 ~ 1.0
|
||||
private mAngle: number = 0.9;
|
||||
// 在图中的位置 取值范围 0.0 ~ 1.0
|
||||
private mXCenter: number = 0.5;
|
||||
// 在图中的位置 取值范围 0.0 ~ 1.0
|
||||
private mYCenter: number = 0.5;
|
||||
|
||||
constructor(degree: number, angle?: number, centerPoint?: Array<number>) {
|
||||
super();
|
||||
this.mDegree = degree;
|
||||
if (angle) {
|
||||
this.mAngle = angle;
|
||||
}
|
||||
if (centerPoint && centerPoint.length === 2) {
|
||||
this.mXCenter = centerPoint[0];
|
||||
this.mYCenter = centerPoint[1];
|
||||
}
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.constructor.name + ';degree:' + this.mDegree + ';angle:' + this.mAngle + ';XCenter:' + this.mXCenter
|
||||
+ ';YCenter:' + this.mYCenter;
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||
if (!imageInfo.size) {
|
||||
console.error("SwirlTransformation The image size does not exist.");
|
||||
return toTransform;
|
||||
}
|
||||
return await this.swirlGPU(toTransform, imageInfo.size.width, imageInfo.size.height);
|
||||
}
|
||||
|
||||
private async swirlGPU(bitmap: image.PixelMap, targetWidth: number, targetHeight: number): Promise<PixelMap> {
|
||||
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||
await bitmap.readPixelsToBuffer(bufferData);
|
||||
let filter = new GPUImageSwirlFilter();
|
||||
filter.setImageData(bufferData, targetWidth, targetHeight);
|
||||
filter.setRadius(this.mDegree);
|
||||
filter.setAngle(this.mAngle);
|
||||
filter.setCenter(this.mXCenter, this.mYCenter);
|
||||
let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight);
|
||||
await bitmap.writeBufferToPixels(buf);
|
||||
return bitmap;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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 { GPUImageToonFilter } from '@ohos/gpu_transform';
|
||||
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import { image } from '@kit.ImageKit';
|
||||
|
||||
/**
|
||||
* 图片变换:动画滤镜效果
|
||||
*/
|
||||
@Sendable
|
||||
export class ToonTransformation extends PixelMapTransformation {
|
||||
private threshold: number = 0.2;
|
||||
private quantizationLevels: number = 10.0;
|
||||
|
||||
constructor(threshold?: number, quantizationLevels?: number) {
|
||||
super();
|
||||
if (threshold) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
if (quantizationLevels) {
|
||||
this.quantizationLevels = quantizationLevels;
|
||||
}
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.constructor.name + ';threshold:' + this.threshold + ';quantizationLevels:' + this.quantizationLevels;
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||
if (!imageInfo.size) {
|
||||
console.error("ToonTransformation The image size does not exist.");
|
||||
return toTransform;
|
||||
}
|
||||
return await this.toonGPU(toTransform, imageInfo.size.width, imageInfo.size.height);
|
||||
}
|
||||
|
||||
private async toonGPU(bitmap: image.PixelMap, targetWidth: number, targetHeight: number) {
|
||||
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||
await bitmap.readPixelsToBuffer(bufferData);
|
||||
let filter = new GPUImageToonFilter();
|
||||
filter.setImageData(bufferData, targetWidth, targetHeight);
|
||||
filter.setThreshold(this.threshold);
|
||||
filter.setQuantizationLevels(this.quantizationLevels);
|
||||
let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight);
|
||||
await bitmap.writeBufferToPixels(buf);
|
||||
return bitmap;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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 { GPUImageVignetterFilter } from '@ohos/gpu_transform';
|
||||
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||
import { image } from '@kit.ImageKit';
|
||||
|
||||
/**
|
||||
* 图片变换:装饰效果
|
||||
*/
|
||||
@Sendable
|
||||
export class VignetterTransformation extends PixelMapTransformation {
|
||||
private mXCenter: number = 0.5;
|
||||
private mYCenter: number = 0.5;
|
||||
private mRed: number = 0.0;
|
||||
private mGreen: number = 0.0;
|
||||
private mBlue: number = 0.0;
|
||||
private mStart: number = 0.3;
|
||||
private mEnd: number = 0.75;
|
||||
|
||||
constructor(centerPoint: Array<number>, vignetteColor: Array<number>, vignetteSpace: Array<number>) {
|
||||
super();
|
||||
if (centerPoint.length === 2) {
|
||||
this.mXCenter = centerPoint[0];
|
||||
this.mYCenter = centerPoint[1];
|
||||
}
|
||||
if (vignetteColor.length === 3) {
|
||||
this.mRed = vignetteColor[0];
|
||||
this.mGreen = vignetteColor[1];
|
||||
this.mBlue = vignetteColor[2];
|
||||
}
|
||||
if (vignetteSpace.length === 2) {
|
||||
this.mStart = vignetteSpace[0];
|
||||
this.mEnd = vignetteSpace[1];
|
||||
}
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.constructor.name + ';XCenter:' + this.mXCenter + ';YCenter:' + this.mYCenter + ';Red:'
|
||||
+ this.mRed + ';Green:' + this.mGreen + ';Blue:' + this.mBlue + ';Start:' + this.mStart + ';End:' + this.mEnd;
|
||||
}
|
||||
|
||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||
if (!imageInfo.size) {
|
||||
console.error("VignetterTransformation The image size does not exist.");
|
||||
return toTransform;
|
||||
}
|
||||
return await this.swirlGPU(toTransform, imageInfo.size.width, imageInfo.size.height);
|
||||
}
|
||||
|
||||
private async swirlGPU(bitmap: image.PixelMap, targetWidth: number, targetHeight: number) {
|
||||
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||
await bitmap.readPixelsToBuffer(bufferData);
|
||||
let filter = new GPUImageVignetterFilter();
|
||||
filter.setImageData(bufferData, targetWidth, targetHeight);
|
||||
filter.setVignetteCenter([this.mXCenter, this.mYCenter]);
|
||||
filter.setVignetteColor([this.mRed, this.mGreen, this.mBlue]);
|
||||
filter.setVignetteStart(this.mStart);
|
||||
filter.setVignetteEnd(this.mEnd);
|
||||
let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight);
|
||||
await bitmap.writeBufferToPixels(buf);
|
||||
return bitmap;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Huawei Device Co., Ltd.
|
||||
* 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
|
||||
|
@ -12,10 +12,15 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import common from '@ohos.app.ability.common'
|
||||
export class PixelEntry {
|
||||
a: number = 0;
|
||||
b: number = 0;
|
||||
r: number = 0;
|
||||
g: number = 0;
|
||||
f: number = 0;
|
||||
pixel: number = 0;
|
||||
|
||||
export class GetRes2{
|
||||
static getSample2():Resource {
|
||||
return $r('app.media.icon_loading');
|
||||
public toString(): string {
|
||||
return "PixelEntry a:" + this.a + ";b:" + this.b + ";r:" + this.r + ";g:" + this.g + ";f:" + this.f;
|
||||
}
|
||||
}
|