From 75f08250a285f17896ebe87c58819af617dd1c31 Mon Sep 17 00:00:00 2001 From: tyBrave Date: Thu, 2 Feb 2023 16:59:13 +0800 Subject: [PATCH] add gpu transform module Signed-off-by: tyBrave --- build-profile.json5 | 6 +- entry/src/main/ets/pages/cropImagePage2.ets | 3 +- .../main/ets/pages/transformPixelMapPage.ets | 311 +++++-- gpu_transform/.gitignore | 4 + gpu_transform/build-profile.json5 | 19 + gpu_transform/hvigorfile.ts | 2 + gpu_transform/index.ets | 33 + gpu_transform/package.json | 14 + gpu_transform/src/main/cpp/CMakeLists.txt | 33 + .../src/main/cpp/common/native_common.h | 57 ++ .../src/main/cpp/constant/constant_shape.h | 448 ++++++++++ gpu_transform/src/main/cpp/napi/napi_init.cpp | 99 +++ .../src/main/cpp/render/EGLRender.cpp | 822 ++++++++++++++++++ gpu_transform/src/main/cpp/render/EGLRender.h | 120 +++ .../src/main/cpp/types/libentry/index.d.ts | 16 + .../src/main/cpp/types/libentry/package.json | 4 + gpu_transform/src/main/cpp/util/DebugLog.h | 32 + gpu_transform/src/main/cpp/util/GLUtils.cpp | 109 +++ gpu_transform/src/main/cpp/util/GLUtils.h | 37 + gpu_transform/src/main/cpp/util/NapiUtil.cpp | 49 ++ gpu_transform/src/main/cpp/util/NapiUtil.h | 35 + gpu_transform/src/main/cpp/util/NativeImage.h | 162 ++++ .../GPUImage3x3TextureSamplingFilter.ts | 51 ++ .../main/ets/gpu/filter/GPUImageBlurFilter.ts | 81 ++ .../gpu/filter/GPUImageBrightnessFilter.ts | 44 + .../gpu/filter/GPUImageColorInvertFilter.ts | 37 + .../gpu/filter/GPUImageColorMatrixFilter.ts | 57 ++ .../ets/gpu/filter/GPUImageContrastFilter.ts | 46 + .../src/main/ets/gpu/filter/GPUImageFilter.ts | 331 +++++++ .../ets/gpu/filter/GPUImageFilterGroup.ts | 38 + .../ets/gpu/filter/GPUImageGrayscaleFilter.ts | 36 + .../ets/gpu/filter/GPUImageKuwaharaFilter.ts | 45 + .../gpu/filter/GPUImagePixelationFilter.ts | 43 + .../ets/gpu/filter/GPUImageSepiaToneFilter.ts | 40 + .../ets/gpu/filter/GPUImageSketchFilter.ts | 37 + .../ets/gpu/filter/GPUImageSwirlFilter.ts | 55 ++ .../main/ets/gpu/filter/GPUImageToonFilter.ts | 49 ++ .../ets/gpu/filter/GPUImageVignetterFilter.ts | 58 ++ .../src/main/ets/gpu/gl/GPUFilterType.ts | 31 + .../src/main/ets/gpu/gl/NativeEglRender.ts | 101 +++ .../src/main/ets/gpu/interface/Runnable.ts | 18 + gpu_transform/src/main/module.json5 | 10 + .../main/resources/base/element/string.json | 8 + .../main/resources/en_US/element/string.json | 8 + .../main/resources/zh_CN/element/string.json | 8 + imageknife/index.ets | 3 + imageknife/package.json | 7 +- .../components/imageknife/RequestOption.ets | 164 ++-- .../transform/BlurTransformation.ets | 6 +- .../BrightnessFilterTransformation.ets | 16 +- .../ContrastFilterTransformation.ets | 16 +- .../transform/GrayscaleTransformation.ets | 13 + .../transform/InvertFilterTransformation.ets | 13 + .../transform/KuwaharaFilterTransform.ts | 101 +++ .../PixelationFilterTransformation.ets | 8 +- .../transform/SepiaFilterTransformation.ets | 16 +- .../transform/SketchFilterTransformation.ets | 6 +- .../transform/SwirlFilterTransformation.ets | 44 +- .../transform/ToonFilterTransform.ts | 108 +++ .../transform/VignetteFilterTransform.ts | 114 +++ .../imageknife/utils/CalculatePixelUtils.ets | 45 +- .../components/imageknife/utils/FastBlur.ets | 35 +- .../imageknife/utils/PixelUtils.ets | 27 + 63 files changed, 4207 insertions(+), 182 deletions(-) create mode 100644 gpu_transform/.gitignore create mode 100644 gpu_transform/build-profile.json5 create mode 100644 gpu_transform/hvigorfile.ts create mode 100644 gpu_transform/index.ets create mode 100644 gpu_transform/package.json create mode 100644 gpu_transform/src/main/cpp/CMakeLists.txt create mode 100644 gpu_transform/src/main/cpp/common/native_common.h create mode 100644 gpu_transform/src/main/cpp/constant/constant_shape.h create mode 100644 gpu_transform/src/main/cpp/napi/napi_init.cpp create mode 100644 gpu_transform/src/main/cpp/render/EGLRender.cpp create mode 100644 gpu_transform/src/main/cpp/render/EGLRender.h create mode 100644 gpu_transform/src/main/cpp/types/libentry/index.d.ts create mode 100644 gpu_transform/src/main/cpp/types/libentry/package.json create mode 100644 gpu_transform/src/main/cpp/util/DebugLog.h create mode 100644 gpu_transform/src/main/cpp/util/GLUtils.cpp create mode 100644 gpu_transform/src/main/cpp/util/GLUtils.h create mode 100644 gpu_transform/src/main/cpp/util/NapiUtil.cpp create mode 100644 gpu_transform/src/main/cpp/util/NapiUtil.h create mode 100644 gpu_transform/src/main/cpp/util/NativeImage.h create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImage3x3TextureSamplingFilter.ts create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImageBlurFilter.ts create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImageBrightnessFilter.ts create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImageColorInvertFilter.ts create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImageColorMatrixFilter.ts create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImageContrastFilter.ts create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImageFilter.ts create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImageFilterGroup.ts create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImageGrayscaleFilter.ts create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImageKuwaharaFilter.ts create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImagePixelationFilter.ts create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImageSepiaToneFilter.ts create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImageSketchFilter.ts create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImageSwirlFilter.ts create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImageToonFilter.ts create mode 100644 gpu_transform/src/main/ets/gpu/filter/GPUImageVignetterFilter.ts create mode 100644 gpu_transform/src/main/ets/gpu/gl/GPUFilterType.ts create mode 100644 gpu_transform/src/main/ets/gpu/gl/NativeEglRender.ts create mode 100644 gpu_transform/src/main/ets/gpu/interface/Runnable.ts create mode 100644 gpu_transform/src/main/module.json5 create mode 100644 gpu_transform/src/main/resources/base/element/string.json create mode 100644 gpu_transform/src/main/resources/en_US/element/string.json create mode 100644 gpu_transform/src/main/resources/zh_CN/element/string.json create mode 100644 imageknife/src/main/ets/components/imageknife/transform/KuwaharaFilterTransform.ts create mode 100644 imageknife/src/main/ets/components/imageknife/transform/ToonFilterTransform.ts create mode 100644 imageknife/src/main/ets/components/imageknife/transform/VignetteFilterTransform.ts 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..c31527e 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) + .openEfficient() .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) + .openEfficient() .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) + .openEfficient() .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) + .openEfficient() .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) + .openEfficient() .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) + .openEfficient() .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) + .openEfficient() .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) + .openEfficient() .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) + .openEfficient() .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); } + + /** + *kuwahar + */ + 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) + .openEfficient() + .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) + .openEfficient() + .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) + .openEfficient() + .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/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..9590234 --- /dev/null +++ b/gpu_transform/package.json @@ -0,0 +1,14 @@ +{ + "license": "ISC", + "types": "", + "devDependencies": {}, + "name": "@ohos/gpu_transform", + "description": "a npm package which contains arkUI2.0 page", + "ohos": { + "org": "" + }, + "main": "index.ets", + "type": "module", + "version": "1.0.0", + "dependencies": {} +} diff --git a/gpu_transform/src/main/cpp/CMakeLists.txt b/gpu_transform/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000..fcd5572 --- /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 + napi/napi_init.cpp + render/EGLRender.cpp + util/GLUtils.cpp + 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..4d21ea1 --- /dev/null +++ b/gpu_transform/src/main/cpp/common/native_common.h @@ -0,0 +1,57 @@ +/* + * 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, +// please include "napi/native_api.h". + +#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..a7dcc1e --- /dev/null +++ b/gpu_transform/src/main/cpp/constant/constant_shape.h @@ -0,0 +1,448 @@ +/* + * 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, +// please include "napi/native_api.h". + +#ifndef GPU_ImageETS_constant_shape_H +#define GPU_ImageETS_constant_shape_H + +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" + "int 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..da6b550 --- /dev/null +++ b/gpu_transform/src/main/cpp/napi/napi_init.cpp @@ -0,0 +1,99 @@ +/* + * 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, +// please include "napi/native_api.h". + + +#include +#include +#include +#include "DebugLog.h" +#include "native_common.h" +#include "EGLRender.h" + +static napi_value Add(napi_env env, napi_callback_info info) +{ + size_t requireArgc = 2; + size_t argc = 2; + napi_value args[2] = {nullptr}; + + napi_get_cb_info(env, info, &argc, args , nullptr, nullptr); + + napi_valuetype valuetype0; + napi_typeof(env, args[0], &valuetype0); + + napi_valuetype valuetype1; + napi_typeof(env, args[1], &valuetype1); + + double value0; + napi_get_value_double(env, args[0], &value0); + + double value1; + napi_get_value_double(env, args[1], &value1); + + napi_value sum; + napi_create_double(env, value0 + value1, &sum); + + return sum; + +} + +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..95e2570 --- /dev/null +++ b/gpu_transform/src/main/cpp/render/EGLRender.cpp @@ -0,0 +1,822 @@ +/* + * 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, +// please include "napi/native_api.h". + +#include "EGLRender.h" + +#include "native_common.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "DebugLog.h" +#include "constant/constant_shape.h" +#include "GLUtils.h" +#include "../util/NapiUtil.h" + + +#define PARAM_TYPE_SHADER_INDEX 300 + +#define VERTEX_POS_LOC 0 +#define TEXTURE_POS_LOC 1 + +const int32_t STR_DEFAULT_SIZE = 1024; +EGLRender *EGLRender::sInstance = nullptr; + +//顶点坐标 +const 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 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 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 GLushort indices[] = { 0, 1, 2, 1, 3, 2 }; + + +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 * 4); + + 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 * 4; + 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) { + //7 . 渲染 + 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], 1024, locationContent); + + char* location = (char*)locationContent.c_str(); + + std::string content; + NapiUtil::JsValueToString(env, args[1], 1024, 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 = 2; + }else if (strcmp(key, "glUniform3fv") == 0) { + uniformType = 3; + }else if (strcmp(key, "glUniform4fv") == 0) { + uniformType = 4; + }else if (strcmp(key, "glUniform1fv") == 0) { + uniformType = 1; + }else if (strcmp(key, "glUniform2f") == 0) { + uniformType = 21; + } + + 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], 1024, 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, 3); + + 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], 1024, 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, 4); + 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], 1024, 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, 0); + 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], 1024, 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, 1); + 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], 1024, 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, 10); + 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::Init() { + if (CreateGlEnv() == 0) + { + m_IsGLContextReady = true; + } + if (!m_IsGLContextReady) { + return; + } + + 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); + + + m_ProgramObj = GLUtils::CreateProgram(vShaderStr, fShaderStr0, m_VertexShader, + m_FragmentShader); + if (!m_ProgramObj) { + GLUtils::CheckGLError("Create Program"); + return; + } + + // Generate VBO Ids and load the VBOs width data + glGenBuffers(3, m_VboIds); + glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[0]); + glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices), vVertices, GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[1]); + glBufferData(GL_ARRAY_BUFFER, sizeof(vFboTexCoors), vTexCoors, GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_VboIds[2]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); + + // Generate VAO Ids + glGenVertexArrays(1, m_VaoIds); + + // FBO off screen rendering VAO + glBindVertexArray(m_VaoIds[0]); + + glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[0]); + glEnableVertexAttribArray(VERTEX_POS_LOC); + glVertexAttribPointer(VERTEX_POS_LOC, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (const void *)0); + glBindBuffer(GL_ARRAY_BUFFER,GL_NONE); + + glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[1]); + glEnableVertexAttribArray(TEXTURE_POS_LOC); + glVertexAttribPointer(TEXTURE_POS_LOC, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (const void *)0); + glBindBuffer(GL_ARRAY_BUFFER,GL_NONE); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_VboIds[2]); + 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 + }; + // EGL context attributes + const EGLint ctxAttr[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + // surface attributes + // the surface size is set to the input frame size + 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) { + switch(eglGetError()) + { + case EGL_BAD_ALLOC: + LOGI("gl-->::CreateGlesEnv Not enough resources available"); + break; + case EGL_BAD_CONFIG: + LOGI("gl-->::CreateGlesEnv provided EGLConfig is invalid"); + break; + case EGL_BAD_PARAMETER: + LOGI("gl-->::CreateGlesEnv provided EGL_WIDTH and EGL_HEIGHT is invalid"); + break; + case EGL_BAD_MATCH: + LOGI("gl-->::CreateGlesEnv Check window and EGLConfig attributes"); + 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) + { + LOGI("gl-->::CreateGlesEnv EGL_BAD_CONFIG"); + resultCode = -1; + break; + } + } + + //绑定上下文 + if(!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglCtx)) + { + resultCode = -1; + break; + } + LOGI("gl-->::CreateGlesEnv initialize success"); + } while (false); + + if(resultCode != 0) + { + LOGI("gl-->::CreateGlesEnv fail"); + } + + 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 *4); + + 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 4: + { + fShader[0] = fShaderStr3; + break; + } + case 7: + { + fShader[0] = swirlFShaderStr; + break; + } + case 0: + { + fShader[0] = brightFShaderStr; + break; + } + case 1: + { + fShader[0] = contrastFShaderStr; + break; + } + case 2: + { + fShader[0] = invertFShaderStr; + break; + } + case 3: + { + fShader[0] = pixelFShaderStr; + break; + } + case 5: + { + fShader[0] = colorMatrixFShaderStr; + break; + } + case 6: + { + fShader[0] = sketchShaderStr; + vShader[0] = v3x3ShaderStr; + break; + } + case 8: + { + fShader[0] = toonFShaderStr; + vShader[0] = v3x3ShaderStr; + break; + } + case 9: + { + fShader[0] = vignetteFShaderStr; + break; + } + case 10: + { + fShader[0] = grayScaleShaderStr; + break; + } + case 12: + { + fShader[0] = blurShaderStr; + 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* strLocation, float value, int unType) { + GLint location = glGetUniformLocation(m_ProgramObj, strLocation); + switch(unType) + { + case 0: + glUniform1i(location, (int)value); + break; + case 1: + glUniform1f(location, value); + break; + } +} + +void EGLRender::GlUniformArray(char* strLocation, float* value, int unType) { + GLint location = glGetUniformLocation(m_ProgramObj, strLocation); + switch(unType) + { + case 10: + GLfloat vec2[2]; + vec2[0] = value[0] * m_RenderImage.width; + vec2[1] = value[1] * m_RenderImage.height; + glUniform2fv(location, 1, vec2); + break; + case 21: + glUniform2f(location, value[0], value[1]); + break; + case 1: + glUniform1fv(location, 1, value); + break; + case 2: + glUniform2fv(location, 1, value); + break; + case 3: + glUniform3fv(location, 1, value); + break; + case 4: + glUniform4fv(location, 1, value); + break; + } +} + +void EGLRender::GlUniformMatrix(char* strLocation, float* value, int unType) { + GLint location = glGetUniformLocation(m_ProgramObj, strLocation); + switch(unType) + { + case 3: + glUniformMatrix3fv(location, 1, false,value); + break; + case 4: + glUniformMatrix4fv(location, 1, false, value); + break; + } +} + +void EGLRender::UnInit() { + if (m_ProgramObj) + { + glDeleteProgram(m_ProgramObj); + m_ProgramObj = GL_NONE; + } + + if(m_ImageTextureId) + { + glDeleteTextures(1, &m_ImageTextureId); + m_ImageTextureId = GL_NONE; + } + + if (m_FboTextureId) + { + glDeleteTextures(1, &m_FboTextureId); + m_FboTextureId = GL_NONE; + } + + if (m_VboIds[0]) + { + glDeleteBuffers(3, m_VboIds); + m_VboIds[0] = GL_NONE; + m_VboIds[1] = GL_NONE; + m_VboIds[2] = GL_NONE; + } + + if (m_VaoIds[0]) + { + glDeleteVertexArrays(1, m_VaoIds); + m_VaoIds[0] = 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..07ae4d5 --- /dev/null +++ b/gpu_transform/src/main/cpp/render/EGLRender.h @@ -0,0 +1,120 @@ +/* + * 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, +// please include "napi/native_api.h". + +#ifndef GPU_ImageETS_EGLRender_H +#define GPU_ImageETS_EGLRender_H +#include +#include +#include +#include +#include +#include "NativeImage.h" + +#define EGL_FEATURE_NUM 7 + +class EGLRender { + + public: + EGLRender(); + ~EGLRender(); + + static EGLRender* GetInstance() { + if(sInstance == nullptr) { + sInstance = new EGLRender(); + } + return sInstance; + } + + static void DestroyRender() { + if(sInstance) { + delete sInstance; + sInstance = nullptr; + } + } + 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(); + + 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..f7314d0 --- /dev/null +++ b/gpu_transform/src/main/cpp/types/libentry/index.d.ts @@ -0,0 +1,16 @@ +/* + * 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 add: (a: number, b: number) => number; \ 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..5ab3f74 --- /dev/null +++ b/gpu_transform/src/main/cpp/util/DebugLog.h @@ -0,0 +1,32 @@ +/* + * 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, +// please include "napi/native_api.h". + +#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..8e0c2b3 --- /dev/null +++ b/gpu_transform/src/main/cpp/util/GLUtils.cpp @@ -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/21. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, +// please include "napi/native_api.h". + +#include "GLUtils.h" +#include "DebugLog.h" +#include +#include + +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..3dccdfa --- /dev/null +++ b/gpu_transform/src/main/cpp/util/GLUtils.h @@ -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. + */ + +// +// Created on 2022/12/21. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, +// please include "napi/native_api.h". + +#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..30df64b --- /dev/null +++ b/gpu_transform/src/main/cpp/util/NapiUtil.cpp @@ -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. + */ + +// +// Created on 2022/12/21. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, +// please include "napi/native_api.h". + +#include "NapiUtil.h" +#include "DebugLog.h" +#include +#include +#include +#include +#include + +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..34c02fd --- /dev/null +++ b/gpu_transform/src/main/cpp/util/NapiUtil.h @@ -0,0 +1,35 @@ +/* + * 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, +// please include "napi/native_api.h". + +#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..f15b367 --- /dev/null +++ b/gpu_transform/src/main/cpp/util/NativeImage.h @@ -0,0 +1,162 @@ +/* + * 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, +// please include "napi/native_api.h". + +#ifndef GPU_ImageETS_NativeImage_H +#define GPU_ImageETS_NativeImage_H + +#include +#include +#include +#include +#include +#include +#include "DebugLog.h" +#include + +#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[3]; + + NativeImage() + { + width = 0; + height = 0; + format = 0; + ppPlane[0] = nullptr; + ppPlane[1] = nullptr; + ppPlane[2] = nullptr; + } +}; + +class NativeImageUtil +{ + public: + static void AllocNativeImage(NativeImage *pImage) + { + if (pImage ->height ==0 || pImage ->width == 0) return; + switch(pImage -> format) + { + case IMAGE_FORMAT_RGBA: + { + pImage->ppPlane[0] = static_cast(malloc(pImage->width * pImage ->height * 4)); + } + break; + case IMAGE_FORMAT_YUYV: + { + pImage->ppPlane[0] = static_cast(malloc(pImage->width * pImage ->height * 2)); + } + break; + case IMAGE_FORMAT_NV12: + case IMAGE_FORMAT_NV21: + { + pImage->ppPlane[0] = static_cast(malloc(pImage->width * pImage ->height * 1.5)); + pImage->ppPlane[1] = pImage->ppPlane[0] + pImage->width * pImage->height; + } + break; + case IMAGE_FORMAT_I420: + { + pImage->ppPlane[0] = static_cast(malloc(pImage->width * pImage ->height * 1.5)); + pImage->ppPlane[1] = pImage->ppPlane[0] + pImage->width * pImage->height; + pImage->ppPlane[2] = pImage->ppPlane[1] + pImage->width * (pImage->height >> 2); + } + break; + case IMAGE_FORMAT_GRAY: + { + pImage->ppPlane[0] = static_cast(malloc(pImage->width * pImage ->height)); + } + break; + case IMAGE_FORMAT_I444: + { + pImage->ppPlane[0] = static_cast(malloc(pImage->width * pImage ->height * 3)); + } + break; + case IMAGE_FORMAT_P010: + { + pImage->ppPlane[0] = static_cast(malloc(pImage->width * pImage ->height * 3)); + pImage->ppPlane[1] = pImage->ppPlane[0] + pImage->width * pImage->height * 2; + } + break; + default: + break; + } + } + + static void FreeNativeImage(NativeImage *pImage) + { + if (pImage == nullptr || pImage->ppPlane[0] == nullptr) return; + free(pImage->ppPlane[0]); + pImage->ppPlane[0] = nullptr; + pImage->ppPlane[1] = nullptr; + pImage->ppPlane[2] = nullptr; + } + + static bool CreateArrayBuffer(napi_env env, void* src, size_t srcLen, napi_value *res) + { + if (src == nullptr || srcLen == 0) + { + 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 * 4; + int oneLineLength = width * 4; + uint8_t* tmp = (uint8_t*)malloc(totalLength); + memcpy(tmp, *buf, totalLength); + memset(*buf, 0, 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..8719877 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImage3x3TextureSamplingFilter.ts @@ -0,0 +1,51 @@ +/* + * 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..8ca86c1 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageBlurFilter.ts @@ -0,0 +1,81 @@ +/* + * 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..0e41c2a --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageBrightnessFilter.ts @@ -0,0 +1,44 @@ +/* + * 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..d7251e7 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageColorInvertFilter.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 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..fb520ce --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageColorMatrixFilter.ts @@ -0,0 +1,57 @@ +/* + * 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..a14fc3e --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageContrastFilter.ts @@ -0,0 +1,46 @@ +/* + * 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..23adf93 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageFilter.ts @@ -0,0 +1,331 @@ +/* + * 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 image from '@ohos.multimedia.image'; +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(); + let filterType :number; + switch(filter){ + case GPUFilterType.BRIGHT: + filterType = 0; + break; + case GPUFilterType.CONTRAST: + filterType = 1; + break; + case GPUFilterType.INVERT: + filterType = 2; + break; + case GPUFilterType.PIXELATION: + filterType = 3; + break; + case GPUFilterType.KUWAHARA: + filterType = 4; + break; + case GPUFilterType.SEPIA: + filterType = 5; + break; + case GPUFilterType.SKETCH: + filterType = 6; + break; + case GPUFilterType.SWIRL: + filterType = 7; + break; + case GPUFilterType.TOON: + filterType = 8; + break; + case GPUFilterType.VIGNETTE: + filterType = 9; + break; + case GPUFilterType.GRAYSCALE: + filterType = 10; + break; + case GPUFilterType.X3TEXTURE: + filterType = 11; + break; + case GPUFilterType.BLUR: + filterType = 12; + break; + case GPUFilterType.COLOR_M: + filterType = 100; + break; + } + if (!this.render.native_glIsInit()) { + throw new Error("the egl surface not init"); + } + this.render.native_EglRenderSetIntParams(300,filterType); + } + + 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.ifNeedInit(); + 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(); + } + }) + } + + + ifNeedInit(){ + 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.ifNeedInit(); + that.render.native_setInteger(location,value); + } + } + this.addRunOnDraw(able); + } + + protected setFloat(location:string,value:number){ + let that = this; + let able:Runnable = { + run(){ + that.ifNeedInit(); + 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.ifNeedInit(); + 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.ifNeedInit(); + 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.ifNeedInit(); + 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.ifNeedInit(); + 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.ifNeedInit(); + 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.ifNeedInit(); + 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.ifNeedInit(); + 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..1c10cbe --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageFilterGroup.ts @@ -0,0 +1,38 @@ +/* + * 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..6d87b4f --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageGrayscaleFilter.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 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..c25a181 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageKuwaharaFilter.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 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..36f4098 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImagePixelationFilter.ts @@ -0,0 +1,43 @@ +/* + * 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..9380270 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageSepiaToneFilter.ts @@ -0,0 +1,40 @@ +/* + * 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..d83ddb5 --- /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..f05ac8f --- /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..d0fd942 --- /dev/null +++ b/gpu_transform/src/main/ets/gpu/filter/GPUImageVignetterFilter.ts @@ -0,0 +1,58 @@ +/* + * 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..fd6ee5b --- /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, + KUWAHARA, + PIXELATION, + SEPIA, + SKETCH, + SWIRL, + TOON, + VIGNETTE, + COLOR_M, + GRAYSCALE, + X3TEXTURE, + BLUR +} \ 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..30afbcd --- /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..39f4bc1 --- /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..ac6225a 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变换绘制 + isOpenGpuTransform: 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变换绘制 + openEfficient() { + this.isOpenGpuTransform = 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..4523ba6 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.isOpenGpuTransform) { + 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..d3a72d4 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.isOpenGpuTransform) { + 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..a7c2ddb 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.isOpenGpuTransform) { + 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..621feeb 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.isOpenGpuTransform) { + 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..40fe63c 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.isOpenGpuTransform) { + 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.ts b/imageknife/src/main/ets/components/imageknife/transform/KuwaharaFilterTransform.ts new file mode 100644 index 0000000..7e8fb80 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/KuwaharaFilterTransform.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 { 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 { fastBlur } from "../utils/FastBlur" +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.isOpenGpuTransform) { + LogUtil.error(Constants.PROJECT_TAG + ";the KuwaharaFilterTransform supported only in GPU mode"); + 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); + }) + }) + } + + async kuwahara(bitmap: any, 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..e8812fd 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.isOpenGpuTransform) { + 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..56eee5b 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.isOpenGpuTransform) { + 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..af55d3f 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.isOpenGpuTransform) { + 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..a01ac47 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: any, 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.isOpenGpuTransform) { + 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.ts b/imageknife/src/main/ets/components/imageknife/transform/ToonFilterTransform.ts new file mode 100644 index 0000000..eb83f50 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/ToonFilterTransform.ts @@ -0,0 +1,108 @@ +/* + * 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 { fastBlur } from "../utils/FastBlur" +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.isOpenGpuTransform) { + LogUtil.error(Constants.PROJECT_TAG + ";the ToonFilterTransform supported only in GPU mode"); + 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); + }) + }) + } + + async toon(bitmap: any, 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.ts b/imageknife/src/main/ets/components/imageknife/transform/VignetteFilterTransform.ts new file mode 100644 index 0000000..176a7cd --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/VignetteFilterTransform.ts @@ -0,0 +1,114 @@ +/* + * 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 { fastBlur } from "../utils/FastBlur" +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.isOpenGpuTransform) { + LogUtil.error(Constants.PROJECT_TAG + ";the VignetteFilterTransform supported only in GPU mode"); + 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); + }) + }) + } + + async vignette(bitmap: any, 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