1.属性改为小写imageKnifeOption

2.支持使用一个或多个图片变换,如模糊,高亮等

Signed-off-by: madixin <madixin@huawei.com>
This commit is contained in:
madixin 2024-05-03 14:10:54 +08:00
parent be0f5ff8ef
commit 00f5e81571
29 changed files with 464 additions and 117 deletions

View File

@ -1,3 +1,7 @@
## 3.0.0-rc.2
- 新增支持使用一个或多个图片变换,如模糊,高亮等
## 3.0.0-rc.1 ## 3.0.0-rc.1
- 新增从内存或文件缓存获取图片数据接口getCacheImage - 新增从内存或文件缓存获取图片数据接口getCacheImage
- 新增图片预加载preLoadCache并返回文件缓存路径 - 新增图片预加载preLoadCache并返回文件缓存路径

View File

@ -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自会图片
- mainScaleTypeborder等参数新版本与系统Image保持一致 - mainScaleTypeborder等参数新版本与系统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 |
## 约束与限制 ## 约束与限制

View File

@ -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()
}
} }

View File

@ -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
}
}
}

View File

@ -87,6 +87,13 @@ struct Index {
}); });
}) })
Button("图片变换").margin({top:10}).onClick(()=>{
router.push({
uri: 'pages/ImageTransformation',
});
})
} }
.width('100%') .width('100%')

View File

@ -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%')

View File

@ -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"),

View File

@ -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,

View File

@ -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)
} }

View File

@ -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)
} }

View File

@ -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%')

View File

@ -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")
} }
}) })

View File

@ -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)

View File

@ -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%')

View File

@ -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(()=>{

View File

@ -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)

View File

@ -11,6 +11,7 @@
"pages/SignatureTestPage", "pages/SignatureTestPage",
"pages/TestPrefetchToFileCache", "pages/TestPrefetchToFileCache",
"pages/TestIsUrlExist", "pages/TestIsUrlExist",
"pages/TestHeader" "pages/TestHeader",
"pages/ImageTransformation"
] ]
} }

View File

@ -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'

View File

@ -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();

View File

@ -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
} }

View File

@ -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() {
} }

View File

@ -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

View File

@ -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()
}
} }

View File

@ -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
} }

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}