1.属性改为小写imageKnifeOption
2.支持使用一个或多个图片变换,如模糊,高亮等 Signed-off-by: madixin <madixin@huawei.com>
This commit is contained in:
parent
be0f5ff8ef
commit
00f5e81571
|
@ -1,3 +1,7 @@
|
||||||
|
|
||||||
|
## 3.0.0-rc.2
|
||||||
|
- 新增支持使用一个或多个图片变换,如模糊,高亮等
|
||||||
|
|
||||||
## 3.0.0-rc.1
|
## 3.0.0-rc.1
|
||||||
- 新增从内存或文件缓存获取图片数据接口getCacheImage
|
- 新增从内存或文件缓存获取图片数据接口getCacheImage
|
||||||
- 新增图片预加载preLoadCache并返回文件缓存路径
|
- 新增图片预加载preLoadCache并返回文件缓存路径
|
||||||
|
|
45
README.md
45
README.md
|
@ -6,10 +6,9 @@
|
||||||
|
|
||||||
本项目参考开源库 [Glide](https://github.com/bumptech/glide) 进行OpenHarmony的自研版本:
|
本项目参考开源库 [Glide](https://github.com/bumptech/glide) 进行OpenHarmony的自研版本:
|
||||||
|
|
||||||
- 支持内存缓存,使用LRUCache算法,对图片数据进行内存缓存。
|
- 支持自定义内存缓存策略,支持设置内存缓存的大小。
|
||||||
- 支持通过initMemoryCache自定义策略内存缓存策略和大小。
|
|
||||||
- 支持磁盘二级缓存,对于下载图片会保存一份至磁盘当中。
|
- 支持磁盘二级缓存,对于下载图片会保存一份至磁盘当中。
|
||||||
- 支持option自定义实现图片获取/网络下载
|
- 支持自定义实现图片获取/网络下载
|
||||||
- 支持监听网络下载回调进度
|
- 支持监听网络下载回调进度
|
||||||
- 继承Image的能力,支持option传入border,设置边框,圆角
|
- 继承Image的能力,支持option传入border,设置边框,圆角
|
||||||
- 继承Image的能力,支持option传入objectFit设置图片缩放,包括objectFit为auto时根据图片自适应高度
|
- 继承Image的能力,支持option传入objectFit设置图片缩放,包括objectFit为auto时根据图片自适应高度
|
||||||
|
@ -17,28 +16,27 @@
|
||||||
- 并发请求数量,支持请求排队队列的优先级
|
- 并发请求数量,支持请求排队队列的优先级
|
||||||
- 支持生命周期已销毁的图片,不再发起请求
|
- 支持生命周期已销毁的图片,不再发起请求
|
||||||
- 自定义缓存key
|
- 自定义缓存key
|
||||||
- 自定义请求头规格
|
- 自定义http网络请求头
|
||||||
- 支持writeCacheStrategy控制缓存的存入策略(只存入内存或文件缓存)
|
- 支持writeCacheStrategy控制缓存的存入策略(只存入内存或文件缓存)
|
||||||
- 支持preLoadCache预加载图片
|
- 支持preLoadCache预加载图片
|
||||||
- 支持onlyRetrieveFromCache仅用缓存加载
|
- 支持onlyRetrieveFromCache仅用缓存加载
|
||||||
|
- 支持使用一个或多个图片变换,如模糊,高亮等
|
||||||
|
|
||||||
待实现特性
|
待实现特性
|
||||||
- gif/webp动图显示与控制
|
- gif/webp动图显示与控制
|
||||||
- 内存降采样优化,节约内存的占用
|
- 内存降采样优化,节约内存的占用
|
||||||
- 支持自定义图片解码
|
- 支持自定义图片解码
|
||||||
- 支持进行图片变换: 支持图像像素源图片变换效果。
|
|
||||||
|
|
||||||
注意:3.x版本相对2.x版本做了重大的重构,主要体现在:
|
注意:3.x版本相对2.x版本做了重大的重构,主要体现在:
|
||||||
- 使用Image组件代替Canvas组件渲染
|
- 使用Image组件代替Canvas组件渲染
|
||||||
- 重构Dispatch分发逻辑,支持控制并发请求数,支持请求排队队列的优先级
|
- 重构Dispatch分发逻辑,支持控制并发请求数,支持请求排队队列的优先级
|
||||||
- 支持通过initMemoryCache自定义策略内存缓存策略和大小。
|
- 支持通过initMemoryCache自定义策略内存缓存策略和大小
|
||||||
- 支持option自定义实现图片获取/网络下载
|
- 支持option自定义实现图片获取/网络下载
|
||||||
|
|
||||||
因此API及能力上,目前有部分差异,主要体现在:
|
因此API及能力上,目前有部分差异,主要体现在:
|
||||||
- 不支持drawLifeCycle接口,通过canvas自会图片
|
- 不支持drawLifeCycle接口,通过canvas自会图片
|
||||||
- mainScaleType,border等参数,新版本与系统Image保持一致
|
- mainScaleType,border等参数,新版本与系统Image保持一致
|
||||||
- gif/webp动图播放与控制
|
- gif/webp动图播放与控制
|
||||||
- 支持进行图片变换: 支持图像像素源图片变换效果。
|
|
||||||
- 抗锯齿相关参数
|
- 抗锯齿相关参数
|
||||||
|
|
||||||
## 下载安装
|
## 下载安装
|
||||||
|
@ -122,33 +120,48 @@ ImageKnifeComponent({ ImageKnifeOption:
|
||||||
}
|
}
|
||||||
}).width(100).height(100)
|
}).width(100).height(100)
|
||||||
```
|
```
|
||||||
|
#### 7.支持option图片变换
|
||||||
|
```
|
||||||
|
ImageKnifeComponent({ ImageKnifeOption:
|
||||||
|
{
|
||||||
|
loadSrc: $r("app.media.rabbit"),
|
||||||
|
border: {radius:50},
|
||||||
|
transformation: new BlurTransformation(3)
|
||||||
|
}
|
||||||
|
}).width(100).height(100)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## 接口说明
|
## 接口说明
|
||||||
### ImageKnifeOption参数列表
|
### ImageKnifeOption参数列表
|
||||||
|
|
||||||
| 参数名称 | 入参内容 | 功能简介 |
|
| 参数名称 | 入参内容 | 功能简介 |
|
||||||
|-----------------------|-------------------------------|---------------|
|
|-----------------------|-------------------------------|-----------------|
|
||||||
| loadSrc | string、PixelMap、Resource | 主图展示 |
|
| loadSrc | string、PixelMap、Resource | 主图展示 |
|
||||||
| placeholderSrc | PixelMap、Resource | 占位图图展示(可选) |
|
| placeholderSrc | PixelMap、Resource | 占位图图展示(可选) |
|
||||||
| errorholderSrc | PixelMap、Resource | 错误图展示(可选) |
|
| errorholderSrc | PixelMap、Resource | 错误图展示(可选) |
|
||||||
| objectFit | ImageFit | 图片展示样式(可选) |
|
| objectFit | ImageFit | 图片展示样式(可选) |
|
||||||
| writeCacheStrategy | WriteCacheStrategyType | 写入缓存策略(可选) |
|
| writeCacheStrategy | WriteCacheStrategyType | 写入缓存策略(可选) |
|
||||||
| onlyRetrieveFromCache | boolean | 跳过网络和本地请求(可选) |
|
| onlyRetrieveFromCache | boolean | 是否跳过网络和本地请求(可选) |
|
||||||
| customGetImage | (context: Context, src: string | 自定义网络(可选) | | Resource | 错误占位图数据源 |
|
| customGetImage | (context: Context, src: string | 自定义下载图片(可选) | | Resource | 错误占位图数据源 |
|
||||||
| border | BorderOptions | 边框圆角(可选) |
|
| border | BorderOptions | 边框圆角(可选) |
|
||||||
| priority | taskpool.Priority | 加载优先级(可选) |
|
| priority | taskpool.Priority | 加载优先级(可选) |
|
||||||
| context | common.UIAbilityContext | 上下文(可选) |
|
| context | common.UIAbilityContext | 上下文(可选) |
|
||||||
| progressListener | (progress: number)=>void | 进度(可选) |
|
| progressListener | (progress: number)=>void | 进度(可选) |
|
||||||
| signature | ObjectKey | 自定义缓存关键字 |
|
| signature | ObjectKey | 自定义缓存关键字(可选) |
|
||||||
| headerOption | Array<HeaderOptions> | 设置请求头 |
|
| headerOption | Array<HeaderOptions> | 设置请求头(可选) |
|
||||||
|
| transformation | PixelMapTransformation | 图片变换(可选) |
|
||||||
|
|
||||||
### ImageKnife接口
|
### ImageKnife接口
|
||||||
| 参数名称 | 入参内容 | 功能简介 |
|
| 参数名称 | 入参内容 | 功能简介 |
|
||||||
|--------------|---------------------------|---------------|
|
|------------------|---------------------------|---------------|
|
||||||
|
| initMemoryCache | newMemoryCache: IMemoryCache | 自定义内存缓存策略 |
|
||||||
|
| initFileCache | context: Context, size: number, memory: number | 初始化文件缓存数量和大小 |
|
||||||
| preLoadCache | url:string | 预加载并返回文件缓存路径 |
|
| preLoadCache | url:string | 预加载并返回文件缓存路径 |
|
||||||
| getCacheImage | url: string, cacheType: CacheType | 从内存或文件缓存中获取资源 |
|
| getCacheImage | url: string, cacheType: CacheType | 从内存或文件缓存中获取资源 |
|
||||||
| addHeader | key: string, value: Object | 全局添加请求头属性 |
|
| addHeader | key: string, value: Object | 全局添加http请求头 |
|
||||||
| serHeaderOptions | Array<HeaderOptions> | 全局设置请求头 |
|
| setHeaderOptions | Array<HeaderOptions> | 全局设置http请求头 |
|
||||||
| deleteHeader | key: string | 全局删除请求头 |
|
| deleteHeader | key: string | 全局删除http请求头 |
|
||||||
| setEngineKeyImpl | CustomEngineKeyImpl | 全局配置缓存key |
|
| setEngineKeyImpl | CustomEngineKeyImpl | 全局配置缓存key |
|
||||||
|
|
||||||
## 约束与限制
|
## 约束与限制
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
@ -13,34 +13,48 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import util from '@ohos.util';
|
import util from '@ohos.util';
|
||||||
import { IEngineKey, ObjectKey } from '@ohos/imageknife';
|
import { IEngineKey, ImageKnifeOption, ObjectKey , PixelMapTransformation } from '@ohos/imageknife';
|
||||||
import { SparkMD5 } from '@ohos/imageknife/src/main/ets/3rd_party/sparkmd5/spark-md5';
|
import { SparkMD5 } from '@ohos/imageknife/src/main/ets/3rd_party/sparkmd5/spark-md5';
|
||||||
|
|
||||||
//全局自定义key demo
|
//全局自定义key demo
|
||||||
export class CustomEngineKeyImpl implements IEngineKey {
|
export class CustomEngineKeyImpl implements IEngineKey {
|
||||||
private keyCache: util.LRUCache<string,string> = new util.LRUCache(1024)
|
private memoryKeyCache: util.LRUCache<string, string> = new util.LRUCache(1024)
|
||||||
|
private fileKeyCache: util.LRUCache<string, string> = new util.LRUCache(1024)
|
||||||
|
|
||||||
// 生成内存缓存
|
// 生成内存缓存key
|
||||||
generateCacheKey(loadSrc: string | PixelMap | Resource, signature?: ObjectKey | undefined): string {
|
generateMemoryKey(loadSrc: string | PixelMap | Resource, imageKnifeOption: ImageKnifeOption): string {
|
||||||
let key = "loadSrc=" + this.generateKey(loadSrc) + ";";
|
let src = "loadSrc=" + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";"
|
||||||
if (signature) {
|
if (imageKnifeOption.signature) {
|
||||||
key += "signature=" + signature.getKey() + ";"
|
src += "signature=" + imageKnifeOption.signature.getKey() + ";"
|
||||||
}
|
}
|
||||||
return key;
|
if (imageKnifeOption.transformation) {
|
||||||
|
src += "transformation=" + this.getTransformation(imageKnifeOption.transformation) + ";"
|
||||||
|
}
|
||||||
|
return this.generateKey(src, this.memoryKeyCache)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成文件缓存key
|
||||||
|
generateFileKey(loadSrc: string | PixelMap | Resource, signature?: ObjectKey | undefined): string {
|
||||||
|
let src = "loadSrc=" + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";"
|
||||||
|
if (signature) {
|
||||||
|
src += "signature=" + signature.getKey() + ";"
|
||||||
|
}
|
||||||
|
return this.generateKey(src, this.fileKeyCache)
|
||||||
}
|
}
|
||||||
|
|
||||||
// key缓存策略,避免无意义的 JSON.stringify
|
// key缓存策略,避免无意义的 JSON.stringify
|
||||||
private generateKey(key: string | PixelMap | Resource): string {
|
private generateKey(keyCache: string, cache: util.LRUCache<string, string>): string {
|
||||||
let keyCache = typeof key == "string" ? key : JSON.stringify(key)
|
let result = cache.get(keyCache)
|
||||||
let result = this.keyCache.get(keyCache)
|
|
||||||
if (result != undefined) {
|
if (result != undefined) {
|
||||||
return result
|
return result
|
||||||
} else {
|
} else {
|
||||||
result = SparkMD5.hashBinary(keyCache)
|
result = SparkMD5.hashBinary(keyCache)
|
||||||
this.keyCache.put(keyCache, result)
|
cache.put(keyCache, result)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getTransformation(transformation: PixelMapTransformation): string {
|
||||||
|
return transformation.getName()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
import { BlurTransformation, BrightnessTransformation, ImageKnifeComponent, ImageKnifeOption,
|
||||||
|
MultiTransTransformation,
|
||||||
|
PixelMapTransformation } from '@ohos/imageknife'
|
||||||
|
import { collections } from '@kit.ArkTS'
|
||||||
|
|
||||||
|
@Entry
|
||||||
|
@Component
|
||||||
|
struct ImageTransformation {
|
||||||
|
@State imageKnifeOption: ImageKnifeOption = {
|
||||||
|
loadSrc: "http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
|
||||||
|
placeholderSrc: $r("app.media.loading"),
|
||||||
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
objectFit: ImageFit.Contain
|
||||||
|
}
|
||||||
|
isBlur: boolean = false
|
||||||
|
isBrightness: boolean = false
|
||||||
|
|
||||||
|
build() {
|
||||||
|
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.upedateImageKnifeOption()
|
||||||
|
})
|
||||||
|
.mark({
|
||||||
|
strokeColor: Color.Black,
|
||||||
|
size: 50,
|
||||||
|
strokeWidth: 5
|
||||||
|
})
|
||||||
|
.unselectedColor(Color.Red)
|
||||||
|
.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.upedateImageKnifeOption()
|
||||||
|
})
|
||||||
|
.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) => {
|
||||||
|
console.info('Checkbox3 change is' + value)
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('Checkbox3').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageKnifeComponent({
|
||||||
|
imageKnifeOption: this.imageKnifeOption
|
||||||
|
}).width(300).height(300)
|
||||||
|
}
|
||||||
|
.height('100%')
|
||||||
|
.width('100%')
|
||||||
|
}
|
||||||
|
|
||||||
|
upedateImageKnifeOption() {
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
this.imageKnifeOption = {
|
||||||
|
loadSrc: "http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
|
||||||
|
placeholderSrc: $r("app.media.loading"),
|
||||||
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
objectFit: ImageFit.Contain,
|
||||||
|
transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -87,6 +87,13 @@ struct Index {
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Button("图片变换").margin({top:10}).onClick(()=>{
|
||||||
|
router.push({
|
||||||
|
uri: 'pages/ImageTransformation',
|
||||||
|
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
.width('100%')
|
.width('100%')
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ struct ListPage {
|
||||||
Row() {
|
Row() {
|
||||||
List({ space: 10 }) {
|
List({ space: 10 }) {
|
||||||
ForEach(this.datas, (item: string) => {
|
ForEach(this.datas, (item: string) => {
|
||||||
ImageKnifeComponent({ ImageKnifeOption: this.ImageKnifeOption }).height(200).width(200)
|
ImageKnifeComponent({ imageKnifeOption: this.ImageKnifeOption }).height(200).width(200)
|
||||||
}, (item: string) => item)
|
}, (item: string) => item)
|
||||||
}
|
}
|
||||||
.width('100%')
|
.width('100%')
|
||||||
|
|
|
@ -25,7 +25,7 @@ struct LongImagePage {
|
||||||
|
|
||||||
// Image($r("app.media.aaa")).objectFit(ImageFit.Auto).width(200)
|
// Image($r("app.media.aaa")).objectFit(ImageFit.Auto).width(200)
|
||||||
ImageKnifeComponent({
|
ImageKnifeComponent({
|
||||||
ImageKnifeOption: {
|
imageKnifeOption: {
|
||||||
loadSrc:"https://wx2.sinaimg.cn/mw690/006HyQKGgy1hnqp08dw09j30u04twu0x.jpg",
|
loadSrc:"https://wx2.sinaimg.cn/mw690/006HyQKGgy1hnqp08dw09j30u04twu0x.jpg",
|
||||||
//src:$r("app.media.aaa"),
|
//src:$r("app.media.aaa"),
|
||||||
// placeholderSrc: $r("app.media.loading"),
|
// placeholderSrc: $r("app.media.loading"),
|
||||||
|
|
|
@ -36,7 +36,7 @@ struct ManyPhotoShowPage {
|
||||||
// loadSrc: item.thumbnail,
|
// loadSrc: item.thumbnail,
|
||||||
// mainScaleType: ScaleType.FIT_XY,
|
// mainScaleType: ScaleType.FIT_XY,
|
||||||
// } })
|
// } })
|
||||||
ImageKnifeComponent({ImageKnifeOption:{
|
ImageKnifeComponent({imageKnifeOption:{
|
||||||
loadSrc: item.thumbnail,
|
loadSrc: item.thumbnail,
|
||||||
//src:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
|
//src:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
|
||||||
// src: this.localFile,
|
// src: this.localFile,
|
||||||
|
|
|
@ -43,7 +43,7 @@ struct SignatureTestPage {
|
||||||
signature: new ObjectKey("1")
|
signature: new ObjectKey("1")
|
||||||
}
|
}
|
||||||
}).margin({ top: 5, left: 3 })
|
}).margin({ top: 5, left: 3 })
|
||||||
ImageKnifeComponent({ ImageKnifeOption: this.imageKnifeOption1 }).width(300).height(300)
|
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).width(300).height(300)
|
||||||
}.width('100%').backgroundColor(Color.Pink)
|
}.width('100%').backgroundColor(Color.Pink)
|
||||||
|
|
||||||
Text("key每次变化:时间戳").fontSize(15)
|
Text("key每次变化:时间戳").fontSize(15)
|
||||||
|
@ -56,7 +56,7 @@ struct SignatureTestPage {
|
||||||
signature: new ObjectKey(new Date().getTime().toString())
|
signature: new ObjectKey(new Date().getTime().toString())
|
||||||
}
|
}
|
||||||
}).margin({ top: 5, left: 3 })
|
}).margin({ top: 5, left: 3 })
|
||||||
ImageKnifeComponent({ ImageKnifeOption: this.imageKnifeOption2 }).width(300).height(300)
|
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption2 }).width(300).height(300)
|
||||||
}.width('100%').backgroundColor(Color.Pink)
|
}.width('100%').backgroundColor(Color.Pink)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { ImageKnifeComponent } from '@ohos/imageknife';
|
import { ImageKnifeComponent,BlurTransformation } from '@ohos/imageknife';
|
||||||
import fs from '@ohos.file.fs';
|
import fs from '@ohos.file.fs';
|
||||||
|
|
||||||
@Entry
|
@Entry
|
||||||
|
@ -37,7 +37,7 @@ struct SingleImage {
|
||||||
.fontSize(30)
|
.fontSize(30)
|
||||||
.fontWeight(FontWeight.Bold)
|
.fontWeight(FontWeight.Bold)
|
||||||
ImageKnifeComponent({
|
ImageKnifeComponent({
|
||||||
ImageKnifeOption: {
|
imageKnifeOption: {
|
||||||
loadSrc: $r("app.media.app_icon"),
|
loadSrc: $r("app.media.app_icon"),
|
||||||
placeholderSrc: $r("app.media.loading"),
|
placeholderSrc: $r("app.media.loading"),
|
||||||
errorholderSrc: $r("app.media.app_icon"),
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
@ -48,7 +48,7 @@ struct SingleImage {
|
||||||
.fontSize(30)
|
.fontSize(30)
|
||||||
.fontWeight(FontWeight.Bold)
|
.fontWeight(FontWeight.Bold)
|
||||||
ImageKnifeComponent({
|
ImageKnifeComponent({
|
||||||
ImageKnifeOption: {
|
imageKnifeOption: {
|
||||||
loadSrc: this.localFile,
|
loadSrc: this.localFile,
|
||||||
placeholderSrc: $r("app.media.loading"),
|
placeholderSrc: $r("app.media.loading"),
|
||||||
errorholderSrc: $r("app.media.app_icon"),
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
@ -59,7 +59,7 @@ struct SingleImage {
|
||||||
.fontSize(30)
|
.fontSize(30)
|
||||||
.fontWeight(FontWeight.Bold)
|
.fontWeight(FontWeight.Bold)
|
||||||
ImageKnifeComponent({
|
ImageKnifeComponent({
|
||||||
ImageKnifeOption: {
|
imageKnifeOption: {
|
||||||
loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
|
loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
|
||||||
placeholderSrc: $r("app.media.loading"),
|
placeholderSrc: $r("app.media.loading"),
|
||||||
errorholderSrc: $r("app.media.app_icon"),
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
@ -71,12 +71,13 @@ struct SingleImage {
|
||||||
.fontSize(30)
|
.fontSize(30)
|
||||||
.fontWeight(FontWeight.Bold)
|
.fontWeight(FontWeight.Bold)
|
||||||
ImageKnifeComponent({
|
ImageKnifeComponent({
|
||||||
ImageKnifeOption: {
|
imageKnifeOption: {
|
||||||
loadSrc: "https://file.atomgit.com/uploads/user/1704857786989_8994.jpeg",
|
loadSrc: "https://file.atomgit.com/uploads/user/1704857786989_8994.jpeg",
|
||||||
placeholderSrc: $r("app.media.loading"),
|
placeholderSrc: $r("app.media.loading"),
|
||||||
errorholderSrc: $r("app.media.app_icon"),
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
objectFit: ImageFit.Contain,
|
objectFit: ImageFit.Contain,
|
||||||
customGetImage: custom
|
customGetImage: custom,
|
||||||
|
transformation: new BlurTransformation(10)
|
||||||
}
|
}
|
||||||
}).width(100).height(100)
|
}).width(100).height(100)
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ struct TestPrefetchToFileCachePage {
|
||||||
build() {
|
build() {
|
||||||
Column() {
|
Column() {
|
||||||
ImageKnifeComponent({
|
ImageKnifeComponent({
|
||||||
ImageKnifeOption: this.imageKnifeOption
|
imageKnifeOption: this.imageKnifeOption
|
||||||
}).width(300).height(300)
|
}).width(300).height(300)
|
||||||
}
|
}
|
||||||
.height('100%') .width('100%')
|
.height('100%') .width('100%')
|
||||||
|
|
|
@ -59,19 +59,19 @@ export struct MsgItem {
|
||||||
build(){
|
build(){
|
||||||
if (this.count % 2 == 0 && this.count <6){
|
if (this.count % 2 == 0 && this.count <6){
|
||||||
ImageKnifeComponent({
|
ImageKnifeComponent({
|
||||||
ImageKnifeOption:{
|
imageKnifeOption:{
|
||||||
loadSrc:$r("app.media.startIcon")
|
loadSrc:$r("app.media.startIcon")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}else if (this.count > 6 && this.count - 6 < this.data.length){
|
}else if (this.count > 6 && this.count - 6 < this.data.length){
|
||||||
ImageKnifeComponent({
|
ImageKnifeComponent({
|
||||||
ImageKnifeOption:{
|
imageKnifeOption:{
|
||||||
loadSrc:this.data[this.count - 6],
|
loadSrc:this.data[this.count - 6],
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}else {
|
}else {
|
||||||
ImageKnifeComponent({
|
ImageKnifeComponent({
|
||||||
ImageKnifeOption:{
|
imageKnifeOption:{
|
||||||
loadSrc:$r("app.media.loading")
|
loadSrc:$r("app.media.loading")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -73,7 +73,7 @@ struct TestIsUrlExist {
|
||||||
}.margin({ top: 10 })
|
}.margin({ top: 10 })
|
||||||
|
|
||||||
ImageKnifeComponent({
|
ImageKnifeComponent({
|
||||||
ImageKnifeOption: this.imageKnifeOption
|
imageKnifeOption: this.imageKnifeOption
|
||||||
}).width(200).height(200).margin({ top: 10 })
|
}).width(200).height(200).margin({ top: 10 })
|
||||||
Image(this.source).margin({ top: 10 })
|
Image(this.source).margin({ top: 10 })
|
||||||
.width(200).height(200)
|
.width(200).height(200)
|
||||||
|
|
|
@ -34,7 +34,7 @@ struct TestPrefetchToFileCachePage {
|
||||||
this.imageKnifeOption.loadSrc = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658"
|
this.imageKnifeOption.loadSrc = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658"
|
||||||
})
|
})
|
||||||
ImageKnifeComponent({
|
ImageKnifeComponent({
|
||||||
ImageKnifeOption: this.imageKnifeOption
|
imageKnifeOption: this.imageKnifeOption
|
||||||
}).width(300).height(300).margin({top:30})
|
}).width(300).height(300).margin({top:30})
|
||||||
}
|
}
|
||||||
.height('100%') .width('100%')
|
.height('100%') .width('100%')
|
||||||
|
|
|
@ -31,7 +31,7 @@ struct TransformPage {
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
Column() {
|
Column() {
|
||||||
ImageKnifeComponent({ ImageKnifeOption: this.ImageKnifeOption }).height(200).width(200)
|
ImageKnifeComponent({ imageKnifeOption: this.ImageKnifeOption }).height(200).width(200)
|
||||||
.transform(this.matrix1)
|
.transform(this.matrix1)
|
||||||
// Image($r('app.media.rabbit')).objectFit(ImageFit.Contain).height(200).width(200).transform(this.matrix1)
|
// Image($r('app.media.rabbit')).objectFit(ImageFit.Contain).height(200).width(200).transform(this.matrix1)
|
||||||
Button("放大").onClick(()=>{
|
Button("放大").onClick(()=>{
|
||||||
|
|
|
@ -63,7 +63,7 @@ export struct UserAvatar {
|
||||||
Row() {
|
Row() {
|
||||||
// Image(this.imageKnifeOption.loadSrc)
|
// Image(this.imageKnifeOption.loadSrc)
|
||||||
|
|
||||||
ImageKnifeComponent({ ImageKnifeOption: this.ImageKnifeOption })
|
ImageKnifeComponent({ imageKnifeOption: this.ImageKnifeOption })
|
||||||
.borderRadius(this.radius)
|
.borderRadius(this.radius)
|
||||||
.clip(true)
|
.clip(true)
|
||||||
.width(this.calcImgSize)
|
.width(this.calcImgSize)
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"pages/SignatureTestPage",
|
"pages/SignatureTestPage",
|
||||||
"pages/TestPrefetchToFileCache",
|
"pages/TestPrefetchToFileCache",
|
||||||
"pages/TestIsUrlExist",
|
"pages/TestIsUrlExist",
|
||||||
"pages/TestHeader"
|
"pages/TestHeader",
|
||||||
|
"pages/ImageTransformation"
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -16,6 +16,12 @@ export { ObjectKey } from './src/main/ets/model/ObjectKey'
|
||||||
|
|
||||||
export { ImageKnifeData , ReadCacheStrategyType} from "./src/main/ets/model/ImageKnifeData"
|
export { ImageKnifeData , ReadCacheStrategyType} from "./src/main/ets/model/ImageKnifeData"
|
||||||
|
|
||||||
|
export { PixelMapTransformation } from './src/main/ets/transform/PixelMapTransformation'
|
||||||
|
|
||||||
|
export { MultiTransTransformation } from './src/main/ets/transform/MultiTransTransformation'
|
||||||
|
|
||||||
|
export { BrightnessTransformation } from './src/main/ets/transform/BrightnessTransformation'
|
||||||
|
|
||||||
|
export { BlurTransformation } from './src/main/ets/transform/BlurTransformation'
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ export class ImageKnife {
|
||||||
let imageKnifeOption = new ImageKnifeOption()
|
let imageKnifeOption = new ImageKnifeOption()
|
||||||
imageKnifeOption.loadSrc = loadSrc
|
imageKnifeOption.loadSrc = loadSrc
|
||||||
let engineKeyImpl: IEngineKey = new DefaultEngineKey()
|
let engineKeyImpl: IEngineKey = new DefaultEngineKey()
|
||||||
let keys = engineKeyImpl.generateCacheKey(loadSrc)
|
let keys = engineKeyImpl.generateMemoryKey(loadSrc, imageKnifeOption)
|
||||||
let cachePath = ImageKnife.getInstance().getFileCache().getFileToPath(keys)
|
let cachePath = ImageKnife.getInstance().getFileCache().getFileToPath(keys)
|
||||||
if(cachePath == null || cachePath == "" || cachePath == undefined) {
|
if(cachePath == null || cachePath == "" || cachePath == undefined) {
|
||||||
let request = new ImageKnifeRequest(
|
let request = new ImageKnifeRequest(
|
||||||
|
@ -156,26 +156,33 @@ export class ImageKnife {
|
||||||
* @param cacheType 缓存策略
|
* @param cacheType 缓存策略
|
||||||
* @returns 图片数据
|
* @returns 图片数据
|
||||||
*/
|
*/
|
||||||
getCacheImage(loadSrc: string, cacheType: ReadCacheStrategyType = ReadCacheStrategyType.Default):Promise<ImageKnifeData | undefined> {
|
getCacheImage(loadSrc: string,
|
||||||
return new Promise((resolve,reject)=>{
|
cacheType: ReadCacheStrategyType = ReadCacheStrategyType.Default): Promise<ImageKnifeData | undefined> {
|
||||||
|
let option: ImageKnifeOption = {
|
||||||
|
loadSrc: loadSrc
|
||||||
|
}
|
||||||
let engineKeyImpl: IEngineKey = new DefaultEngineKey()
|
let engineKeyImpl: IEngineKey = new DefaultEngineKey()
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
if (cacheType == ReadCacheStrategyType.Memory) {
|
if (cacheType == ReadCacheStrategyType.Memory) {
|
||||||
resolve(this.ReadMemoryCache(loadSrc,engineKeyImpl))
|
resolve(this.readMemoryCache(loadSrc, option, engineKeyImpl))
|
||||||
} else if (cacheType == ReadCacheStrategyType.File) {
|
} else if (cacheType == ReadCacheStrategyType.File) {
|
||||||
this.ReadFileCache(loadSrc,engineKeyImpl,resolve)
|
this.readFileCache(loadSrc, engineKeyImpl, resolve)
|
||||||
} else {
|
} else {
|
||||||
let data = this.ReadMemoryCache(loadSrc,engineKeyImpl)
|
let data = this.readMemoryCache(loadSrc, option, engineKeyImpl)
|
||||||
data == undefined ? this.ReadFileCache(loadSrc,engineKeyImpl,resolve) : data
|
data == undefined ? this.readFileCache(loadSrc, engineKeyImpl, resolve) : data
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ReadMemoryCache(loadSrc:string,engineKey:IEngineKey): ImageKnifeData | undefined{
|
|
||||||
let keys = engineKey.generateCacheKey(loadSrc)
|
private readMemoryCache(loadSrc: string,option: ImageKnifeOption, engineKey: IEngineKey): ImageKnifeData | undefined {
|
||||||
|
let keys = engineKey.generateMemoryKey(loadSrc,option)
|
||||||
return ImageKnife.getInstance()
|
return ImageKnife.getInstance()
|
||||||
.loadFromMemoryCache(keys)
|
.loadFromMemoryCache(keys)
|
||||||
}
|
}
|
||||||
ReadFileCache(loadSrc:string,engineKey:IEngineKey,onComplete:(data:ImageKnifeData | undefined)=>void){
|
|
||||||
let keys = engineKey.generateCacheKey(loadSrc)
|
private readFileCache(loadSrc:string,engineKey:IEngineKey,onComplete:(data:ImageKnifeData | undefined)=>void){
|
||||||
|
let keys = engineKey.generateFileKey(loadSrc)
|
||||||
let buffer = ImageKnife.getInstance().loadFromFileCache(keys)
|
let buffer = ImageKnife.getInstance().loadFromFileCache(keys)
|
||||||
if(buffer != undefined) {
|
if(buffer != undefined) {
|
||||||
let fileTypeUtil = new FileTypeUtil();
|
let fileTypeUtil = new FileTypeUtil();
|
||||||
|
|
|
@ -34,6 +34,7 @@ import util from '@ohos.util';
|
||||||
import { IEngineKey } from './key/IEngineKey';
|
import { IEngineKey } from './key/IEngineKey';
|
||||||
import { DefaultEngineKey } from './key/DefaultEngineKey';
|
import { DefaultEngineKey } from './key/DefaultEngineKey';
|
||||||
import { HeaderOptions } from './ImageKnifeOption';
|
import { HeaderOptions } from './ImageKnifeOption';
|
||||||
|
import { PixelMapTransformation } from './transform/PixelMapTransformation';
|
||||||
|
|
||||||
export class ImageKnifeDispatcher {
|
export class ImageKnifeDispatcher {
|
||||||
// 最大并发
|
// 最大并发
|
||||||
|
@ -47,7 +48,7 @@ export class ImageKnifeDispatcher {
|
||||||
|
|
||||||
showFromMemomry(request: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource): boolean {
|
showFromMemomry(request: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource): boolean {
|
||||||
let memoryCache: ImageKnifeData | undefined = ImageKnife.getInstance()
|
let memoryCache: ImageKnifeData | undefined = ImageKnife.getInstance()
|
||||||
.loadFromMemoryCache(this.engineKeyImpl.generateCacheKey(imageSrc, request.ImageKnifeOption.signature))
|
.loadFromMemoryCache(this.engineKeyImpl.generateMemoryKey(imageSrc, request.ImageKnifeOption))
|
||||||
if (memoryCache !== undefined) {
|
if (memoryCache !== undefined) {
|
||||||
// 画主图
|
// 画主图
|
||||||
if (request.requestState === ImageKnifeRequestState.PROGRESS) {
|
if (request.requestState === ImageKnifeRequestState.PROGRESS) {
|
||||||
|
@ -96,12 +97,13 @@ export class ImageKnifeDispatcher {
|
||||||
* 获取和显示图片
|
* 获取和显示图片
|
||||||
*/
|
*/
|
||||||
getAndShowImage(currentRequest: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource): void {
|
getAndShowImage(currentRequest: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource): void {
|
||||||
let key: string = this.engineKeyImpl.generateCacheKey(imageSrc, currentRequest.ImageKnifeOption.signature)
|
let keyMemory: string = this.engineKeyImpl.generateMemoryKey(imageSrc, currentRequest.ImageKnifeOption)
|
||||||
let requestList: List<ImageKnifeRequestWithSource> | undefined = this.executingJobMap.get(key)
|
let keyFile: string = this.engineKeyImpl.generateFileKey(imageSrc, currentRequest.ImageKnifeOption.signature)
|
||||||
|
let requestList: List<ImageKnifeRequestWithSource> | undefined = this.executingJobMap.get(keyMemory)
|
||||||
if (requestList == undefined) {
|
if (requestList == undefined) {
|
||||||
requestList = new List()
|
requestList = new List()
|
||||||
requestList.add({ request: currentRequest, source: requestSource })
|
requestList.add({ request: currentRequest, source: requestSource })
|
||||||
this.executingJobMap.set(key, requestList)
|
this.executingJobMap.set(keyMemory, requestList)
|
||||||
} else {
|
} else {
|
||||||
requestList.add({ request: currentRequest, source: requestSource })
|
requestList.add({ request: currentRequest, source: requestSource })
|
||||||
return
|
return
|
||||||
|
@ -110,11 +112,12 @@ export class ImageKnifeDispatcher {
|
||||||
let request: RequestJobRequest = {
|
let request: RequestJobRequest = {
|
||||||
context: currentRequest.context,
|
context: currentRequest.context,
|
||||||
src: imageSrc,
|
src: imageSrc,
|
||||||
key: key,
|
key: keyFile,
|
||||||
headers:currentRequest.ImageKnifeOption.headerOption,
|
headers:currentRequest.ImageKnifeOption.headerOption,
|
||||||
allHeaders:currentRequest.headers,
|
allHeaders:currentRequest.headers,
|
||||||
customGetImage: currentRequest.ImageKnifeOption.customGetImage,
|
customGetImage: currentRequest.ImageKnifeOption.customGetImage,
|
||||||
onlyRetrieveFromCache: currentRequest.ImageKnifeOption.onlyRetrieveFromCache,
|
onlyRetrieveFromCache: currentRequest.ImageKnifeOption.onlyRetrieveFromCache,
|
||||||
|
transformation:currentRequest.ImageKnifeOption.transformation,
|
||||||
requestSource
|
requestSource
|
||||||
}
|
}
|
||||||
// 启动线程下载和解码主图
|
// 启动线程下载和解码主图
|
||||||
|
@ -140,15 +143,15 @@ export class ImageKnifeDispatcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.executingJobMap.remove(key)
|
this.executingJobMap.remove(keyMemory)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LogUtil.log("error: no requestlist need to draw for key = " + key)
|
LogUtil.log("error: no requestlist need to draw for key = " + keyMemory)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 保存文件缓存
|
// 保存文件缓存
|
||||||
if (requestJobResult.bufferSize > 0 && currentRequest.ImageKnifeOption.writeCacheStrategy !== WriteCacheStrategyType.Memory) {
|
if (requestJobResult.bufferSize > 0 && currentRequest.ImageKnifeOption.writeCacheStrategy !== WriteCacheStrategyType.Memory) {
|
||||||
ImageKnife.getInstance().saveWithoutWriteFile(key, requestJobResult.bufferSize)
|
ImageKnife.getInstance().saveWithoutWriteFile(keyFile, requestJobResult.bufferSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
let ImageKnifeData: ImageKnifeData = {
|
let ImageKnifeData: ImageKnifeData = {
|
||||||
|
@ -160,7 +163,7 @@ export class ImageKnifeDispatcher {
|
||||||
// 保存内存缓存
|
// 保存内存缓存
|
||||||
if(currentRequest.ImageKnifeOption.writeCacheStrategy !== WriteCacheStrategyType.File) {
|
if(currentRequest.ImageKnifeOption.writeCacheStrategy !== WriteCacheStrategyType.File) {
|
||||||
ImageKnife.getInstance()
|
ImageKnife.getInstance()
|
||||||
.saveMemoryCache(this.engineKeyImpl.generateCacheKey(imageSrc, currentRequest.ImageKnifeOption.signature),
|
.saveMemoryCache(this.engineKeyImpl.generateMemoryKey(imageSrc, currentRequest.ImageKnifeOption),
|
||||||
ImageKnifeData)
|
ImageKnifeData)
|
||||||
}
|
}
|
||||||
if (requestList !== undefined) {
|
if (requestList !== undefined) {
|
||||||
|
@ -186,11 +189,11 @@ export class ImageKnifeDispatcher {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.executingJobMap.remove(key)
|
this.executingJobMap.remove(keyMemory)
|
||||||
this.dispatchNextJob()
|
this.dispatchNextJob()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LogUtil.log("error: no requestlist need to draw for key = " + key)
|
LogUtil.log("error: no requestlist need to draw for key = " + keyMemory)
|
||||||
}
|
}
|
||||||
// })
|
// })
|
||||||
|
|
||||||
|
@ -359,6 +362,11 @@ async function requestJob(request: RequestJobRequest): Promise<RequestJobResult
|
||||||
imageSource.release()
|
imageSource.release()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 图形变化
|
||||||
|
if (request.requestSource == 0 && request.transformation !== undefined) {
|
||||||
|
resPixelmap = await request.transformation?.transform(request.context, resPixelmap!, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pixelMap: resPixelmap,
|
pixelMap: resPixelmap,
|
||||||
bufferSize: bufferSize
|
bufferSize: bufferSize
|
||||||
|
@ -392,4 +400,5 @@ interface RequestJobRequest {
|
||||||
customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>,
|
customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>,
|
||||||
onlyRetrieveFromCache?: boolean
|
onlyRetrieveFromCache?: boolean
|
||||||
requestSource:ImageKnifeRequestSource
|
requestSource:ImageKnifeRequestSource
|
||||||
|
transformation?: PixelMapTransformation
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@ import taskpool from '@ohos.taskpool';
|
||||||
import common from '@ohos.app.ability.common'
|
import common from '@ohos.app.ability.common'
|
||||||
import { ObjectKey } from './model/ObjectKey';
|
import { ObjectKey } from './model/ObjectKey';
|
||||||
import { WriteCacheStrategyType } from './model/ImageKnifeData';
|
import { WriteCacheStrategyType } from './model/ImageKnifeData';
|
||||||
|
import { PixelMapTransformation } from './transform/PixelMapTransformation';
|
||||||
|
|
||||||
export interface HeaderOptions {
|
export interface HeaderOptions {
|
||||||
key: string;
|
key: string;
|
||||||
value: Object;
|
value: Object;
|
||||||
|
@ -50,6 +52,8 @@ export class ImageKnifeOption {
|
||||||
|
|
||||||
progressListener?: (progress: number)=>void;
|
progressListener?: (progress: number)=>void;
|
||||||
|
|
||||||
|
transformation?: PixelMapTransformation
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,14 +17,10 @@ import { ImageKnifeRequest, ImageKnifeRequestState } from '../ImageKnifeRequest'
|
||||||
import common from '@ohos.app.ability.common';
|
import common from '@ohos.app.ability.common';
|
||||||
import { ImageKnife } from '../ImageKnife';
|
import { ImageKnife } from '../ImageKnife';
|
||||||
import { LogUtil } from '../utils/LogUtil';
|
import { LogUtil } from '../utils/LogUtil';
|
||||||
import componentUtils from '@ohos.arkui.componentUtils'
|
|
||||||
import util from '@ohos.util'
|
|
||||||
import inspector from '@ohos.arkui.inspector'
|
|
||||||
import { ImageKnifeData } from '../model/ImageKnifeData'
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
export struct ImageKnifeComponent {
|
export struct ImageKnifeComponent {
|
||||||
@Watch('watchImageKnifeOption') @ObjectLink ImageKnifeOption: ImageKnifeOption;
|
@Watch('watchImageKnifeOption') @ObjectLink imageKnifeOption: ImageKnifeOption;
|
||||||
@State pixelMap: PixelMap | string | undefined = undefined
|
@State pixelMap: PixelMap | string | undefined = undefined
|
||||||
@State adaptiveWidth: Length = '100%'
|
@State adaptiveWidth: Length = '100%'
|
||||||
@State adaptiveHeight: Length = '100%'
|
@State adaptiveHeight: Length = '100%'
|
||||||
|
@ -66,10 +62,10 @@ export struct ImageKnifeComponent {
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
Image(this.pixelMap)
|
Image(this.pixelMap)
|
||||||
.objectFit(this.ImageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.ImageKnifeOption.objectFit)
|
.objectFit(this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit)
|
||||||
.width(this.adaptiveWidth)
|
.width(this.adaptiveWidth)
|
||||||
.height(this.adaptiveHeight)
|
.height(this.adaptiveHeight)
|
||||||
.border(this.ImageKnifeOption.border)
|
.border(this.imageKnifeOption.border)
|
||||||
.onSizeChange((oldValue:SizeOptions, newValue:SizeOptions) => {
|
.onSizeChange((oldValue:SizeOptions, newValue:SizeOptions) => {
|
||||||
this.currentWidth = newValue.width as number
|
this.currentWidth = newValue.width as number
|
||||||
this.currentHeight = newValue.height as number
|
this.currentHeight = newValue.height as number
|
||||||
|
@ -106,8 +102,8 @@ export struct ImageKnifeComponent {
|
||||||
getRequest(width: number, height: number): ImageKnifeRequest {
|
getRequest(width: number, height: number): ImageKnifeRequest {
|
||||||
if (this.request == undefined) {
|
if (this.request == undefined) {
|
||||||
this.request = new ImageKnifeRequest(
|
this.request = new ImageKnifeRequest(
|
||||||
this.ImageKnifeOption,
|
this.imageKnifeOption,
|
||||||
this.ImageKnifeOption.context !== undefined ? this.ImageKnifeOption.context : this.getCurrentContext(),
|
this.imageKnifeOption.context !== undefined ? this.imageKnifeOption.context : this.getCurrentContext(),
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
this.componentVersion,
|
this.componentVersion,
|
||||||
|
@ -118,7 +114,7 @@ export struct ImageKnifeComponent {
|
||||||
}
|
}
|
||||||
this.pixelMap = pixelMap
|
this.pixelMap = pixelMap
|
||||||
if (typeof this.pixelMap !== 'string') {
|
if (typeof this.pixelMap !== 'string') {
|
||||||
if (this.ImageKnifeOption.objectFit === ImageFit.Auto) {
|
if (this.imageKnifeOption.objectFit === ImageFit.Auto) {
|
||||||
let info = await this.pixelMap.getImageInfo()
|
let info = await this.pixelMap.getImageInfo()
|
||||||
|
|
||||||
this.adaptiveWidth = this.currentWidth
|
this.adaptiveWidth = this.currentWidth
|
||||||
|
|
|
@ -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');
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
@ -14,34 +14,51 @@
|
||||||
*/
|
*/
|
||||||
import util from '@ohos.util';
|
import util from '@ohos.util';
|
||||||
import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5';
|
import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5';
|
||||||
import { ObjectKey } from '../model/ObjectKey';
|
import { ImageKnifeOption } from '../ImageKnifeOption';
|
||||||
import { IEngineKey } from './IEngineKey';
|
import { IEngineKey } from './IEngineKey';
|
||||||
|
import { ObjectKey } from '../model/ObjectKey';
|
||||||
|
import { PixelMapTransformation } from '../transform/PixelMapTransformation';
|
||||||
|
|
||||||
export class DefaultEngineKey implements IEngineKey {
|
export class DefaultEngineKey implements IEngineKey {
|
||||||
|
private memoryKeyCache: util.LRUCache<string, string> = new util.LRUCache(1024)
|
||||||
|
private fileKeyCache: util.LRUCache<string, string> = new util.LRUCache(1024)
|
||||||
|
|
||||||
private keyCache: util.LRUCache<string,string> = new util.LRUCache(1024)
|
// 生成内存缓存key
|
||||||
|
generateMemoryKey(loadSrc: string | PixelMap | Resource, imageKnifeOption: ImageKnifeOption): string {
|
||||||
// 生成内存缓存
|
let src = "loadSrc=" + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";"
|
||||||
generateCacheKey(loadSrc: string | PixelMap | Resource, signature?: ObjectKey | undefined): string {
|
if (imageKnifeOption.signature) {
|
||||||
let key = "loadSrc=" + this.generateKey(loadSrc) + ";";
|
src += "signature=" + imageKnifeOption.signature.getKey() + ";"
|
||||||
if (signature) {
|
|
||||||
key += "signature=" + signature.getKey() + ";"
|
|
||||||
}
|
}
|
||||||
return key;
|
if (imageKnifeOption.transformation) {
|
||||||
|
src += "transformation=" + this.getTransformation(imageKnifeOption.transformation) + ";"
|
||||||
|
}
|
||||||
|
return this.generateKey(src, this.memoryKeyCache)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成文件缓存key
|
||||||
|
generateFileKey(loadSrc: string | PixelMap | Resource, signature?: ObjectKey | undefined): string {
|
||||||
|
let src = "loadSrc=" + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";"
|
||||||
|
if (signature) {
|
||||||
|
src += "signature=" + signature.getKey() + ";"
|
||||||
|
}
|
||||||
|
return this.generateKey(src, this.fileKeyCache)
|
||||||
}
|
}
|
||||||
|
|
||||||
// key缓存策略,避免无意义的 JSON.stringify
|
// key缓存策略,避免无意义的 JSON.stringify
|
||||||
private generateKey(key: string | PixelMap | Resource): string {
|
private generateKey(keyCache: string, cache: util.LRUCache<string, string>): string {
|
||||||
let keyCache = typeof key == "string" ? key : JSON.stringify(key)
|
let result = cache.get(keyCache)
|
||||||
let result = this.keyCache.get(keyCache)
|
|
||||||
if (result != undefined) {
|
if (result != undefined) {
|
||||||
return result
|
return result
|
||||||
} else {
|
} else {
|
||||||
result = SparkMD5.hashBinary(keyCache)
|
result = SparkMD5.hashBinary(keyCache)
|
||||||
this.keyCache.put(keyCache, result)
|
cache.put(keyCache, result)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getTransformation(transformation: PixelMapTransformation): string {
|
||||||
|
return transformation.getName()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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');
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
@ -12,11 +12,15 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
import { ImageKnifeOption } from '../ImageKnifeOption'
|
||||||
import { ObjectKey } from '../model/ObjectKey'
|
import { ObjectKey } from '../model/ObjectKey'
|
||||||
|
|
||||||
export interface IEngineKey {
|
export interface IEngineKey {
|
||||||
// 生成缓存key
|
// 生成内存缓存key
|
||||||
generateCacheKey(loadSrc: string | PixelMap | Resource, signature?: ObjectKey | undefined): string
|
generateMemoryKey(loadSrc: string | PixelMap | Resource, imageKnifeOption: ImageKnifeOption): string
|
||||||
|
|
||||||
|
// 生成文件缓存key
|
||||||
|
generateFileKey(loadSrc: string | PixelMap | Resource, signature?: ObjectKey | undefined): string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||||
|
import effectKit from '@ohos.effectKit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片变换:模糊效果
|
||||||
|
*/
|
||||||
|
@Sendable
|
||||||
|
export class BlurTransformation extends PixelMapTransformation {
|
||||||
|
private radius: number // 模糊半径,单位是像素。模糊效果与所设置的值成正比,值越大效果越明显。
|
||||||
|
|
||||||
|
constructor(radius: number) {
|
||||||
|
super()
|
||||||
|
this.radius = 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,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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,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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue