支持多种组合变换
Signed-off-by: zhang_hanyong <zhang_hanyong@h-partners.com>
This commit is contained in:
parent
27094f0db9
commit
52e5d1f5bf
|
@ -1,3 +1,6 @@
|
||||||
|
## 3.0.0-rc.6
|
||||||
|
- 支持多种组合变换
|
||||||
|
|
||||||
## 3.0.0-rc.5
|
## 3.0.0-rc.5
|
||||||
- 图片加载事件增加请求开始的回调,以及修复有缓存时,没有回调的bug
|
- 图片加载事件增加请求开始的回调,以及修复有缓存时,没有回调的bug
|
||||||
- 修复对已销毁组件不再下发请求的逻辑
|
- 修复对已销毁组件不再下发请求的逻辑
|
||||||
|
|
51
README.md
51
README.md
|
@ -147,6 +147,26 @@ ImageKnifeComponent({ ImageKnifeOption:
|
||||||
}
|
}
|
||||||
}).width(100).height(100)
|
}).width(100).height(100)
|
||||||
```
|
```
|
||||||
|
多种组合变换用法
|
||||||
|
|
||||||
|
```
|
||||||
|
let transformations: collections.Array<PixelMapTransformation> = new collections.Array<PixelMapTransformation>();
|
||||||
|
transformations.push(new BlurTransformation(5));
|
||||||
|
transformations.push(new BrightnessTransformation(0.2));
|
||||||
|
ImageKnifeComponent({
|
||||||
|
{
|
||||||
|
loadSrc: $r('app.media.pngSample'),
|
||||||
|
placeholderSrc: $r("app.media.loading"),
|
||||||
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
objectFit: ImageFit.Contain,
|
||||||
|
border: { radius: { topLeft: 50, bottomRight: 50 } }, // 圆角设置
|
||||||
|
transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined // 图形变换组
|
||||||
|
}
|
||||||
|
}).width(300)
|
||||||
|
.height(300)
|
||||||
|
.rotate({ angle: 90 }) // 旋转90度
|
||||||
|
.contrast(12) // 对比度滤波器
|
||||||
|
```
|
||||||
|
|
||||||
#### 8.监听图片加载成功与失败
|
#### 8.监听图片加载成功与失败
|
||||||
|
|
||||||
|
@ -210,7 +230,38 @@ ImageKnifeComponent({ ImageKnifeOption:
|
||||||
| putCacheImage | url: string, pixelMap: PixelMap, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string | 写入内存磁盘缓存 |
|
| putCacheImage | url: string, pixelMap: PixelMap, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string | 写入内存磁盘缓存 |
|
||||||
| removeMemoryCache| url: string | ImageKnifeOption | 清理指定内存缓存 |
|
| removeMemoryCache| url: string | ImageKnifeOption | 清理指定内存缓存 |
|
||||||
| removeFileCache | url: string | ImageKnifeOption | 清理指定磁盘缓存 |
|
| removeFileCache | url: string | ImageKnifeOption | 清理指定磁盘缓存 |
|
||||||
|
### 图形变换类型(需要为GPUImage添加依赖项)
|
||||||
|
|
||||||
|
| 类型 | 相关描述 |
|
||||||
|
| ---------------------------------- | ----------------------------- |
|
||||||
|
| BlurTransformation | 模糊处理 |
|
||||||
|
| BrightnessTransformation | 亮度滤波器 |
|
||||||
|
| CropCircleTransformation | 圆形剪裁显示 |
|
||||||
|
| CropCircleWithBorderTransformation | 圆环展示 |
|
||||||
|
| CropSquareTransformation | 正方形剪裁 |
|
||||||
|
| CropTransformation | 自定义矩形剪裁 |
|
||||||
|
| GrayScaleTransformation | 灰度级滤波器 |
|
||||||
|
| InvertTransformation | 反转滤波器 |
|
||||||
|
| KuwaharaTransformation | 桑原滤波器(使用GPUIImage) |
|
||||||
|
| MaskTransformation | 遮罩 |
|
||||||
|
| PixelationTransformation | 像素化滤波器(使用GPUIImage) |
|
||||||
|
| SepiaTransformation | 乌墨色滤波器(使用GPUIImage) |
|
||||||
|
| SketchTransformation | 素描滤波器(使用GPUIImage) |
|
||||||
|
| SwirlTransformation | 扭曲滤波器(使用GPUIImage) |
|
||||||
|
| ToonTransformation | 动画滤波器(使用GPUIImage) |
|
||||||
|
| VignetterTransformation | 装饰滤波器(使用GPUIImage) |
|
||||||
|
|
||||||
|
## 下载安装GPUImage依赖
|
||||||
|
方法一:在Terminal窗口中,执行如下命令安装三方包,DevEco Studio会自动在工程的oh-package.json5中自动添加三方包依赖。
|
||||||
|
```
|
||||||
|
ohpm install @ohos/gpu_transform
|
||||||
|
```
|
||||||
|
方法二: 在工程的oh-package.json5中设置三方包依赖,配置示例如下:
|
||||||
|
```
|
||||||
|
"dependencies": {
|
||||||
|
"@ohos/gpu_transform": "^1.0.2"
|
||||||
|
}
|
||||||
|
```
|
||||||
## 约束与限制
|
## 约束与限制
|
||||||
|
|
||||||
在下述版本验证通过:
|
在下述版本验证通过:
|
||||||
|
|
|
@ -1,82 +1,417 @@
|
||||||
import { BlurTransformation, BrightnessTransformation, ImageKnifeComponent, ImageKnifeOption,
|
import {
|
||||||
|
BlurTransformation,
|
||||||
|
BrightnessTransformation,
|
||||||
|
CropCircleTransformation,
|
||||||
|
CropCircleWithBorderTransformation,
|
||||||
|
CropSquareTransformation,
|
||||||
|
CropTransformation,
|
||||||
|
GrayScaleTransformation,
|
||||||
|
ImageKnifeComponent,
|
||||||
|
ImageKnifeOption,
|
||||||
|
InvertTransformation,
|
||||||
|
KuwaharaTransformation,
|
||||||
|
MaskTransformation,
|
||||||
MultiTransTransformation,
|
MultiTransTransformation,
|
||||||
PixelMapTransformation } from '@ohos/libraryimageknife'
|
PixelationTransformation,
|
||||||
|
PixelMapTransformation,
|
||||||
|
SepiaTransformation,
|
||||||
|
SketchTransformation,
|
||||||
|
SwirlTransformation,
|
||||||
|
ToonTransformation,
|
||||||
|
VignetterTransformation
|
||||||
|
} from '@ohos/imageknife';
|
||||||
import { collections } from '@kit.ArkTS'
|
import { collections } from '@kit.ArkTS'
|
||||||
|
|
||||||
@Entry
|
@Entry
|
||||||
@Component
|
@Component
|
||||||
struct ImageTransformation {
|
struct ImageTransformation {
|
||||||
@State imageKnifeOption: ImageKnifeOption = {
|
@State imageKnifeOption: ImageKnifeOption = {
|
||||||
loadSrc: "http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
|
loadSrc: $r('app.media.pngSample'),
|
||||||
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
|
||||||
}
|
}
|
||||||
|
@State isRound: boolean = false;
|
||||||
|
@State isContrast: boolean = false;
|
||||||
|
@State isRotate: boolean = false;
|
||||||
isBlur: boolean = false
|
isBlur: boolean = false
|
||||||
isBrightness: boolean = false
|
isBrightness: boolean = false
|
||||||
|
isGrayScale: boolean = false;
|
||||||
|
isInvert: boolean = false;
|
||||||
|
isToon: boolean = false;
|
||||||
|
isCropCircle: boolean = false;
|
||||||
|
isCropCircleWithBorder: boolean = false;
|
||||||
|
isKuwahara: boolean = false;
|
||||||
|
isPixelation: boolean = false;
|
||||||
|
isSketch: boolean = false;
|
||||||
|
isSwirl: boolean = false;
|
||||||
|
isVignetter: boolean = false;
|
||||||
|
isCropSquare: boolean = false;
|
||||||
|
isCropTop: boolean = false;
|
||||||
|
isCropCenter: boolean = false;
|
||||||
|
isCropBottom: boolean = false;
|
||||||
|
isMask: boolean = false;
|
||||||
|
isSepia: boolean = false;
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
Column() {
|
Scroll() {
|
||||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
Column() {
|
||||||
Checkbox({ name: 'checkbox1', group: 'checkboxGroup' })
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
.selectedColor(0x39a2db)
|
Checkbox({ name: 'checkbox1', group: 'checkboxGroup' })
|
||||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
.selectedColor(0x39a2db)
|
||||||
.onChange((value: boolean) => {
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
this.isBlur = value
|
.onChange((value: boolean) => {
|
||||||
this.upedateImageKnifeOption()
|
this.isBlur = value;
|
||||||
})
|
this.updateImageKnifeOption();
|
||||||
.width(30)
|
})
|
||||||
.height(30)
|
.width(30)
|
||||||
Text('模糊效果').fontSize(20)
|
.height(30)
|
||||||
}
|
Text('模糊效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
Checkbox({ name: 'checkbox2', group: 'checkboxGroup' })
|
Checkbox({ name: 'checkbox2', group: 'checkboxGroup' })
|
||||||
.selectedColor(0x39a2db)
|
.selectedColor(0x39a2db)
|
||||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
.onChange((value: boolean) => {
|
.onChange((value: boolean) => {
|
||||||
this.isBrightness = value
|
this.isBrightness = value;
|
||||||
this.upedateImageKnifeOption()
|
this.updateImageKnifeOption();
|
||||||
})
|
})
|
||||||
.width(30)
|
.width(30)
|
||||||
.height(30)
|
.height(30)
|
||||||
Text('高亮效果').fontSize(20)
|
Text('高亮效果').fontSize(20)
|
||||||
}
|
}
|
||||||
|
|
||||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
Checkbox({ name: 'checkbox3', group: 'checkboxGroup' })
|
Checkbox({ name: 'checkbox3', group: 'checkboxGroup' })
|
||||||
.selectedColor(0x39a2db)
|
.selectedColor(0x39a2db)
|
||||||
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
.onChange((value: boolean) => {
|
.onChange((value: boolean) => {
|
||||||
console.info('Checkbox3 change is' + value)
|
this.isGrayScale = value;
|
||||||
})
|
this.updateImageKnifeOption();
|
||||||
.width(30)
|
})
|
||||||
.height(30)
|
.width(30)
|
||||||
Text('Checkbox3').fontSize(20)
|
.height(30)
|
||||||
}
|
Text('灰化效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
ImageKnifeComponent({
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
imageKnifeOption: this.imageKnifeOption
|
Checkbox({ name: 'checkbox4', group: 'checkboxGroup' })
|
||||||
}).width(300).height(300)
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isInvert = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('反转效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox5', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isToon = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('动画滤镜效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox6', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isCropCircle = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('裁剪圆形效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox7', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isCropCircleWithBorder = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('裁剪圆形带边框效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox8', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isContrast = value;
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('对比度效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox9', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isSepia = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('乌墨色滤波效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox10', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isRotate = value;
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('旋转效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox11', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isRound = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('圆角效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox12', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isKuwahara = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('桑原滤波效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox13', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isPixelation = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('像素化滤波效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox14', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isSketch = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('素描滤波效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox15', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isSwirl = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('扭曲滤波效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox16', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isVignetter = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('装饰滤波效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox17', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isCropSquare = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('正方形裁剪效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox18', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isCropTop = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('上方裁剪效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox19', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isCropCenter = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('中间裁剪效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox20', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isCropBottom = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('底下裁剪效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
||||||
|
Checkbox({ name: 'checkbox21', group: 'checkboxGroup' })
|
||||||
|
.selectedColor(0x39a2db)
|
||||||
|
.shape(CheckBoxShape.ROUNDED_SQUARE)
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
this.isMask = value;
|
||||||
|
this.updateImageKnifeOption();
|
||||||
|
})
|
||||||
|
.width(30)
|
||||||
|
.height(30)
|
||||||
|
Text('遮罩效果').fontSize(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isContrast) {
|
||||||
|
ImageKnifeComponent({
|
||||||
|
imageKnifeOption: this.imageKnifeOption
|
||||||
|
})
|
||||||
|
.width(300)
|
||||||
|
.height(300)
|
||||||
|
.rotate({ angle: this.isRotate ? 90 : 0 })
|
||||||
|
.contrast(12)
|
||||||
|
.backgroundColor(Color.Pink)
|
||||||
|
} else {
|
||||||
|
ImageKnifeComponent({
|
||||||
|
imageKnifeOption: this.imageKnifeOption
|
||||||
|
}).width(300)
|
||||||
|
.height(300)
|
||||||
|
.rotate({ angle: this.isRotate ? 90 : 0 })
|
||||||
|
.backgroundColor(Color.Pink)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.height('100%')
|
.height('100%')
|
||||||
.width('100%')
|
.width('100%')
|
||||||
}
|
}
|
||||||
|
|
||||||
upedateImageKnifeOption() {
|
updateImageKnifeOption() {
|
||||||
let transformations: collections.Array<PixelMapTransformation> = new collections.Array<PixelMapTransformation>()
|
let transformations: collections.Array<PixelMapTransformation> = new collections.Array<PixelMapTransformation>()
|
||||||
if (this.isBlur){
|
if (this.isBlur) {
|
||||||
transformations.push(new BlurTransformation(5))
|
transformations.push(new BlurTransformation(5));
|
||||||
}
|
}
|
||||||
if (this.isBrightness){
|
if (this.isBrightness) {
|
||||||
transformations.push(new BrightnessTransformation(0.2))
|
transformations.push(new BrightnessTransformation(0.2));
|
||||||
|
}
|
||||||
|
if (this.isGrayScale) {
|
||||||
|
transformations.push(new GrayScaleTransformation());
|
||||||
|
}
|
||||||
|
if (this.isInvert) {
|
||||||
|
transformations.push(new InvertTransformation());
|
||||||
|
}
|
||||||
|
if (this.isToon) {
|
||||||
|
transformations.push(new ToonTransformation(0.3, 10.0));
|
||||||
|
}
|
||||||
|
if (this.isCropCircle) {
|
||||||
|
transformations.push(new CropCircleTransformation());
|
||||||
|
}
|
||||||
|
if (this.isCropCircleWithBorder) {
|
||||||
|
transformations.push(new CropCircleWithBorderTransformation(16, { r_color: 100, g_color: 100, b_color: 0 }));
|
||||||
|
}
|
||||||
|
if (this.isKuwahara) {
|
||||||
|
transformations.push(new KuwaharaTransformation(10));
|
||||||
|
}
|
||||||
|
if (this.isPixelation) {
|
||||||
|
transformations.push(new PixelationTransformation(5.0));
|
||||||
|
}
|
||||||
|
if (this.isSketch) {
|
||||||
|
transformations.push(new SketchTransformation());
|
||||||
|
}
|
||||||
|
if (this.isSwirl) {
|
||||||
|
transformations.push(new SwirlTransformation(200, 1.0, [0.5, 0.5]));
|
||||||
|
}
|
||||||
|
if (this.isVignetter) {
|
||||||
|
transformations.push(new VignetterTransformation([0.5, 0.5], [0.0, 0.0, 0.0], [0.3, 0.75]));
|
||||||
|
}
|
||||||
|
if (this.isCropSquare) {
|
||||||
|
transformations.push(new CropSquareTransformation());
|
||||||
|
}
|
||||||
|
if (this.isCropTop) {
|
||||||
|
transformations.push(new CropTransformation(25, 25, 0));
|
||||||
|
}
|
||||||
|
if (this.isCropCenter) {
|
||||||
|
transformations.push(new CropTransformation(25, 25, 1));
|
||||||
|
}
|
||||||
|
if (this.isCropBottom) {
|
||||||
|
transformations.push(new CropTransformation(25, 25, 2));
|
||||||
|
}
|
||||||
|
if (this.isSepia) {
|
||||||
|
transformations.push(new SepiaTransformation());
|
||||||
|
}
|
||||||
|
if (this.isMask) {
|
||||||
|
transformations.push(new MaskTransformation($r('app.media.mask_starfish')));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.imageKnifeOption = {
|
this.imageKnifeOption = {
|
||||||
loadSrc: "http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
|
loadSrc: $r('app.media.pngSample'),
|
||||||
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,
|
||||||
|
border: { radius: this.isRound ? { topLeft: 50, bottomRight: 50 } : 0 },
|
||||||
transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined
|
transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.9 MiB |
|
@ -17,6 +17,7 @@ import FileLruCacheTest from './FileLruCache.test';
|
||||||
import ImageKnifeOptionTest from './ImageKnifeOption.test';
|
import ImageKnifeOptionTest from './ImageKnifeOption.test';
|
||||||
import MemoryLruCacheTest from './MemoryLruCache.test';
|
import MemoryLruCacheTest from './MemoryLruCache.test';
|
||||||
import ImageKnifeTest from './ImageKnife.test';
|
import ImageKnifeTest from './ImageKnife.test';
|
||||||
|
import Transform from './transform.test';
|
||||||
|
|
||||||
export default function testsuite() {
|
export default function testsuite() {
|
||||||
MemoryLruCacheTest();
|
MemoryLruCacheTest();
|
||||||
|
@ -24,4 +25,5 @@ export default function testsuite() {
|
||||||
DefaultJobQueueTest();
|
DefaultJobQueueTest();
|
||||||
ImageKnifeOptionTest();
|
ImageKnifeOptionTest();
|
||||||
ImageKnifeTest();
|
ImageKnifeTest();
|
||||||
|
Transform();
|
||||||
}
|
}
|
|
@ -0,0 +1,226 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'
|
||||||
|
import {
|
||||||
|
BlurTransformation,
|
||||||
|
BrightnessTransformation,
|
||||||
|
CropCircleTransformation,
|
||||||
|
CropCircleWithBorderTransformation,
|
||||||
|
CropSquareTransformation,
|
||||||
|
CropTransformation,
|
||||||
|
GrayScaleTransformation,
|
||||||
|
InvertTransformation,
|
||||||
|
KuwaharaTransformation,
|
||||||
|
MaskTransformation,
|
||||||
|
PixelationTransformation,
|
||||||
|
SepiaTransformation,
|
||||||
|
SketchTransformation,
|
||||||
|
SwirlTransformation,
|
||||||
|
ToonTransformation,
|
||||||
|
VignetterTransformation
|
||||||
|
} from '@ohos/imageknife'
|
||||||
|
|
||||||
|
const BASE_COUNT: number = 1000;
|
||||||
|
|
||||||
|
export default function Transform() {
|
||||||
|
describe('Transform', () => {
|
||||||
|
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
|
||||||
|
beforeAll(() => {
|
||||||
|
// Presets an action, which is performed only once before all test cases of the test suite start.
|
||||||
|
// This API supports only one parameter: preset action function.
|
||||||
|
|
||||||
|
})
|
||||||
|
beforeEach(() => {
|
||||||
|
// Presets an action, which is performed before each unit test case starts.
|
||||||
|
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||||
|
// This API supports only one parameter: preset action function.
|
||||||
|
})
|
||||||
|
afterEach(() => {
|
||||||
|
// Presets a clear action, which is performed after each unit test case ends.
|
||||||
|
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||||
|
// This API supports only one parameter: clear action function.
|
||||||
|
})
|
||||||
|
afterAll(() => {
|
||||||
|
// Presets a clear action, which is performed after all test cases of the test suite end.
|
||||||
|
// This API supports only one parameter: clear action function.
|
||||||
|
})
|
||||||
|
it('TestBlurTransformation', 0, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new BlurTransformation(15);
|
||||||
|
}
|
||||||
|
endTime(startTime, 'TestBlurTransformation');
|
||||||
|
let blur = new BlurTransformation(15);
|
||||||
|
expect(blur.getName()).assertEqual('BlurTransformation;radius:15');
|
||||||
|
})
|
||||||
|
it('TestBrightnessTransformation', 1, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new BrightnessTransformation(20);
|
||||||
|
}
|
||||||
|
endTime(startTime, 'BrightnessTransformation');
|
||||||
|
let bright = new BrightnessTransformation(20);
|
||||||
|
expect(bright.getName()).assertEqual("BrightnessTransformation;bright:20");
|
||||||
|
})
|
||||||
|
it('TestCropCircleTransformation', 3, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new CropCircleTransformation();
|
||||||
|
}
|
||||||
|
endTime(startTime, 'TestCropCircleTransformation');
|
||||||
|
let cropCircle = new CropCircleTransformation();
|
||||||
|
expect(cropCircle.getName()).assertContain("CropCircleTransformation");
|
||||||
|
expect(cropCircle.getName()).assertContain(";mCenterX:");
|
||||||
|
expect(cropCircle.getName()).assertContain(";mCenterY:");
|
||||||
|
expect(cropCircle.getName()).assertContain(";mRadius:");
|
||||||
|
})
|
||||||
|
it('TestCropCircleWithBorderTransformation', 4, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new CropCircleWithBorderTransformation(10, {
|
||||||
|
r_color: 100, g_color: 100, b_color: 100
|
||||||
|
});
|
||||||
|
}
|
||||||
|
endTime(startTime, 'TestCropCircleWithBorderTransformation');
|
||||||
|
let CropCircleWithBorder = new CropCircleWithBorderTransformation(10, {
|
||||||
|
r_color: 100, g_color: 100, b_color: 100
|
||||||
|
});
|
||||||
|
expect(CropCircleWithBorder.getName()).assertContain("CropCircleWithBorderTransformation")
|
||||||
|
expect(CropCircleWithBorder.getName()).assertContain(";mCenterX:");
|
||||||
|
expect(CropCircleWithBorder.getName()).assertContain(";mCenterY:");
|
||||||
|
expect(CropCircleWithBorder.getName()).assertContain(";mRadius:");
|
||||||
|
expect(CropCircleWithBorder.getName()).assertContain(";mBorderSize:");
|
||||||
|
expect(CropCircleWithBorder.getName()).assertContain(";mRColor:");
|
||||||
|
expect(CropCircleWithBorder.getName()).assertContain(";mGColor:");
|
||||||
|
expect(CropCircleWithBorder.getName()).assertContain(";mBColor:");
|
||||||
|
})
|
||||||
|
it('TestCropSquareTransformation', 5, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new CropSquareTransformation();
|
||||||
|
}
|
||||||
|
endTime(startTime, 'TestCropSquareTransformation');
|
||||||
|
let CropSquare = new CropSquareTransformation();
|
||||||
|
expect(CropSquare.getName()).assertContain("CropSquareTransformation");
|
||||||
|
})
|
||||||
|
it('TestCropTransformation', 6, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new CropTransformation(10, 10, 1);
|
||||||
|
}
|
||||||
|
endTime(startTime, 'TestCropTransformation');
|
||||||
|
let crop = new CropTransformation(10, 10, 1);
|
||||||
|
expect(crop.getName()).assertContain("CropTransformation" + ";mWidth:10" + ";mHeight:10" + ";mCropType:1")
|
||||||
|
})
|
||||||
|
it('TestGrayScaleTransformation', 7, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new GrayScaleTransformation();
|
||||||
|
}
|
||||||
|
endTime(startTime, 'GrayScaleTransformation');
|
||||||
|
let grayscale = new GrayScaleTransformation();
|
||||||
|
expect(grayscale.getName()).assertContain("GrayScaleTransformation")
|
||||||
|
})
|
||||||
|
it('TestInvertTransformation', 8, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new InvertTransformation();
|
||||||
|
}
|
||||||
|
endTime(startTime, 'TestInvertFilterTransformation');
|
||||||
|
let invert = new InvertTransformation();
|
||||||
|
expect(invert.getName()).assertContain("InvertTransformation");
|
||||||
|
})
|
||||||
|
it('TestPixelationTransformation', 9, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new PixelationTransformation();
|
||||||
|
}
|
||||||
|
endTime(startTime, 'TestPixelationTransformation');
|
||||||
|
let pixelation = new PixelationTransformation();
|
||||||
|
expect(pixelation.getName()).assertContain("PixelationTransformation");
|
||||||
|
})
|
||||||
|
it('TestSepiaTransformation', 12, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new SepiaTransformation();
|
||||||
|
}
|
||||||
|
endTime(startTime, 'SepiaTransformation');
|
||||||
|
let speia = new SepiaTransformation();
|
||||||
|
expect(speia.getName()).assertContain("SepiaTransformation");
|
||||||
|
})
|
||||||
|
it('TestSketchTransformation', 13, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new SketchTransformation();
|
||||||
|
}
|
||||||
|
endTime(startTime, 'TestSketchTransformation');
|
||||||
|
let Sketch = new SketchTransformation();
|
||||||
|
expect(Sketch.getName()).assertContain("SketchTransformation");
|
||||||
|
})
|
||||||
|
it('TestMaskTransformation', 14, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new MaskTransformation($r('app.media.icon'));
|
||||||
|
}
|
||||||
|
endTime(startTime, 'TestMaskTransformation');
|
||||||
|
let mask = new MaskTransformation($r('app.media.icon'));
|
||||||
|
expect(mask.getName()).assertContain("MaskTransformation");
|
||||||
|
})
|
||||||
|
it('TestSwirlTransformation', 15, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new SwirlTransformation(10, 180, [10, 10]);
|
||||||
|
}
|
||||||
|
endTime(startTime, 'TestSwirlTransformation');
|
||||||
|
let swirl = new SwirlTransformation(10, 180, [10, 10]);
|
||||||
|
expect(swirl.getName()).assertContain("SwirlTransformation");
|
||||||
|
})
|
||||||
|
it('TestKuwaharaTransformation', 16, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new KuwaharaTransformation(10);
|
||||||
|
}
|
||||||
|
endTime(startTime, 'TestKuwaharaTransformation');
|
||||||
|
let kuwahara = new KuwaharaTransformation(10);
|
||||||
|
expect(kuwahara.getName()).assertContain("KuwaharaTransformation;radius:10");
|
||||||
|
})
|
||||||
|
it('TestToonTransformation', 17, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new ToonTransformation(10);
|
||||||
|
}
|
||||||
|
endTime(startTime, 'TestToonTransformation');
|
||||||
|
let toon = new ToonTransformation(10);
|
||||||
|
expect(toon.getName()).assertContain("ToonTransformation;threshold:10");
|
||||||
|
})
|
||||||
|
it('TestVignetterTransformation', 18, () => {
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
for (let index = 0; index < BASE_COUNT; index++) {
|
||||||
|
new VignetterTransformation([0.5, 0.5], [0.0, 0.0, 0.0], [0.3, 0.75]);
|
||||||
|
}
|
||||||
|
endTime(startTime, 'TestVignetterTransformation');
|
||||||
|
let vignette = new VignetterTransformation([0.5, 0.5], [0.0, 0.0, 0.0], [0.3, 0.75]);
|
||||||
|
expect(vignette.getName()).assertContain("VignetterTransformation");
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function endTime(startTime: number, tag: string) {
|
||||||
|
let endTime: number = new Date().getTime();
|
||||||
|
let averageTime = ((endTime - startTime) * 1000 / BASE_COUNT);
|
||||||
|
console.info(tag + " startTime: " + endTime);
|
||||||
|
console.info(tag + " endTime: " + endTime);
|
||||||
|
console.log(tag + " averageTime: " + averageTime + "μs");
|
||||||
|
}
|
|
@ -24,4 +24,30 @@ export { BlurTransformation } from './src/main/ets/transform/BlurTransformation'
|
||||||
|
|
||||||
export { SparkMD5 } from "./src/main/ets/3rd_party/sparkmd5/spark-md5"
|
export { SparkMD5 } from "./src/main/ets/3rd_party/sparkmd5/spark-md5"
|
||||||
|
|
||||||
|
export { GrayScaleTransformation } from './src/main/ets/transform/GrayScaleTransformation'
|
||||||
|
|
||||||
|
export { InvertTransformation } from './src/main/ets/transform/InvertTransformation'
|
||||||
|
|
||||||
|
export { ToonTransformation } from './src/main/ets/transform/ToonTransformation'
|
||||||
|
|
||||||
|
export { CropCircleTransformation } from './src/main/ets/transform/CropCircleTransformation'
|
||||||
|
|
||||||
|
export { CropCircleWithBorderTransformation } from './src/main/ets/transform/CropCircleWithBorderTransformation'
|
||||||
|
|
||||||
|
export { KuwaharaTransformation } from './src/main/ets/transform/KuwaharaTransformation'
|
||||||
|
|
||||||
|
export { PixelationTransformation } from './src/main/ets/transform/PixelationTransformation'
|
||||||
|
|
||||||
|
export { SketchTransformation } from './src/main/ets/transform/SketchTransformation'
|
||||||
|
|
||||||
|
export { SwirlTransformation } from './src/main/ets/transform/SwirlTransformation'
|
||||||
|
|
||||||
|
export { VignetterTransformation } from './src/main/ets/transform/VignetterTransformation'
|
||||||
|
|
||||||
|
export { CropSquareTransformation } from './src/main/ets/transform/CropSquareTransformation'
|
||||||
|
|
||||||
|
export { CropTransformation } from './src/main/ets/transform/CropTransformation'
|
||||||
|
|
||||||
|
export { MaskTransformation } from './src/main/ets/transform/MaskTransformation'
|
||||||
|
|
||||||
|
export { SepiaTransformation } from './src/main/ets/transform/SepiaTransformation'
|
|
@ -16,7 +16,7 @@
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "3.0.0-rc.4",
|
"version": "3.0.0-rc.4",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ohos/gpu_transform": "^1.0.2"
|
||||||
},
|
},
|
||||||
"tags": [
|
"tags": [
|
||||||
"ImageCache",
|
"ImageCache",
|
||||||
|
|
|
@ -146,6 +146,8 @@ export class ImageKnifeDispatcher {
|
||||||
src: imageSrc,
|
src: imageSrc,
|
||||||
headers: currentRequest.imageKnifeOption.headerOption,
|
headers: currentRequest.imageKnifeOption.headerOption,
|
||||||
allHeaders: currentRequest.headers,
|
allHeaders: currentRequest.headers,
|
||||||
|
componentWidth:currentRequest.componentWidth,
|
||||||
|
componentHeight:currentRequest.componentHeight,
|
||||||
customGetImage: currentRequest.imageKnifeOption.customGetImage,
|
customGetImage: currentRequest.imageKnifeOption.customGetImage,
|
||||||
onlyRetrieveFromCache: currentRequest.imageKnifeOption.onlyRetrieveFromCache,
|
onlyRetrieveFromCache: currentRequest.imageKnifeOption.onlyRetrieveFromCache,
|
||||||
transformation: currentRequest.imageKnifeOption.transformation,
|
transformation: currentRequest.imageKnifeOption.transformation,
|
||||||
|
@ -470,7 +472,7 @@ async function requestJob(request: RequestJobRequest): Promise<RequestJobResult
|
||||||
|
|
||||||
// 图形变化
|
// 图形变化
|
||||||
if (request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined) {
|
if (request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined) {
|
||||||
resPixelmap = await request.transformation?.transform(request.context, resPixelmap!, 0, 0)
|
resPixelmap = await request.transformation?.transform(request.context, resPixelmap!, request.componentWidth, request.componentHeight);
|
||||||
}
|
}
|
||||||
LogUtil.log("ImageKnife_DataTime_requestJob_createPixelMap.end:"+request.src)
|
LogUtil.log("ImageKnife_DataTime_requestJob_createPixelMap.end:"+request.src)
|
||||||
LogUtil.log("ImageKnife_DataTime_requestJob.end:"+request.src)
|
LogUtil.log("ImageKnife_DataTime_requestJob.end:"+request.src)
|
||||||
|
|
|
@ -71,6 +71,8 @@ export interface RequestJobRequest {
|
||||||
src: string | PixelMap | Resource,
|
src: string | PixelMap | Resource,
|
||||||
headers?: Array<HeaderOptions>,
|
headers?: Array<HeaderOptions>,
|
||||||
allHeaders: Map<string, Object>,
|
allHeaders: Map<string, Object>,
|
||||||
|
componentWidth: number,
|
||||||
|
componentHeight: number,
|
||||||
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
|
||||||
|
|
|
@ -27,6 +27,10 @@ export class BlurTransformation extends PixelMapTransformation {
|
||||||
this.radius = radius
|
this.radius = radius
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getName(): string {
|
||||||
|
return this.constructor.name + ';radius:' + this.radius;
|
||||||
|
}
|
||||||
|
|
||||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
let headFilter = effectKit.createEffect(toTransform);
|
let headFilter = effectKit.createEffect(toTransform);
|
||||||
if (headFilter != null) {
|
if (headFilter != null) {
|
||||||
|
|
|
@ -27,6 +27,10 @@ export class BrightnessTransformation extends PixelMapTransformation {
|
||||||
this.bright = bright
|
this.bright = bright
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getName(): string {
|
||||||
|
return this.constructor.name + ';bright:' + this.bright;
|
||||||
|
}
|
||||||
|
|
||||||
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
let headFilter = effectKit.createEffect(toTransform);
|
let headFilter = effectKit.createEffect(toTransform);
|
||||||
if (headFilter != null) {
|
if (headFilter != null) {
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||||
|
import { Size } from '@kit.ArkUI';
|
||||||
|
import { image } from '@kit.ImageKit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片变换:圆形裁剪效果
|
||||||
|
*/
|
||||||
|
@Sendable
|
||||||
|
export class CropCircleTransformation extends PixelMapTransformation {
|
||||||
|
private mCenterX: number = 0;
|
||||||
|
private mCenterY: number = 0;
|
||||||
|
private mRadius: number = 0;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
getName(): string {
|
||||||
|
return this.constructor.name + ';mCenterX:' + this.mCenterX + ';mCenterY:' + this.mCenterY + ';mRadius:' + this.mRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
|
return await this.transformCircle(toTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async transformCircle(data: PixelMap): Promise<PixelMap> {
|
||||||
|
let imageInfo: image.ImageInfo = await data.getImageInfo();
|
||||||
|
let size: Size = {
|
||||||
|
width: imageInfo.size.width,
|
||||||
|
height: imageInfo.size.height
|
||||||
|
};
|
||||||
|
if (!size) {
|
||||||
|
console.error("CropCircleTransformation The image size does not exist.");
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
let height: number = size.height;
|
||||||
|
let width: number = size.width;
|
||||||
|
this.mRadius = 0;
|
||||||
|
if (width > height) {
|
||||||
|
this.mRadius = height / 2;
|
||||||
|
} else {
|
||||||
|
this.mRadius = width / 2;
|
||||||
|
}
|
||||||
|
this.mCenterX = width / 2;
|
||||||
|
this.mCenterY = height / 2;
|
||||||
|
|
||||||
|
let bufferData: ArrayBuffer = new ArrayBuffer(data.getPixelBytesNumber());
|
||||||
|
await data.readPixelsToBuffer(bufferData);
|
||||||
|
|
||||||
|
let dataArray = new Uint8Array(bufferData);
|
||||||
|
|
||||||
|
for (let h = 0; h <= height; h++) {
|
||||||
|
for (let w = 0; w <= width; w++) {
|
||||||
|
if (this.isContainsCircle(w, h)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 针对的点
|
||||||
|
let index = (h * width + w) * 4;
|
||||||
|
dataArray[index] = 0;
|
||||||
|
dataArray[index+1] = 0;
|
||||||
|
dataArray[index+2] = 0;
|
||||||
|
dataArray[index+3] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await data.writeBufferToPixels(bufferData);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
isContainsCircle(x: number, y: number): boolean {
|
||||||
|
let a = Math.pow((this.mCenterX - x), 2);
|
||||||
|
let b = Math.pow((this.mCenterY - y), 2);
|
||||||
|
let c = Math.sqrt((a + b));
|
||||||
|
return c <= this.mRadius;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||||
|
import { Size } from '@kit.ArkUI';
|
||||||
|
import { image } from '@kit.ImageKit';
|
||||||
|
|
||||||
|
export interface rgbColor {
|
||||||
|
r_color: number,
|
||||||
|
g_color: number,
|
||||||
|
b_color: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片变换:圆环裁剪效果
|
||||||
|
*/
|
||||||
|
@Sendable
|
||||||
|
export class CropCircleWithBorderTransformation extends PixelMapTransformation {
|
||||||
|
private mBorderSize: number = 5;
|
||||||
|
private mCenterX: number = 0;
|
||||||
|
private mCenterY: number = 0;
|
||||||
|
private mRadius: number = 0;
|
||||||
|
private mRColor: number = 0;
|
||||||
|
private mGColor: number = 0;
|
||||||
|
private mBColor: number = 0;
|
||||||
|
|
||||||
|
constructor(borderSize: number, value: rgbColor) {
|
||||||
|
super();
|
||||||
|
this.mRColor = value.g_color;
|
||||||
|
this.mGColor = value.g_color;
|
||||||
|
this.mBColor = value.b_color;
|
||||||
|
this.mBorderSize = borderSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
getConstructorParams() {
|
||||||
|
return JSON.stringify([this.mBorderSize, {
|
||||||
|
r_color: this.mRColor,
|
||||||
|
g_color: this.mGColor,
|
||||||
|
b_color: this.mBColor
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
getName(): string {
|
||||||
|
return this.constructor.name + ';mBorderSize:' + this.mBorderSize + ';mCenterX:' + this.mCenterX + ';mCenterY:'
|
||||||
|
+ this.mCenterY + ';mRadius:' + this.mRadius + ';mRColor:' + this.mRColor + ';mGColor:' + this.mGColor + ';mBColor:' + this.mBColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
|
return await this.transformPixelMap(toTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async transformPixelMap(pixelMap: PixelMap): Promise<PixelMap> {
|
||||||
|
let imageInfo: image.ImageInfo = await pixelMap.getImageInfo();
|
||||||
|
let size: Size = {
|
||||||
|
width: imageInfo.size.width,
|
||||||
|
height: imageInfo.size.height
|
||||||
|
};
|
||||||
|
if (!size) {
|
||||||
|
console.error("CropCircleWithBorderTransformation The image size does not exist.");
|
||||||
|
return pixelMap;
|
||||||
|
}
|
||||||
|
let height: number = size.height;
|
||||||
|
let width: number = size.width;
|
||||||
|
this.mRadius = 0;
|
||||||
|
if (width > height) {
|
||||||
|
this.mRadius = height / 2;
|
||||||
|
} else {
|
||||||
|
this.mRadius = width / 2;
|
||||||
|
}
|
||||||
|
this.mCenterX = width / 2;
|
||||||
|
this.mCenterY = height / 2;
|
||||||
|
|
||||||
|
|
||||||
|
let bufferData = new ArrayBuffer(pixelMap.getPixelBytesNumber());
|
||||||
|
await pixelMap.readPixelsToBuffer(bufferData);
|
||||||
|
|
||||||
|
let dataArray = new Uint8Array(bufferData);
|
||||||
|
|
||||||
|
for (let h = 0; h <= height; h++) {
|
||||||
|
for (let w = 0; w <= width; w++) {
|
||||||
|
// 不在大圆之内的设置透明
|
||||||
|
// 在大圆与小圆之间的 设置rgb值
|
||||||
|
// 小圆之内的不变
|
||||||
|
let isSmallCircle: boolean = this.isContainsSmallCircle(w, h);
|
||||||
|
let isBigCircle: boolean = this.isContainsCircle(w, h);
|
||||||
|
if (isSmallCircle) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let index = (h * width + w) * 4;
|
||||||
|
if (!isBigCircle) {
|
||||||
|
// 设置透明
|
||||||
|
dataArray[index] = 0;
|
||||||
|
dataArray[index+1] = 0;
|
||||||
|
dataArray[index+2] = 0;
|
||||||
|
dataArray[index+3] = 0;
|
||||||
|
} else {
|
||||||
|
// 设置broke
|
||||||
|
dataArray[index] = this.mRColor;
|
||||||
|
dataArray[index+1] = this.mGColor;
|
||||||
|
dataArray[index+2] = this.mBColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await pixelMap.writeBufferToPixels(bufferData);
|
||||||
|
return pixelMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
isContainsCircle(x: number, y: number): boolean {
|
||||||
|
let a: number = Math.pow((this.mCenterX - x), 2);
|
||||||
|
let b: number = Math.pow((this.mCenterY - y), 2);
|
||||||
|
let c: number = Math.sqrt((a + b));
|
||||||
|
return c <= this.mRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
isContainsSmallCircle(x: number, y: number): boolean {
|
||||||
|
let a: number = Math.pow((this.mCenterX - x), 2);
|
||||||
|
let b: number = Math.pow((this.mCenterY - y), 2);
|
||||||
|
let c: number = Math.sqrt((a + b));
|
||||||
|
return c <= (this.mRadius - this.mBorderSize);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||||
|
import { Size } from '@kit.ArkUI';
|
||||||
|
import { image } from '@kit.ImageKit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片变换:正方形裁剪效果
|
||||||
|
*/
|
||||||
|
@Sendable
|
||||||
|
export class CropSquareTransformation extends PixelMapTransformation {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
|
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||||
|
let size: Size = {
|
||||||
|
width: imageInfo.size.width,
|
||||||
|
height: imageInfo.size.height
|
||||||
|
};
|
||||||
|
if (!size) {
|
||||||
|
console.error("CropSquareTransformation The image size does not exist.");
|
||||||
|
return toTransform;
|
||||||
|
}
|
||||||
|
let pixelMapWidth: number = size.width;
|
||||||
|
let pixelMapHeight: number = size.height;
|
||||||
|
let targetSize: number = pixelMapWidth > pixelMapHeight ? pixelMapHeight : pixelMapWidth;
|
||||||
|
let region: image.Region = {
|
||||||
|
size: { width: targetSize, height: targetSize },
|
||||||
|
x: pixelMapWidth / 2 - targetSize / 2,
|
||||||
|
y: pixelMapHeight / 2 - targetSize / 2
|
||||||
|
};
|
||||||
|
await toTransform.crop(region);
|
||||||
|
return toTransform;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||||
|
import { Size } from '@kit.ArkUI';
|
||||||
|
import { image } from '@kit.ImageKit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片变换:自定义裁剪效果
|
||||||
|
*/
|
||||||
|
@Sendable
|
||||||
|
export class CropTransformation extends PixelMapTransformation {
|
||||||
|
private mWidth: number = 0;
|
||||||
|
private mHeight: number = 0;
|
||||||
|
private mCropType: number = 0;
|
||||||
|
|
||||||
|
constructor(width: number, height: number, cropType: number) {
|
||||||
|
super();
|
||||||
|
this.mWidth = width;
|
||||||
|
this.mHeight = height;
|
||||||
|
this.mCropType = cropType;
|
||||||
|
}
|
||||||
|
|
||||||
|
getName(): string {
|
||||||
|
return this.constructor.name + ";mWidth:" + this.mWidth + ";mHeight:" + this.mHeight + ";mCropType:" + this.mCropType;
|
||||||
|
}
|
||||||
|
|
||||||
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
|
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||||
|
let size: Size = {
|
||||||
|
width: imageInfo.size.width,
|
||||||
|
height: imageInfo.size.height
|
||||||
|
};
|
||||||
|
if (!size) {
|
||||||
|
console.error("CropTransformation The image size does not exist.");
|
||||||
|
return toTransform;
|
||||||
|
}
|
||||||
|
let pixelMapWidth: number = size.width;
|
||||||
|
let pixelMapHeight: number = size.height;
|
||||||
|
this.mWidth = this.mWidth == 0 ? pixelMapWidth : this.mWidth;
|
||||||
|
this.mHeight = this.mHeight == 0 ? pixelMapHeight : this.mHeight;
|
||||||
|
let scaleX: number = this.mWidth / pixelMapWidth;
|
||||||
|
let scaleY: number = this.mHeight / pixelMapHeight;
|
||||||
|
let scale: number = Math.max(scaleX, scaleY);
|
||||||
|
let scaledWidth: number = scale * pixelMapWidth;
|
||||||
|
let scaledHeight: number = scale * pixelMapHeight;
|
||||||
|
let left: number = (this.mWidth - scaledWidth) / 2;
|
||||||
|
let top: number = Math.abs(this.getTop(pixelMapHeight));
|
||||||
|
let region: image.Region = {
|
||||||
|
size: {
|
||||||
|
width: scaledWidth > pixelMapWidth ? pixelMapWidth : scaledWidth,
|
||||||
|
height: scaledHeight > pixelMapHeight ? pixelMapHeight : scaledHeight
|
||||||
|
},
|
||||||
|
x: left < 0 ? 0 : left,
|
||||||
|
y: top < 0 ? 0 : top
|
||||||
|
};
|
||||||
|
toTransform.cropSync(region);
|
||||||
|
return toTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTop(scaledHeight: number): number {
|
||||||
|
switch (this.mCropType) {
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
|
case 1:
|
||||||
|
return (this.mHeight - scaledHeight) / 2;
|
||||||
|
case 2:
|
||||||
|
return this.mHeight - scaledHeight;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||||
|
import { effectKit } from '@kit.ArkGraphics2D';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片变换:灰化效果
|
||||||
|
*/
|
||||||
|
@Sendable
|
||||||
|
export class GrayScaleTransformation extends PixelMapTransformation {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
|
let headFilter = effectKit.createEffect(toTransform);
|
||||||
|
if (headFilter != null) {
|
||||||
|
return await headFilter.grayscale().getEffectPixelMap();
|
||||||
|
}
|
||||||
|
return toTransform;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||||
|
import { effectKit } from '@kit.ArkGraphics2D';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片变换:反转效果
|
||||||
|
*/
|
||||||
|
@Sendable
|
||||||
|
export class InvertTransformation extends PixelMapTransformation {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
|
let headFilter = effectKit.createEffect(toTransform);
|
||||||
|
if (headFilter != null) {
|
||||||
|
return await headFilter.invert().getEffectPixelMap();
|
||||||
|
}
|
||||||
|
return toTransform;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { GPUImageKuwaharaFilter } from '@ohos/gpu_transform';
|
||||||
|
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||||
|
import { image } from '@kit.ImageKit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片变换:桑原滤波效果
|
||||||
|
*/
|
||||||
|
@Sendable
|
||||||
|
export class KuwaharaTransformation extends PixelMapTransformation {
|
||||||
|
private radius: number;
|
||||||
|
|
||||||
|
constructor(radius: number) {
|
||||||
|
super();
|
||||||
|
this.radius = radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
getName(): string {
|
||||||
|
return this.constructor.name + ';radius:' + this.radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
|
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||||
|
if (!imageInfo.size) {
|
||||||
|
console.error("KuwaharaTransformation The image size does not exist.");
|
||||||
|
return toTransform;
|
||||||
|
}
|
||||||
|
return await this.kuwaharaGpu(toTransform, imageInfo.size.width, imageInfo.size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async kuwaharaGpu(bitmap: PixelMap, targetWidth: number, targetHeight: number): Promise<PixelMap> {
|
||||||
|
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||||
|
await bitmap.readPixelsToBuffer(bufferData);
|
||||||
|
let filter = new GPUImageKuwaharaFilter();
|
||||||
|
filter.setImageData(bufferData, targetWidth, targetHeight);
|
||||||
|
filter.setRadius(this.radius);
|
||||||
|
let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight);
|
||||||
|
bitmap.writeBufferToPixels(buf);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,198 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||||
|
import { Size } from '@kit.ArkUI';
|
||||||
|
import { image } from '@kit.ImageKit';
|
||||||
|
import { resourceManager } from '@kit.LocalizationKit';
|
||||||
|
import { CalculatePixelUtils } from '../utils/CalculatePixelUtils';
|
||||||
|
import { ColorUtils } from '../utils/ColorUtils';
|
||||||
|
import { PixelEntry } from './entry/PixelEntry';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片变换:遮罩效果
|
||||||
|
*/
|
||||||
|
@Sendable
|
||||||
|
export class MaskTransformation extends PixelMapTransformation {
|
||||||
|
private mResourceId: number;
|
||||||
|
private mResourceModuleName: string;
|
||||||
|
|
||||||
|
constructor(resource: Resource) {
|
||||||
|
super();
|
||||||
|
this.mResourceId = resource.id;
|
||||||
|
this.mResourceModuleName = resource.moduleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
getName(): string {
|
||||||
|
return this.constructor.name + ';resourceId:' + this.mResourceId + ';resourceModuleName:' + this.mResourceModuleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
|
let imageInfo = await toTransform.getImageInfo();
|
||||||
|
let size: Size = {
|
||||||
|
width: imageInfo.size.width,
|
||||||
|
height: imageInfo.size.height
|
||||||
|
};
|
||||||
|
if (!size) {
|
||||||
|
console.error("MaskTransformation The image size does not exist.");
|
||||||
|
return toTransform;
|
||||||
|
}
|
||||||
|
let pixelMapWidth: number = size.width;
|
||||||
|
let pixelMapHeight: number = size.height;
|
||||||
|
let targetWidth: number = width;
|
||||||
|
let targetHeight: number = height;
|
||||||
|
if (pixelMapWidth > targetWidth && pixelMapHeight > targetHeight) {
|
||||||
|
let scale = Math.max(targetWidth / pixelMapWidth, targetHeight / pixelMapHeight);
|
||||||
|
await toTransform.scale(scale, scale);
|
||||||
|
return await this.openInternal(context, toTransform, scale * pixelMapWidth, scale * pixelMapHeight);
|
||||||
|
}
|
||||||
|
return await this.openInternal(context, toTransform, size.width, size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async openInternal(context: Context, bitmap: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
|
if (context == undefined) {
|
||||||
|
console.error("MaskTransformation openInternal the context is undefined.");
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
let moduleContext = context.createModuleContext(this.mResourceModuleName);
|
||||||
|
if (moduleContext == undefined) {
|
||||||
|
console.error("MaskTransformation openInternal the moduleContext is undefined.");
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
let resourceManager = moduleContext.resourceManager as resourceManager.ResourceManager;
|
||||||
|
if (resourceManager == undefined) {
|
||||||
|
console.error("MaskTransformation openInternal the resourceManager is undefined.");
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
let array: Uint8Array = await resourceManager.getMediaContent(this.mResourceId);
|
||||||
|
let buffer = array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset);
|
||||||
|
let imageSource: image.ImageSource = image.createImageSource(buffer);
|
||||||
|
let options: image.DecodingOptions = {
|
||||||
|
editable: true,
|
||||||
|
desiredSize: {
|
||||||
|
width: width,
|
||||||
|
height: height
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let maskBitmap: PixelMap = await imageSource.createPixelMap(options);
|
||||||
|
return await this.mask(bitmap, maskBitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
async mask(bitmap: PixelMap, maskBitmap: PixelMap): Promise<PixelMap> {
|
||||||
|
let imageInfo = await bitmap.getImageInfo();
|
||||||
|
let size: Size = {
|
||||||
|
width: imageInfo.size.width,
|
||||||
|
height: imageInfo.size.height
|
||||||
|
};
|
||||||
|
if (!size) {
|
||||||
|
console.error("MaskTransformation mask the image size does not exist.");
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
let width = size.width;
|
||||||
|
let height = size.height;
|
||||||
|
let rgbData = CalculatePixelUtils.createInt2DArray(height, width);
|
||||||
|
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||||
|
await bitmap.readPixelsToBuffer(bufferData);
|
||||||
|
let dataArray = new Uint8Array(bufferData);
|
||||||
|
let ph = 0;
|
||||||
|
let pw = 0;
|
||||||
|
for (let index = 0; index < dataArray.length; index += 4) {
|
||||||
|
const r = dataArray[index];
|
||||||
|
const g = dataArray[index+1];
|
||||||
|
const b = dataArray[index+2];
|
||||||
|
const f = dataArray[index+3];
|
||||||
|
let entry = new PixelEntry();
|
||||||
|
entry.a = 0;
|
||||||
|
entry.b = b;
|
||||||
|
entry.g = g;
|
||||||
|
entry.r = r;
|
||||||
|
entry.f = f;
|
||||||
|
entry.pixel = ColorUtils.rgb(entry.r, entry.g, entry.b);
|
||||||
|
rgbData[ph][pw] = ColorUtils.rgb(entry.r, entry.g, entry.b);
|
||||||
|
if (pw == width - 1) {
|
||||||
|
pw = 0;
|
||||||
|
ph++;
|
||||||
|
} else {
|
||||||
|
pw++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let imageInfoMask = await maskBitmap.getImageInfo();
|
||||||
|
let sizeMask: Size = {
|
||||||
|
width: imageInfoMask.size.width,
|
||||||
|
height: imageInfoMask.size.height
|
||||||
|
};
|
||||||
|
if (!sizeMask) {
|
||||||
|
console.error("MaskTransformation mask the sizeMask size does not exist.");
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
let widthMask = sizeMask.width;
|
||||||
|
let heightMask = sizeMask.height;
|
||||||
|
let rgbDataMask = CalculatePixelUtils.createInt2DArray(heightMask, widthMask);
|
||||||
|
let pixEntry: Array<PixelEntry> = new Array();
|
||||||
|
let bufferDataM = new ArrayBuffer(maskBitmap.getPixelBytesNumber());
|
||||||
|
await maskBitmap.readPixelsToBuffer(bufferDataM);
|
||||||
|
let dataArrayM = new Uint8Array(bufferDataM);
|
||||||
|
let phM = 0;
|
||||||
|
let pwM = 0;
|
||||||
|
for (let index = 0; index < dataArrayM.length; index += 4) {
|
||||||
|
const r = dataArrayM[index];
|
||||||
|
const g = dataArrayM[index+1];
|
||||||
|
const b = dataArrayM[index+2];
|
||||||
|
const f = dataArrayM[index+3];
|
||||||
|
let entry = new PixelEntry();
|
||||||
|
entry.a = 0;
|
||||||
|
entry.b = b;
|
||||||
|
entry.g = g;
|
||||||
|
entry.r = r;
|
||||||
|
entry.f = f;
|
||||||
|
entry.pixel = ColorUtils.rgb(entry.r, entry.g, entry.b);
|
||||||
|
pixEntry.push(entry);
|
||||||
|
if (entry.r == 0 && entry.g == 0 && entry.b == 0) {
|
||||||
|
rgbDataMask[phM][pwM] = rgbData[phM][pwM];
|
||||||
|
} else {
|
||||||
|
rgbDataMask[phM][pwM] = ColorUtils.rgb(entry.r, entry.g, entry.b);
|
||||||
|
}
|
||||||
|
if (pwM == widthMask - 1) {
|
||||||
|
pwM = 0;
|
||||||
|
phM++;
|
||||||
|
} else {
|
||||||
|
pwM++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let bufferNewData = new ArrayBuffer(maskBitmap.getPixelBytesNumber());
|
||||||
|
let dataNewArray = new Uint8Array(bufferNewData);
|
||||||
|
let index = 0;
|
||||||
|
let mh = 0;
|
||||||
|
let nw = 0;
|
||||||
|
for (let i = 0; i < dataNewArray.length; i += 4) {
|
||||||
|
let pixel1 = rgbDataMask[mh][nw];
|
||||||
|
if (nw == widthMask - 1) {
|
||||||
|
nw = 0;
|
||||||
|
mh++;
|
||||||
|
} else {
|
||||||
|
nw++;
|
||||||
|
}
|
||||||
|
let pR = ColorUtils.red(pixel1);
|
||||||
|
let pG = ColorUtils.green(pixel1);
|
||||||
|
let pB = ColorUtils.blue(pixel1);
|
||||||
|
dataNewArray[i] = pR;
|
||||||
|
dataNewArray[i+1] = pG;
|
||||||
|
dataNewArray[i+2] = pB;
|
||||||
|
dataNewArray[i+3] = pixEntry[index].f;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
await maskBitmap.writeBufferToPixels(bufferNewData);
|
||||||
|
return maskBitmap;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { GPUImagePixelationFilter } from '@ohos/gpu_transform';
|
||||||
|
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||||
|
import { image } from '@kit.ImageKit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a Pixelation effect to the image.
|
||||||
|
* The pixel with a default of 10.0.
|
||||||
|
*/
|
||||||
|
@Sendable
|
||||||
|
export class PixelationTransformation extends PixelMapTransformation {
|
||||||
|
private mPixel: number = 10.0;
|
||||||
|
|
||||||
|
constructor(pixel?: number) {
|
||||||
|
super();
|
||||||
|
if (pixel) {
|
||||||
|
this.mPixel = pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getName(): string {
|
||||||
|
return this.constructor.name + ';pixel:' + this.mPixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
|
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||||
|
if (!imageInfo.size) {
|
||||||
|
console.error("PixelationTransformation The image size does not exist.");
|
||||||
|
return toTransform;
|
||||||
|
}
|
||||||
|
return await this.pixelGPU(toTransform, imageInfo.size.width, imageInfo.size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async pixelGPU(bitmap: PixelMap, targetWidth: number, targetHeight: number): Promise<PixelMap> {
|
||||||
|
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||||
|
await bitmap.readPixelsToBuffer(bufferData);
|
||||||
|
let filter = new GPUImagePixelationFilter();
|
||||||
|
filter.setImageData(bufferData, targetWidth, targetHeight);
|
||||||
|
filter.setPixel(this.mPixel);
|
||||||
|
let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight);
|
||||||
|
await bitmap.writeBufferToPixels(buf);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { GPUImageSepiaToneFilter } from '@ohos/gpu_transform';
|
||||||
|
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||||
|
import { image } from '@kit.ImageKit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片变换:乌墨色滤波效果
|
||||||
|
*/
|
||||||
|
@Sendable
|
||||||
|
export class SepiaTransformation extends PixelMapTransformation {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
|
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||||
|
if (!imageInfo.size) {
|
||||||
|
console.error("SepiaTransformation The image size does not exist.");
|
||||||
|
return toTransform;
|
||||||
|
}
|
||||||
|
return await this.sepiaGPU(toTransform, imageInfo.size.width, imageInfo.size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async sepiaGPU(bitmap: PixelMap, targetWidth: number, targetHeight: number): Promise<PixelMap> {
|
||||||
|
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||||
|
await bitmap.readPixelsToBuffer(bufferData);
|
||||||
|
let filter = new GPUImageSepiaToneFilter();
|
||||||
|
filter.setImageData(bufferData, targetWidth, targetHeight);
|
||||||
|
let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight);
|
||||||
|
bitmap.writeBufferToPixels(buf);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { GPUImageSketchFilter } from '@ohos/gpu_transform';
|
||||||
|
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||||
|
import { image } from '@kit.ImageKit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片变换:素描效果
|
||||||
|
*/
|
||||||
|
@Sendable
|
||||||
|
export class SketchTransformation extends PixelMapTransformation {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
|
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||||
|
if (!imageInfo.size) {
|
||||||
|
console.error("SketchTransformation The image size does not exist.");
|
||||||
|
return toTransform;
|
||||||
|
}
|
||||||
|
return await this.sketchGPU(toTransform, imageInfo.size.width, imageInfo.size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async sketchGPU(bitmap: PixelMap, targetWidth: number, targetHeight: number): Promise<PixelMap> {
|
||||||
|
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||||
|
await bitmap.readPixelsToBuffer(bufferData);
|
||||||
|
let filter = new GPUImageSketchFilter();
|
||||||
|
filter.setImageData(bufferData, targetWidth, targetHeight);
|
||||||
|
let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight);
|
||||||
|
bitmap.writeBufferToPixels(buf);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { GPUImageSwirlFilter } from '@ohos/gpu_transform';
|
||||||
|
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||||
|
import { image } from '@kit.ImageKit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片变换:扭曲效果
|
||||||
|
*/
|
||||||
|
@Sendable
|
||||||
|
export class SwirlTransformation extends PixelMapTransformation {
|
||||||
|
// degree:值越大范围越大
|
||||||
|
private mDegree: number = 0;
|
||||||
|
// 取值范围 0.0 ~ 1.0
|
||||||
|
private mAngle: number = 0.9;
|
||||||
|
// 在图中的位置 取值范围 0.0 ~ 1.0
|
||||||
|
private mXCenter: number = 0.5;
|
||||||
|
// 在图中的位置 取值范围 0.0 ~ 1.0
|
||||||
|
private mYCenter: number = 0.5;
|
||||||
|
|
||||||
|
constructor(degree: number, angle?: number, centerPoint?: Array<number>) {
|
||||||
|
super();
|
||||||
|
this.mDegree = degree;
|
||||||
|
if (angle) {
|
||||||
|
this.mAngle = angle;
|
||||||
|
}
|
||||||
|
if (centerPoint && centerPoint.length === 2) {
|
||||||
|
this.mXCenter = centerPoint[0];
|
||||||
|
this.mYCenter = centerPoint[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getName(): string {
|
||||||
|
return this.constructor.name + ';degree:' + this.mDegree + ';angle:' + this.mAngle + ';XCenter:' + this.mXCenter
|
||||||
|
+ ';YCenter:' + this.mYCenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
|
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||||
|
if (!imageInfo.size) {
|
||||||
|
console.error("SwirlTransformation The image size does not exist.");
|
||||||
|
return toTransform;
|
||||||
|
}
|
||||||
|
return await this.swirlGPU(toTransform, imageInfo.size.width, imageInfo.size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async swirlGPU(bitmap: image.PixelMap, targetWidth: number, targetHeight: number): Promise<PixelMap> {
|
||||||
|
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||||
|
await bitmap.readPixelsToBuffer(bufferData);
|
||||||
|
let filter = new GPUImageSwirlFilter();
|
||||||
|
filter.setImageData(bufferData, targetWidth, targetHeight);
|
||||||
|
filter.setRadius(this.mDegree);
|
||||||
|
filter.setAngle(this.mAngle);
|
||||||
|
filter.setCenter(this.mXCenter, this.mYCenter);
|
||||||
|
let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight);
|
||||||
|
await bitmap.writeBufferToPixels(buf);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { GPUImageToonFilter } from '@ohos/gpu_transform';
|
||||||
|
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||||
|
import { image } from '@kit.ImageKit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片变换:动画滤镜效果
|
||||||
|
*/
|
||||||
|
@Sendable
|
||||||
|
export class ToonTransformation extends PixelMapTransformation {
|
||||||
|
private threshold: number = 0.2;
|
||||||
|
private quantizationLevels: number = 10.0;
|
||||||
|
|
||||||
|
constructor(threshold?: number, quantizationLevels?: number) {
|
||||||
|
super();
|
||||||
|
if (threshold) {
|
||||||
|
this.threshold = threshold;
|
||||||
|
}
|
||||||
|
if (quantizationLevels) {
|
||||||
|
this.quantizationLevels = quantizationLevels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getName(): string {
|
||||||
|
return this.constructor.name + ';threshold:' + this.threshold + ';quantizationLevels:' + this.quantizationLevels;
|
||||||
|
}
|
||||||
|
|
||||||
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
|
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||||
|
if (!imageInfo.size) {
|
||||||
|
console.error("ToonTransformation The image size does not exist.");
|
||||||
|
return toTransform;
|
||||||
|
}
|
||||||
|
return await this.toonGPU(toTransform, imageInfo.size.width, imageInfo.size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async toonGPU(bitmap: image.PixelMap, targetWidth: number, targetHeight: number) {
|
||||||
|
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||||
|
await bitmap.readPixelsToBuffer(bufferData);
|
||||||
|
let filter = new GPUImageToonFilter();
|
||||||
|
filter.setImageData(bufferData, targetWidth, targetHeight);
|
||||||
|
filter.setThreshold(this.threshold);
|
||||||
|
filter.setQuantizationLevels(this.quantizationLevels);
|
||||||
|
let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight);
|
||||||
|
bitmap.writeBufferToPixels(buf);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { GPUImageVignetterFilter } from '@ohos/gpu_transform';
|
||||||
|
import { PixelMapTransformation } from './PixelMapTransformation';
|
||||||
|
import { image } from '@kit.ImageKit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片变换:装饰效果
|
||||||
|
*/
|
||||||
|
@Sendable
|
||||||
|
export class VignetterTransformation extends PixelMapTransformation {
|
||||||
|
private mXCenter: number = 0.5;
|
||||||
|
private mYCenter: number = 0.5;
|
||||||
|
private mRed: number = 0.0;
|
||||||
|
private mGreen: number = 0.0;
|
||||||
|
private mBlue: number = 0.0;
|
||||||
|
private mStart: number = 0.3;
|
||||||
|
private mEnd: number = 0.75;
|
||||||
|
|
||||||
|
constructor(centerPoint: Array<number>, vignetteColor: Array<number>, vignetteSpace: Array<number>) {
|
||||||
|
super();
|
||||||
|
if (centerPoint.length === 2) {
|
||||||
|
this.mXCenter = centerPoint[0];
|
||||||
|
this.mYCenter = centerPoint[1];
|
||||||
|
}
|
||||||
|
if (vignetteColor.length === 3) {
|
||||||
|
this.mRed = vignetteColor[0];
|
||||||
|
this.mGreen = vignetteColor[1];
|
||||||
|
this.mBlue = vignetteColor[2];
|
||||||
|
}
|
||||||
|
if (vignetteSpace.length === 2) {
|
||||||
|
this.mStart = vignetteSpace[0];
|
||||||
|
this.mEnd = vignetteSpace[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getName(): string {
|
||||||
|
return this.constructor.name + ';XCenter:' + this.mXCenter + ';YCenter:' + this.mYCenter + ';Red:'
|
||||||
|
+ this.mRed + ';Green:' + this.mGreen + ';Blue:' + this.mBlue + ';Start:' + this.mStart + ';End:' + this.mEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
|
||||||
|
let imageInfo: image.ImageInfo = await toTransform.getImageInfo();
|
||||||
|
if (!imageInfo.size) {
|
||||||
|
console.error("VignetterTransformation The image size does not exist.");
|
||||||
|
return toTransform;
|
||||||
|
}
|
||||||
|
return await this.swirlGPU(toTransform, imageInfo.size.width, imageInfo.size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async swirlGPU(bitmap: image.PixelMap, targetWidth: number, targetHeight: number) {
|
||||||
|
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
|
||||||
|
await bitmap.readPixelsToBuffer(bufferData);
|
||||||
|
let filter = new GPUImageVignetterFilter();
|
||||||
|
filter.setImageData(bufferData, targetWidth, targetHeight);
|
||||||
|
filter.setVignetteCenter([this.mXCenter, this.mYCenter]);
|
||||||
|
filter.setVignetteColor([this.mRed, this.mGreen, this.mBlue]);
|
||||||
|
filter.setVignetteStart(this.mStart);
|
||||||
|
filter.setVignetteEnd(this.mEnd);
|
||||||
|
let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight);
|
||||||
|
await bitmap.writeBufferToPixels(buf);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
export class PixelEntry {
|
||||||
|
a: number = 0;
|
||||||
|
b: number = 0;
|
||||||
|
r: number = 0;
|
||||||
|
g: number = 0;
|
||||||
|
f: number = 0;
|
||||||
|
pixel: number = 0;
|
||||||
|
|
||||||
|
public toString(): string {
|
||||||
|
return "PixelEntry a:" + this.a + ";b:" + this.b + ";r:" + this.r + ";g:" + this.g + ";f:" + this.f;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* 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 namespace CalculatePixelUtils {
|
||||||
|
|
||||||
|
export function createInt2DArray(first_len: number, second_len: number): Array<Array<number>> {
|
||||||
|
let array = new Array<Array<number>>();
|
||||||
|
for (let f = 0; f < first_len; f++) {
|
||||||
|
let s1 = new Array<number>();
|
||||||
|
for (let s = 0; s < second_len; s++) {
|
||||||
|
s1.push(0);
|
||||||
|
}
|
||||||
|
array.push(s1);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* 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 namespace ColorUtils {
|
||||||
|
|
||||||
|
export function red(color: number): number {
|
||||||
|
return (color >> 16) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function green(color: number): number {
|
||||||
|
return (color >> 8) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function blue(color: number): number {
|
||||||
|
return color & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function alpha(color: number): number {
|
||||||
|
return color >>> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function rgb(red: number, green: number, blue: number): number {
|
||||||
|
return 0xff000000 | (red << 16) | (green << 8) | blue;
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,8 +7,10 @@
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "",
|
"license": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ohos/gpu_transform": "^1.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ohos/hypium": "1.0.16"
|
"@ohos/hypium": "1.0.16"
|
||||||
}
|
},
|
||||||
|
"dynamicDependencies": {}
|
||||||
}
|
}
|
|
@ -30,4 +30,32 @@ export { BlurTransformation } from '@ohos/imageknife'
|
||||||
|
|
||||||
export { SparkMD5 } from "@ohos/imageknife"
|
export { SparkMD5 } from "@ohos/imageknife"
|
||||||
|
|
||||||
export { ImageKnifeRequestSource } from "@ohos/imageknife"
|
export { ImageKnifeRequestSource } from "@ohos/imageknife"
|
||||||
|
|
||||||
|
export { CropCircleTransformation } from '@ohos/imageknife'
|
||||||
|
|
||||||
|
export { CropCircleWithBorderTransformation } from '@ohos/imageknife'
|
||||||
|
|
||||||
|
export { CropSquareTransformation } from '@ohos/imageknife'
|
||||||
|
|
||||||
|
export { CropTransformation } from '@ohos/imageknife'
|
||||||
|
|
||||||
|
export { GrayScaleTransformation } from '@ohos/imageknife'
|
||||||
|
|
||||||
|
export { InvertTransformation } from '@ohos/imageknife'
|
||||||
|
|
||||||
|
export { KuwaharaTransformation } from '@ohos/imageknife'
|
||||||
|
|
||||||
|
export { MaskTransformation } from '@ohos/imageknife'
|
||||||
|
|
||||||
|
export { PixelationTransformation } from '@ohos/imageknife'
|
||||||
|
|
||||||
|
export { SepiaTransformation } from '@ohos/imageknife'
|
||||||
|
|
||||||
|
export { SketchTransformation } from '@ohos/imageknife'
|
||||||
|
|
||||||
|
export { SwirlTransformation } from '@ohos/imageknife'
|
||||||
|
|
||||||
|
export { ToonTransformation } from '@ohos/imageknife'
|
||||||
|
|
||||||
|
export { VignetterTransformation } from '@ohos/imageknife'
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Entry
|
||||||
|
@Component
|
||||||
|
export struct IndexPage {
|
||||||
|
build() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"src": [
|
"src": [
|
||||||
"pages/Index"
|
"pages/IndexPage"
|
||||||
]
|
]
|
||||||
}
|
}
|
Loading…
Reference in New Issue