diff --git a/README-en.md b/README-en.md index 41bb5c6..e7967bf 100644 --- a/README-en.md +++ b/README-en.md @@ -43,7 +43,7 @@ allprojects { // module build.gradle dependencies { - implementation 'com.github.ChillingVan:android-openGL-canvas:v1.5.3.0' + implementation 'com.github.ChillingVan:android-openGL-canvas:v1.5.4.0' } ``` @@ -130,6 +130,7 @@ It has sync and async modes. * The CanvasGL doesn't support drawPath or drawText. You can try IAndroidCanvasHelper but this just uses Android canvas to generate a Bitmap. So heed the performance. ## Latest Update +* Add GaussianBlurFilter & Fix FilterGroup ViewPort Issue (1.5.4, Thanks to [@iffly](https://github.com/feiyin0719)) * Add record screen demo * Add clearTextureCache to help clear cache faster than WeakHashMap. (1.5.2) * Can operate bitmap when using AndroidCanvasHelper (1.5.2) diff --git a/README.md b/README.md index 1c882fe..48302c7 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ allprojects { // module build.gradle dependencies { - implementation 'com.github.ChillingVan:android-openGL-canvas:v1.5.3.0' + implementation 'com.github.ChillingVan:android-openGL-canvas:v1.5.4.0' } ``` @@ -140,6 +140,7 @@ public class MyGLView extends GLView { ## 最近更新 +* 添加高斯模糊 & 修复FilterGroup ViewPort 宽高问题(1.5.4 感谢[@iffly](https://github.com/feiyin0719))) * 添加录屏demo * 添加clearTextureCache,比弱引用更快释放内存 (1.5.2) * AndroidCanvasHelper能直接操作Canvas里的bitmap了 (1.5.2) diff --git a/canvasgl/build.gradle b/canvasgl/build.gradle index 20b1c11..c87cfe7 100644 --- a/canvasgl/build.gradle +++ b/canvasgl/build.gradle @@ -22,7 +22,7 @@ apply plugin: 'com.android.library' apply plugin: 'maven-publish' def NAMESPACE="com.github.ChillingVan" group = NAMESPACE -def VERSION_NAME="1.5.3.0" +def VERSION_NAME="1.5.4.0" android { namespace = NAMESPACE @@ -30,7 +30,7 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 32 - versionCode 105030 + versionCode 105040 versionName VERSION_NAME testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } diff --git a/canvasgl/src/main/java/com/chillingvan/canvasgl/ICanvasGL.java b/canvasgl/src/main/java/com/chillingvan/canvasgl/ICanvasGL.java index 7f50154..6941938 100644 --- a/canvasgl/src/main/java/com/chillingvan/canvasgl/ICanvasGL.java +++ b/canvasgl/src/main/java/com/chillingvan/canvasgl/ICanvasGL.java @@ -26,9 +26,6 @@ import android.graphics.SurfaceTexture; import android.opengl.GLES20; import android.opengl.Matrix; -import androidx.annotation.IntRange; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import com.chillingvan.canvasgl.glcanvas.BasicTexture; import com.chillingvan.canvasgl.glcanvas.BitmapTexture; @@ -40,6 +37,10 @@ import com.chillingvan.canvasgl.matrix.IBitmapMatrix; import com.chillingvan.canvasgl.textureFilter.TextureFilter; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + /** * Created by Matthew on 2016/9/26. */ @@ -197,7 +198,7 @@ public float[] obtainResultMatrix(int viewportW, int viewportH, float x, float y final float absTransY = Math.abs(transform[TRANSLATE_Y]); // Make sure realViewportH - viewportY includes viewportH int realViewportW = (int) (viewPortRatio * viewportW + 2*absTransX); int realViewportH = (int) (viewPortRatio * viewportH + 2*absTransY); - realViewportW = Math.max(realViewportW, maxViewPortInt); + realViewportW = Math.min(realViewportW, maxViewPortInt); realViewportH = Math.min(realViewportH, maxViewPortInt); int viewportX = (int) (drawW / 2 - realViewportW / 2 + transform[TRANSLATE_X]); int viewportY = (int) (-drawH / 2 - transform[TRANSLATE_Y] - realViewportH / 2 + viewportH); diff --git a/canvasgl/src/main/java/com/chillingvan/canvasgl/glcanvas/GLES20Canvas.java b/canvasgl/src/main/java/com/chillingvan/canvasgl/glcanvas/GLES20Canvas.java index 4f6e27c..7cc5db4 100644 --- a/canvasgl/src/main/java/com/chillingvan/canvasgl/glcanvas/GLES20Canvas.java +++ b/canvasgl/src/main/java/com/chillingvan/canvasgl/glcanvas/GLES20Canvas.java @@ -555,11 +555,11 @@ private void draw(ShaderParameter[] params, int type, int count, float x, float private void setMatrix(ShaderParameter[] params, float x, float y, float width, float height, ICustomMVPMatrix customMVPMatrix) { if (customMVPMatrix != null) { - GLES20.glUniformMatrix4fv(params[INDEX_MATRIX].handle, 1, false, customMVPMatrix.getMVPMatrix(mScreenWidth, mScreenHeight, x, y, width, height), 0); + GLES20.glUniformMatrix4fv(params[INDEX_MATRIX].handle, 1, false, customMVPMatrix.getMVPMatrix(mWidth, mHeight, x, y, width, height), 0); checkError(); return; } - GLES20.glViewport(0, 0, mScreenWidth, mScreenHeight); + GLES20.glViewport(0, 0, mWidth, mHeight); Matrix.translateM(mTempMatrix, 0, mMatrices, mCurrentMatrixIndex, x, y, 0f); Matrix.scaleM(mTempMatrix, 0, width, height, 1f); Matrix.multiplyMM(mTempMatrix, MATRIX_SIZE, mProjectionMatrix, 0, mTempMatrix, 0); diff --git a/canvasgl/src/main/java/com/chillingvan/canvasgl/textureFilter/GaussianBlurFilter.java b/canvasgl/src/main/java/com/chillingvan/canvasgl/textureFilter/GaussianBlurFilter.java new file mode 100644 index 0000000..603e983 --- /dev/null +++ b/canvasgl/src/main/java/com/chillingvan/canvasgl/textureFilter/GaussianBlurFilter.java @@ -0,0 +1,142 @@ +package com.chillingvan.canvasgl.textureFilter; + +import android.opengl.GLES20; + +import com.chillingvan.canvasgl.ICanvasGL; +import com.chillingvan.canvasgl.OpenGLUtil; +import com.chillingvan.canvasgl.glcanvas.BasicTexture; + +import java.util.ArrayList; + +public class GaussianBlurFilter extends FilterGroup { + public static class GaussianFilter extends BasicTextureFilter { + private float blurSize; + private int dir; + public static final String TEXEL_WIDTH_OFFSET = "texelWidthOffset"; + public static final String TEXEL_HEIGHT_OFFSET = "texelHeightOffset"; + public static final String BLUR_COORDINATES = "blurCoordinates"; + + + public GaussianFilter(int dir, float blurSize) { + this.dir = dir; + this.blurSize = blurSize; + + + } + + public GaussianFilter(int dir) { + this(dir, 1f); + } + + public static final String VERTEX_SHADER = + "precision mediump float;\n" + + "uniform mat4 " + MATRIX_UNIFORM + ";\n" + + "uniform mat4 " + TEXTURE_MATRIX_UNIFORM + ";\n" + + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n" + + "const int GAUSSIAN_SAMPLES = 9;\n" + + "\n" + + "uniform float " + TEXEL_WIDTH_OFFSET + ";\n" + + "uniform float " + TEXEL_HEIGHT_OFFSET + ";\n" + + "\n" + + "varying vec2 " + VARYING_TEXTURE_COORD + ";\n" + + "varying vec2 " + BLUR_COORDINATES + "[GAUSSIAN_SAMPLES];\n" + + "\n" + + "void main()\n" + + "{\n" + + " vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n" + + " gl_Position = " + MATRIX_UNIFORM + "* pos;\n" + + VARYING_TEXTURE_COORD + " = (" + TEXTURE_MATRIX_UNIFORM + " * pos).xy;\n" + + " \n" + + " int multiplier = 0;\n" + + " vec2 blurStep;\n" + + " vec2 singleStepOffset = vec2(" + TEXEL_HEIGHT_OFFSET + ", " + TEXEL_WIDTH_OFFSET + ");\n" + + " \n" + + " for (int i = 0; i < GAUSSIAN_SAMPLES; i++)\n" + + " {\n" + + " multiplier = (i - ((GAUSSIAN_SAMPLES - 1) / 2));\n" + + " // Blur in x (horizontal)\n" + + " blurStep = float(multiplier) * singleStepOffset;\n" + + " " + BLUR_COORDINATES + "[i] = " + VARYING_TEXTURE_COORD + ".xy + blurStep;\n" + + " }\n" + + "}\n"; + + public static final String FRAGMENT_SHADER = + "uniform sampler2D " + TEXTURE_SAMPLER_UNIFORM + ";\n" + + "\n" + + "const lowp int GAUSSIAN_SAMPLES = 9;\n" + + "\n" + + "varying highp vec2 " + VARYING_TEXTURE_COORD + ";\n" + + "varying highp vec2 " + BLUR_COORDINATES + "[GAUSSIAN_SAMPLES];\n" + + "\n" + + "void main()\n" + + "{\n" + + " lowp vec3 sum = vec3(0.0);\n" + + " lowp vec4 fragColor=texture2D(" + TEXTURE_SAMPLER_UNIFORM + "," + VARYING_TEXTURE_COORD + ");\n" + + " \n" + + " sum += texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", " + BLUR_COORDINATES + "[0]).rgb * 0.05;\n" + + " sum += texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", " + BLUR_COORDINATES + "[1]).rgb * 0.09;\n" + + " sum += texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", " + BLUR_COORDINATES + "[2]).rgb * 0.12;\n" + + " sum += texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", " + BLUR_COORDINATES + "[3]).rgb * 0.15;\n" + + " sum += texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", " + BLUR_COORDINATES + "[4]).rgb * 0.18;\n" + + " sum += texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", " + BLUR_COORDINATES + "[5]).rgb * 0.15;\n" + + " sum += texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", " + BLUR_COORDINATES + "[6]).rgb * 0.12;\n" + + " sum += texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", " + BLUR_COORDINATES + "[7]).rgb * 0.09;\n" + + " sum += texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", " + BLUR_COORDINATES + "[8]).rgb * 0.05;\n" + + "\n" + + " gl_FragColor = vec4(sum,fragColor.a);\n" + + "}"; + + + @Override + public String getVertexShader() { + return VERTEX_SHADER; + } + + @Override + public String getFragmentShader() { + return FRAGMENT_SHADER; + } + + + @Override + public void onPreDraw(int program, BasicTexture texture, ICanvasGL canvas) { + super.onPreDraw(program, texture, canvas); + int widthOffsetLocation = GLES20.glGetUniformLocation(program, TEXEL_WIDTH_OFFSET); + int heightOffsetLocation = GLES20.glGetUniformLocation(program, TEXEL_HEIGHT_OFFSET); + if (dir == 0) { + OpenGLUtil.setFloat(widthOffsetLocation, blurSize / texture.getWidth()); + OpenGLUtil.setFloat(heightOffsetLocation, 0); + + } else { + OpenGLUtil.setFloat(widthOffsetLocation, 0); + OpenGLUtil.setFloat(heightOffsetLocation, blurSize / texture.getHeight()); + } + + + } + + public void setBlurSize(float blurSize) { + this.blurSize = blurSize; + } + + + } + + + public GaussianBlurFilter(float blurSize) { + super(new ArrayList()); + mFilters.add(new GaussianFilter(0, blurSize)); + mFilters.add(new GaussianFilter(1, blurSize)); + updateMergedFilters(); + } + + public void setBlurSize(float blurSize) { + for (TextureFilter textureFilter : mFilters) { + if (textureFilter instanceof GaussianFilter) { + GaussianFilter gaussianFilter = (GaussianFilter) textureFilter; + gaussianFilter.setBlurSize(blurSize); + } + + } + } +} diff --git a/canvasglsample/src/main/java/com/chillingvan/canvasglsample/filter/FilterActivity.java b/canvasglsample/src/main/java/com/chillingvan/canvasglsample/filter/FilterActivity.java index c70eb79..d77d97f 100644 --- a/canvasglsample/src/main/java/com/chillingvan/canvasglsample/filter/FilterActivity.java +++ b/canvasglsample/src/main/java/com/chillingvan/canvasglsample/filter/FilterActivity.java @@ -36,6 +36,7 @@ import com.chillingvan.canvasgl.textureFilter.DirectionalSobelEdgeDetectionFilter; import com.chillingvan.canvasgl.textureFilter.FilterGroup; import com.chillingvan.canvasgl.textureFilter.GammaFilter; +import com.chillingvan.canvasgl.textureFilter.GaussianBlurFilter; import com.chillingvan.canvasgl.textureFilter.HueFilter; import com.chillingvan.canvasgl.textureFilter.LightenBlendFilter; import com.chillingvan.canvasgl.textureFilter.LookupFilter; @@ -62,6 +63,7 @@ import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter; import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilterGroup; import jp.co.cyberagent.android.gpuimage.filter.GPUImageGammaFilter; +import jp.co.cyberagent.android.gpuimage.filter.GPUImageGaussianBlurFilter; import jp.co.cyberagent.android.gpuimage.filter.GPUImageHueFilter; import jp.co.cyberagent.android.gpuimage.filter.GPUImageLightenBlendFilter; import jp.co.cyberagent.android.gpuimage.filter.GPUImageLookupFilter; @@ -103,7 +105,6 @@ protected void onCreate(Bundle savedInstanceState) { initSeekBar(); - adapter = new CommonBaseAdapter<>(renderEntityList); listView.setAdapter(adapter); refreshDataList(); @@ -145,10 +146,12 @@ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { } @Override - public void onStartTrackingTouch(SeekBar seekBar) { } + public void onStartTrackingTouch(SeekBar seekBar) { + } @Override - public void onStopTrackingTouch(SeekBar seekBar) { } + public void onStopTrackingTouch(SeekBar seekBar) { + } }); } @@ -162,7 +165,7 @@ private List createRenderEntities() { int width = firstBitmap.getWidth(); int height = firstBitmap.getHeight(); - CropFilter cropFilter = new CropFilter(CropFilter.calc(width/2, width), 0, 1, CropFilter.calc(height/2, height)); + CropFilter cropFilter = new CropFilter(CropFilter.calc(width / 2, width), 0, 1, CropFilter.calc(height / 2, height)); renderEntityList.add(new CaseEntity(cropFilter, new GPUImageFilter(), firstBitmap)); Bitmap lookupAmatorka = BitmapFactory.decodeResource(getResources(), R.drawable.lookup_amatorka); @@ -233,6 +236,10 @@ private List createRenderEntities() { GPUImageColorMatrixFilter gpuImageColorMatrixFilter = new GPUImageColorMatrixFilter(0.3f, matrix4); renderEntityList.add(new CaseEntity(colorMatrixFilter, gpuImageColorMatrixFilter, firstBitmap)); + GaussianBlurFilter gaussianBlurFilter = new GaussianBlurFilter(5f); + GPUImageGaussianBlurFilter gpuImageGaussianBlurFilter = new GPUImageGaussianBlurFilter(5f); + renderEntityList.add(new CaseEntity(gaussianBlurFilter, gpuImageGaussianBlurFilter, firstBitmap)); + return renderEntityList; } @@ -287,7 +294,7 @@ private void startPicActivity(int requestPickImage) { } public static class Range { - float min ; + float min; float max; public Range(float min, float max) { @@ -296,7 +303,7 @@ public Range(float min, float max) { } public float value(float percentage) { - return min + (max - min) * (percentage /100); + return min + (max - min) * (percentage / 100); } } }