diff --git a/README.md b/README.md index 15d70fb..f20fcbd 100644 --- a/README.md +++ b/README.md @@ -433,6 +433,9 @@ request.skipMemoryCache(true) | request.sketchFilter() | SketchFilterTransformation | 素描滤波器 | | request.mask() | MaskTransformation | 遮罩 | | request.swirlFilter() | SwirlFilterTransformation | 扭曲滤波器 | +| request.kuwaharaFilter() | KuwaharaFilterTransform | 桑原滤波器 | +| request.toonFilter() | ToonFilterTransform | 动画滤波器 | +| request.vignetteFilter() | VignetteFilterTransform | 装饰滤波器 | diff --git a/build-profile.json5 b/build-profile.json5 index daded0e..46629bc 100644 --- a/build-profile.json5 +++ b/build-profile.json5 @@ -7,7 +7,7 @@ "name": "default", "signingConfig": "default" } - ], + ] }, "modules": [ { @@ -25,6 +25,10 @@ { "name": "imageknife", "srcPath": "./imageknife" + }, + { + "name": "gpu_transform", + "srcPath": "./gpu_transform" } ] } \ No newline at end of file diff --git a/entry/src/main/ets/pages/cropImagePage2.ets b/entry/src/main/ets/pages/cropImagePage2.ets index 2643e39..a273999 100644 --- a/entry/src/main/ets/pages/cropImagePage2.ets +++ b/entry/src/main/ets/pages/cropImagePage2.ets @@ -22,8 +22,9 @@ import { CropCallback } from '@ohos/imageknife' import { FileUtils } from '@ohos/imageknife' -@Component + @Entry +@Component export struct CropImagePage2 { @State options1: PixelMapCrop.Options = new PixelMapCrop.Options(); @State cropTap: boolean = false; diff --git a/entry/src/main/ets/pages/transformPixelMapPage.ets b/entry/src/main/ets/pages/transformPixelMapPage.ets index bcffc37..c12da4a 100644 --- a/entry/src/main/ets/pages/transformPixelMapPage.ets +++ b/entry/src/main/ets/pages/transformPixelMapPage.ets @@ -27,11 +27,11 @@ import { BrightnessFilterTransformation } from '@ohos/imageknife' import { ContrastFilterTransformation } from '@ohos/imageknife' import { InvertFilterTransformation } from '@ohos/imageknife' import { SepiaFilterTransformation } from '@ohos/imageknife' -import {SketchFilterTransformation} from '@ohos/imageknife' -import {BlurTransformation} from '@ohos/imageknife' -import {PixelationFilterTransformation} from '@ohos/imageknife' -import {MaskTransformation} from '@ohos/imageknife' -import {SwirlFilterTransformation} from '@ohos/imageknife' +import { SketchFilterTransformation } from '@ohos/imageknife' +import { BlurTransformation } from '@ohos/imageknife' +import { PixelationFilterTransformation } from '@ohos/imageknife' +import { MaskTransformation } from '@ohos/imageknife' +import { SwirlFilterTransformation } from '@ohos/imageknife' /** @@ -44,26 +44,29 @@ let mUrl = $r('app.media.pngSample'); @Entry @Component struct TransformPixelMapPage { - @State url: string= ""; - @State mCropPixelMap: PixelMap= undefined; - @State mRoundPixelMap: PixelMap= undefined; - @State mCirclePixelMap: PixelMap= undefined; - @State mCircleBorderPixelMap: PixelMap= undefined; - @State mRotatePixelMap: PixelMap= undefined; - @State mSquarePixelMap: PixelMap= undefined; - @State mClipTopPixelMap: PixelMap= undefined; - @State mClipCenterPixelMap: PixelMap= undefined; - @State mClipBottomPixelMap: PixelMap= undefined; - @State mGrayscalePixelMap: PixelMap= undefined; - @State mBrightnessPixelMap: PixelMap= undefined; - @State mContrastPixelMap: PixelMap= undefined; - @State mInvertPixelMap: PixelMap= undefined; - @State mSepiaPixelMap: PixelMap= undefined; - @State mSketchPixelMap: PixelMap= undefined; - @State mBlurPixelMap: PixelMap= undefined; - @State mPixelPixelMap: PixelMap= undefined; - @State mSwirlPixelMap: PixelMap= undefined; - @State mMaskPixelMap: PixelMap= undefined; + @State url: string = ""; + @State mCropPixelMap: PixelMap = undefined; + @State mRoundPixelMap: PixelMap = undefined; + @State mCirclePixelMap: PixelMap = undefined; + @State mCircleBorderPixelMap: PixelMap = undefined; + @State mRotatePixelMap: PixelMap = undefined; + @State mSquarePixelMap: PixelMap = undefined; + @State mClipTopPixelMap: PixelMap = undefined; + @State mClipCenterPixelMap: PixelMap = undefined; + @State mClipBottomPixelMap: PixelMap = undefined; + @State mGrayscalePixelMap: PixelMap = undefined; + @State mBrightnessPixelMap: PixelMap = undefined; + @State mContrastPixelMap: PixelMap = undefined; + @State mInvertPixelMap: PixelMap = undefined; + @State mSepiaPixelMap: PixelMap = undefined; + @State mSketchPixelMap: PixelMap = undefined; + @State mBlurPixelMap: PixelMap = undefined; + @State mPixelPixelMap: PixelMap = undefined; + @State mSwirlPixelMap: PixelMap = undefined; + @State mMaskPixelMap: PixelMap = undefined; + @State mKuwaharaPixelMap: PixelMap = undefined; + @State mToonPixelMap: PixelMap = undefined; + @State mVignettePixelMap: PixelMap = undefined; build() { Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) { @@ -98,7 +101,7 @@ struct TransformPixelMapPage { }); }.margin({ top: 10 }) - Image(this.mCropPixelMap ) + Image(this.mCropPixelMap) .objectFit(ImageFit.None) .width(100) .height(100) @@ -151,7 +154,7 @@ struct TransformPixelMapPage { }); }.margin({ top: 10 }) - Image(this.mRoundPixelMap ) + Image(this.mRoundPixelMap) .objectFit(ImageFit.Fill) .width(100) .height(100) @@ -170,7 +173,7 @@ struct TransformPixelMapPage { .onClick(() => { this.circleTransformation(); }); - Image(this.mCirclePixelMap ) + Image(this.mCirclePixelMap) .width(200) .height(200) .margin({ top: 10 }) @@ -188,7 +191,7 @@ struct TransformPixelMapPage { .onClick(() => { this.circleBorderTransformation(5); }); - Image(this.mCircleBorderPixelMap ) + Image(this.mCircleBorderPixelMap) .width(200) .height(200) .margin({ top: 10 }) @@ -210,7 +213,7 @@ struct TransformPixelMapPage { } this.transformRotate(mRotate); }); - Image(this.mRotatePixelMap ) + Image(this.mRotatePixelMap) .width(200) .height(200) .margin({ top: 10 }) @@ -228,7 +231,7 @@ struct TransformPixelMapPage { .onClick(() => { this.transformSquare(); }); - Image(this.mSquarePixelMap ) + Image(this.mSquarePixelMap) .objectFit(ImageFit.Fill) .width(200) .height(200) @@ -266,17 +269,17 @@ struct TransformPixelMapPage { }.margin({ top: 10 }) Row({ space: 1 }) { - Image(this.mClipTopPixelMap ) + Image(this.mClipTopPixelMap) .objectFit(ImageFit.Fill) .width(100) .height(100) .margin({ top: 10 }) - Image(this.mClipCenterPixelMap ) + Image(this.mClipCenterPixelMap) .objectFit(ImageFit.Fill) .width(100) .height(100) .margin({ top: 10 }) - Image(this.mClipBottomPixelMap ) + Image(this.mClipBottomPixelMap) .objectFit(ImageFit.Fill) .width(100) .height(100) @@ -295,7 +298,7 @@ struct TransformPixelMapPage { .onClick(() => { this.grayscalePixelMap(); }); - Image(this.mGrayscalePixelMap ) + Image(this.mGrayscalePixelMap) .objectFit(ImageFit.Fill) .width(200) .height(200) @@ -313,7 +316,7 @@ struct TransformPixelMapPage { .onClick(() => { this.brightnessPixelMap(0.8); }); - Image(this.mBrightnessPixelMap ) + Image(this.mBrightnessPixelMap) .objectFit(ImageFit.Fill) .width(200) .height(200) @@ -331,7 +334,7 @@ struct TransformPixelMapPage { .onClick(() => { this.contrastPixelMap(4); }); - Image(this.mContrastPixelMap ) + Image(this.mContrastPixelMap) .objectFit(ImageFit.Fill) .width(200) .height(200) @@ -349,7 +352,7 @@ struct TransformPixelMapPage { .onClick(() => { this.invertPixelMap(); }); - Image(this.mInvertPixelMap ) + Image(this.mInvertPixelMap) .objectFit(ImageFit.Fill) .width(200) .height(200) @@ -368,7 +371,7 @@ struct TransformPixelMapPage { .onClick(() => { this.sepiaPixelMap(); }); - Image(this.mSepiaPixelMap ) + Image(this.mSepiaPixelMap) .objectFit(ImageFit.Fill) .width(200) .height(200) @@ -386,7 +389,7 @@ struct TransformPixelMapPage { .onClick(() => { this.sketchPixelMap(); }); - Image(this.mSketchPixelMap ) + Image(this.mSketchPixelMap) .objectFit(ImageFit.Fill) .width(200) .height(200) @@ -405,7 +408,7 @@ struct TransformPixelMapPage { .onClick(() => { this.blurHandlePixelMap(20); }); - Image(this.mBlurPixelMap ) + Image(this.mBlurPixelMap) .objectFit(ImageFit.Fill) .width(200) .height(200) @@ -425,7 +428,7 @@ struct TransformPixelMapPage { .onClick(() => { this.pixelHandlePixelMap(20); }); - Image(this.mPixelPixelMap ) + Image(this.mPixelPixelMap) .objectFit(ImageFit.Fill) .width(200) .height(200) @@ -444,7 +447,7 @@ struct TransformPixelMapPage { .onClick(() => { this.swirlHandlePixelMap(); }); - Image(this.mSwirlPixelMap ) + Image(this.mSwirlPixelMap) .objectFit(ImageFit.Fill) .width(200) .height(200) @@ -463,7 +466,64 @@ struct TransformPixelMapPage { .onClick(() => { this.maskHandlePixelMap($r('app.media.mask_starfish')); }); - Image(this.mMaskPixelMap ) + Image(this.mMaskPixelMap) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("KuwaharaFilterTransform").fontColor(Color.Gray).fontSize(16); + Button() { + Text("图片kuwahara").fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.kuwaharaHandlePixelMap(); + }); + Image(this.mKuwaharaPixelMap) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("ToonFilterTransform").fontColor(Color.Gray).fontSize(16); + Button() { + Text("图片toon").fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.toonHandlePixelMap(); + }); + Image(this.mToonPixelMap) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("VignetteFilterTransform").fontColor(Color.Gray).fontSize(16); + Button() { + Text("图片vignette").fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.vignetteHandlePixelMap(); + }); + Image(this.mVignettePixelMap) .objectFit(ImageFit.Fill) .width(200) .height(200) @@ -481,19 +541,19 @@ struct TransformPixelMapPage { } -/** + /** * centerCrop */ centerCrop() { var imageKnifeOption = new RequestOption(); imageKnifeOption.load($r('app.media.jpgSample')) - // imageKnifeOption.load(mUrl) + // imageKnifeOption.load(mUrl) .addListener((err, data) => { let result = undefined; this.mCropPixelMap = result; setTimeout(() => { let result2 = undefined; - result2 = data.drawPixelMap.imagePixelMap as PixelMap; + result2 = data.drawPixelMap.imagePixelMap as PixelMap; this.mCropPixelMap = result2; }, 100) return false; @@ -504,7 +564,7 @@ struct TransformPixelMapPage { ImageKnife.call(imageKnifeOption); } -/** + /** * centerInside */ centerInside() { @@ -515,7 +575,7 @@ struct TransformPixelMapPage { this.mCropPixelMap = result; setTimeout(() => { let result2 = undefined; - result2 = data.drawPixelMap.imagePixelMap as PixelMap; + result2 = data.drawPixelMap.imagePixelMap as PixelMap; this.mCropPixelMap = result2; }, 100) return false; @@ -526,7 +586,7 @@ struct TransformPixelMapPage { ImageKnife.call(imageKnifeOption); } -/** + /** * centerInside */ fitCenter() { @@ -537,7 +597,7 @@ struct TransformPixelMapPage { this.mCropPixelMap = result; setTimeout(() => { let result2 = undefined; - result2 = data.drawPixelMap.imagePixelMap as PixelMap; + result2 = data.drawPixelMap.imagePixelMap as PixelMap; this.mCropPixelMap = result2; }, 100) return false; @@ -547,11 +607,11 @@ struct TransformPixelMapPage { .fitCenter(); ImageKnife.call(imageKnifeOption); } -/** + /** * 圆角设置 */ roundedCornersTransformation(top_left: number, - bottom_left: number, top_right: number, bottom_right: number) { + bottom_left: number, top_right: number, bottom_right: number) { var imageKnifeOption = new RequestOption(); imageKnifeOption.load(mUrl) @@ -560,18 +620,23 @@ struct TransformPixelMapPage { this.mRoundPixelMap = result; setTimeout(() => { let result2 = undefined; - result2 = data.drawPixelMap.imagePixelMap as PixelMap; + result2 = data.drawPixelMap.imagePixelMap as PixelMap; this.mRoundPixelMap = result2; }, 100) return false; }) .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) .skipMemoryCache(true) - .roundedCorners({ top_left: top_left, top_right: top_right, bottom_left: bottom_left, bottom_right: bottom_right }) + .roundedCorners({ + top_left: top_left, + top_right: top_right, + bottom_left: bottom_left, + bottom_right: bottom_right + }) ImageKnife.call(imageKnifeOption); } -/** + /** * 裁剪圆 */ circleTransformation() { @@ -579,7 +644,7 @@ struct TransformPixelMapPage { imageKnifeOption.load(mUrl) .addListener((err, data) => { let result = undefined; - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mCirclePixelMap = result; return false; }) @@ -589,7 +654,7 @@ struct TransformPixelMapPage { ImageKnife.call(imageKnifeOption); } -/** + /** * 圆环裁剪 */ circleBorderTransformation(border: number) { @@ -599,7 +664,7 @@ struct TransformPixelMapPage { imageKnifeOption.load(mUrl) .addListener((err, data) => { let result = undefined; - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mCircleBorderPixelMap = result; return false; }) @@ -610,7 +675,7 @@ struct TransformPixelMapPage { ImageKnife.call(imageKnifeOption); } -/** + /** * 旋转 */ transformRotate(angled: number) { @@ -619,7 +684,7 @@ struct TransformPixelMapPage { imageKnifeOption.load(mUrl) .addListener((err, data) => { let result = undefined; - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mRotatePixelMap = result; return false; }) @@ -629,7 +694,7 @@ struct TransformPixelMapPage { ImageKnife.call(imageKnifeOption); } -/** + /** * 正方形裁剪 */ transformSquare() { @@ -638,7 +703,7 @@ struct TransformPixelMapPage { imageKnifeOption.load(mUrl) .addListener((err, data) => { let result = undefined; - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mSquarePixelMap = result; return false; }) @@ -648,7 +713,7 @@ struct TransformPixelMapPage { ImageKnife.call(imageKnifeOption); } -/** + /** * 区域裁剪 */ clipPixelMap(width: number, height: number, cropType: CropType) { @@ -658,13 +723,13 @@ struct TransformPixelMapPage { .addListener((err, data) => { let result = undefined; if (cropType == CropType.TOP) { - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mClipTopPixelMap = result; } else if (cropType == CropType.CENTER) { - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mClipCenterPixelMap = result; } else if (cropType == CropType.BOTTOM) { - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mClipBottomPixelMap = result; } return false; @@ -676,7 +741,7 @@ struct TransformPixelMapPage { } -/** + /** * 灰度 */ grayscalePixelMap() { @@ -685,18 +750,19 @@ struct TransformPixelMapPage { imageKnifeOption.load(mUrl) .addListener((err, data) => { let result = undefined; - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mGrayscalePixelMap = result; return false; }) .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) .skipMemoryCache(true) + .enableGPU() .grayscale() ImageKnife.call(imageKnifeOption); } -/** + /** *亮度b */ brightnessPixelMap(brightness: number) { @@ -705,18 +771,19 @@ struct TransformPixelMapPage { imageKnifeOption.load(mUrl) .addListener((err, data) => { let result = undefined; - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mBrightnessPixelMap = result; return false; }) .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) .skipMemoryCache(true) + .enableGPU() .brightnessFilter(brightness) ImageKnife.call(imageKnifeOption); } -/** + /** *对比度 */ contrastPixelMap(contrast: number) { @@ -725,18 +792,19 @@ struct TransformPixelMapPage { imageKnifeOption.load(mUrl) .addListener((err, data) => { let result = undefined; - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mContrastPixelMap = result; return false; }) .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) .skipMemoryCache(true) + .enableGPU() .contrastFilter(contrast) ImageKnife.call(imageKnifeOption); } -/** + /** *反转处理 */ invertPixelMap() { @@ -745,18 +813,19 @@ struct TransformPixelMapPage { imageKnifeOption.load(mUrl) .addListener((err, data) => { let result = undefined; - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mInvertPixelMap = result; return false; }) .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) .skipMemoryCache(true) + .enableGPU() .invertFilter() ImageKnife.call(imageKnifeOption); } -/** + /** *照片老旧出来(黑褐色) */ sepiaPixelMap() { @@ -765,18 +834,19 @@ struct TransformPixelMapPage { imageKnifeOption.load(mUrl) .addListener((err, data) => { let result = undefined; - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mSepiaPixelMap = result; return false; }) .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) .skipMemoryCache(true) + .enableGPU() .sepiaFilter() ImageKnife.call(imageKnifeOption); } -/** + /** *素描 */ sketchPixelMap() { @@ -785,18 +855,19 @@ struct TransformPixelMapPage { imageKnifeOption.load(mUrl) .addListener((err, data) => { let result = undefined; - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mSketchPixelMap = result; return false; }) .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) .skipMemoryCache(true) + .enableGPU() .sketchFilter() ImageKnife.call(imageKnifeOption); } -/** + /** *模糊 */ blurHandlePixelMap(radius: number) { @@ -805,17 +876,18 @@ struct TransformPixelMapPage { imageKnifeOption.load(mUrl) .addListener((err, data) => { let result = undefined; - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mBlurPixelMap = result; return false; }) .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) .skipMemoryCache(true) + .enableGPU() .blur(radius) ImageKnife.call(imageKnifeOption); } -/** + /** *马赛克 */ pixelHandlePixelMap(pixel: number) { @@ -824,18 +896,19 @@ struct TransformPixelMapPage { imageKnifeOption.load(mUrl) .addListener((err, data) => { let result = undefined; - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mPixelPixelMap = result; return false; }) .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) .skipMemoryCache(true) + .enableGPU() .pixelationFilter(pixel) ImageKnife.call(imageKnifeOption); } -/** + /** *扭曲 */ swirlHandlePixelMap() { @@ -844,18 +917,19 @@ struct TransformPixelMapPage { imageKnifeOption.load(mUrl) .addListener((err, data) => { let result = undefined; - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mSwirlPixelMap = result; return false; }) .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) .skipMemoryCache(true) + .enableGPU() .swirlFilter(80) // .diskCacheStrategy(new NONE()) ImageKnife.call(imageKnifeOption); } -/** + /** *遮罩 */ maskHandlePixelMap(maskResource: Resource) { @@ -865,7 +939,7 @@ struct TransformPixelMapPage { imageKnifeOption.load(mUrl) .addListener((err, data) => { let result = undefined; - result = data.drawPixelMap.imagePixelMap as PixelMap; + result = data.drawPixelMap.imagePixelMap as PixelMap; this.mMaskPixelMap = result; return false; }) @@ -876,6 +950,69 @@ struct TransformPixelMapPage { ImageKnife.call(imageKnifeOption); } + + /** + *kuwahara + */ + kuwaharaHandlePixelMap() { + let imageKnifeOption = new RequestOption(); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = undefined; + result = data.drawPixelMap.imagePixelMap as PixelMap; + this.mKuwaharaPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .enableGPU() + .kuwaharaFilter(20.0) + // .diskCacheStrategy(new NONE()) + ImageKnife.call(imageKnifeOption); + + } + + /** + *toon + */ + toonHandlePixelMap() { + let imageKnifeOption = new RequestOption(); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = undefined; + result = data.drawPixelMap.imagePixelMap as PixelMap; + this.mToonPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .enableGPU() + .toonFilter(0.2, 50.0); + // .diskCacheStrategy(new NONE()) + ImageKnife.call(imageKnifeOption); + + } + + /** + *vignette + */ + vignetteHandlePixelMap() { + let imageKnifeOption = new RequestOption(); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = undefined; + result = data.drawPixelMap.imagePixelMap as PixelMap; + this.mVignettePixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .enableGPU() + .vignetteFilter([0.5, 0.5], [0.0, 0.0, 0.0], [0.3, 0.5]) + // .diskCacheStrategy(new NONE()) + ImageKnife.call(imageKnifeOption); + + } } var ImageKnife = globalThis.ImageKnife \ No newline at end of file diff --git a/gpu_transform/.gitignore b/gpu_transform/.gitignore new file mode 100644 index 0000000..5a6ba80 --- /dev/null +++ b/gpu_transform/.gitignore @@ -0,0 +1,4 @@ +/node_modules +/.preview +/build +/.cxx \ No newline at end of file diff --git a/gpu_transform/CHANGELOG.md b/gpu_transform/CHANGELOG.md new file mode 100644 index 0000000..b6f5f7b --- /dev/null +++ b/gpu_transform/CHANGELOG.md @@ -0,0 +1,16 @@ +## 1.0.0 +获取图片的buffer数据,使用openGL、着色器(Shader),操作GPU,达到图片滤波器的效果 +- 支持模糊滤波器 +- 支持亮度滤波器 +- 支持颜色反转滤波器 +- 支持对比度滤波器 +- 支持灰色滤波器 +- 支持桑原滤波器 +- 支持马赛克滤波器 +- 支持乌墨色滤波器 +- 支持素描滤波器 +- 支持扭曲滤波器 +- 支持动画滤波器 +- 支持装饰滤波器 + + diff --git a/gpu_transform/LICENSE b/gpu_transform/LICENSE new file mode 100644 index 0000000..8dada3e --- /dev/null +++ b/gpu_transform/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. diff --git a/gpu_transform/README.OpenSource b/gpu_transform/README.OpenSource new file mode 100644 index 0000000..f7d9005 --- /dev/null +++ b/gpu_transform/README.OpenSource @@ -0,0 +1,11 @@ +[ + { + "Name": "android-gpuimage", + "License": " Apache License, Version 2.0", + "License File": "https://github.com/cats-oss/android-gpuimage", + "Version Number": "4.13.1", + "Owner" : "cats-oss", + "Upstream URL": "https://github.com/cats-oss/android-gpuimage", + "Description": "Android filters based on OpenGL (idea from GPUImage for iOS)" + } +] \ No newline at end of file diff --git a/gpu_transform/README.md b/gpu_transform/README.md new file mode 100644 index 0000000..08e3ad5 --- /dev/null +++ b/gpu_transform/README.md @@ -0,0 +1,79 @@ +## gpu_transform + +该module通过获取图片的buffer数据,使用openGL、着色器(Shader),操作GPU,达到图片滤波器的效果。 + +本项目基于开源库 [android-gpuimage](https://github.com/cats-oss/android-gpuimage) 进行OpenHarmony的自研版本: + +## 下载安装 +``` + npm install @ohos/gpu_transform --save +``` + +## 例子说明 +``` + //获取像素点数据 + let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber()); + await bitmap.readPixelsToBuffer(bufferData); + + // 使用GPUImageVignetterFilter过滤器 + let filter = new GPUImageVignetterFilter(); + filter.setImageData(bufferData, targetWidth, targetHeight); + filter.setVignetteCenter(this.centerPoint); + filter.setVignetteColor(this.vignetteColor); + filter.setVignetteStart(this.vignetteSpace[0]); + filter.setVignetteEnd(this.vignetteSpace[1]); + + //获取经过gpu处理的像素点数据 + let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight) + + //像素点数据写入 + bitmap.writeBufferToPixels(buf); + +``` + +## 滤波器类型说明 +| 滤波器类型 | 描述 | +| ---------------------------- | ---------------------------| +| GPUImageBlurFilter | 模糊滤波器 | +| GPUImageBrightnessFilter | 亮度滤波器 | +| GPUImageColorInvertFilter | 颜色反转滤波器 | +| GPUImageContrastFilter | 对比度滤波器 | +| GPUImageGrayscaleFilter | 灰色滤波器 | +| GPUImageKuwaharaFilter | 桑原滤波器 | +| GPUImagePixelationFilter | 马赛克滤波器 | +| GPUImageSepiaToneFilter | 乌墨色滤波器 | +| GPUImageSketchFilter | 素描滤波器 | +| GPUImageSwirlFilter | 扭曲滤波器 | +| GPUImageToonFilter | 动画滤波器 | +| GPUImageVignetterFilter | 装饰滤波器 | + + +## 目录结构 +``` +/gpu_transform/src/main + --cpp + --common # napi公共方法封装 + --constant # 顶点、片元着色器 + --napi # native入口 + --render # 绘制 + --util # 工具层 + --ets + --filter # 各种滤波器 + --gl # native的js层 + --interface # 接口 +``` + + +## 兼容性 + +支持 OpenHarmony API version 9 及以上版本。 + +## 贡献代码 + +使用过程中发现任何问题都可以提 [issue](https://gitee.com/openharmony-tpc/ImageKnife/issues) 给我们,当然,我们也非常欢迎你给我们发 [PR](https://gitee.com/openharmony-tpc/ImageKnife/issues) 。 + +## 开源协议 + +本项目基于 [Apache License 2.0](https://gitee.com/openharmony-tpc/ImageKnife/blob/master/LICENSE) ,请自由的享受和参与开源。 + + diff --git a/gpu_transform/build-profile.json5 b/gpu_transform/build-profile.json5 new file mode 100644 index 0000000..85011b1 --- /dev/null +++ b/gpu_transform/build-profile.json5 @@ -0,0 +1,19 @@ +{ + "apiType": "stageMode", + "buildOption": { + "externalNativeOptions": { + "path": "./src/main/cpp/CMakeLists.txt", + "arguments": "", + "abiFilters": [ + "armeabi-v7a", + "arm64-v8a" + ], + "cppFlags": "" + }, + }, + "targets": [ + { + "name": "default" + } + ] +} diff --git a/gpu_transform/hvigorfile.ts b/gpu_transform/hvigorfile.ts new file mode 100644 index 0000000..47e6e1f --- /dev/null +++ b/gpu_transform/hvigorfile.ts @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +export { harTasks } from '@ohos/hvigor-ohos-plugin'; \ No newline at end of file diff --git a/gpu_transform/index.ets b/gpu_transform/index.ets new file mode 100644 index 0000000..ddc8ea4 --- /dev/null +++ b/gpu_transform/index.ets @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { GPUImage3x3TextureSamplingFilter } from './src/main/ets/gpu/filter/GPUImage3x3TextureSamplingFilter' +export { GPUImageBlurFilter } from './src/main/ets/gpu/filter/GPUImageBlurFilter' +export { GPUImageBrightnessFilter } from './src/main/ets/gpu/filter/GPUImageBrightnessFilter' +export { GPUImageColorInvertFilter } from './src/main/ets/gpu/filter/GPUImageColorInvertFilter' +export { GPUImageColorMatrixFilter } from './src/main/ets/gpu/filter/GPUImageColorMatrixFilter' +export { GPUImageContrastFilter } from './src/main/ets/gpu/filter/GPUImageContrastFilter' +export { GPUImageFilter } from './src/main/ets/gpu/filter/GPUImageFilter' +export { GPUImageFilterGroup } from './src/main/ets/gpu/filter/GPUImageFilterGroup' +export { GPUImageGrayscaleFilter } from './src/main/ets/gpu/filter/GPUImageGrayscaleFilter' +export { GPUImageKuwaharaFilter } from './src/main/ets/gpu/filter/GPUImageKuwaharaFilter' +export { GPUImagePixelationFilter } from './src/main/ets/gpu/filter/GPUImagePixelationFilter' +export { GPUImageSepiaToneFilter } from './src/main/ets/gpu/filter/GPUImageSepiaToneFilter' +export { GPUImageSketchFilter } from './src/main/ets/gpu/filter/GPUImageSketchFilter' +export { GPUImageSwirlFilter } from './src/main/ets/gpu/filter/GPUImageSwirlFilter' +export { GPUImageToonFilter } from './src/main/ets/gpu/filter/GPUImageToonFilter' +export { GPUImageVignetterFilter } from './src/main/ets/gpu/filter/GPUImageVignetterFilter' + + diff --git a/gpu_transform/package.json b/gpu_transform/package.json new file mode 100644 index 0000000..e2644e5 --- /dev/null +++ b/gpu_transform/package.json @@ -0,0 +1,24 @@ +{ + "license":"Apache License 2.0", + "types":"", + "devDependencies":{}, + "keywords":[ + "OpenHarmony", + "transformation", + "gpu_transform" + ], + "name":"@ohos/gpu_transform", + "description":"based on OpenHarmony system, it can quickly realize image blur, Mosaic, sketch and other transformation effects through GPU", + "author":"ohos_tpc", + "ohos":{ + "org":"opensource" + }, + "tags":[ + "Tool" + ], + "main":"index.ets", + "repository":"https://gitee.com/openharmony-tpc/ImageKnife", + "type":"module", + "version":"1.0.0", + "dependencies":{} +} \ No newline at end of file diff --git a/gpu_transform/src/main/cpp/CMakeLists.txt b/gpu_transform/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000..6407f87 --- /dev/null +++ b/gpu_transform/src/main/cpp/CMakeLists.txt @@ -0,0 +1,33 @@ +# the minimum version of CMake. +cmake_minimum_required(VERSION 3.4.1) +project(gpu_transform) + +set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +include_directories(${NATIVERENDER_ROOT_PATH} + ${NATIVERENDER_ROOT_PATH}/include + ${NATIVERENDER_ROOT_PATH}/util + ${NATIVERENDER_ROOT_PATH}/napi + ${NATIVERENDER_ROOT_PATH}/common + ${NATIVERENDER_ROOT_PATH}/render + ${NATIVERENDER_ROOT_PATH}/constant + ) + +add_library(nativeGpu SHARED + ${NATIVERENDER_ROOT_PATH}/napi/napi_init.cpp + ${NATIVERENDER_ROOT_PATH}/render/EGLRender.cpp + ${NATIVERENDER_ROOT_PATH}/util/GLUtils.cpp + ${NATIVERENDER_ROOT_PATH}/util/NapiUtil.cpp + ) + +find_library ( + hilog-lib + hilog_ndk.z ) +find_library ( + EGL-lib + EGL ) +find_library ( + GLES-lib + GLESv3 ) + +target_link_libraries(nativeGpu PUBLIC ${hilog-lib} ${EGL-lib} ${GLES-lib} libace_napi.z.so libc++.a) \ No newline at end of file diff --git a/gpu_transform/src/main/cpp/common/native_common.h b/gpu_transform/src/main/cpp/common/native_common.h new file mode 100644 index 0000000..1c178b8 --- /dev/null +++ b/gpu_transform/src/main/cpp/common/native_common.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Created on 2022/12/15. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, + +#ifndef GPU_ImageETS_native_common_H +#define GPU_ImageETS_native_common_H + +#define NAPI_RETVAL_NOTHING + +#define GET_AND_THROW_LAST_ERROR(env) \ + do { \ + const napi_extended_error_info* errorInfo = nullptr; \ + napi_get_last_error_info((env), &errorInfo); \ + bool isPending = false; \ + napi_is_exception_pending((env), &isPending); \ + if (!isPending && errorInfo != nullptr) { \ + const char* errorMessage = \ + errorInfo->error_message != nullptr ? errorInfo->error_message : "empty error message"; \ + napi_throw_error((env), nullptr, errorMessage); \ + } \ + } while (0) + +#define DECLARE_NAPI_FUNCTION(name, func) \ + { \ + (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr \ + } + + +#define NAPI_CALL_BASE(env, theCall, retVal) \ + do { \ + if ((theCall) != napi_ok) { \ + GET_AND_THROW_LAST_ERROR((env)); \ + return retVal; \ + } \ + } while (0) + + +#define NAPI_CALL(env, theCall) NAPI_CALL_BASE(env, theCall, nullptr) + +#endif // GPU_ImageETS_native_common_H diff --git a/gpu_transform/src/main/cpp/constant/constant_shape.h b/gpu_transform/src/main/cpp/constant/constant_shape.h new file mode 100644 index 0000000..1cac03d --- /dev/null +++ b/gpu_transform/src/main/cpp/constant/constant_shape.h @@ -0,0 +1,475 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Created on 2022/12/16. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, + +#ifndef GPU_ImageETS_constant_shape_H +#define GPU_ImageETS_constant_shape_H + + +const int UNIFORM_TYPE_2FV_SIZE = 10; +const int UNIFORM_TYPE_FV = 1; +const int UNIFORM_TYPE_2FV = 2; +const int UNIFORM_TYPE_3FV = 3; +const int UNIFORM_TYPE_4FV = 4; +const int UNIFORM_TYPE_2F = 21; + +const int DEFAULT_ZERO = 0; +const int DEFAULT_ONE = 1; +const int DEFAULT_TWO = 2; +const int DEFAULT_THREE = 3; +const int DEFAULT_FOUR = 4; +const float DEFAULT_ONE_HALF = 1.5; + +const int UNIFORM_TYPE_ZERO = 0; +const int UNIFORM_TYPE_ONE = 1; +const int UNIFORM_TYPE_THREE = 3; +const int UNIFORM_TYPE_FOUR = 4; + + +const int SHADER_TYPE_BRIGHT = 0; +const int SHADER_TYPE_CONTRAST = 1; +const int SHADER_TYPE_INVERT = 2; +const int SHADER_TYPE_PIXELATION = 3; +const int SHADER_TYPE_KUWAHARA = 4; +const int SHADER_TYPE_SEPIA = 5; +const int SHADER_TYPE_SKETCH = 6; +const int SHADER_TYPE_SWIRL = 7; +const int SHADER_TYPE_TOON = 8; +const int SHADER_TYPE_VIGNETTE = 9; +const int SHADER_TYPE_GRAYSCALE = 10; +const int SHADER_TYPE_BLUR = 12; + + +const char vShaderStr[] = + "#version 300 es \n" + "layout(location = 0) in vec4 a_position; \n" + "layout(location = 1) in vec2 a_texCoord; \n" + "out vec2 v_texCoord; \n" + "void main() \n" + "{ \n" + " gl_Position = a_position; \n" + " v_texCoord = a_texCoord; \n" + "} \n"; + +const char fShaderStr0[] = + "#version 300 es \n" + "precision mediump float; \n" + "in vec2 v_texCoord; \n" + "layout(location = 0) out vec4 outColor; \n" + "uniform sampler2D s_TextureMap; \n" + "void main() \n" + "{ \n" + "outColor = texture(s_TextureMap,v_texCoord); \n" + "} \n"; + +const char v3x3ShaderStr[] = + "#version 300 es\n" + "precision highp float;\n" + "layout(location = 0) in vec4 a_position;\n" + "layout(location = 1) in vec2 a_texCoord;\n" + "uniform highp float texelWidth;\n" + "uniform highp float texelHeight;\n" + "out vec2 v_texCoord;\n" + "out vec2 leftTextureCoordinate;\n" + "out vec2 rightTextureCoordinate;\n" + "out vec2 topTextureCoordinate;\n" + "out vec2 topLeftTextureCoordinate;\n" + "out vec2 topRightTextureCoordinate;\n" + "out vec2 bottomTextureCoordinate;\n" + "out vec2 bottomLeftTextureCoordinate;\n" + "out vec2 bottomRightTextureCoordinate;\n" + "void main()\n" + "{\n" + "gl_Position = a_position;\n" + "vec2 widthStep = vec2(texelWidth, 0.0);\n" + "vec2 heightStep = vec2(0.0, texelHeight);\n" + "vec2 widthHeightStep = vec2(texelWidth, texelHeight);\n" + "vec2 widthNegativeHeightStep = vec2(texelWidth, -texelHeight);\n" + "v_texCoord = a_texCoord;\n" + "leftTextureCoordinate = a_texCoord - widthStep;\n" + "rightTextureCoordinate = a_texCoord + widthStep;\n" + "\n" + "topTextureCoordinate = a_texCoord - heightStep;\n" + "topLeftTextureCoordinate = a_texCoord - widthHeightStep;\n" + "topRightTextureCoordinate = a_texCoord + widthNegativeHeightStep;\n" + "\n" + "bottomTextureCoordinate = a_texCoord +heightStep;\n" + "bottomLeftTextureCoordinate = a_texCoord - widthNegativeHeightStep;\n" + "bottomRightTextureCoordinate = a_texCoord + widthHeightStep;\n" + "}"; + +// kuwahara +const char fShaderStr3[] = + "#version 300 es\n" + "precision highp float;\n" + "layout(location = 0) out vec4 outColor;\n" + "in vec2 v_texCoord;\n" + "uniform lowp sampler2D s_TextureMap;\n" + "uniform vec2 u_texSize;\n" + "uniform highp float radius;\n" + "const vec2 src_size = vec2(1.0 / 768.0, 1.0 / 1024.0);\n" + "void main() {\n" + "vec2 uv = v_texCoord;\n" + "float n = float((radius + 1.0) * (radius + 1.0));\n" + "int i ; int j ;\n" + "vec3 m0 = vec3(0.0); vec3 m1 = vec3(0.0); vec3 m2 = vec3(0.0); vec3 m3 = vec3(0.0);\n" + "vec3 s0 = vec3(0.0); vec3 s1 = vec3(0.0); vec3 s2 = vec3(0.0); vec3 s3 = vec3(0.0);\n" + "vec3 c;\n" + "for (j = -int(radius); j <=0; ++j) {\n" + "for (i = -int(radius); i <=0; ++i) {\n" + "c = texture(s_TextureMap,uv + vec2(i,j) * src_size).rgb;\n" + "m0 += c;\n" + "s0 += c * c;\n" + "}\n" + "}\n" + "for (j = -int(radius); j <=0; ++j) {\n" + "for (i =0; i <=int(radius); ++i) {\n" + "c = texture(s_TextureMap,uv + vec2(i,j) * src_size).rgb;\n" + "m1 += c;\n" + "s1 += c * c;\n" + "}\n" + "}\n" + "for (j = 0; j <=int(radius); ++j) {\n" + "for (i = 0; i <= int(radius); ++i) {\n" + "c = texture(s_TextureMap,uv + vec2(i,j) * src_size).rgb;\n" + "m2 += c;\n" + "s2 += c * c;\n" + "}\n" + "}\n" + "for (j = 0; j <=int(radius); ++j) {\n" + "for (i = -int(radius); i <= 0; ++i) {\n" + "c = texture(s_TextureMap,uv + vec2(i,j) * src_size).rgb;\n" + "m3 += c;\n" + "s3 += c * c;\n" + "}\n" + "}\n" + "\n" + "\n" + "float min_sigma2 = 1e+2;\n" + "m0 /= n;\n" + "s0 = abs(s0 /n - m0 * m0);\n" + "\n" + "float sigma2 = s0.r + s0.g + s0.b;\n" + "if (sigma2 < min_sigma2) {\n" + "min_sigma2 = sigma2;\n" + "outColor = vec4(m0,1.0);\n" + "}\n" + "\n" + "m1 /= n;\n" + "s1 = abs(s1 / n -m1 * m1);\n" + "\n" + "sigma2 = s1.r + s1.g + s1.b;\n" + "if (sigma2 < min_sigma2) {\n" + "min_sigma2 = sigma2;\n" + "outColor = vec4(m1,1.0);\n" + "}\n" + "\n" + "m2 /= n;\n" + "s2 = abs(s2 / n -m2 * m2);\n" + "\n" + "sigma2 = s2.r + s2.g + s2.b;\n" + "if (sigma2 < min_sigma2) {\n" + "min_sigma2 = sigma2;\n" + "outColor = vec4(m2,1.0);\n" + "}\n" + "\n" + "m3 /= n;\n" + "s3 = abs(s3 / n -m3 * m3);\n" + "\n" + "sigma2 = s3.r + s3.g + s3.b;\n" + "if (sigma2 < min_sigma2) {\n" + "min_sigma2 = sigma2;\n" + "outColor = vec4(m3,1.0);\n" + "}\n" + "}\n"; + +// 旋转 +const char swirlFShaderStr[] = + "#version 300 es\n" + "precision highp float;\n" + "layout(location = 0) out vec4 outColor;\n" + "in vec2 v_texCoord;\n" + "uniform lowp sampler2D s_TextureMap;\n" + "uniform vec2 u_texSize;\n" + "uniform highp float radius;\n" + "uniform highp float angle;\n" + "uniform vec2 center;\n" + "void main() {\n" + "vec2 tc = v_texCoord * u_texSize;\n" + "tc -= center;\n" + "float dist = length(tc);\n" + "if (dist < radius) {\n" + "float percent = (radius - dist) / radius;\n" + "float theta = percent * percent * angle * 8.0;\n" + "float s = sin(theta);\n" + "float c = cos(theta);\n" + "tc = vec2(dot(tc, vec2(c, -s)), dot(tc, vec2(s, c)));\n" + "}\n" + "tc += center;\n" + "outColor = texture(s_TextureMap, tc / u_texSize);\n" + "}"; + +// 亮度 +const char brightFShaderStr[] = + "#version 300 es\n" + "precision highp float;\n" + "in vec2 v_texCoord;\n" + "\n" + "uniform lowp sampler2D s_TextureMap;\n" + "uniform lowp float brightness;\n" + "layout(location = 0) out vec4 outColor;\n" + "\n" + "void main()\n" + "{\n" + "lowp vec4 textureColor = texture(s_TextureMap, v_texCoord);\n" + "\n" + "outColor = vec4((textureColor.rgb + vec3(brightness)), textureColor.w);\n" + "}"; + +// 反转 +const char contrastFShaderStr[] = + "#version 300 es\n" + "precision highp float;\n" + "in vec2 v_texCoord;\n" + "\n" + "uniform lowp sampler2D s_TextureMap;\n" + "uniform lowp float contrast;\n" + "layout(location = 0) out vec4 outColor;\n" + "\n" + "void main()\n" + "{\n" + "lowp vec4 textureColor = texture(s_TextureMap, v_texCoord);\n" + "\n" + "outColor = vec4(((textureColor.rgb - vec3(0.5)) * contrast + vec3(0.5)), textureColor.w);\n" + "}"; + +// invert +const char invertFShaderStr[] = + "#version 300 es\n" + "precision highp float;\n" + "in vec2 v_texCoord;\n" + "\n" + "uniform lowp sampler2D s_TextureMap;\n" + "layout(location = 0) out vec4 outColor;\n" + "\n" + "void main()\n" + "{\n" + "lowp vec4 textureColor = texture(s_TextureMap, v_texCoord);\n" + "\n" + "outColor = vec4((1.0 - textureColor.rgb), textureColor.w);\n" + "}"; + +// pixel +const char pixelFShaderStr[] = + "#version 300 es\n" + "precision highp float;\n" + "in vec2 v_texCoord;\n" + "uniform float imageWidthFactor;\n" + "uniform float imageHeightFactor;\n" + "uniform lowp sampler2D s_TextureMap;\n" + "uniform float pixel;\n" + "layout(location = 0) out vec4 outColor;\n" + + "void main()\n" + "{\n" + "vec2 uv = v_texCoord.xy;\n" + "float dx = pixel * imageWidthFactor;\n" + "float dy = pixel * imageHeightFactor;\n" + "vec2 coord = vec2(dx * floor(uv.x / dx), dy * floor(uv.y / dy));\n" + "vec3 tc = texture(s_TextureMap, coord).xyz;\n" + "outColor = vec4(tc, 1.0);\n" + "}"; + +// vignette +const char vignetteFShaderStr[] = + "#version 300 es\n" + "precision highp float;\n" + "uniform lowp sampler2D s_TextureMap;\n" + "in vec2 v_texCoord;\n" + "layout(location = 0) out vec4 outColor;\n" + "\n" + "uniform lowp vec2 vignetteCenter;\n" + "uniform lowp vec3 vignetteColor;\n" + "uniform highp float vignetteStart;\n" + "uniform highp float vignetteEnd;\n" + "\n" + "void main()\n" + "{\n" + "lowp vec3 rgb = texture(s_TextureMap, v_texCoord).rgb;\n" + "lowp float d = distance(v_texCoord, vec2(0.5,0.5));\n" + "rgb *= (1.0 - smoothstep(vignetteStart , vignetteEnd, d));\n" + "outColor = vec4(vec3(rgb), 1.0);\n" + "\n" + "lowp vec3 rgb2 = texture(s_TextureMap, v_texCoord).rgb;\n" + "lowp float d2 = distance(v_texCoord, vec2(vignetteCenter.x, vignetteCenter.y));\n" + "lowp float percent = smoothstep(vignetteStart, vignetteEnd, d2);\n" + "outColor = vec4(mix(rgb2.x,vignetteColor.x,percent), mix(rgb2.y, vignetteColor.y, percent), mix(rgb2.z, vignetteColor.z, percent), 1.0);\n" + "}"; + +// ColorMatrix +const char colorMatrixFShaderStr[] = + "#version 300 es\n" + "precision highp float;\n" + "in vec2 v_texCoord;\n" + "uniform lowp sampler2D s_TextureMap;\n" + "layout(location = 0) out vec4 outColor;\n" + "\n" + "uniform lowp mat4 colorMatrix;\n" + "uniform lowp float intensity;\n" + "void main()\n" + "{\n" + "lowp vec4 textureColor = texture(s_TextureMap, v_texCoord);\n" + "lowp vec4 outputColor = textureColor * colorMatrix;\n" + "outColor = (intensity * outputColor) + ((1.0 - intensity) * textureColor);\n" + "}"; + +// toon +const char toonFShaderStr[] = + "#version 300 es\n" + "precision highp float;\n" + "in vec2 v_texCoord;\n" + "layout(location = 0) out vec4 outColor;\n" + "in vec2 leftTextureCoordinate;\n" + "in vec2 rightTextureCoordinate;\n" + "in vec2 topTextureCoordinate;\n" + "in vec2 topLeftTextureCoordinate;\n" + "in vec2 topRightTextureCoordinate;\n" + "in vec2 bottomTextureCoordinate;\n" + "in vec2 bottomLeftTextureCoordinate;\n" + "in vec2 bottomRightTextureCoordinate;\n" + "uniform lowp sampler2D s_TextureMap;\n" + "uniform highp float intensity;\n" + "uniform highp float threshold;\n" + "uniform highp float quantizationLevels;\n" + "const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\n" + "void main()\n" + "{\n" + "vec4 textureColor = texture(s_TextureMap, v_texCoord);\n" + "float bottomLeftIntensity = texture(s_TextureMap, bottomLeftTextureCoordinate).r;\n" + "float topRightIntensity = texture(s_TextureMap, topRightTextureCoordinate).r;\n" + "float topLeftIntensity = texture(s_TextureMap, topLeftTextureCoordinate).r;\n" + "float bottomRightIntensity = texture(s_TextureMap, bottomRightTextureCoordinate).r;\n" + "float leftIntensity = texture(s_TextureMap, leftTextureCoordinate).r;\n" + "float rightIntensity = texture(s_TextureMap, rightTextureCoordinate).r;\n" + "float bottomIntensity = texture(s_TextureMap, bottomTextureCoordinate).r;\n" + "float topIntensity = texture(s_TextureMap, topTextureCoordinate).r;\n" + "float h = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity +2.0 * bottomIntensity + bottomRightIntensity;\n" + "float v = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity +2.0 * rightIntensity + topRightIntensity;\n" + "float mag = length(vec2(h, v));\n" + "\n" + "vec3 posterizedImageColor = floor((textureColor.rgb * quantizationLevels) + 0.5) / quantizationLevels;\n" + "\n" + "float thresholdTest = 1.0 - step(threshold, mag);\n" + "\n" + "outColor = vec4(posterizedImageColor * thresholdTest, textureColor.a);\n" + "}"; + +// grayScale +const char grayScaleShaderStr[] = + "#version 300 es\n" + "precision highp float;\n" + "in vec2 v_texCoord;\n" + "uniform lowp sampler2D s_TextureMap;\n" + "layout(location = 0) out vec4 outColor;\n" + "const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\n" + "void main()\n" + "{\n" + "lowp vec4 textureColor = texture(s_TextureMap, v_texCoord);\n" + "float luminance = dot(textureColor.rgb, W);\n" + "outColor = vec4(vec3(luminance), textureColor.a);\n" + "}"; + +// sketch +const char sketchShaderStr[] = + "#version 300 es\n" + "precision highp float;\n" + "layout(location = 0) out vec4 outColor;\n" + "uniform lowp sampler2D s_TextureMap;\n" + + "in vec2 textureCoordinate;\n" + "in vec2 leftTextureCoordinate;\n" + "in vec2 rightTextureCoordinate;\n" + "\n" + "in vec2 topTextureCoordinate;\n" + "in vec2 topLeftTextureCoordinate;\n" + "in vec2 topRightTextureCoordinate;\n" + "\n" + "in vec2 bottomTextureCoordinate;\n" + "in vec2 bottomLeftTextureCoordinate;\n" + "in vec2 bottomRightTextureCoordinate;\n" + "\n" + "void main()\n" + "{\n" + "float bottomLeftIntensity = texture(s_TextureMap, bottomLeftTextureCoordinate).r;\n" + "float topRightIntensity = texture(s_TextureMap, topRightTextureCoordinate).r;\n" + "float topLeftIntensity = texture(s_TextureMap, topLeftTextureCoordinate).r;\n" + "float bottomRightIntensity = texture(s_TextureMap, bottomRightTextureCoordinate).r;\n" + "float leftIntensity = texture(s_TextureMap, leftTextureCoordinate).r;\n" + "float rightIntensity = texture(s_TextureMap, rightTextureCoordinate).r;\n" + "float bottomIntensity = texture(s_TextureMap, bottomTextureCoordinate).r;\n" + "float topIntensity = texture(s_TextureMap, topTextureCoordinate).r;\n" + "float h = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity +2.0 * bottomIntensity + bottomRightIntensity;\n" + "float v = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity +2.0 * rightIntensity + topRightIntensity;\n" + "float mag = 1.0-length(vec2(h, v));\n" + "outColor = vec4(vec3(mag), 1.0);\n" + "}"; + +// blur +const char blurShaderStr[] = + "#version 300 es\n" + "precision highp float;\n" + "uniform lowp sampler2D s_TextureMap;\n" + "in vec2 v_texCoord;\n" + "layout(location = 0) out vec4 outColor;\n" + + "uniform highp int blurRadius;\n" + "uniform highp vec2 blurOffset;\n" + "\n" + "uniform highp float sumWeight;\n" + "float PI = 3.1415926;\n" + "float getWeight(int i)\n" + "{\n" + "float sigma = float(blurRadius) / 3.0 ;\n" + "return (1.0 / sqrt(2.0 * PI * sigma * sigma)) * exp(-float(i * i) / (2.0 * sigma * sigma)) / sumWeight;\n" + "}\n" + + "vec2 clampCoordinate (vec2 coordinate)\n" + "{\n" + "return vec2(clamp(coordinate.x, 0.0, 1.0), clamp(coordinate.y, 0.0, 1.0));\n" + "}\n" + "\n" + "void main()\n" + "{\n" + "vec4 sourceColor = texture(s_TextureMap, v_texCoord);\n" + "if (blurRadius <= 1)\n" + "{\n" + "outColor = sourceColor;\n" + "return;\n" + "}\n" + "float weight = getWeight(0);\n" + "vec3 finalColor = sourceColor.rgb * weight;\n" + "for(int i = 1; i < blurRadius; i++) {\n" + "weight = getWeight(i);\n" + "finalColor += texture(s_TextureMap, clampCoordinate(v_texCoord - blurOffset * float(i))).rgb * weight;\n" + "finalColor += texture(s_TextureMap, clampCoordinate(v_texCoord + blurOffset * float(i))).rgb * weight;\n" + "}\n" + "outColor = vec4(finalColor, sourceColor.a);\n" + "}\n"; + +#endif // GPU_ImageETS_constant_shape_H diff --git a/gpu_transform/src/main/cpp/napi/napi_init.cpp b/gpu_transform/src/main/cpp/napi/napi_init.cpp new file mode 100644 index 0000000..da55125 --- /dev/null +++ b/gpu_transform/src/main/cpp/napi/napi_init.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Created on 2022/12/20. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, + + +#include +#include +#include +#include "DebugLog.h" +#include "native_common.h" +#include "EGLRender.h" + +static napi_value Init(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("EglRenderInit", EGLRender::RenderInit), + DECLARE_NAPI_FUNCTION("EglRenderSetImageData", EGLRender::RenderSetData), + DECLARE_NAPI_FUNCTION("EglPixelMapSurface", EGLRender::GetPixelMapOfSurface), + DECLARE_NAPI_FUNCTION("EglRenderSetIntParams", EGLRender::RenderSetIntParams), + DECLARE_NAPI_FUNCTION("EglIsInit", EGLRender::EGLIsInit), + DECLARE_NAPI_FUNCTION("EglDestroy", EGLRender::DestroyGlesEnv), + + DECLARE_NAPI_FUNCTION("EglUseProgram", EGLRender::StartUseProgram), + DECLARE_NAPI_FUNCTION("EglRendering", EGLRender::Rendering), + + DECLARE_NAPI_FUNCTION("EglUniform1i", EGLRender::RenderGlUniform1i), + DECLARE_NAPI_FUNCTION("EglUniform1f", EGLRender::RenderGlUniform1f), + DECLARE_NAPI_FUNCTION("EglUniform2fv", EGLRender::RenderGlUniform2fv), + + DECLARE_NAPI_FUNCTION("EglSetTypeArrayOfFloat", EGLRender::setTypeArrayOfFloat), + + DECLARE_NAPI_FUNCTION("EglSetTypeArrayOfMatrix3f", EGLRender::setTypeArrayOfMatrix3f), + DECLARE_NAPI_FUNCTION("EglSetTypeArrayOfMatrix4f", EGLRender::setTypeArrayOfMatrix4f), + }; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + return exports; +} + +/** + * Napi Module define + */ +static napi_module nativeGpuModule = { + .nm_version =1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "nativeGpu", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ + napi_module_register(&nativeGpuModule); +} \ No newline at end of file diff --git a/gpu_transform/src/main/cpp/render/EGLRender.cpp b/gpu_transform/src/main/cpp/render/EGLRender.cpp new file mode 100644 index 0000000..0a051de --- /dev/null +++ b/gpu_transform/src/main/cpp/render/EGLRender.cpp @@ -0,0 +1,801 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Created on 2022/12/20. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, + +#include "EGLRender.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "native_common.h" +#include "DebugLog.h" +#include "constant/constant_shape.h" +#include "GLUtils.h" +#include "../util/NapiUtil.h" + + +const int PARAM_TYPE_SHADER_INDEX = 300; + +const int VERTEX_POS_LOC = 0; +const int TEXTURE_POS_LOC = 1; + +const int32_t STR_DEFAULT_SIZE = 1024; +EGLRender *EGLRender::sInstance = nullptr; + +// 顶点坐标 +const static GLfloat vVertices[] = { + -1.0f, -1.0f, 0.0f, // bottom left + 1.0f, -1.0f, 0.0f, // bottom right + -1.0f, 1.0f, 0.0f, // top left + 1.0f, 1.0f, 0.0f, // top right +}; + +// 正常纹理坐标 +const static GLfloat vTexCoors[] = { + 0.0f, 1.0f, // bottom left + 1.0f, 1.0f, // bottom right + 0.0f, 0.0f, // top left + 1.0f, 0.0f, // top right +}; + +// fbo 纹理坐标与正常纹理方向不同(上下镜像) +const static GLfloat vFboTexCoors[] = { + 0.0f, 0.0f, // bottom left + 1.0f, 0.0f, // bottom right + 0.0f, 1.0f, // top left + 1.0f, 1.0f, // top right +}; + +const static GLushort indices[] = { 0, 1, 2, 1, 3, 2 }; +std::mutex mtx; + +EGLRender* EGLRender::GetInstance() +{ + mtx.lock(); + if (sInstance == nullptr) { + sInstance = new EGLRender(); + } + mtx.unlock(); + return sInstance; +} + +napi_value EGLRender::RenderInit(napi_env env, napi_callback_info info) +{ + napi_value exports; + NAPI_CALL(env, napi_create_object(env, &exports)); + napi_property_descriptor desc[] = {}; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + EGLRender::GetInstance() ->Init(); + return exports; +} + + +napi_value EGLRender::RenderSetData(napi_env env, napi_callback_info info) +{ + size_t argc = 3; + napi_value args[3] = { nullptr }; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + void* buffer; + size_t bufferLength; + napi_status buffStatus = napi_get_arraybuffer_info(env, args[0], &buffer, &bufferLength); + if (buffStatus != napi_ok) { + return nullptr; + } + + uint8_t* uint8_buf = reinterpret_cast(buffer); + uint32_t width; + napi_status wStatus = napi_get_value_uint32(env, args[1], &width); + if (wStatus != napi_ok) { + return nullptr; + } + uint32_t height; + napi_status hStatus = napi_get_value_uint32(env, args[2], &height); + if (hStatus != napi_ok) { + return nullptr; + } + + EGLRender::GetInstance() -> SetImageData(uint8_buf, width, height); + return nullptr; +} + +napi_value EGLRender::RenderSetIntParams(napi_env env, napi_callback_info info) +{ + LOGI("gl--> RenderSetIntParams start"); + size_t argc = 2; + napi_value args[2] = { nullptr }; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + uint32_t type; + napi_status tStatus = napi_get_value_uint32(env, args[0], &type); + if (tStatus != napi_ok) { + return nullptr; + } + uint32_t param; + napi_status pStatus = napi_get_value_uint32(env, args[1], ¶m); + if (pStatus != napi_ok) { + return nullptr; + } + EGLRender::GetInstance() -> SetIntParams(type, param); + return nullptr; +} + +napi_value EGLRender::GetPixelMapOfSurface(napi_env env, napi_callback_info info) +{ + size_t argc = 4; + napi_value args[4] = { nullptr }; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + uint32_t x; + napi_status xStatus = napi_get_value_uint32(env, args[0], &x); + if (xStatus != napi_ok) { + return nullptr; + } + + uint32_t y; + napi_status yStatus = napi_get_value_uint32(env, args[1], &y); + if (yStatus != napi_ok) { + return nullptr; + } + + uint32_t surfaceWidth; + napi_status swStatus = napi_get_value_uint32(env, args[2], &surfaceWidth); + if (swStatus != napi_ok) { + return nullptr; + } + + uint32_t surfaceHeight; + napi_status shStatus = napi_get_value_uint32(env, args[3], &surfaceHeight); + if (shStatus != napi_ok) { + return nullptr; + } + + uint8_t* pixels = (uint8_t*) malloc(surfaceWidth * surfaceHeight * DEFAULT_FOUR); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(x, y, surfaceWidth, surfaceHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + NativeImageUtil::Flip(&pixels, surfaceWidth, surfaceHeight); + napi_value array; + int byte_length = surfaceWidth * surfaceHeight * DEFAULT_FOUR; + if (!NativeImageUtil::CreateArrayBuffer(env, pixels, byte_length, &array)) { + LOGI("gl--> GetPixelMapOfSurface error"); + } + free(pixels); + return array; +} + +napi_value EGLRender::EGLIsInit(napi_env env, napi_callback_info info) +{ + napi_value isInit; + int32_t value; + if (EGLRender::GetInstance() -> m_IsGLContextReady) { + value = 1; + } else { + value = 0; + } + napi_status status = napi_create_int32(env, value, &isInit); + if (status != napi_ok) { + return nullptr; + } + return isInit; +} + +napi_value EGLRender::DestroyGlesEnv(napi_env env, napi_callback_info info) +{ + EGLRender::GetInstance() -> UnInit(); + return nullptr; +} + +napi_value EGLRender::StartUseProgram(napi_env env, napi_callback_info info) +{ + EGLRender::GetInstance() -> UseProgram(); + return nullptr; +} + +napi_value EGLRender::Rendering(napi_env env, napi_callback_info info) +{ + // 渲染 + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const void *)0); + glBindVertexArray(GL_NONE); + glBindTexture(GL_TEXTURE_2D, GL_NONE); + return nullptr; +} + +napi_value EGLRender::setTypeArrayOfFloat(napi_env env, napi_callback_info info) +{ + size_t argc = 3; + napi_value args[3] = { nullptr }; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + std::string locationContent; + NapiUtil::JsValueToString(env, args[0], STR_DEFAULT_SIZE, locationContent); + + char* location = (char*)locationContent.c_str(); + + std::string content; + NapiUtil::JsValueToString(env, args[1], STR_DEFAULT_SIZE, content); + + char* key = (char*)content.c_str(); + + napi_typedarray_type dataType = napi_float32_array; + void* buffer; + size_t bufferLength; + size_t byte_offset; + napi_status buffStatus = napi_get_typedarray_info(env, + args[2], &dataType, &bufferLength, &buffer, &args[2], &byte_offset); + if (buffStatus != napi_ok) { + return nullptr; + } + + float* value = reinterpret_cast(buffer); + + int uniformType; + + if (strcmp(key, "glUniform2fv") == 0) { + uniformType = UNIFORM_TYPE_2FV; + } else if (strcmp(key, "glUniform3fv") == 0) { + uniformType = UNIFORM_TYPE_3FV; + } else if (strcmp(key, "glUniform4fv") == 0) { + uniformType = UNIFORM_TYPE_4FV; + } else if (strcmp(key, "glUniform1fv") == 0) { + uniformType = UNIFORM_TYPE_FV; + } else if (strcmp(key, "glUniform2f") == 0) { + uniformType = UNIFORM_TYPE_2F; + } + + EGLRender::GetInstance() -> GlUniformArray(location, value, uniformType); + return nullptr; +} + +napi_value EGLRender::setTypeArrayOfMatrix3f(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value args[2] = { nullptr }; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + std::string locationContent; + NapiUtil::JsValueToString(env, args[0], STR_DEFAULT_SIZE, locationContent); + + char* location = (char*)locationContent.c_str(); + + napi_typedarray_type dataType = napi_float32_array; + void* buffer; + size_t bufferLength; + size_t byte_offset; + napi_status buffStatus = napi_get_typedarray_info(env, + args[1], &dataType, &bufferLength, &buffer, &args[1], &byte_offset); + if (buffStatus != napi_ok) { + return nullptr; + } + + float* value = reinterpret_cast(buffer); + + EGLRender::GetInstance() -> GlUniformMatrix(location, value, UNIFORM_TYPE_THREE); + + return nullptr; +} + +napi_value EGLRender::setTypeArrayOfMatrix4f(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value args[2] = { nullptr }; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + std::string locationContent; + NapiUtil::JsValueToString(env, args[0], STR_DEFAULT_SIZE, locationContent); + + char* location = (char*)locationContent.c_str(); + + napi_typedarray_type dataType = napi_float32_array; + void* buffer; + size_t bufferLength; + size_t byte_offset; + napi_status buffStatus = napi_get_typedarray_info(env, + args[1], &dataType, &bufferLength, &buffer, &args[1], &byte_offset); + if (buffStatus != napi_ok) { + return nullptr; + } + + float* value = reinterpret_cast(buffer); + + EGLRender::GetInstance() -> GlUniformMatrix(location, value, UNIFORM_TYPE_FOUR); + return nullptr; +} + +napi_value EGLRender::RenderGlUniform1i(napi_env env, napi_callback_info info) +{ + // int + size_t argc = 2; + napi_value args[2] = { nullptr }; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + std::string content; + NapiUtil::JsValueToString(env, args[0], STR_DEFAULT_SIZE, content); + uint32_t value; + napi_status status = napi_get_value_uint32(env, args[1], &value); + if (status != napi_ok) { + return nullptr; + } + EGLRender::GetInstance() -> GlUniform((char*)content.c_str(), value, UNIFORM_TYPE_ZERO); + return nullptr; +} + +napi_value EGLRender::RenderGlUniform1f(napi_env env, napi_callback_info info) +{ + // float + size_t argc = 2; + napi_value args[2] = { nullptr }; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + std::string content; + NapiUtil::JsValueToString(env, args[0], STR_DEFAULT_SIZE, content); + double value; + napi_status status = napi_get_value_double(env, args[1], &value); + if (status != napi_ok) { + return nullptr; + } + EGLRender::GetInstance() -> GlUniform((char*)content.c_str(), value, UNIFORM_TYPE_ONE); + return nullptr; +} + +napi_value EGLRender::RenderGlUniform2fv(napi_env env, napi_callback_info info) +{ + // float 数组 + size_t argc = 3; + napi_value args[3] = { nullptr }; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + std::string content; + NapiUtil::JsValueToString(env, args[0], STR_DEFAULT_SIZE, content); + + double value; + napi_status status = napi_get_value_double(env, args[1], &value); + if (status != napi_ok) { + return nullptr; + } + double value2; + napi_status status2 = napi_get_value_double(env, args[2], &value2); + if (status2 != napi_ok) { + return nullptr; + } + + float vce2[2]; + vce2[0] = value; + vce2[1] = value2; + EGLRender::GetInstance() -> GlUniformArray((char*)content.c_str(), vce2, UNIFORM_TYPE_2FV_SIZE); + return nullptr; +} + +EGLRender::EGLRender() +{ + m_ImageTextureId = GL_NONE; + m_FboTextureId = GL_NONE; + m_SamplerLoc = GL_NONE; + m_TexSizeLoc = GL_NONE; + + m_FboId = GL_NONE; + m_ProgramObj = GL_NONE; + m_VertexShader = GL_NONE; + m_FragmentShader = GL_NONE; + m_eglDisplay = nullptr; + m_IsGLContextReady = false; + m_ShaderIndex = 0; +} +EGLRender::~EGLRender() +{ +} +void EGLRender::TexturesInit() +{ + glGenTextures(1, &m_ImageTextureId); // 生成纹理名称 + glBindTexture(GL_TEXTURE_2D, m_ImageTextureId); // 允许建立一个绑定到目标纹理的有名称的纹理 + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, GL_NONE); + glGenTextures(1, &m_FboTextureId); + glBindTexture(GL_TEXTURE_2D, m_FboTextureId); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, GL_NONE); +} +void EGLRender::Init() +{ + if (CreateGlEnv() == 0) { + m_IsGLContextReady = true; + } + if (!m_IsGLContextReady) { + return; + } + EGLRender::GetInstance() -> TexturesInit(); + m_ProgramObj = GLUtils::CreateProgram(vShaderStr, fShaderStr0, m_VertexShader, + m_FragmentShader); + if (!m_ProgramObj) { + GLUtils::CheckGLError("Create Program"); + return; + } + glGenBuffers(DEFAULT_THREE, m_VboIds); + glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[DEFAULT_ZERO]); + glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices), vVertices, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[DEFAULT_ONE]); + glBufferData(GL_ARRAY_BUFFER, sizeof(vFboTexCoors), vTexCoors, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_VboIds[DEFAULT_TWO]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); + glGenVertexArrays(DEFAULT_ONE, m_VaoIds); + glBindVertexArray(m_VaoIds[DEFAULT_ZERO]); + glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[DEFAULT_ZERO]); + glEnableVertexAttribArray(VERTEX_POS_LOC); + glVertexAttribPointer(VERTEX_POS_LOC, + DEFAULT_THREE, + GL_FLOAT, GL_FALSE, + DEFAULT_THREE * sizeof(GLfloat), + (const void *)DEFAULT_ZERO); + glBindBuffer(GL_ARRAY_BUFFER, GL_NONE); + glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[DEFAULT_ONE]); + glEnableVertexAttribArray(TEXTURE_POS_LOC); + glVertexAttribPointer(TEXTURE_POS_LOC, + DEFAULT_TWO, + GL_FLOAT, + GL_FALSE, + DEFAULT_TWO * sizeof(GLfloat), + (const void *)DEFAULT_ZERO); + glBindBuffer(GL_ARRAY_BUFFER, GL_NONE); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_VboIds[DEFAULT_TWO]); + glBindVertexArray(GL_NONE); +} + +int EGLRender::CreateGlEnv() +{ + const EGLint confAttr[] = { + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR, EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 16, EGL_STENCIL_SIZE, 8, EGL_NONE + }; + const EGLint ctxAttr[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE + }; + const EGLint surfaceAttr[] = { + EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE + }; + EGLint eglMajVers, eglMinVers; + EGLint numConfigs; + int resultCode = 0; + do { + m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (m_eglDisplay == EGL_NO_DISPLAY) { + resultCode = -1; + break; + } + // 初始化 egl 方法 + if (!eglInitialize(m_eglDisplay, &eglMajVers, &eglMinVers)) { + resultCode = -1; + break; + } + // 获取 EGLConfig 对象,确定渲染表面的配置信息 + if (!eglChooseConfig(m_eglDisplay, confAttr, &m_eglConf, 1, &numConfigs)) { + resultCode = -1; + break; + } + // 创建渲染表面 EGLSurface 使用 eglCreateBufferSurface 创建屏幕外渲染区域 + m_eglSurface = eglCreatePbufferSurface(m_eglDisplay, m_eglConf, surfaceAttr); + if (m_eglSurface == EGL_NO_SURFACE) { + LOGI("gl-->::CreateGlesEnv happen default error"); + break; + } + // 创建渲染上下文 EGLContext + m_eglCtx = eglCreateContext(m_eglDisplay, m_eglConf, EGL_NO_CONTEXT, ctxAttr); + if (m_eglCtx == EGL_NO_CONTEXT) { + EGLint error = eglGetError(); + if (error == EGL_BAD_CONFIG) { + resultCode = -1; + break; + } + } + // 绑定上下文 + if (!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglCtx)) { + resultCode = -1; + break; + } + } while (false); + return resultCode; +} + +void EGLRender::SetImageData(uint8_t *pData, int width, int height) +{ + if (pData && m_IsGLContextReady) { + if (m_RenderImage.ppPlane[0]) { + NativeImageUtil::FreeNativeImage(&m_RenderImage); + m_RenderImage.ppPlane[0] = nullptr; + } + m_RenderImage.width = width; + m_RenderImage.height = height; + m_RenderImage.format = IMAGE_FORMAT_RGBA; + NativeImageUtil::AllocNativeImage(&m_RenderImage); + memcpy(m_RenderImage.ppPlane[0], pData, width * height * DEFAULT_FOUR); + + glBindTexture(GL_TEXTURE_2D, m_ImageTextureId); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA, + m_RenderImage.width, + m_RenderImage.height, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + m_RenderImage.ppPlane[0]); + glBindTexture(GL_TEXTURE_2D, GL_NONE); + + if (m_FboId == GL_NONE) { + // Create FBO + glGenFramebuffers(1, &m_FboId); + glBindFramebuffer(GL_FRAMEBUFFER, m_FboId); + glBindTexture(GL_TEXTURE_2D, m_FboTextureId); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_FboTextureId, 0); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA, + m_RenderImage.width, + m_RenderImage.height, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + nullptr); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + LOGI("gl--> EGLRender ::SetImageData glCheckFramebufferStatus status != GL_FRAMEBUFFER_COMPLETE"); + } + glBindTexture(GL_TEXTURE_2D, GL_NONE); + glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE); + } + LOGI("gl--> :: SetImageData end"); + } +} + +void EGLRender::SetIntParams(int paramType, int param) +{ + LOGI("gl--> EGLRender::SetIntParams paramType = %{public}d,param = %{public}d", paramType, param); + switch (paramType) { + case PARAM_TYPE_SHADER_INDEX: { + if (param >= 0) { + if (m_ProgramObj) { + glDeleteProgram(m_ProgramObj); + m_ProgramObj = GL_NONE; + } + const char* vShader[1]; + vShader[0] = vShaderStr; + const char* fShader[1]; + switch (param) { + case SHADER_TYPE_KUWAHARA: { + fShader[0] = fShaderStr3; + break; + } + case SHADER_TYPE_SWIRL: { + fShader[0] = swirlFShaderStr; + break; + } + case SHADER_TYPE_BRIGHT: { + fShader[0] = brightFShaderStr; + break; + } + case SHADER_TYPE_CONTRAST: { + fShader[0] = contrastFShaderStr; + break; + } + case SHADER_TYPE_INVERT: { + fShader[0] = invertFShaderStr; + break; + } + case SHADER_TYPE_PIXELATION: { + fShader[0] = pixelFShaderStr; + break; + } + case SHADER_TYPE_SEPIA: { + fShader[0] = colorMatrixFShaderStr; + break; + } + case SHADER_TYPE_SKETCH: { + fShader[0] = sketchShaderStr; + vShader[0] = v3x3ShaderStr; + break; + } + case SHADER_TYPE_TOON: { + fShader[0] = toonFShaderStr; + vShader[0] = v3x3ShaderStr; + break; + } + case SHADER_TYPE_VIGNETTE: { + fShader[0] = vignetteFShaderStr; + break; + } + case SHADER_TYPE_GRAYSCALE: { + fShader[0] = grayScaleShaderStr; + break; + } + case SHADER_TYPE_BLUR: { + fShader[0] = blurShaderStr; + break; + } + default: + vShader[0] = vShaderStr; + break; + } + m_ProgramObj = GLUtils::CreateProgram(vShader[0], fShader[0], m_VertexShader, + m_FragmentShader); + if (!m_ProgramObj) { + GLUtils::CheckGLError("Create Program"); + LOGI("gl--> EGLRender::SetIntParams Could not create program."); + return; + } + m_SamplerLoc = glGetUniformLocation(m_ProgramObj, "s_TextureMap"); + m_TexSizeLoc = glGetUniformLocation(m_ProgramObj, "u_texSize"); + } + } + break; + default: + break; + } +} + +void EGLRender::UseProgram() +{ + if (m_ProgramObj == GL_NONE) { + return; + } + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glViewport(0, 0, m_RenderImage.width, m_RenderImage.height); + + // DO FBO off screen rendering + glUseProgram(m_ProgramObj); + glBindFramebuffer(GL_FRAMEBUFFER, m_FboId); + + glBindVertexArray(m_VaoIds[0]); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_ImageTextureId); + glUniform1i(m_SamplerLoc, 0); + + if (m_TexSizeLoc > -1) { + GLfloat size[2]; + size[0] = m_RenderImage.width; + size[1] = m_RenderImage.height; + glUniform2f(m_TexSizeLoc, size[0], size[1]); + } +} + +void EGLRender::GlUniform(char* location, float value, int unType) +{ + GLint ll = glGetUniformLocation(m_ProgramObj, location); + switch (unType) { + case UNIFORM_TYPE_ZERO: + glUniform1i(ll, (int)value); + break; + case UNIFORM_TYPE_ONE: + glUniform1f(ll, value); + break; + default: + break; + } +} + +void EGLRender::GlUniformArray(char* location, float* value, int unType) +{ + GLint ll = glGetUniformLocation(m_ProgramObj, location); + switch (unType) { + case UNIFORM_TYPE_2FV_SIZE: + GLfloat vec2[2]; + vec2[0] = value[0] * m_RenderImage.width; + vec2[1] = value[1] * m_RenderImage.height; + glUniform2fv(ll, 1, vec2); + break; + case UNIFORM_TYPE_2F: + glUniform2f(ll, value[0], value[1]); + break; + case UNIFORM_TYPE_FV: + glUniform1fv(ll, 1, value); + break; + case UNIFORM_TYPE_2FV: + glUniform2fv(ll, 1, value); + break; + case UNIFORM_TYPE_3FV: + glUniform3fv(ll, 1, value); + break; + case UNIFORM_TYPE_4FV: + glUniform4fv(ll, 1, value); + break; + default: + break; + } +} + +void EGLRender::GlUniformMatrix(char* location, float* value, int unType) +{ + GLint ll = glGetUniformLocation(m_ProgramObj, location); + switch (unType) { + case UNIFORM_TYPE_THREE: + glUniformMatrix3fv(ll, 1, false, value); + break; + case UNIFORM_TYPE_FOUR: + glUniformMatrix4fv(ll, 1, false, value); + break; + default: + break; + } +} + +void EGLRender::UnInit() +{ + if (m_ProgramObj) { + glDeleteProgram(m_ProgramObj); + m_ProgramObj = GL_NONE; + } + + if (m_ImageTextureId) { + glDeleteTextures(DEFAULT_ONE, &m_ImageTextureId); + m_ImageTextureId = GL_NONE; + } + + if (m_FboTextureId) { + glDeleteTextures(DEFAULT_ONE, &m_FboTextureId); + m_FboTextureId = GL_NONE; + } + + if (m_VboIds[DEFAULT_ZERO]) { + glDeleteBuffers(DEFAULT_THREE, m_VboIds); + m_VboIds[DEFAULT_ZERO] = GL_NONE; + m_VboIds[DEFAULT_ONE] = GL_NONE; + m_VboIds[DEFAULT_TWO] = GL_NONE; + } + + if (m_VaoIds[DEFAULT_ZERO]) { + glDeleteVertexArrays(DEFAULT_ONE, m_VaoIds); + m_VaoIds[DEFAULT_ZERO] = GL_NONE; + } + + if (m_FboId) { + glDeleteFramebuffers(1, &m_FboId); + m_FboId = GL_NONE; + } + if (m_IsGLContextReady) { + DestroyGl(); + m_IsGLContextReady = false; + } +} +void EGLRender::DestroyGl() +{ + // 释放 EGL 环境 + if (m_eglDisplay != EGL_NO_DISPLAY) { + eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(m_eglDisplay, m_eglCtx); + eglDestroySurface(m_eglDisplay, m_eglSurface); + eglReleaseThread(); + eglTerminate(m_eglDisplay); + } + + m_eglDisplay = EGL_NO_DISPLAY; + m_eglSurface = EGL_NO_SURFACE; + m_eglCtx = EGL_NO_CONTEXT; +} diff --git a/gpu_transform/src/main/cpp/render/EGLRender.h b/gpu_transform/src/main/cpp/render/EGLRender.h new file mode 100644 index 0000000..7456ba5 --- /dev/null +++ b/gpu_transform/src/main/cpp/render/EGLRender.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Created on 2022/12/20. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, + +#ifndef GPU_ImageETS_EGLRender_H +#define GPU_ImageETS_EGLRender_H +#include +#include +#include +#include +#include +#include "NativeImage.h" + +const int EGL_FEATURE_NUM = 7; +class EGLRender { +private: + EGLRender(); + ~EGLRender(); +public: + static void DestroyRender() + { + if (sInstance) { + delete sInstance; + sInstance = nullptr; + } + } + static EGLRender* GetInstance(); + static napi_value RenderInit(napi_env env, napi_callback_info info); + static napi_value RenderSetData(napi_env env, napi_callback_info info); + static napi_value GetPixelMapOfSurface(napi_env env, napi_callback_info info); + static napi_value RenderSetIntParams(napi_env env, napi_callback_info info); + static napi_value EGLIsInit(napi_env env, napi_callback_info info); + + static napi_value DestroyGlesEnv(napi_env env, napi_callback_info info); + + static napi_value StartUseProgram(napi_env env, napi_callback_info info); + + static napi_value Rendering(napi_env env, napi_callback_info info); + + static napi_value RenderGlUniform1i(napi_env env, napi_callback_info info); + static napi_value RenderGlUniform1f(napi_env env, napi_callback_info info); + static napi_value RenderGlUniform2fv(napi_env env, napi_callback_info info); + static napi_value setTypeArrayOfFloat(napi_env env, napi_callback_info info); + + static napi_value setTypeArrayOfMatrix3f(napi_env env, napi_callback_info info); + static napi_value setTypeArrayOfMatrix4f(napi_env env, napi_callback_info info); + + void Init(); + void TexturesInit(); + int CreateGlEnv(); + + void SetImageData(uint8_t *pData, int width, int height); + + void SetIntParams(int paramType, int param); + + void UseProgram(); + + void Draw(); + + void GlUniform(char* location, float value, int unType); + void GlUniformArray(char* location, float* value, int unType); + + void GlUniformMatrix(char* location, float* value, int unType); + + void DestroyGl(); + + void UnInit(); + +private: + static EGLRender* sInstance; + GLuint m_ImageTextureId; + GLuint m_FboTextureId; + GLuint m_FboId; + GLuint m_VaoIds[1] = {GL_NONE}; + GLuint m_VboIds[3] = {GL_NONE}; + GLint m_SamplerLoc; + GLint m_TexSizeLoc; + + NativeImage m_RenderImage; + GLuint m_ProgramObj; + GLuint m_VertexShader; + GLuint m_FragmentShader; + + EGLConfig m_eglConf; + EGLSurface m_eglSurface; + EGLContext m_eglCtx; + EGLDisplay m_eglDisplay; + bool m_IsGLContextReady; + const char* m_fShaderStrs[EGL_FEATURE_NUM]; + int m_ShaderIndex; +}; + +#endif // GPU_ImageETS_EGLRender_H diff --git a/gpu_transform/src/main/cpp/types/libentry/index.d.ts b/gpu_transform/src/main/cpp/types/libentry/index.d.ts new file mode 100644 index 0000000..dc8e76e --- /dev/null +++ b/gpu_transform/src/main/cpp/types/libentry/index.d.ts @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const EglRenderInit: () => void; +export const EglRenderSetImageData: (bytes:ArrayBuffer,width:number,height:number) => void; +export const EglRenderSetIntParams: (paramType:number,param:number) => void; +export const EglPixelMapSurface: (x:number,y:number,w:number,h:number) => ArrayBuffer; +export const EglIsInit: () => number; +export const EglUseProgram: () => void; +export const EglRendering: () => void; +export const EglUniform1i: (key:string,value:number) => void; +export const EglUniform1f: (key:string,value:number) => void; +export const EglUniform2fv: (key:string,vf1:number,vf2:number) => void; +export const EglSetTypeArrayOfFloat: (key:string,uniformType:string,data:Float32Array) => void; +export const EglSetTypeArrayOfMatrix3f: (key:string,value:Float32Array) => void; +export const EglSetTypeArrayOfMatrix4f: (key:string,value:Float32Array) => void; +export const EglDestroy: () => void; \ No newline at end of file diff --git a/gpu_transform/src/main/cpp/types/libentry/package.json b/gpu_transform/src/main/cpp/types/libentry/package.json new file mode 100644 index 0000000..cf40ccb --- /dev/null +++ b/gpu_transform/src/main/cpp/types/libentry/package.json @@ -0,0 +1,4 @@ +{ + "name": "libentry.so", + "types": "./index.d.ts" +} \ No newline at end of file diff --git a/gpu_transform/src/main/cpp/util/DebugLog.h b/gpu_transform/src/main/cpp/util/DebugLog.h new file mode 100644 index 0000000..d3fea9c --- /dev/null +++ b/gpu_transform/src/main/cpp/util/DebugLog.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Created on 2022/12/21. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, + +#ifndef GPU_ImageETS_DebugLog_H +#define GPU_ImageETS_DebugLog_H + +#include + +#define LOGI(...)((void)OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "OH_GPU_LOG", __VA_ARGS__)) +#define LOGD(...)((void)OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, "OH_GPU_LOG", __VA_ARGS__)) +#define LOGW(...)((void)OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, "OH_GPU_LOG", __VA_ARGS__)) +#define LOGE(...)((void)OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "OH_GPU_LOG", __VA_ARGS__)) + +#endif // GPU_ImageETS_DebugLog_H diff --git a/gpu_transform/src/main/cpp/util/GLUtils.cpp b/gpu_transform/src/main/cpp/util/GLUtils.cpp new file mode 100644 index 0000000..cbced39 --- /dev/null +++ b/gpu_transform/src/main/cpp/util/GLUtils.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Created on 2022/12/21. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, + +#include +#include +#include "DebugLog.h" +#include "GLUtils.h" + +GLuint GLUtils::LoadShader(GLenum shaderType, const char *pSource) +{ + GLuint shader = 0; + shader = glCreateShader(shaderType); + if (shader) { + glShaderSource(shader, 1, &pSource, NULL); + glCompileShader(shader); + GLint compiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint infoLen = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen) { + char* buf = (char*) malloc((size_t)infoLen); + if (buf) { + glGetShaderInfoLog(shader, infoLen, NULL, buf); + free(buf); + } + glDeleteShader(shader); + shader = 0; + } + } + } + return shader; +} + +GLuint GLUtils::CreateProgram(const char *pVertexShaderSource, + const char *pFragShaderSource, + GLuint &vertexShaderHandle, + GLuint &fragShaderHandle) +{ + GLuint program = 0; + vertexShaderHandle = LoadShader(GL_VERTEX_SHADER, pVertexShaderSource); + if (!vertexShaderHandle) return program; + fragShaderHandle = LoadShader(GL_FRAGMENT_SHADER, pFragShaderSource); + if (!fragShaderHandle) return program; + + program = glCreateProgram(); + if (program) { + glAttachShader(program, vertexShaderHandle); + CheckGLError("glAttachShader"); + glAttachShader(program, fragShaderHandle); + CheckGLError("glAttachShader"); + glLinkProgram(program); + GLint linkStatus = GL_FALSE; + glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); + + glDetachShader(program, vertexShaderHandle); + glDeleteShader(vertexShaderHandle); + vertexShaderHandle = 0; + glDetachShader(program, fragShaderHandle); + glDeleteShader(fragShaderHandle); + fragShaderHandle = 0; + + if (linkStatus != GL_TRUE) { + GLint bufLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); + if (bufLength) { + char* buf = (char*) malloc((size_t)bufLength); + if (buf) { + glGetProgramInfoLog(program, bufLength, NULL, buf); + free(buf); + } + } + glDeleteProgram(program); + program = 0; + } + } + return program; +} + +void GLUtils::CheckGLError(const char *pGLOperation) +{ + for (GLint error = glGetError(); error; error = glGetError()) { + LOGI("GLUtils::CheckGLError GL Operation %{public}s() glError (0x%x)\n", pGLOperation, error); + } +} diff --git a/gpu_transform/src/main/cpp/util/GLUtils.h b/gpu_transform/src/main/cpp/util/GLUtils.h new file mode 100644 index 0000000..df80ce9 --- /dev/null +++ b/gpu_transform/src/main/cpp/util/GLUtils.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Created on 2022/12/21. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, + +#ifndef GPU_ImageETS_GLUtils_H +#define GPU_ImageETS_GLUtils_H + +#include + +class GLUtils { +public: + static GLuint LoadShader(GLenum shaderType, const char *pSource); + static GLuint CreateProgram(const char *pVertexShaderSource, const char *pFragShaderSource, + GLuint &vertexShaderHandle, + GLuint &fragShaderHandle); + static GLuint CreateProgram(const char *pVertexShaderSource, const char *pFragShaderSource); + static void CheckGLError(const char *pGLOperation); +}; + +#endif // GPU_ImageETS_GLUtils_H diff --git a/gpu_transform/src/main/cpp/util/NapiUtil.cpp b/gpu_transform/src/main/cpp/util/NapiUtil.cpp new file mode 100644 index 0000000..eba879f --- /dev/null +++ b/gpu_transform/src/main/cpp/util/NapiUtil.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Created on 2022/12/21. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, + +#include "NapiUtil.h" + +#include +#include +#include +#include +#include +#include "DebugLog.h" + +const int32_t MAX_STR_LENGTH = 1024; + +void NapiUtil::JsValueToString(const napi_env &env, const napi_value &value, const int32_t bufLen, std::string &target) +{ + if (bufLen <= 0 || bufLen > MAX_STR_LENGTH) { + LOGI("%s string too long malloc failed", __func__); + return; + } + + std::unique_ptr buf = std::make_unique (bufLen); + if (buf.get() == nullptr) { + LOGI("%s nullptr js object to string malloc failed", __func__); + return; + } + (void) memset(buf.get(), 0, bufLen); + size_t result = 0; + napi_get_value_string_utf8(env, value, buf.get(), bufLen, &result); + target = buf.get(); +} \ No newline at end of file diff --git a/gpu_transform/src/main/cpp/util/NapiUtil.h b/gpu_transform/src/main/cpp/util/NapiUtil.h new file mode 100644 index 0000000..3d2b375 --- /dev/null +++ b/gpu_transform/src/main/cpp/util/NapiUtil.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Created on 2022/12/21. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, + +#ifndef GPU_ImageETS_NapiUtil_H +#define GPU_ImageETS_NapiUtil_H + +#include +#include +#include "native_common.h" + +class NapiUtil { +public: + static void JsValueToString(const napi_env &env, const napi_value &value, const int32_t bufLen, + std::string &target); +}; + +#endif // GPU_ImageETS_NapiUtil_H diff --git a/gpu_transform/src/main/cpp/util/NativeImage.h b/gpu_transform/src/main/cpp/util/NativeImage.h new file mode 100644 index 0000000..d79018d --- /dev/null +++ b/gpu_transform/src/main/cpp/util/NativeImage.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Created on 2022/12/21. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, + +#ifndef GPU_ImageETS_NativeImage_H +#define GPU_ImageETS_NativeImage_H + +#include +#include +#include +#include +#include +#include +#include +#include "DebugLog.h" +#include "constant/constant_shape.h" + +#define IMAGE_FORMAT_RGBA 0x01 +#define IMAGE_FORMAT_NV21 0x02 +#define IMAGE_FORMAT_NV12 0x03 +#define IMAGE_FORMAT_I420 0x04 +#define IMAGE_FORMAT_YUYV 0x05 +#define IMAGE_FORMAT_GRAY 0x06 +#define IMAGE_FORMAT_I444 0x07 +#define IMAGE_FORMAT_P010 0x08 + +#define IMAGE_FORMAT_RGBA_EXT "RGB32" +#define IMAGE_FORMAT_NV21_EXT "NV21" +#define IMAGE_FORMAT_NV12_EXT "NV12" +#define IMAGE_FORMAT_I420_EXT "I420" +#define IMAGE_FORMAT_YUYV_EXT "YUYV" +#define IMAGE_FORMAT_GRAY_EXT "GRAY" +#define IMAGE_FORMAT_I444_EXT "I444" +#define IMAGE_FORMAT_P010_EXT "P010" // 16bit NV21 + + +struct NativeImage { + int width; + int height; + int format; + uint8_t *ppPlane[DEFAULT_THREE]; + + NativeImage() + { + width = DEFAULT_ZERO; + height = DEFAULT_ZERO; + format = DEFAULT_ZERO; + ppPlane[DEFAULT_ZERO] = nullptr; + ppPlane[DEFAULT_ONE] = nullptr; + ppPlane[DEFAULT_TWO] = nullptr; + } +}; + +class NativeImageUtil { +public: + static void AllocNativeImage(NativeImage *pImage) + { + if (pImage ->height == DEFAULT_ZERO || pImage ->width == DEFAULT_ZERO) return; + switch (pImage -> format) { + case IMAGE_FORMAT_RGBA: { + pImage->ppPlane[DEFAULT_ZERO] = + static_cast(malloc(pImage->width * pImage ->height * DEFAULT_FOUR)); + } + break; + case IMAGE_FORMAT_YUYV: { + pImage->ppPlane[DEFAULT_ZERO] = + static_cast(malloc(pImage->width * pImage ->height * DEFAULT_TWO)); + } + break; + case IMAGE_FORMAT_NV12: + case IMAGE_FORMAT_NV21: { + pImage->ppPlane[DEFAULT_ZERO] = + static_cast(malloc(pImage->width * pImage ->height * DEFAULT_ONE_HALF)); + pImage->ppPlane[DEFAULT_ONE] = + pImage->ppPlane[DEFAULT_ZERO] + pImage->width * pImage->height; + } + break; + case IMAGE_FORMAT_I420: { + pImage->ppPlane[DEFAULT_ZERO] = + static_cast(malloc(pImage->width * pImage ->height * DEFAULT_ONE_HALF)); + pImage->ppPlane[DEFAULT_ONE] = + pImage->ppPlane[DEFAULT_ZERO] + pImage->width * pImage->height; + pImage->ppPlane[DEFAULT_TWO] = + pImage->ppPlane[DEFAULT_ONE] + pImage->width * (pImage->height >> DEFAULT_TWO); + } + break; + case IMAGE_FORMAT_GRAY: { + pImage->ppPlane[DEFAULT_ZERO] = + static_cast(malloc(pImage->width * pImage ->height)); + } + break; + case IMAGE_FORMAT_I444: { + pImage->ppPlane[DEFAULT_ZERO] = + static_cast(malloc(pImage->width * pImage ->height * DEFAULT_THREE)); + } + break; + case IMAGE_FORMAT_P010: { + pImage->ppPlane[DEFAULT_ZERO] = + static_cast(malloc(pImage->width * pImage ->height * DEFAULT_THREE)); + pImage->ppPlane[DEFAULT_ONE] = + pImage->ppPlane[DEFAULT_ZERO] + pImage->width * pImage->height * DEFAULT_TWO; + } + break; + default: + break; + } + } + + static void FreeNativeImage(NativeImage *pImage) + { + if (pImage == nullptr || pImage->ppPlane[DEFAULT_ZERO] == nullptr) return; + free(pImage->ppPlane[DEFAULT_ZERO]); + pImage->ppPlane[DEFAULT_ZERO] = nullptr; + pImage->ppPlane[DEFAULT_ONE] = nullptr; + pImage->ppPlane[DEFAULT_TWO] = nullptr; + } + + static bool CreateArrayBuffer(napi_env env, void* src, size_t srcLen, napi_value *res) + { + if (src == nullptr || srcLen == DEFAULT_ZERO) { + return false; + } + void *nativePtr = nullptr; + if (napi_create_arraybuffer(env, srcLen, &nativePtr, res) != napi_ok || nativePtr == nullptr) { + return false; + } + memcpy(nativePtr, src, srcLen); + return true; + } + + static void Flip(uint8_t** buf, int width, int height) + { + int totalLength = width * height * DEFAULT_FOUR; + int oneLineLength = width * DEFAULT_FOUR; + uint8_t* tmp = (uint8_t*)malloc(totalLength); + memcpy(tmp, *buf, totalLength); + memset(*buf, DEFAULT_ZERO, sizeof(uint8_t)*totalLength); + for (int i = 0; i < height; i++) { + memcpy(*buf + oneLineLength * i, tmp + totalLength - oneLineLength * (i+1), oneLineLength); + } + free(tmp); + } +}; + +#endif // GPU_ImageETS_NativeImage_H diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImage3x3TextureSamplingFilter.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImage3x3TextureSamplingFilter.ts new file mode 100644 index 0000000..14d74c4 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImage3x3TextureSamplingFilter.ts @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GPUImageFilter } from './GPUImageFilter' +import { GPUFilterType } from '../gl/GPUFilterType' + +export class GPUImage3x3TextureSamplingFilter extends GPUImageFilter { + private texelWidth: number; + private texelHeight: number; + private lineSize: number = 1.0; + + constructor() { + super(); + } + + getFilterType(): GPUFilterType { + return GPUFilterType.X3TEXTURE; + } + + onInitialized() { + + } + + onReadySize() { + + } + + setLineSize(lineSize: number) { + this.lineSize = lineSize; + } + + setTexelWidth(texelWidth: number) { + this.texelWidth = this.lineSize / texelWidth; + this.setFloat("texelWidth", this.texelWidth); + } + + setTexelHeight(texelHeight: number) { + this.texelHeight = this.lineSize / texelHeight; + this.setFloat("texelHeight", this.texelHeight); + } +} \ No newline at end of file diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImageBlurFilter.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImageBlurFilter.ts new file mode 100644 index 0000000..08930fa --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageBlurFilter.ts @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GPUImageFilter } from './GPUImageFilter' +import { GPUFilterType } from '../gl/GPUFilterType' + +export class GPUImageBlurFilter extends GPUImageFilter { + private blurRadius: number; + private blurOffset: Array; + private sumWeight: number; + + constructor() { + super(); + } + + getFilterType(): GPUFilterType { + return GPUFilterType.BLUR; + } + + onInitialized() { + + } + + onReadySize() { + + } + + setBlurRadius(blurRadius: number) { + this.blurRadius = blurRadius; + this.setInteger("blurRadius", this.blurRadius); + this.calculateSumWeight(); + } + + setBlurOffset(blurOffset: Array) { + let offset = new Array(2); + + if (this.width <= 0 || this.height <= 0) { + throw new Error("the width or height must be greater than 0"); + } + if (!blurOffset || blurOffset.length !== 2) { + throw new Error("you should a valid value needs to be set.") + } + offset[0] = blurOffset[0] / this.width; + offset[1] = blurOffset[1] / this.height; + this.blurOffset = offset; + this.setFloat2f("blurOffset", this.blurOffset); + } + + setSumWeight(sumWeight: number) { + this.sumWeight = sumWeight; + this.setFloat("sumWeight", this.sumWeight); + } + + private calculateSumWeight() { + if (this.blurRadius < 1) { + this.setSumWeight(0); + return; + } + let sumWeight = 0; + let sigma = this.blurRadius / 3.0; + for (let i = 0; i < this.blurRadius; i++) { + let weight = ((1.0 / Math.sqrt(2.0 * Math.PI * sigma * sigma)) * Math.exp(-(i * i) / (2.0 * sigma * sigma))); + sumWeight += weight; + if (i != 0) { + sumWeight += weight; + } + } + this.setSumWeight(sumWeight); + } +} \ No newline at end of file diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImageBrightnessFilter.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImageBrightnessFilter.ts new file mode 100644 index 0000000..bc60f9e --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageBrightnessFilter.ts @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GPUImageFilter } from './GPUImageFilter' +import { GPUFilterType } from '../gl/GPUFilterType' + +export class GPUImageBrightnessFilter extends GPUImageFilter { + private brightness: number = 25 + + constructor(brightness?: number) { + super() + if (brightness) { + this.brightness = brightness; + } + } + + getFilterType(): GPUFilterType { + return GPUFilterType.BRIGHT; + } + + onInitialized() { + + } + + onReadySize() { + + } + + setBrightness(brightness: number) { + this.brightness = brightness; + this.setFloat("brightness", this.brightness); + } +} \ No newline at end of file diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImageColorInvertFilter.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImageColorInvertFilter.ts new file mode 100644 index 0000000..c7699ca --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageColorInvertFilter.ts @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GPUImageFilter } from './GPUImageFilter' +import { GPUFilterType } from '../gl/GPUFilterType' + +export class GPUImageColorInvertFilter extends GPUImageFilter { + constructor() { + super() + + } + + getFilterType(): GPUFilterType { + return GPUFilterType.INVERT; + } + + onInitialized() { + + } + + onReadySize() { + + } +} \ No newline at end of file diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImageColorMatrixFilter.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImageColorMatrixFilter.ts new file mode 100644 index 0000000..606588a --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageColorMatrixFilter.ts @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GPUImageFilter } from './GPUImageFilter' +import { GPUFilterType } from '../gl/GPUFilterType' + +export class GPUImageColorMatrixFilter extends GPUImageFilter { + private intensity: number = 1.0; + private colorMatrix: Array = [ + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + ] + + constructor(intensity?: number) { + super() + if (intensity) { + this.intensity = intensity; + } + } + + getFilterType(): GPUFilterType { + return GPUFilterType.CONTRAST; + } + + onInitialized() { + + } + + onReadySize() { + + } + + setIntensity(intensity: number) { + this.intensity = intensity; + this.setFloat("intensity", this.intensity); + } + + setColorMatrix(colorMatrix: Array) { + this.colorMatrix = colorMatrix; + this.setUniformMatrix4f("colorMatrix", this.colorMatrix); + } +} \ No newline at end of file diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImageContrastFilter.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImageContrastFilter.ts new file mode 100644 index 0000000..9d35176 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageContrastFilter.ts @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GPUImageFilter } from './GPUImageFilter' +import { GPUFilterType } from '../gl/GPUFilterType' + +export class GPUImageContrastFilter extends GPUImageFilter { + private contrast: number = 1.0; + + constructor(contrast?: number) { + super() + if (contrast) { + this.contrast = contrast; + } + } + + getFilterType(): GPUFilterType { + return GPUFilterType.CONTRAST; + } + + onInitialized() { + + } + + onReadySize() { + + } + + setContrast(contrast: number) { + this.contrast = contrast; + this.setFloat("contrast", this.contrast); + } +} \ No newline at end of file diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImageFilter.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImageFilter.ts new file mode 100644 index 0000000..3dbccff --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageFilter.ts @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NativeEglRender } from '../gl/NativeEglRender' +import { GPUFilterType } from '../gl/GPUFilterType' +import { Runnable } from '../interface/Runnable' +import LinkedList from '@ohos.util.LinkedList'; +import ArrayList from '@ohos.util.ArrayList'; + +export abstract class GPUImageFilter { + private render: NativeEglRender; + private isInitialized: boolean; + private runOnDraw: LinkedList; + protected width: number; + protected height: number; + + constructor() { + this.render = new NativeEglRender(); + this.runOnDraw = new LinkedList(); + } + + private init() { + if (this.render) { + this.render.native_EglRenderInit(); + } + this.onInitialized(); + } + + protected setSurfaceFilterType() { + let filter = this.getFilterType(); + if (!this.render.native_glIsInit()) { + throw new Error("the egl surface not init"); + } + this.render.native_EglRenderSetIntParams(300, filter.valueOf()); + } + + setImageData(buf: ArrayBuffer, width: number, height: number) { + if (!buf) { + throw new Error("this pixelMap data is empty"); + } + if (width <= 0 || height <= 0) { + throw new Error("this pixelMap width and height is invalidation") + } + this.width = width; + this.height = height; + this.ensureInit(); + this.onReadySize(); + this.setSurfaceFilterType(); + this.render.native_EglRenderSetImageData(buf, width, height); + } + + protected onDraw() { + if (!this.render.native_glIsInit()) { + throw new Error("the egl surface not init") + } + this.render.native_EglUseProgram(); + this.runPendingOnDrawTasks(); + this.onRendering(); + } + + protected onRendering() { + this.render.native_EglRendering(); + } + + getPixelMapBuf(x: number, y: number, width: number, height: number): Promise { + if (x < 0 || y < 0) { + throw new Error("the x or y should be greater than 0") + } + if (width <= 0 || height <= 0) { + throw new Error("the width or height should be greater than 0") + } + let that = this; + return new Promise((resolve, rejects) => { + that.onDraw(); + let buf = this.render.native_EglBitmapFromGLSurface(x, y, width, height); + if (!buf) { + rejects(new Error("get pixelMap fail")) + } else { + resolve(buf); + that.destroy(); + } + }) + } + + ensureInit() { + if (this.render) { + this.isInitialized = this.render.native_glIsInit(); + if (!this.isInitialized) { + this.init(); + } + } + } + + protected runPendingOnDrawTasks() { + while (this.runOnDraw.length > 0) { + this.runOnDraw.removeFirst().run(); + } + } + + protected addRunOnDraw(runAble: Runnable) { + if (!runAble) { + return; + } + this.runOnDraw.add(runAble); + } + + protected setInteger(location: string, value: number) { + let that = this; + let able: Runnable = { + run() { + that.ensureInit(); + that.render.native_setInteger(location, value); + } + } + this.addRunOnDraw(able); + } + + protected setFloat(location: string, value: number) { + let that = this; + let able: Runnable = { + run() { + that.ensureInit(); + that.render.native_setFloat(location, value); + } + } + this.addRunOnDraw(able); + } + + protected setPoint(location: string, vf1: number, vf2: number) { + + let that = this; + let able: Runnable = { + run() { + that.ensureInit(); + that.render.native_setPoint(location, vf1, vf2); + } + } + this.addRunOnDraw(able); + } + + protected setFloat2f(location: string, value: Array) { + if (value.length !== 2) { + return; + } + let that = this; + let able: Runnable = { + run() { + that.ensureInit(); + let array = new Float32Array(2); + array[0] = value[0]; + array[1] = value[1]; + that.render.native_setFloat2f(location, array); + } + } + this.addRunOnDraw(able); + } + + protected setFloatVec2(location: string, value: Array) { + if (value.length !== 2) { + return; + } + let that = this; + let able: Runnable = { + run() { + that.ensureInit(); + let array = new Float32Array(2); + array[0] = value[0]; + array[1] = value[1]; + that.render.native_setFloatVec2(location, array); + } + } + this.addRunOnDraw(able); + } + + protected setFloatVec3(location: string, value: Array) { + if (value.length !== 3) { + return; + } + let that = this; + let able: Runnable = { + run() { + that.ensureInit(); + let array = new Float32Array(3); + array[0] = value[0]; + array[1] = value[1]; + array[2] = value[2]; + that.render.native_setFloatVec3(location, array); + } + } + this.addRunOnDraw(able); + } + + protected setFloatVec4(location: string, value: Array) { + if (value.length !== 4) { + return; + } + let that = this; + let able: Runnable = { + run() { + that.ensureInit(); + let array = new Float32Array(4); + array[0] = value[0]; + array[1] = value[1]; + array[2] = value[2]; + array[3] = value[3]; + + that.render.native_setFloatVec4(location, array); + } + } + this.addRunOnDraw(able); + } + + protected setUniformMatrix3f(location: string, value: Array) { + if (!value) { + return; + } + let that = this; + let able: Runnable = { + run() { + that.ensureInit(); + let array = new Float32Array(value.length); + for (let i = 0; i < value.length; i++) { + array[i] = value[i]; + + } + that.render.native_setUniformMatrix3f(location, array); + } + } + this.addRunOnDraw(able); + } + + protected setUniformMatrix4f(location: string, value: Array) { + if (!value) { + return; + } + let that = this; + let able: Runnable = { + run() { + that.ensureInit(); + let array = new Float32Array(value.length); + for (let i = 0; i < value.length; i++) { + array[i] = value[i]; + + } + that.render.native_setUniformMatrix4f(location, array); + } + } + this.addRunOnDraw(able); + } + + getFilters(): ArrayList { + return null; + } + + destroy() { + this.render.native_glIsDestroy(); + this.render = null; + this.isInitialized = false; + } + + abstract getFilterType(): GPUFilterType; + + abstract onReadySize(); + + abstract onInitialized(); +} \ No newline at end of file diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImageFilterGroup.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImageFilterGroup.ts new file mode 100644 index 0000000..7cef433 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageFilterGroup.ts @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GPUImageFilter } from './GPUImageFilter' +import { GPUFilterType } from '../gl/GPUFilterType' +import ArrayList from '@ohos.util.ArrayList'; + +export abstract class GPUImageFilterGroup extends GPUImageFilter { + private filters: ArrayList; + + constructor() { + super() + this.filters = new ArrayList(); + } + + addFilter(aFilter: GPUImageFilter) { + this.filters.add(aFilter); + } + + getFilters(): ArrayList { + return this.filters; + } +} + diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImageGrayscaleFilter.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImageGrayscaleFilter.ts new file mode 100644 index 0000000..9ae8521 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageGrayscaleFilter.ts @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GPUImageFilter } from './GPUImageFilter' +import { GPUFilterType } from '../gl/GPUFilterType' + +export class GPUImageGrayscaleFilter extends GPUImageFilter { + constructor() { + super() + + } + + getFilterType(): GPUFilterType { + return GPUFilterType.GRAYSCALE; + } + + onInitialized() { + + } + + onReadySize() { + + } +} + diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImageKuwaharaFilter.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImageKuwaharaFilter.ts new file mode 100644 index 0000000..6aff40f --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageKuwaharaFilter.ts @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GPUImageFilter } from './GPUImageFilter' +import { GPUFilterType } from '../gl/GPUFilterType' + +export class GPUImageKuwaharaFilter extends GPUImageFilter { + private _radius: number = 25; + + constructor(radius?: number) { + super() + if (radius) { + this._radius = radius; + } + + } + + getFilterType(): GPUFilterType { + return GPUFilterType.KUWAHARA; + } + + onInitialized() { + + } + + onReadySize() { + + } + + setRadius(radius: number) { + this._radius = radius; + this.setFloat("radius", this._radius); + } +} + diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImagePixelationFilter.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImagePixelationFilter.ts new file mode 100644 index 0000000..1959db8 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImagePixelationFilter.ts @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GPUImageFilter } from './GPUImageFilter' +import { GPUFilterType } from '../gl/GPUFilterType' + +export class GPUImagePixelationFilter extends GPUImageFilter { + private pixel: number = 1.0; + + constructor() { + super() + } + + getFilterType(): GPUFilterType { + return GPUFilterType.PIXELATION; + } + + onInitialized() { + + } + + onReadySize() { + + } + + setPixel(pixel: number) { + this.pixel = pixel; + this.setFloat("imageWidthFactor", 1.0 / this.width); + this.setFloat("imageHeightFactor", 1.0 / this.height); + this.setFloat("pixel", this.pixel); + } +} + diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImageSepiaToneFilter.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImageSepiaToneFilter.ts new file mode 100644 index 0000000..f28c1c0 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageSepiaToneFilter.ts @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GPUImageColorMatrixFilter } from './GPUImageColorMatrixFilter' +import { GPUFilterType } from '../gl/GPUFilterType' + +export class GPUImageSepiaToneFilter extends GPUImageColorMatrixFilter { + constructor(intensity?: number) { + super() + this.setIntensity(intensity ? intensity : 1.0); + this.setColorMatrix([ + 0.3588, 0.7044, 0.1368, 0.0, + 0.2990, 0.5870, 0.1140, 0.0, + 0.2392, 0.4696, 0.0912, 0.0, + 0.0, 0.0, 0.0, 1.0 + ]) + } + + getFilterType(): GPUFilterType { + return GPUFilterType.SEPIA; + } + + onReadySize() { + + } +} + diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImageSketchFilter.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImageSketchFilter.ts new file mode 100644 index 0000000..d7c37fd --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageSketchFilter.ts @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GPUImage3x3TextureSamplingFilter } from './GPUImage3x3TextureSamplingFilter' +import { GPUFilterType } from '../gl/GPUFilterType' + +export class GPUImageSketchFilter extends GPUImage3x3TextureSamplingFilter { + constructor() { + super() + } + + getFilterType(): GPUFilterType { + return GPUFilterType.SKETCH; + } + + onInitialized() { + + } + + onReadySize() { + this.setTexelWidth(this.width); + this.setTexelHeight(this.height); + } +} + diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImageSwirlFilter.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImageSwirlFilter.ts new file mode 100644 index 0000000..2209327 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageSwirlFilter.ts @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GPUImageFilter } from './GPUImageFilter' +import { GPUFilterType } from '../gl/GPUFilterType' + +export class GPUImageSwirlFilter extends GPUImageFilter { + private _radius: number = 25; + private _angle: number = 0.9; + private _xCenter: number = 0.5; + private _yCenter: number = 0.5; + + constructor() { + super() + } + + getFilterType(): GPUFilterType { + return GPUFilterType.SWIRL; + } + + onInitialized() { + + } + + onReadySize() { + } + + setRadius(radius: number) { + this._radius = radius; + this.setFloat("radius", this._radius); + } + + setAngle(angle: number) { + this._angle = angle; + this.setFloat("angle", this._angle); + } + + setCenter(x_center: number, y_center: number) { + this._xCenter = x_center; + this._yCenter = y_center; + this.setPoint("center", x_center, y_center); + } +} \ No newline at end of file diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImageToonFilter.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImageToonFilter.ts new file mode 100644 index 0000000..595f97c --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageToonFilter.ts @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GPUImage3x3TextureSamplingFilter } from './GPUImage3x3TextureSamplingFilter' +import { GPUFilterType } from '../gl/GPUFilterType' + +export class GPUImageToonFilter extends GPUImage3x3TextureSamplingFilter { + private threshold: number = 0.2; + private quantizationLevels: number = 10.0; + + constructor() { + super() + } + + getFilterType(): GPUFilterType { + return GPUFilterType.TOON; + } + + onInitialized() { + + } + + onReadySize() { + this.setTexelWidth(this.width); + this.setTexelHeight(this.height); + } + + setThreshold(threshold: number) { + this.threshold = threshold; + this.setFloat("threshold", threshold); + } + + setQuantizationLevels(quantizationLevels: number) { + this.quantizationLevels = quantizationLevels; + this.setFloat("quantizationLevels", quantizationLevels); + } +} \ No newline at end of file diff --git a/gpu_transform/src/main/ets/gpu/filter/GPUImageVignetterFilter.ts b/gpu_transform/src/main/ets/gpu/filter/GPUImageVignetterFilter.ts new file mode 100644 index 0000000..00ebeed --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageVignetterFilter.ts @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GPUImageFilter } from './GPUImageFilter' +import { GPUFilterType } from '../gl/GPUFilterType' + +export class GPUImageVignetterFilter extends GPUImageFilter { + private vignetteCenter: Array = [0.0, 0.0]; + private vignetteColor: Array = [0.0, 0.0, 0.0]; + private vignetteStart: number; + private vignetteEnd: number; + + constructor() { + super() + } + + getFilterType(): GPUFilterType { + return GPUFilterType.VIGNETTE; + } + + onInitialized() { + + } + + onReadySize() { + } + + setVignetteCenter(center: Array) { + this.vignetteCenter = center; + this.setFloatVec2("vignetteCenter", center); + } + + setVignetteColor(colors: Array) { + this.vignetteColor = colors; + this.setFloatVec3("vignetteColor", colors); + } + + setVignetteStart(start: number) { + this.vignetteStart = start; + this.setFloat("vignetteStart", this.vignetteStart); + } + + setVignetteEnd(end: number) { + this.vignetteEnd = end; + this.setFloat("vignetteEnd", this.vignetteEnd); + } +} \ No newline at end of file diff --git a/gpu_transform/src/main/ets/gpu/gl/GPUFilterType.ts b/gpu_transform/src/main/ets/gpu/gl/GPUFilterType.ts new file mode 100644 index 0000000..df20c38 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/gl/GPUFilterType.ts @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export enum GPUFilterType { + BRIGHT, + CONTRAST, + INVERT, + PIXELATION, + KUWAHARA, + SEPIA, + SKETCH, + SWIRL, + TOON, + VIGNETTE, + GRAYSCALE, + X3TEXTURE, + BLUR, + COLOR_M +} \ No newline at end of file diff --git a/gpu_transform/src/main/ets/gpu/gl/NativeEglRender.ts b/gpu_transform/src/main/ets/gpu/gl/NativeEglRender.ts new file mode 100644 index 0000000..5b1da6b --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/gl/NativeEglRender.ts @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import nativeGpu from "libnativeGpu.so" + +export class NativeEglRender { + static EGLTrue: number = 1; + + native_EglRenderInit(): void { + nativeGpu.EglRenderInit(); + } + + native_EglRenderSetImageData(bytes: ArrayBuffer, width: number, height: number) { + nativeGpu.EglRenderSetImageData(bytes, width, height); + } + + native_EglRenderSetIntParams(paramType: number, param: number) { + nativeGpu.EglRenderSetIntParams(paramType, param); + } + + native_EglBitmapFromGLSurface(x: number, y: number, w: number, h: number): ArrayBuffer { + let num = nativeGpu.EglPixelMapSurface(x, y, w, h); + return num; + } + + native_glIsInit(): boolean { + let initStatus = nativeGpu.EglIsInit(); + if (initStatus === NativeEglRender.EGLTrue) { + return true; + } + return false; + } + + native_EglUseProgram() { + nativeGpu.EglUseProgram(); + } + + native_EglRendering() { + nativeGpu.EglRendering(); + } + + native_setInteger(key: string, value: number) { + nativeGpu.EglUniform1i(key, value) + } + + native_setFloat(key: string, value: number) { + nativeGpu.EglUniform1f(key, value) + } + + native_setPoint(key: string, vf1: number, vf2: number) { + nativeGpu.EglUniform2fv(key, vf1, vf2); + } + + native_setFloat2f(key: string, value: Float32Array) { + this.native_setTypeArray(key, "glUniform2f", value); + } + + native_setFloatVec2(key: string, value: Float32Array) { + this.native_setTypeArray(key, "glUniform2fv", value); + } + + native_setFloatVec3(key: string, value: Float32Array) { + this.native_setTypeArray(key, "glUniform3fv", value); + } + + native_setFloatVec4(key: string, value: Float32Array) { + this.native_setTypeArray(key, "glUniform4fv", value); + } + + native_setFloatArray(key: string, value: Float32Array) { + this.native_setTypeArray(key, "glUniform1fv", value); + } + + native_setUniformMatrix3f(key: string, value: Float32Array) { + nativeGpu.EglSetTypeArrayOfMatrix3f(key, value); + } + + native_setUniformMatrix4f(key: string, value: Float32Array) { + nativeGpu.EglSetTypeArrayOfMatrix4f(key, value); + } + + native_setTypeArray(key: string, uniformType: string, data: Float32Array) { + nativeGpu.EglSetTypeArrayOfFloat(key, uniformType, data); + } + + native_glIsDestroy() { + nativeGpu.EglDestroy(); + } +} \ No newline at end of file diff --git a/gpu_transform/src/main/ets/gpu/interface/Runnable.ts b/gpu_transform/src/main/ets/gpu/interface/Runnable.ts new file mode 100644 index 0000000..39597d4 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/interface/Runnable.ts @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface Runnable { + run(); +} \ No newline at end of file diff --git a/gpu_transform/src/main/module.json5 b/gpu_transform/src/main/module.json5 new file mode 100644 index 0000000..ad730e4 --- /dev/null +++ b/gpu_transform/src/main/module.json5 @@ -0,0 +1,10 @@ +{ + "module": { + "name": "gpu_transform", + "type": "har", + "deviceTypes": [ + "default", + "tablet" + ] + } +} diff --git a/gpu_transform/src/main/resources/base/element/string.json b/gpu_transform/src/main/resources/base/element/string.json new file mode 100644 index 0000000..1e76de0 --- /dev/null +++ b/gpu_transform/src/main/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "page_show", + "value": "page from npm package" + } + ] +} diff --git a/gpu_transform/src/main/resources/en_US/element/string.json b/gpu_transform/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000..1e76de0 --- /dev/null +++ b/gpu_transform/src/main/resources/en_US/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "page_show", + "value": "page from npm package" + } + ] +} diff --git a/gpu_transform/src/main/resources/zh_CN/element/string.json b/gpu_transform/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000..1e76de0 --- /dev/null +++ b/gpu_transform/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "page_show", + "value": "page from npm package" + } + ] +} diff --git a/imageknife/index.ets b/imageknife/index.ets index d4ee93c..b37f483 100644 --- a/imageknife/index.ets +++ b/imageknife/index.ets @@ -70,6 +70,9 @@ export * from './src/main/ets/components/imageknife/transform/SepiaFilterTransfo export * from './src/main/ets/components/imageknife/transform/SketchFilterTransformation' export * from './src/main/ets/components/imageknife/transform/MaskTransformation' export * from './src/main/ets/components/imageknife/transform/SwirlFilterTransformation' +export * from './src/main/ets/components/imageknife/transform/KuwaharaFilterTransform' +export * from './src/main/ets/components/imageknife/transform/ToonFilterTransform' +export * from './src/main/ets/components/imageknife/transform/VignetteFilterTransform' export * from './src/main/ets/components/imageknife/transform/TransformUtils' export * from './src/main/ets/components/imageknife/transform/TransformType' export * from './src/main/ets/components/imageknife/transform/pixelmap/CenterCrop' diff --git a/imageknife/package.json b/imageknife/package.json index 40edd3c..7de7f53 100644 --- a/imageknife/package.json +++ b/imageknife/package.json @@ -12,6 +12,7 @@ }, "main": "index.ets", "repository": "https://gitee.com/openharmony-tpc/ImageKnife", + "type": "module", "version": "1.0.5", "dependencies": { "pako": "^1.0.5", @@ -19,7 +20,8 @@ "@ohos/disklrucache": "^1.0.0", "@ohos/svg": "1.1.0", "crc-32": "^1.2.0", - "spark-md5": "^3.0.2" + "spark-md5": "^3.0.2", + "@ohos/gpu_transform": "file:../gpu_transform" }, "tags": [ "ImageCache", @@ -27,6 +29,5 @@ ], "license": "Apache License 2.0", "devDependencies": {}, - "name": "@ohos/imageknife", - "type": "module" + "name": "@ohos/imageknife" } diff --git a/imageknife/src/main/ets/components/imageknife/RequestOption.ets b/imageknife/src/main/ets/components/imageknife/RequestOption.ets index 066dd27..14c27f1 100644 --- a/imageknife/src/main/ets/components/imageknife/RequestOption.ets +++ b/imageknife/src/main/ets/components/imageknife/RequestOption.ets @@ -13,36 +13,39 @@ * limitations under the License. */ -import {DiskStrategy} from "../cache/diskstrategy/DiskStrategy" -import {AsyncCallback} from "../imageknife/interface/asynccallback" -import {AsyncSuccess} from "../imageknife/interface/AsyncSuccess" -import {IAllCacheInfoCallback} from "../imageknife/interface/IAllCacheInfoCallback" -import {AUTOMATIC} from "../cache/diskstrategy/enum/AUTOMATIC" -import {BaseTransform} from "../imageknife/transform/BaseTransform" -import {RotateImageTransformation} from "../imageknife/transform/RotateImageTransformation" -import {ImageKnifeData} from "../imageknife/ImageKnifeData" -import {CenterCrop} from '../imageknife/transform/pixelmap/CenterCrop' -import {CenterInside} from '../imageknife/transform/pixelmap/CenterInside' -import {FitCenter} from '../imageknife/transform/pixelmap/FitCenter' -import {RoundedCornersTransformation} from '../imageknife/transform/RoundedCornersTransformation' +import { DiskStrategy } from "../cache/diskstrategy/DiskStrategy" +import { AsyncCallback } from "../imageknife/interface/asynccallback" +import { AsyncSuccess } from "../imageknife/interface/AsyncSuccess" +import { IAllCacheInfoCallback } from "../imageknife/interface/IAllCacheInfoCallback" +import { AUTOMATIC } from "../cache/diskstrategy/enum/AUTOMATIC" +import { BaseTransform } from "../imageknife/transform/BaseTransform" +import { RotateImageTransformation } from "../imageknife/transform/RotateImageTransformation" +import { ImageKnifeData } from "../imageknife/ImageKnifeData" +import { CenterCrop } from '../imageknife/transform/pixelmap/CenterCrop' +import { CenterInside } from '../imageknife/transform/pixelmap/CenterInside' +import { FitCenter } from '../imageknife/transform/pixelmap/FitCenter' +import { RoundedCornersTransformation } from '../imageknife/transform/RoundedCornersTransformation' -import {CropCircleTransformation} from '../imageknife/transform/CropCircleTransformation' +import { CropCircleTransformation } from '../imageknife/transform/CropCircleTransformation' -import {CropCircleWithBorderTransformation} from '../imageknife/transform/CropCircleWithBorderTransformation' -import {CropSquareTransformation} from '../imageknife/transform/CropSquareTransformation' -import {CropTransformation} from '../imageknife/transform/CropTransformation' -import {CropType} from '../imageknife/transform/CropTransformation' -import {GrayscaleTransformation} from '../imageknife/transform/GrayscaleTransformation' -import {BrightnessFilterTransformation} from '../imageknife/transform/BrightnessFilterTransformation' -import {ContrastFilterTransformation} from '../imageknife/transform/ContrastFilterTransformation' -import {InvertFilterTransformation} from '../imageknife/transform/InvertFilterTransformation' -import {SepiaFilterTransformation} from '../imageknife/transform/SepiaFilterTransformation' -import {SketchFilterTransformation} from '../imageknife/transform/SketchFilterTransformation' -import {BlurTransformation} from '../imageknife/transform/BlurTransformation' -import {PixelationFilterTransformation} from '../imageknife/transform/PixelationFilterTransformation' -import {MaskTransformation} from '../imageknife/transform/MaskTransformation' -import {SwirlFilterTransformation} from '../imageknife/transform/SwirlFilterTransformation' -import {LogUtil} from '../imageknife/utils/LogUtil' +import { CropCircleWithBorderTransformation } from '../imageknife/transform/CropCircleWithBorderTransformation' +import { CropSquareTransformation } from '../imageknife/transform/CropSquareTransformation' +import { CropTransformation } from '../imageknife/transform/CropTransformation' +import { CropType } from '../imageknife/transform/CropTransformation' +import { GrayscaleTransformation } from '../imageknife/transform/GrayscaleTransformation' +import { BrightnessFilterTransformation } from '../imageknife/transform/BrightnessFilterTransformation' +import { ContrastFilterTransformation } from '../imageknife/transform/ContrastFilterTransformation' +import { InvertFilterTransformation } from '../imageknife/transform/InvertFilterTransformation' +import { SepiaFilterTransformation } from '../imageknife/transform/SepiaFilterTransformation' +import { SketchFilterTransformation } from '../imageknife/transform/SketchFilterTransformation' +import { BlurTransformation } from '../imageknife/transform/BlurTransformation' +import { PixelationFilterTransformation } from '../imageknife/transform/PixelationFilterTransformation' +import { MaskTransformation } from '../imageknife/transform/MaskTransformation' +import { SwirlFilterTransformation } from '../imageknife/transform/SwirlFilterTransformation' +import { KuwaharaFilterTransform } from '../imageknife/transform/KuwaharaFilterTransform' +import { ToonFilterTransform } from '../imageknife/transform/ToonFilterTransform' +import { VignetteFilterTransform } from '../imageknife/transform/VignetteFilterTransform' +import { LogUtil } from '../imageknife/utils/LogUtil' export class RequestOption { loadSrc: string | PixelMap | Resource; @@ -67,7 +70,6 @@ export class RequestOption { retryholderSrc: PixelMap | Resource; retryholderFunc: AsyncSuccess retryholderData: ImageKnifeData - size: { width: number, height: number @@ -78,6 +80,8 @@ export class RequestOption { onlyRetrieveFromCache: boolean = false; isCacheable: boolean = true; + //开启GPU变换绘制 + gpuEnabled: boolean = false; // 变换相关 transformations: Array> = new Array(); generateCacheKey: string = ""; @@ -173,10 +177,10 @@ export class RequestOption { return this; } - thumbnail(sizeMultiplier: number, func?: AsyncSuccess,displayTime?:number) { + thumbnail(sizeMultiplier: number, func?: AsyncSuccess, displayTime?: number) { this.thumbSizeMultiplier = sizeMultiplier; this.thumbHolderFunc = func; - if(displayTime){ + if (displayTime) { this.thumbDelayTime = displayTime; } return this; @@ -187,8 +191,6 @@ export class RequestOption { return this; } - - addListener(func: AsyncCallback) { this.requestListeners.push(func); return this; @@ -218,111 +220,153 @@ export class RequestOption { this.transformations.push(new CenterCrop()); return this; } + centerInside() { this.transformations.push(new CenterInside()); return this; } + fitCenter() { this.transformations.push(new FitCenter()); return this; } - roundedCorners(obj:{ top_left: number, top_right: number, bottom_left: number, bottom_right: number }){ - let transformation = new RoundedCornersTransformation({top_left: obj.top_left, top_right: obj.top_right, bottom_left: obj.bottom_left, bottom_right: obj.bottom_right}) + roundedCorners(obj: { + top_left: number, + top_right: number, + bottom_left: number, + bottom_right: number + }) { + let transformation = new RoundedCornersTransformation({ + top_left: obj.top_left, + top_right: obj.top_right, + bottom_left: obj.bottom_left, + bottom_right: obj.bottom_right + }) this.transformations.push(transformation); return this; } - cropCircle(){ + cropCircle() { let transformation = new CropCircleTransformation() this.transformations.push(transformation); return this; } - cropCircleWithBorder(border:number, obj:{ r_color: number, g_color: number, b_color: number }){ - let transformation = new CropCircleWithBorderTransformation(border,obj) + cropCircleWithBorder(border: number, obj: { + r_color: number, + g_color: number, + b_color: number + }) { + let transformation = new CropCircleWithBorderTransformation(border, obj) this.transformations.push(transformation); return this; } - cropSquare(){ + cropSquare() { let transformation = new CropSquareTransformation() this.transformations.push(transformation); return this; } - crop(width: number, height: number, cropType: CropType){ + crop(width: number, height: number, cropType: CropType) { let transformation = new CropTransformation(width, height, cropType) this.transformations.push(transformation); return this; } - grayscale(){ + grayscale() { let transformation = new GrayscaleTransformation() this.transformations.push(transformation); return this; } - brightnessFilter(brightness:number){ + brightnessFilter(brightness: number) { let transformation = new BrightnessFilterTransformation(brightness) this.transformations.push(transformation); return this; } - contrastFilter(contrast:number){ + contrastFilter(contrast: number) { let transformation = new ContrastFilterTransformation(contrast) this.transformations.push(transformation); return this; } - invertFilter(){ + invertFilter() { let transformation = new InvertFilterTransformation() this.transformations.push(transformation); return this; } - sepiaFilter(){ + sepiaFilter() { let transformation = new SepiaFilterTransformation() this.transformations.push(transformation); return this; } - sketchFilter(){ + sketchFilter() { let transformation = new SketchFilterTransformation() this.transformations.push(transformation); return this; } - blur(radius: number){ + blur(radius: number) { let transformation = new BlurTransformation(radius) this.transformations.push(transformation); return this; } - pixelationFilter(pixel: number){ + pixelationFilter(pixel: number) { let transformation = new PixelationFilterTransformation(pixel) this.transformations.push(transformation); return this; } - swirlFilter(degree: number){ + swirlFilter(degree: number) { let transformation = new SwirlFilterTransformation(degree) this.transformations.push(transformation); return this; } - mask(maskResource: Resource){ + + mask(maskResource: Resource) { let transformation = new MaskTransformation(maskResource) this.transformations.push(transformation); return this; } - transform(input:BaseTransform){ + + kuwaharaFilter(radius: number) { + let transformation = new KuwaharaFilterTransform(radius); + this.transformations.push(transformation); + return this; + } + + toonFilter(threshold: number, quantizationLevels: number) { + let transformation = new ToonFilterTransform(threshold, quantizationLevels); + this.transformations.push(transformation); + return this; + } + + vignetteFilter(centerPoint: Array, vignetteColor: Array, vignetteSpace: Array) { + let transformation = new VignetteFilterTransform(centerPoint, vignetteColor, vignetteSpace); + this.transformations.push(transformation); + return this; + } + + transform(input: BaseTransform) { this.transformations.push(input); return this; } - transforms(inputs:BaseTransform[]){ + + transforms(inputs: BaseTransform[]) { this.transformations = inputs; return this; } + //开启GPU变换绘制 + enableGPU() { + this.gpuEnabled = true; + return this; + } // 占位图解析成功 placeholderOnComplete(imageKnifeData: ImageKnifeData) { @@ -340,8 +384,6 @@ export class RequestOption { } - - // 缩略图解析成功 thumbholderOnComplete(imageKnifeData: ImageKnifeData) { if (!this.loadMainReady && !(this.loadErrorReady || this.loadRetryReady)) { @@ -369,15 +411,15 @@ export class RequestOption { LogUtil.log("失败占位图解析失败 error =" + error) } - retryholderOnComplete(imageKnifeData: ImageKnifeData){ + retryholderOnComplete(imageKnifeData: ImageKnifeData) { this.retryholderData = imageKnifeData; - if(this.loadRetryReady){ + if (this.loadRetryReady) { this.retryholderFunc(imageKnifeData) } } - retryholderOnError(error){ - LogUtil.log("重试占位图解析失败 error ="+ error) + retryholderOnError(error) { + LogUtil.log("重试占位图解析失败 error =" + error) } loadComplete(imageKnifeData: ImageKnifeData) { @@ -394,13 +436,13 @@ export class RequestOption { } loadError(err) { - LogUtil.log("loadError:"+err); - LogUtil.log("loadError stack=:"+JSON.stringify(err.stack)); + LogUtil.log("loadError:" + err); + LogUtil.log("loadError stack=:" + JSON.stringify(err.stack)); //失败占位图展示规则 if (this.retryholderFunc) { // 重试图层优先于加载失败展示 this.loadRetryReady = true; - if(this.retryholderData != null){ + if (this.retryholderData != null) { this.retryholderFunc(this.retryholderData) } } else { diff --git a/imageknife/src/main/ets/components/imageknife/transform/BlurTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/BlurTransformation.ets index bd37413..70a479c 100644 --- a/imageknife/src/main/ets/components/imageknife/transform/BlurTransformation.ets +++ b/imageknife/src/main/ets/components/imageknife/transform/BlurTransformation.ets @@ -71,7 +71,11 @@ export class BlurTransformation implements BaseTransform { } imageSource.createPixelMap(options) .then((data) => { - fastBlur.blur(data, this._mRadius, true, func); + if (request.gpuEnabled) { + fastBlur.blurGPU(data, this._mRadius, true, func); + } else { + fastBlur.blur(data, this._mRadius, true, func); + } }) .catch((e) => { LogUtil.log(Constants.PROJECT_TAG + ";error:" + e); diff --git a/imageknife/src/main/ets/components/imageknife/transform/BrightnessFilterTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/BrightnessFilterTransformation.ets index aa05957..d099976 100644 --- a/imageknife/src/main/ets/components/imageknife/transform/BrightnessFilterTransformation.ets +++ b/imageknife/src/main/ets/components/imageknife/transform/BrightnessFilterTransformation.ets @@ -17,9 +17,9 @@ import { BaseTransform } from "../transform/BaseTransform" import { AsyncTransform } from "../transform/AsyncTransform" import { Constants } from "../constants/Constants" import { RequestOption } from "../../imageknife/RequestOption" -import {LogUtil} from '../../imageknife/utils/LogUtil' +import { LogUtil } from '../../imageknife/utils/LogUtil' import image from "@ohos.multimedia.image" - +import { GPUImageBrightnessFilter } from '@ohos/gpu_transform' /** * brightness value ranges from -1.0 to 1.0, with 0.0 as the normal level @@ -78,6 +78,18 @@ export class BrightnessFilterTransformation implements BaseTransform { let bufferData = new ArrayBuffer(data.getPixelBytesNumber()); await data.readPixelsToBuffer(bufferData); + if (request.gpuEnabled) { + let filter = new GPUImageBrightnessFilter(); + filter.setImageData(bufferData, targetWidth, targetHeight); + filter.setBrightness(this._mBrightness); + let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight); + data.writeBufferToPixels(buf); + if (func) { + func("success", data); + } + return; + } + var dataArray = new Uint8Array(bufferData); for (let index = 0; index < dataArray.length; index += 4) { diff --git a/imageknife/src/main/ets/components/imageknife/transform/ContrastFilterTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/ContrastFilterTransformation.ets index b152aac..57d46c4 100644 --- a/imageknife/src/main/ets/components/imageknife/transform/ContrastFilterTransformation.ets +++ b/imageknife/src/main/ets/components/imageknife/transform/ContrastFilterTransformation.ets @@ -17,9 +17,9 @@ import { BaseTransform } from "../transform/BaseTransform" import { AsyncTransform } from "../transform/AsyncTransform" import { Constants } from "../constants/Constants" import { RequestOption } from "../../imageknife/RequestOption" -import {LogUtil} from '../../imageknife/utils/LogUtil' +import { LogUtil } from '../../imageknife/utils/LogUtil' import image from "@ohos.multimedia.image" - +import { GPUImageContrastFilter } from '@ohos/gpu_transform' /** * 以24位色图像为例子,每种色彩都可以用0-255, @@ -91,6 +91,18 @@ export class ContrastFilterTransformation implements BaseTransform { let bufferData = new ArrayBuffer(data.getPixelBytesNumber()); await data.readPixelsToBuffer(bufferData); + if (request.gpuEnabled) { + let filter = new GPUImageContrastFilter(); + filter.setImageData(bufferData, targetWidth, targetHeight); + filter.setContrast(this._mContrast) + let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight); + data.writeBufferToPixels(buf); + if (func) { + func("success", data); + } + return; + } + var dataArray = new Uint8Array(bufferData); let brightness = 0; //亮度的偏移量,可以默认0 diff --git a/imageknife/src/main/ets/components/imageknife/transform/GrayscaleTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/GrayscaleTransformation.ets index 2333d47..1c0fd77 100644 --- a/imageknife/src/main/ets/components/imageknife/transform/GrayscaleTransformation.ets +++ b/imageknife/src/main/ets/components/imageknife/transform/GrayscaleTransformation.ets @@ -20,6 +20,7 @@ import { RequestOption } from "../../imageknife/RequestOption" import { TransformUtils } from "../transform/TransformUtils" import {LogUtil} from '../../imageknife/utils/LogUtil' import image from "@ohos.multimedia.image" +import { GPUImageGrayscaleFilter } from '@ohos/gpu_transform' export class GrayscaleTransformation implements BaseTransform { getName() { @@ -70,6 +71,18 @@ export class GrayscaleTransformation implements BaseTransform { let bufferNewData = new ArrayBuffer(data.getPixelBytesNumber()); await data.readPixelsToBuffer(bufferData); + if (request.gpuEnabled) { + let filter = new GPUImageGrayscaleFilter(); + filter.setImageData(bufferData, targetWidth, targetHeight); + let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight); + data.writeBufferToPixels(buf); + if (func) { + func("success", data); + } + return; + } + + var dataArray = new Uint8Array(bufferData); var dataNewArray = new Uint8Array(bufferNewData); diff --git a/imageknife/src/main/ets/components/imageknife/transform/InvertFilterTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/InvertFilterTransformation.ets index 91b9431..ffd131c 100644 --- a/imageknife/src/main/ets/components/imageknife/transform/InvertFilterTransformation.ets +++ b/imageknife/src/main/ets/components/imageknife/transform/InvertFilterTransformation.ets @@ -19,6 +19,7 @@ import { Constants } from "../constants/Constants" import { RequestOption } from "../../imageknife/RequestOption" import {LogUtil} from '../../imageknife/utils/LogUtil' import image from "@ohos.multimedia.image" +import { GPUImageColorInvertFilter } from '@ohos/gpu_transform' /** ** Image inversion is particularly useful for enhancing white or gray detail in @@ -78,6 +79,18 @@ export class InvertFilterTransformation implements BaseTransform { let bufferData = new ArrayBuffer(data.getPixelBytesNumber()); await data.readPixelsToBuffer(bufferData); + if (request.gpuEnabled) { + let filter = new GPUImageColorInvertFilter(); + filter.setImageData(bufferData, targetWidth, targetHeight); + let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight); + data.writeBufferToPixels(buf); + if (func) { + func("success", data); + } + return; + } + + var dataArray = new Uint8Array(bufferData); for (let index = 0; index < dataArray.length; index += 4) { diff --git a/imageknife/src/main/ets/components/imageknife/transform/KuwaharaFilterTransform.ets b/imageknife/src/main/ets/components/imageknife/transform/KuwaharaFilterTransform.ets new file mode 100644 index 0000000..5ce2725 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/KuwaharaFilterTransform.ets @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BaseTransform } from "../transform/BaseTransform" +import { AsyncTransform } from "../transform/AsyncTransform" +import { Constants } from "../constants/Constants" +import { RequestOption } from "../../imageknife/RequestOption" +import { TransformUtils } from "../transform/TransformUtils" +import image from "@ohos.multimedia.image" +import { LogUtil } from '../../imageknife/utils/LogUtil' +import { GPUImageKuwaharaFilter } from '@ohos/gpu_transform' + + +export class KuwaharaFilterTransform implements BaseTransform { + private _mRadius: number; + + constructor(radius: number) { + this._mRadius = radius; + } + + getName() { + return "KuwaharaFilterTransform _mRadius:" + this._mRadius; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + LogUtil.log(Constants.PROJECT_TAG + ";KuwaharaFilterTransform buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";KuwaharaFilterTransform buf is empty", null); + } + return; + } + if (!request.gpuEnabled) { + LogUtil.error(Constants.PROJECT_TAG + ";the KuwaharaFilterTransform supported only in GPU mode"); + if (func) { + func(Constants.PROJECT_TAG + ";;the KuwaharaFilterTransform supported only in GPU mode", null); + } + return; + } + var that = this; + var imageSource = image.createImageSource(buf as any); + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + imageSource.createPixelMap(options) + .then((data) => { + that.kuwahara(data, targetWidth, targetHeight, func); + }) + .catch((e) => { + LogUtil.log(Constants.PROJECT_TAG + ";error:" + e); + func(e, null); + }) + }) + } + + private async kuwahara(bitmap: image.PixelMap, targetWidth: number, targetHeight: number, func: AsyncTransform) { + let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber()); + await bitmap.readPixelsToBuffer(bufferData); + let filter = new GPUImageKuwaharaFilter(); + filter.setImageData(bufferData, targetWidth, targetHeight); + filter.setRadius(this._mRadius); + let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight) + bitmap.writeBufferToPixels(buf); + if (func) { + func("success", bitmap); + } + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/PixelationFilterTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/PixelationFilterTransformation.ets index 6aece60..32705e5 100644 --- a/imageknife/src/main/ets/components/imageknife/transform/PixelationFilterTransformation.ets +++ b/imageknife/src/main/ets/components/imageknife/transform/PixelationFilterTransformation.ets @@ -18,7 +18,7 @@ import { AsyncTransform } from "../transform/AsyncTransform" import { Constants } from "../constants/Constants" import { RequestOption } from "../../imageknife/RequestOption" import { TransformUtils } from "../transform/TransformUtils" -import {LogUtil} from '../../imageknife/utils/LogUtil' +import { LogUtil } from '../../imageknife/utils/LogUtil' import image from "@ohos.multimedia.image" import { pixelUtils } from "../utils/PixelUtils" @@ -76,7 +76,11 @@ export class PixelationFilterTransformation implements BaseTransform { } imageSource.createPixelMap(options) .then((data) => { - pixelUtils.pixel(data, this._mPixel, func); + if (request.gpuEnabled) { + pixelUtils.pixelGPU(data, this._mPixel, func); + } else { + pixelUtils.pixel(data, this._mPixel, func); + } }) .catch((e) => { LogUtil.log(Constants.PROJECT_TAG + ";error:" + e); diff --git a/imageknife/src/main/ets/components/imageknife/transform/SepiaFilterTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/SepiaFilterTransformation.ets index 98f954e..eee5d66 100644 --- a/imageknife/src/main/ets/components/imageknife/transform/SepiaFilterTransformation.ets +++ b/imageknife/src/main/ets/components/imageknife/transform/SepiaFilterTransformation.ets @@ -17,8 +17,9 @@ import { BaseTransform } from "../transform/BaseTransform" import { AsyncTransform } from "../transform/AsyncTransform" import { Constants } from "../constants/Constants" import { RequestOption } from "../../imageknife/RequestOption" -import {LogUtil} from '../../imageknife/utils/LogUtil' +import { LogUtil } from '../../imageknife/utils/LogUtil' import image from "@ohos.multimedia.image" +import { GPUImageSepiaToneFilter } from '@ohos/gpu_transform' /** * Applies a simple sepia effect. @@ -72,9 +73,20 @@ export class SepiaFilterTransformation implements BaseTransform { let data = await imageSource.createPixelMap(options); let bufferData = new ArrayBuffer(data.getPixelBytesNumber()); - let bufferNewData = new ArrayBuffer(data.getPixelBytesNumber()); await data.readPixelsToBuffer(bufferData); + if (request.gpuEnabled) { + let filter = new GPUImageSepiaToneFilter(); + filter.setImageData(bufferData, targetWidth, targetHeight); + let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight); + data.writeBufferToPixels(buf); + if (func) { + func("success", data); + } + return; + } + + let bufferNewData = new ArrayBuffer(data.getPixelBytesNumber()); var dataArray = new Uint8Array(bufferData); var dataNewArray = new Uint8Array(bufferNewData); diff --git a/imageknife/src/main/ets/components/imageknife/transform/SketchFilterTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/SketchFilterTransformation.ets index e6c004d..aa3dbf7 100644 --- a/imageknife/src/main/ets/components/imageknife/transform/SketchFilterTransformation.ets +++ b/imageknife/src/main/ets/components/imageknife/transform/SketchFilterTransformation.ets @@ -63,7 +63,11 @@ export class SketchFilterTransformation implements BaseTransform { } imageSource.createPixelMap(options) .then((data) => { - CalculatePixelUtils.sketch(data, func); + if (request.gpuEnabled) { + CalculatePixelUtils.sketchGpu(data, func); + } else { + CalculatePixelUtils.sketch(data, func); + } }) .catch((e) => { func(e, null); diff --git a/imageknife/src/main/ets/components/imageknife/transform/SwirlFilterTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/SwirlFilterTransformation.ets index fd6aeea..891f315 100644 --- a/imageknife/src/main/ets/components/imageknife/transform/SwirlFilterTransformation.ets +++ b/imageknife/src/main/ets/components/imageknife/transform/SwirlFilterTransformation.ets @@ -22,16 +22,27 @@ import image from '@ohos.multimedia.image' import { PixelEntry } from '../entry/PixelEntry' import { ColorUtils } from '../utils/ColorUtils' import { CalculatePixelUtils } from '../utils/CalculatePixelUtils' +import { GPUImageSwirlFilter } from '@ohos/gpu_transform' export class SwirlFilterTransformation implements BaseTransform { - private _degree: number; + private radius: number = 0; + private _angle: number = 0.9; + private _xCenter: number = 0.5; + private _yCenter: number = 0.5; - constructor(degree: number) { - this._degree = degree; + constructor(radius: number, angle?: number, centerPoint?: Array) { + this.radius = radius; + if (angle) { + this._angle = angle; + } + if (centerPoint && centerPoint.length === 2) { + this._xCenter = centerPoint[0]; + this._yCenter = centerPoint[1]; + } } getName() { - return 'SwirlFilterTransformation' + this._degree; + return 'SwirlFilterTransformation' + this.radius; } transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { @@ -71,7 +82,7 @@ export class SwirlFilterTransformation implements BaseTransform { } imageSource.createPixelMap(options) .then((data) => { - this.swirl(data, this._degree, func); + this.swirl(data, this.radius, request, func); }) .catch((e) => { func(e, null); @@ -79,7 +90,7 @@ export class SwirlFilterTransformation implements BaseTransform { }) } - private async swirl(bitmap: any, degree: number, func?: AsyncTransform) { + private async swirl(bitmap: image.PixelMap, degree: number, request: RequestOption, func?: AsyncTransform) { let imageInfo = await bitmap.getImageInfo(); let size = { width: imageInfo.size.width, @@ -90,13 +101,28 @@ export class SwirlFilterTransformation implements BaseTransform { } let width = size.width; let height = size.height; - let pixEntry: Array = new Array(); - let rgbData = CalculatePixelUtils.createInt2DArray(height, width); - let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber()); await bitmap.readPixelsToBuffer(bufferData); + if (request.gpuEnabled) { + let filter = new GPUImageSwirlFilter(); + filter.setImageData(bufferData, width, height); + filter.setRadius(degree); + filter.setAngle(this._angle) + filter.setCenter(this._xCenter, this._yCenter) + let buf = await filter.getPixelMapBuf(0, 0, width, height); + bitmap.writeBufferToPixels(buf); + if (func) { + func("success", bitmap); + } + return; + } + + let pixEntry: Array = new Array(); + + let rgbData = CalculatePixelUtils.createInt2DArray(height, width); + let dataArray = new Uint8Array(bufferData); let ph = 0; diff --git a/imageknife/src/main/ets/components/imageknife/transform/ToonFilterTransform.ets b/imageknife/src/main/ets/components/imageknife/transform/ToonFilterTransform.ets new file mode 100644 index 0000000..90e1647 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/ToonFilterTransform.ets @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BaseTransform } from "../transform/BaseTransform" +import { AsyncTransform } from "../transform/AsyncTransform" +import { Constants } from "../constants/Constants" +import { RequestOption } from "../../imageknife/RequestOption" +import { TransformUtils } from "../transform/TransformUtils" +import image from "@ohos.multimedia.image" +import { LogUtil } from '../../imageknife/utils/LogUtil' +import { GPUImageToonFilter } from '@ohos/gpu_transform' + + +export class ToonFilterTransform implements BaseTransform { + private threshold: number = 0.2; + private quantizationLevels: number = 10.0; + + constructor(threshold?: number, quantizationLevels?: number) { + if (threshold) { + this.threshold = threshold; + } + if (quantizationLevels) { + this.quantizationLevels = quantizationLevels; + } + } + + getName() { + return "ToonFilterTransform threshold:" + this.threshold + ";quantizationLevels:" + this.quantizationLevels; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + LogUtil.log(Constants.PROJECT_TAG + ";ToonFilterTransform buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";ToonFilterTransform buf is empty", null); + } + return; + } + if (!request.gpuEnabled) { + LogUtil.error(Constants.PROJECT_TAG + ";the ToonFilterTransform supported only in GPU mode"); + if (func) { + func(Constants.PROJECT_TAG + ";the ToonFilterTransform supported only in GPU mode", null); + } + return; + } + var that = this; + var imageSource = image.createImageSource(buf as any); + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + imageSource.createPixelMap(options) + .then((data) => { + that.toon(data, targetWidth, targetHeight, func); + }) + .catch((e) => { + LogUtil.log(Constants.PROJECT_TAG + ";error:" + e); + func(e, null); + }) + }) + } + + private async toon(bitmap: image.PixelMap, targetWidth: number, targetHeight: number, func: AsyncTransform) { + 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); + if (func) { + func("success", bitmap); + } + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/VignetteFilterTransform.ets b/imageknife/src/main/ets/components/imageknife/transform/VignetteFilterTransform.ets new file mode 100644 index 0000000..4f34dbc --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/VignetteFilterTransform.ets @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BaseTransform } from "../transform/BaseTransform" +import { AsyncTransform } from "../transform/AsyncTransform" +import { Constants } from "../constants/Constants" +import { RequestOption } from "../../imageknife/RequestOption" +import { TransformUtils } from "../transform/TransformUtils" +import image from "@ohos.multimedia.image" +import { LogUtil } from '../../imageknife/utils/LogUtil' +import { GPUImageVignetterFilter } from '@ohos/gpu_transform' + + +export class VignetteFilterTransform implements BaseTransform { + private centerPoint: Array = [0.5, 0.5]; + private vignetteColor: Array = [0.0, 0.0, 0.0]; + private vignetteSpace: Array = [0.3, 0.75]; + + constructor(centerPoint: Array, vignetteColor: Array, vignetteSpace: Array) { + if (centerPoint.length === 2) { + this.centerPoint = centerPoint; + } + if (vignetteColor.length === 3) { + this.vignetteColor = vignetteColor; + } + if (vignetteSpace.length === 2) { + this.vignetteSpace = vignetteSpace; + } + } + + getName() { + return "VignetteFilterTransform centerPoint:" + this.centerPoint + ";vignetteColor:" + this.vignetteColor + ";vignetteSpace:" + this.vignetteSpace; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + LogUtil.log(Constants.PROJECT_TAG + ";VignetteFilterTransform buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";VignetteFilterTransform buf is empty", null); + } + return; + } + if (!request.gpuEnabled) { + LogUtil.error(Constants.PROJECT_TAG + ";the VignetteFilterTransform supported only in GPU mode"); + if (func) { + func(Constants.PROJECT_TAG + ";the VignetteFilterTransform supported only in GPU mode", null); + } + return; + } + var that = this; + var imageSource = image.createImageSource(buf as any); + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + imageSource.createPixelMap(options) + .then((data) => { + that.vignette(data, targetWidth, targetHeight, func); + }) + .catch((e) => { + LogUtil.log(Constants.PROJECT_TAG + ";error:" + e); + func(e, null); + }) + }) + } + + private async vignette(bitmap: image.PixelMap, targetWidth: number, targetHeight: number, func: AsyncTransform) { + let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber()); + await bitmap.readPixelsToBuffer(bufferData); + let filter = new GPUImageVignetterFilter(); + filter.setImageData(bufferData, targetWidth, targetHeight); + filter.setVignetteCenter(this.centerPoint); + filter.setVignetteColor(this.vignetteColor); + filter.setVignetteStart(this.vignetteSpace[0]); + filter.setVignetteEnd(this.vignetteSpace[1]); + let buf = await filter.getPixelMapBuf(0, 0, targetWidth, targetHeight) + bitmap.writeBufferToPixels(buf); + if (func) { + func("success", bitmap); + } + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/utils/CalculatePixelUtils.ets b/imageknife/src/main/ets/components/imageknife/utils/CalculatePixelUtils.ets index c13e4f6..e9d5300 100644 --- a/imageknife/src/main/ets/components/imageknife/utils/CalculatePixelUtils.ets +++ b/imageknife/src/main/ets/components/imageknife/utils/CalculatePixelUtils.ets @@ -12,9 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {PixelEntry} from "../entry/PixelEntry" -import {AsyncTransform} from "../transform/AsyncTransform" -import {ColorUtils} from "./ColorUtils" +import { PixelEntry } from "../entry/PixelEntry" +import { AsyncTransform } from "../transform/AsyncTransform" +import { ColorUtils } from "./ColorUtils" +import { GPUImageSketchFilter } from '@ohos/gpu_transform' export namespace CalculatePixelUtils { export async function sketch(p: any, func: AsyncTransform) { @@ -96,7 +97,7 @@ export namespace CalculatePixelUtils { } var gaussGray = (psrc: Array, horz: number, vert: number, - width: number, height: number): number=> { + width: number, height: number): number => { let dst, src, n_p, n_m, d_p, d_m, bd_p, bd_m, val_p, val_m, initial_p, initial_m: Array; let i, j, t, k, row, col, terms, std_dev, sp_p_idx, sp_m_idx, vp_idx, vm_idx: number; let row_stride = width; @@ -204,8 +205,8 @@ export namespace CalculatePixelUtils { } var findConstants = (n_p: Array, n_m: Array, d_p: Array, - d_m: Array, bd_p: Array - , bd_m: Array, std_dev: number)=> { + d_m: Array, bd_p: Array + , bd_m: Array, std_dev: number) => { let div = Math.sqrt(2 * 3.141593) * std_dev; let x0 = -1.783 / std_dev; let x1 = -1.723 / std_dev; @@ -263,16 +264,16 @@ export namespace CalculatePixelUtils { } var transferGaussPixels = (src1: Array, src2: Array, - dest: Array, bytes: number, width: number)=> { + dest: Array, bytes: number, width: number) => { let i, j, k, b, sum: number; let bend = bytes * width; i = j = k = 0; for (b = 0; b < bend; b++) { sum = src1[i++] + src2[j++]; if (sum > 255) - sum = 255; + sum = 255; else if (sum < 0) - sum = 0; + sum = 0; dest[k++] = sum; } } @@ -296,4 +297,30 @@ export namespace CalculatePixelUtils { } return array; } + + export async function sketchGpu(p: any, func: AsyncTransform) { + let imageInfo = await p.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + if (!size) { + func(new Error("sketch The image size does not exist."), null) + return; + } + + let w = size.width; + let h = size.height; + + let bufferData = new ArrayBuffer(p.getPixelBytesNumber()); + await p.readPixelsToBuffer(bufferData); + let filter = new GPUImageSketchFilter(); + filter.setImageData(bufferData, w, h); + filter.getPixelMapBuf(0, 0, w, h).then((buf) => { + p.writeBufferToPixels(buf); + if (func) { + func("success", p); + } + }) + } } \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/utils/FastBlur.ets b/imageknife/src/main/ets/components/imageknife/utils/FastBlur.ets index 396a871..568b5cc 100644 --- a/imageknife/src/main/ets/components/imageknife/utils/FastBlur.ets +++ b/imageknife/src/main/ets/components/imageknife/utils/FastBlur.ets @@ -17,7 +17,7 @@ import {CalculatePixelUtils} from "./CalculatePixelUtils" import {PixelEntry} from "../entry/PixelEntry" import {AsyncTransform} from "../transform/AsyncTransform" import {ColorUtils} from "./ColorUtils" - +import { GPUImageBlurFilter } from '@ohos/gpu_transform' export namespace fastBlur { @@ -290,4 +290,37 @@ export namespace fastBlur { func("success", bitmap); } } + export async function blurGPU(bitmap: any, radius: number, canReuseInBitmap: boolean, func: AsyncTransform) { + if (radius < 1) { + func("error,radius must be greater than 1 ", null); + return; + } + + let imageInfo = await bitmap.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + + if (!size) { + func(new Error("fastBlur The image size does not exist."), null) + return; + } + + let w = size.width; + let h = size.height; + + let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber()); + await bitmap.readPixelsToBuffer(bufferData); + let filter = new GPUImageBlurFilter(); + filter.setImageData(bufferData, w, h); + filter.setBlurRadius(radius); + filter.setBlurOffset([1.0, 1.0]) + filter.getPixelMapBuf(0, 0, w, h).then((buf) => { + bitmap.writeBufferToPixels(buf); + if (func) { + func("success", bitmap); + } + }) + } } diff --git a/imageknife/src/main/ets/components/imageknife/utils/PixelUtils.ets b/imageknife/src/main/ets/components/imageknife/utils/PixelUtils.ets index 03fd923..2895fc0 100644 --- a/imageknife/src/main/ets/components/imageknife/utils/PixelUtils.ets +++ b/imageknife/src/main/ets/components/imageknife/utils/PixelUtils.ets @@ -17,6 +17,7 @@ import {CalculatePixelUtils} from "./CalculatePixelUtils" import {PixelEntry} from "../entry/PixelEntry" import {AsyncTransform} from "../transform/AsyncTransform" import {ColorUtils} from "./ColorUtils" +import {GPUImagePixelationFilter} from '@ohos/gpu_transform' export namespace pixelUtils { @@ -129,4 +130,30 @@ export namespace pixelUtils { func("success", bitmap); } } + export async function pixelGPU(bitmap: any, pixel: number, func: AsyncTransform) { + + let imageInfo = await bitmap.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + if (!size) { + func(new Error("GrayscaleTransformation The image size does not exist."), null) + return; + } + let w = size.width; + let h = size.height; + + let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber()); + await bitmap.readPixelsToBuffer(bufferData); + let filter = new GPUImagePixelationFilter(); + filter.setImageData(bufferData, w, h); + filter.setPixel(pixel) + filter.getPixelMapBuf(0, 0, w, h).then((buf) => { + bitmap.writeBufferToPixels(buf); + if (func) { + func("success", bitmap); + } + }) + } } \ No newline at end of file diff --git a/package.json b/package.json index fbc532c..d7dc956 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,19 @@ { - "license": "ISC", - "devDependencies": {}, - "name": "imageknife", - "ohos": { - "org": "huawei", - "directoryLevel": "project", - "buildTool": "hvigor" + "license":"ISC", + "devDependencies":{}, + "name":"imageknife", + "ohos":{ + "org":"huawei", + "directoryLevel":"project", + "buildTool":"hvigor" }, - "description": "example description", - "repository": {}, - "version": "1.0.0", - "dependencies": { - "@ohos/hypium": "1.0.3", - "@ohos/hvigor-ohos-plugin": "1.3.1", - "hypium": "^1.0.0", - "@ohos/hvigor": "1.3.1" + "description":"example description", + "repository":{}, + "version":"1.0.0", + "dependencies":{ + "@ohos/hypium":"1.0.3", + "@ohos/hvigor-ohos-plugin":"1.3.1", + "hypium":"^1.0.0", + "@ohos/hvigor":"1.3.1" } -} +} \ No newline at end of file