Feature Live Filters using Shaders (#527)
* added shader effects * added setting shaders * intermediate commit * added shader implementation * refatored code * implemented initial effects * modified few filters * modified all effects * implemented shader while taking picture and video * updated all effects * modified all filters range to 0.0f-1.0f * added control to filter * added shader effects * added setting shaders * intermediate commit * added shader implementation * refatored code * implemented initial effects * modified few filters * modified all effects * implemented shader while taking picture and video * updated all effects * modified all filters range to 0.0f-1.0f * added control to filter * modified shaders and removed the glsurfaceview dependency * changed folder structure * changed allignmen and filters * added annotations * code refacor * changed effect name to filters * changed filter implementation for image and video * fixed for travis buildpull/541/head
parent
ab48a33249
commit
facd26f11d
@ -0,0 +1,96 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Attempts to auto-fix the preview based on histogram equalization. |
||||||
|
*/ |
||||||
|
public class AutoFixFilter extends Filter { |
||||||
|
|
||||||
|
private float scale = 1.0f; |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public AutoFixFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
public float getScale() { |
||||||
|
return scale; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param scale Float, between 0 and 1. Zero means no adjustment, while 1 |
||||||
|
* indicates the maximum amount of adjustment. |
||||||
|
*/ |
||||||
|
public void setScale(float scale) { |
||||||
|
if (scale < 0.0f) |
||||||
|
scale = 0.0f; |
||||||
|
else if (scale > 1.0f) |
||||||
|
scale = 1.0f; |
||||||
|
|
||||||
|
this.scale = scale; |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES tex_sampler_0;\n" |
||||||
|
+ "uniform samplerExternalOES tex_sampler_1;\n" |
||||||
|
+ "uniform samplerExternalOES tex_sampler_2;\n" |
||||||
|
+ " float scale;\n" + " float shift_scale;\n" |
||||||
|
+ " float hist_offset;\n" + " float hist_scale;\n" |
||||||
|
+ " float density_offset;\n" + " float density_scale;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" + "void main() {\n" |
||||||
|
+ " shift_scale = " |
||||||
|
+ (1.0f / 256f) |
||||||
|
+ ";\n" |
||||||
|
+ " hist_offset = " |
||||||
|
+ (0.5f / 766f) |
||||||
|
+ ";\n" |
||||||
|
+ " hist_scale = " |
||||||
|
+ (765f / 766f) |
||||||
|
+ ";\n" |
||||||
|
+ " density_offset = " |
||||||
|
+ (0.5f / 1024f) |
||||||
|
+ ";\n" |
||||||
|
+ " density_scale = " |
||||||
|
+ (1023f / 1024f) |
||||||
|
+ ";\n" |
||||||
|
+ " scale = " |
||||||
|
+ scale |
||||||
|
+ ";\n" |
||||||
|
+ " const vec3 weights = vec3(0.33333, 0.33333, 0.33333);\n" |
||||||
|
+ " vec4 color = texture2D(tex_sampler_0, vTextureCoord);\n" |
||||||
|
+ " float energy = dot(color.rgb, weights);\n" |
||||||
|
+ " float mask_value = energy - 0.5;\n" |
||||||
|
+ " float alpha;\n" |
||||||
|
+ " if (mask_value > 0.0) {\n" |
||||||
|
+ " alpha = (pow(2.0 * mask_value, 1.5) - 1.0) * scale + 1.0;\n" |
||||||
|
+ " } else { \n" |
||||||
|
+ " alpha = (pow(2.0 * mask_value, 2.0) - 1.0) * scale + 1.0;\n" |
||||||
|
+ " }\n" |
||||||
|
+ " float index = energy * hist_scale + hist_offset;\n" |
||||||
|
+ " vec4 temp = texture2D(tex_sampler_1, vec2(index, 0.5));\n" |
||||||
|
+ " float value = temp.g + temp.r * shift_scale;\n" |
||||||
|
+ " index = value * density_scale + density_offset;\n" |
||||||
|
+ " temp = texture2D(tex_sampler_2, vec2(index, 0.5));\n" |
||||||
|
+ " value = temp.g + temp.r * shift_scale;\n" |
||||||
|
+ " float dst_energy = energy * alpha + value * (1.0 - alpha);\n" |
||||||
|
+ " float max_energy = energy / max(color.r, max(color.g, color.b));\n" |
||||||
|
+ " if (dst_energy > max_energy) {\n" |
||||||
|
+ " dst_energy = max_energy;\n" |
||||||
|
+ " }\n" |
||||||
|
+ " if (energy == 0.0) {\n" |
||||||
|
+ " gl_FragColor = color;\n" |
||||||
|
+ " } else {\n" |
||||||
|
+ " gl_FragColor = vec4(color.rgb * dst_energy / energy, color.a);\n" |
||||||
|
+ " }\n" + "}\n"; |
||||||
|
|
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Converts the preview into black and white colors |
||||||
|
*/ |
||||||
|
public class BlackAndWhiteFilter extends Filter { |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize effect |
||||||
|
*/ |
||||||
|
public BlackAndWhiteFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" + "void main() {\n" |
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " float colorR = (color.r + color.g + color.b) / 3.0;\n" |
||||||
|
+ " float colorG = (color.r + color.g + color.b) / 3.0;\n" |
||||||
|
+ " float colorB = (color.r + color.g + color.b) / 3.0;\n" |
||||||
|
+ " gl_FragColor = vec4(colorR, colorG, colorB, color.a);\n" |
||||||
|
+ "}\n"; |
||||||
|
|
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,56 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Adjusts the brightness of the preview. |
||||||
|
*/ |
||||||
|
public class BrightnessFilter extends Filter { |
||||||
|
private float brightnessValue = 2.0f; |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public BrightnessFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* setBrightnessValue |
||||||
|
* |
||||||
|
* @param brightnessvalue Range should be between 0.0- 1.0 with 0.0 being normal. |
||||||
|
*/ |
||||||
|
public void setBrightnessValue(float brightnessvalue) { |
||||||
|
if (brightnessvalue < 0.0f) |
||||||
|
brightnessvalue = 0.0f; |
||||||
|
else if (brightnessvalue > 1.0f) |
||||||
|
brightnessvalue = 1.0f; |
||||||
|
|
||||||
|
//since the shader excepts a range of 1.0 - 2.0
|
||||||
|
// will add the 1.0 to every value
|
||||||
|
this.brightnessValue = 1.0f + brightnessvalue; |
||||||
|
} |
||||||
|
|
||||||
|
public float getBrightnessValue() { |
||||||
|
//since the shader excepts a range of 1.0 - 2.0
|
||||||
|
//to keep it between 0.0f - 1.0f range, will subtract the 1.0 to every value
|
||||||
|
return brightnessValue - 1.0f; |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ "float brightness ;\n" + "varying vec2 vTextureCoord;\n" |
||||||
|
+ "void main() {\n" + " brightness =" + brightnessValue |
||||||
|
+ ";\n" |
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " gl_FragColor = brightness * color;\n" + "}\n"; |
||||||
|
|
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Adjusts the contrast of the preview. |
||||||
|
*/ |
||||||
|
public class ContrastFilter extends Filter { |
||||||
|
private float contrast = 2.0f; |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public ContrastFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* setContrast |
||||||
|
* |
||||||
|
* @param contrast Range should be between 0.0- 1.0 with 0.0 being normal. |
||||||
|
*/ |
||||||
|
public void setContrast(float contrast) { |
||||||
|
if (contrast < 0.0f) |
||||||
|
contrast = 0.0f; |
||||||
|
else if (contrast > 1.0f) |
||||||
|
contrast = 1.0f; |
||||||
|
|
||||||
|
//since the shader excepts a range of 1.0 - 2.0
|
||||||
|
//will add the 1.0 to every value
|
||||||
|
this.contrast = contrast + 1.0f; |
||||||
|
} |
||||||
|
|
||||||
|
public float getContrast() { |
||||||
|
//since the shader excepts a range of 1.0 - 2.0
|
||||||
|
//to keep it between 0.0f - 1.0f range, will subtract the 1.0 to every value
|
||||||
|
return contrast - 1.0f; |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ " float contrast;\n" + "varying vec2 vTextureCoord;\n" |
||||||
|
+ "void main() {\n" + " contrast =" + contrast + ";\n" |
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " color -= 0.5;\n" + " color *= contrast;\n" |
||||||
|
+ " color += 0.5;\n" + " gl_FragColor = color;\n" + "}\n"; |
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Applies a cross process effect on preview, in which the red and green channels |
||||||
|
* are enhanced while the blue channel is restricted. |
||||||
|
*/ |
||||||
|
public class CrossProcessFilter extends Filter { |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public CrossProcessFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" + "void main() {\n" |
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " vec3 ncolor = vec3(0.0, 0.0, 0.0);\n" + " float value;\n" |
||||||
|
+ " if (color.r < 0.5) {\n" + " value = color.r;\n" |
||||||
|
+ " } else {\n" + " value = 1.0 - color.r;\n" + " }\n" |
||||||
|
+ " float red = 4.0 * value * value * value;\n" |
||||||
|
+ " if (color.r < 0.5) {\n" + " ncolor.r = red;\n" |
||||||
|
+ " } else {\n" + " ncolor.r = 1.0 - red;\n" + " }\n" |
||||||
|
+ " if (color.g < 0.5) {\n" + " value = color.g;\n" |
||||||
|
+ " } else {\n" + " value = 1.0 - color.g;\n" + " }\n" |
||||||
|
+ " float green = 2.0 * value * value;\n" |
||||||
|
+ " if (color.g < 0.5) {\n" + " ncolor.g = green;\n" |
||||||
|
+ " } else {\n" + " ncolor.g = 1.0 - green;\n" + " }\n" |
||||||
|
+ " ncolor.b = color.b * 0.5 + 0.25;\n" |
||||||
|
+ " gl_FragColor = vec4(ncolor.rgb, color.a);\n" + "}\n"; |
||||||
|
|
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* This class is to implement any custom effect. |
||||||
|
*/ |
||||||
|
public class CustomFilter extends Filter { |
||||||
|
|
||||||
|
/** |
||||||
|
* Parameterized constructor with vertex and fragment shader as parameter |
||||||
|
* |
||||||
|
* @param vertexShader |
||||||
|
* @param fragmentShader |
||||||
|
*/ |
||||||
|
public CustomFilter(String vertexShader, String fragmentShader) { |
||||||
|
this.mVertexShader = vertexShader; |
||||||
|
this.mFragmentShader = fragmentShader; |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
return mFragmentShader; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,96 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
import java.util.Date; |
||||||
|
import java.util.Random; |
||||||
|
|
||||||
|
/** |
||||||
|
* Applies black and white documentary style effect on preview. |
||||||
|
*/ |
||||||
|
public class DocumentaryFilter extends Filter { |
||||||
|
private Random mRandom; |
||||||
|
|
||||||
|
public DocumentaryFilter() { |
||||||
|
mRandom = new Random(new Date().getTime()); |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
float scale[] = new float[2]; |
||||||
|
if (mPreviewingViewWidth > mPreviewingViewHeight) { |
||||||
|
scale[0] = 1f; |
||||||
|
scale[1] = ((float) mPreviewingViewHeight) / mPreviewingViewWidth; |
||||||
|
} else { |
||||||
|
scale[0] = ((float) mPreviewingViewWidth) / mPreviewingViewHeight; |
||||||
|
scale[1] = 1f; |
||||||
|
} |
||||||
|
float max_dist = ((float) Math.sqrt(scale[0] * scale[0] + scale[1] |
||||||
|
* scale[1])) * 0.5f; |
||||||
|
|
||||||
|
float seed[] = {mRandom.nextFloat(), mRandom.nextFloat()}; |
||||||
|
|
||||||
|
String scaleString[] = new String[2]; |
||||||
|
String seedString[] = new String[2]; |
||||||
|
|
||||||
|
scaleString[0] = "scale[0] = " + scale[0] + ";\n"; |
||||||
|
scaleString[1] = "scale[1] = " + scale[1] + ";\n"; |
||||||
|
|
||||||
|
seedString[0] = "seed[0] = " + seed[0] + ";\n"; |
||||||
|
seedString[1] = "seed[1] = " + seed[1] + ";\n"; |
||||||
|
|
||||||
|
String inv_max_distString = "inv_max_dist = " + 1.0f / max_dist + ";\n"; |
||||||
|
String stepsizeString = "stepsize = " + 1.0f / 255.0f + ";\n"; |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ " vec2 seed;\n" |
||||||
|
+ " float stepsize;\n" |
||||||
|
+ " float inv_max_dist;\n" |
||||||
|
+ " vec2 scale;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" |
||||||
|
+ "float rand(vec2 loc) {\n" |
||||||
|
+ " float theta1 = dot(loc, vec2(0.9898, 0.233));\n" |
||||||
|
+ " float theta2 = dot(loc, vec2(12.0, 78.0));\n" |
||||||
|
+ " float value = cos(theta1) * sin(theta2) + sin(theta1) * cos(theta2);\n" |
||||||
|
+ |
||||||
|
// keep value of part1 in range: (2^-14 to 2^14).
|
||||||
|
" float temp = mod(197.0 * value, 1.0) + value;\n" |
||||||
|
+ " float part1 = mod(220.0 * temp, 1.0) + temp;\n" |
||||||
|
+ " float part2 = value * 0.5453;\n" |
||||||
|
+ " float part3 = cos(theta1 + theta2) * 0.43758;\n" |
||||||
|
+ " return fract(part1 + part2 + part3);\n" |
||||||
|
+ "}\n" |
||||||
|
+ "void main() {\n" |
||||||
|
// Parameters that were created above
|
||||||
|
+ scaleString[0] |
||||||
|
+ scaleString[1] |
||||||
|
+ seedString[0] |
||||||
|
+ seedString[1] |
||||||
|
+ inv_max_distString |
||||||
|
+ stepsizeString |
||||||
|
|
||||||
|
// black white
|
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " float dither = rand(vTextureCoord + seed);\n" |
||||||
|
+ " vec3 xform = clamp(2.0 * color.rgb, 0.0, 1.0);\n" |
||||||
|
+ " vec3 temp = clamp(2.0 * (color.rgb + stepsize), 0.0, 1.0);\n" |
||||||
|
+ " vec3 new_color = clamp(xform + (temp - xform) * (dither - 0.5), 0.0, 1.0);\n" |
||||||
|
+ |
||||||
|
// grayscale
|
||||||
|
" float gray = dot(new_color, vec3(0.299, 0.587, 0.114));\n" |
||||||
|
+ " new_color = vec3(gray, gray, gray);\n" |
||||||
|
+ |
||||||
|
// vignette
|
||||||
|
" vec2 coord = vTextureCoord - vec2(0.5, 0.5);\n" |
||||||
|
+ " float dist = length(coord * scale);\n" |
||||||
|
+ " float lumen = 0.85 / (1.0 + exp((dist * inv_max_dist - 0.83) * 20.0)) + 0.15;\n" |
||||||
|
+ " gl_FragColor = vec4(new_color * lumen, color.a);\n" |
||||||
|
+ "}\n"; |
||||||
|
|
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,85 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import android.graphics.Color; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Representation of preview using only two color tones. |
||||||
|
*/ |
||||||
|
public class DuotoneFilter extends Filter { |
||||||
|
// Default values
|
||||||
|
private int mFirstColor = Color.MAGENTA; |
||||||
|
private int mSecondColor = Color.YELLOW; |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize effect |
||||||
|
*/ |
||||||
|
public DuotoneFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* setDuoToneColors |
||||||
|
* |
||||||
|
* @param firstColor Integer, representing an ARGB color with 8 bits per channel. |
||||||
|
* May be created using Color class. |
||||||
|
* @param secondColor Integer, representing an ARGB color with 8 bits per channel. |
||||||
|
* May be created using Color class. |
||||||
|
*/ |
||||||
|
public void setDuoToneColors(int firstColor, int secondColor) { |
||||||
|
this.mFirstColor = firstColor; |
||||||
|
this.mSecondColor = secondColor; |
||||||
|
} |
||||||
|
|
||||||
|
public int getFirstColor() { |
||||||
|
return mFirstColor; |
||||||
|
} |
||||||
|
|
||||||
|
public int getSecondColor() { |
||||||
|
return mSecondColor; |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
float first[] = {Color.red(mFirstColor) / 255f, |
||||||
|
Color.green(mFirstColor) / 255f, Color.blue(mFirstColor) / 255f}; |
||||||
|
float second[] = {Color.red(mSecondColor) / 255f, |
||||||
|
Color.green(mSecondColor) / 255f, |
||||||
|
Color.blue(mSecondColor) / 255f}; |
||||||
|
|
||||||
|
String firstColorString[] = new String[3]; |
||||||
|
String secondColorString[] = new String[3]; |
||||||
|
|
||||||
|
firstColorString[0] = "first[0] = " + first[0] + ";\n"; |
||||||
|
firstColorString[1] = "first[1] = " + first[1] + ";\n"; |
||||||
|
firstColorString[2] = "first[2] = " + first[2] + ";\n"; |
||||||
|
|
||||||
|
secondColorString[0] = "second[0] = " + second[0] + ";\n"; |
||||||
|
secondColorString[1] = "second[1] = " + second[1] + ";\n"; |
||||||
|
secondColorString[2] = "second[2] = " + second[2] + ";\n"; |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ " vec3 first;\n" |
||||||
|
+ " vec3 second;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" |
||||||
|
+ "void main() {\n" |
||||||
|
// Parameters that were created above
|
||||||
|
+ firstColorString[0] |
||||||
|
+ firstColorString[1] |
||||||
|
+ firstColorString[2] |
||||||
|
+ secondColorString[0] |
||||||
|
+ secondColorString[1] |
||||||
|
+ secondColorString[2] |
||||||
|
|
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " float energy = (color.r + color.g + color.b) * 0.3333;\n" |
||||||
|
+ " vec3 new_color = (1.0 - energy) * first + energy * second;\n" |
||||||
|
+ " gl_FragColor = vec4(new_color.rgb, color.a);\n" + "}\n"; |
||||||
|
|
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,73 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Applies back-light filling to the preview. |
||||||
|
*/ |
||||||
|
public class FillLightFilter extends Filter { |
||||||
|
private float strength = 0.5f; |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public FillLightFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* setStrength |
||||||
|
* |
||||||
|
* @param strength Float, between 0.0 and 1.0 where 0.0 means no change. |
||||||
|
*/ |
||||||
|
public void setStrength(float strength) { |
||||||
|
if (strength < 0.0f) |
||||||
|
strength = 0f; |
||||||
|
else if (strength > 1.0f) |
||||||
|
strength = 1f; |
||||||
|
|
||||||
|
this.strength = strength; |
||||||
|
} |
||||||
|
|
||||||
|
public float getStrength() { |
||||||
|
return strength; |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
float fade_gamma = 0.3f; |
||||||
|
float amt = 1.0f - strength; |
||||||
|
float mult = 1.0f / (amt * 0.7f + 0.3f); |
||||||
|
float faded = fade_gamma + (1.0f - fade_gamma) * mult; |
||||||
|
float igamma = 1.0f / faded; |
||||||
|
|
||||||
|
String multString = "mult = " + mult + ";\n"; |
||||||
|
String igammaString = "igamma = " + igamma + ";\n"; |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ " float mult;\n" |
||||||
|
+ " float igamma;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" |
||||||
|
+ "void main()\n" |
||||||
|
+ "{\n" |
||||||
|
// Parameters that were created above
|
||||||
|
+ multString |
||||||
|
+ igammaString |
||||||
|
|
||||||
|
+ " const vec3 color_weights = vec3(0.25, 0.5, 0.25);\n" |
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " float lightmask = dot(color.rgb, color_weights);\n" |
||||||
|
+ " float backmask = (1.0 - lightmask);\n" |
||||||
|
+ " vec3 ones = vec3(1.0, 1.0, 1.0);\n" |
||||||
|
+ " vec3 diff = pow(mult * color.rgb, igamma * ones) - color.rgb;\n" |
||||||
|
+ " diff = min(diff, 1.0);\n" |
||||||
|
+ " vec3 new_color = min(color.rgb + diff * backmask, 1.0);\n" |
||||||
|
+ " gl_FragColor = vec4(new_color, color.a);\n" + "}\n"; |
||||||
|
|
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,128 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* A Base abstract class that every effect must extend so that there is a common getShader method. |
||||||
|
* <p> |
||||||
|
* This class has a default Vertex Shader implementation which in most cases not required to touch. |
||||||
|
* In Effects like sepia, B/W any many, only pixel color changes which can be managed by only fragment shader. |
||||||
|
* If there is some other effect which requires vertex shader also change, you can override it. |
||||||
|
* <p> |
||||||
|
* If your provide your own vertex and fragment shader, |
||||||
|
* please set the {@link #mPositionVariableName}, {@link #mTextureCoordinateVariableName}, |
||||||
|
* {@link #mMVPMatrixVariableName}, {@link #mTextureMatrixVariableName} |
||||||
|
* according to your shader code. |
||||||
|
* <p> |
||||||
|
* Please note that these shader applies on live preview as well as pictureSnapshot and videoSnapshot, |
||||||
|
* we only support GLES11Ext.GL_TEXTURE_EXTERNAL_OES |
||||||
|
* check EglViewport() |
||||||
|
* <p> |
||||||
|
* The default implementation of this class is NoEffect. |
||||||
|
*/ |
||||||
|
public abstract class Filter { |
||||||
|
|
||||||
|
/** |
||||||
|
* Vertex shader code written in Shader Language (C) and stored as String. |
||||||
|
* This wil be used by GL to apply any effect. |
||||||
|
*/ |
||||||
|
@NonNull |
||||||
|
String mVertexShader = |
||||||
|
"uniform mat4 uMVPMatrix;\n" + |
||||||
|
"uniform mat4 uTexMatrix;\n" + |
||||||
|
"attribute vec4 aPosition;\n" + |
||||||
|
"attribute vec4 aTextureCoord;\n" + |
||||||
|
"varying vec2 vTextureCoord;\n" + |
||||||
|
"void main() {\n" + |
||||||
|
" gl_Position = uMVPMatrix * aPosition;\n" + |
||||||
|
" vTextureCoord = (uTexMatrix * aTextureCoord).xy;\n" + |
||||||
|
"}\n"; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Fragment shader code written in Shader Language (C) and stored as String. |
||||||
|
* This wil be used by GL to apply any effect. |
||||||
|
*/ |
||||||
|
@NonNull |
||||||
|
String mFragmentShader = |
||||||
|
"#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ "void main() {\n" |
||||||
|
+ " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ "}\n"; |
||||||
|
|
||||||
|
/** |
||||||
|
* Width and height of previewing GlSurfaceview. |
||||||
|
* This will be used by a few effects. |
||||||
|
*/ |
||||||
|
int mPreviewingViewWidth = 0; |
||||||
|
int mPreviewingViewHeight = 0; |
||||||
|
|
||||||
|
public void setPreviewingViewSize(int width, int height) { |
||||||
|
mPreviewingViewWidth = width; |
||||||
|
mPreviewingViewHeight = height; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Local variable name which were used in the shader code. |
||||||
|
* These will be used by openGL program to render these vertex and fragment shader |
||||||
|
*/ |
||||||
|
private String mPositionVariableName = "aPosition"; |
||||||
|
private String mTextureCoordinateVariableName = "aTextureCoord"; |
||||||
|
private String mMVPMatrixVariableName = "uMVPMatrix"; |
||||||
|
private String mTextureMatrixVariableName = "uTexMatrix"; |
||||||
|
|
||||||
|
public String getPositionVariableName() { |
||||||
|
return mPositionVariableName; |
||||||
|
} |
||||||
|
|
||||||
|
public void setPositionVariableName(String positionVariableName) { |
||||||
|
this.mPositionVariableName = positionVariableName; |
||||||
|
} |
||||||
|
|
||||||
|
public String getTexttureCoordinateVariableName() { |
||||||
|
return mTextureCoordinateVariableName; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTexttureCoordinateVariableName(String texttureCoordinateVariableName) { |
||||||
|
this.mTextureCoordinateVariableName = texttureCoordinateVariableName; |
||||||
|
} |
||||||
|
|
||||||
|
public String getMVPMatrixVariableName() { |
||||||
|
return mMVPMatrixVariableName; |
||||||
|
} |
||||||
|
|
||||||
|
public void setMVPMatrixVariableName(String mvpMatrixVariableName) { |
||||||
|
this.mMVPMatrixVariableName = mvpMatrixVariableName; |
||||||
|
} |
||||||
|
|
||||||
|
public String getTextureMatrixVariableName() { |
||||||
|
return mTextureMatrixVariableName; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTextureMatrixVariableName(String textureMatrixVariableName) { |
||||||
|
this.mTextureMatrixVariableName = textureMatrixVariableName; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get vertex Shader code |
||||||
|
* |
||||||
|
* @return complete shader code in C |
||||||
|
*/ |
||||||
|
@NonNull |
||||||
|
public String getVertexShader() { |
||||||
|
return mVertexShader; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Get fragment Shader code |
||||||
|
* |
||||||
|
* @return complete shader code in C |
||||||
|
*/ |
||||||
|
@NonNull |
||||||
|
public abstract String getFragmentShader(); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,124 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
public enum Filters { |
||||||
|
NO_FILTER, |
||||||
|
|
||||||
|
AUTO_FIX_FILTER, |
||||||
|
BLACK_AND_WHITE_FILTER, |
||||||
|
BRIGHTNESS_FILTER, |
||||||
|
CONTRAST_FILTER, |
||||||
|
CROSS_PROCESS_FILTER, |
||||||
|
DOCUMENTARY_FILTER, |
||||||
|
DUO_TONE_COLOR_FILTER, |
||||||
|
FILL_LIGHT_FILTER, |
||||||
|
GAMMA_FILTER, |
||||||
|
GRAIN_FILTER, |
||||||
|
GREY_SCALE_FILTER, |
||||||
|
HUE_FILTER, |
||||||
|
INVERT_COLOR_FILTER, |
||||||
|
LAMOISH_FILTER, |
||||||
|
POSTERIZE_FILTER, |
||||||
|
SATURATION_FILTER, |
||||||
|
SEPIA_FILTER, |
||||||
|
SHARPNESS_FILTER, |
||||||
|
TEMPERATURE_FILTER, |
||||||
|
TINT_FILTER, |
||||||
|
VIGNETTE_FILTER; |
||||||
|
|
||||||
|
public Filter newInstance() { |
||||||
|
Filter shaderEffect; |
||||||
|
switch (this) { |
||||||
|
|
||||||
|
case AUTO_FIX_FILTER: |
||||||
|
shaderEffect = new AutoFixFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case BLACK_AND_WHITE_FILTER: |
||||||
|
shaderEffect = new BlackAndWhiteFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case BRIGHTNESS_FILTER: |
||||||
|
shaderEffect = new BrightnessFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case CONTRAST_FILTER: |
||||||
|
shaderEffect = new ContrastFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case CROSS_PROCESS_FILTER: |
||||||
|
shaderEffect = new CrossProcessFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case DOCUMENTARY_FILTER: |
||||||
|
shaderEffect = new DocumentaryFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case DUO_TONE_COLOR_FILTER: |
||||||
|
shaderEffect = new DuotoneFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case FILL_LIGHT_FILTER: |
||||||
|
shaderEffect = new FillLightFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case GAMMA_FILTER: |
||||||
|
shaderEffect = new GammaFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case GRAIN_FILTER: |
||||||
|
shaderEffect = new GrainFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case GREY_SCALE_FILTER: |
||||||
|
shaderEffect = new GreyScaleFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case HUE_FILTER: |
||||||
|
shaderEffect = new HueFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case INVERT_COLOR_FILTER: |
||||||
|
shaderEffect = new InvertColorsFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case LAMOISH_FILTER: |
||||||
|
shaderEffect = new LamoishFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case POSTERIZE_FILTER: |
||||||
|
shaderEffect = new PosterizeFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case SATURATION_FILTER: |
||||||
|
shaderEffect = new SaturationFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case SEPIA_FILTER: |
||||||
|
shaderEffect = new SepiaFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case SHARPNESS_FILTER: |
||||||
|
shaderEffect = new SharpnessFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case TEMPERATURE_FILTER: |
||||||
|
shaderEffect = new TemperatureFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case TINT_FILTER: |
||||||
|
shaderEffect = new TintFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
case VIGNETTE_FILTER: |
||||||
|
shaderEffect = new VignetteFilter(); |
||||||
|
break; |
||||||
|
|
||||||
|
|
||||||
|
case NO_FILTER: |
||||||
|
default: |
||||||
|
shaderEffect = new NoFilter(); |
||||||
|
} |
||||||
|
|
||||||
|
return shaderEffect; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Apply Gamma Effect on preview being played |
||||||
|
*/ |
||||||
|
public class GammaFilter extends Filter { |
||||||
|
private float gammaValue = 2.0f; |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public GammaFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* setGammaValue |
||||||
|
* |
||||||
|
* @param gammaValue Range should be between 0.0 - 1.0 with 0.5 being normal. |
||||||
|
*/ |
||||||
|
public void setGammaValue(float gammaValue) { |
||||||
|
if (gammaValue < 0.0f) |
||||||
|
gammaValue = 0.0f; |
||||||
|
else if (gammaValue > 1.0f) |
||||||
|
gammaValue = 1.0f; |
||||||
|
|
||||||
|
//since the shader excepts a range of 0.0 - 2.0
|
||||||
|
//will multiply the 2.0 to every value
|
||||||
|
this.gammaValue = gammaValue * 2.0f; |
||||||
|
} |
||||||
|
|
||||||
|
public float getGammaValue() { |
||||||
|
//since the shader excepts a range of 0.0 - 2.0
|
||||||
|
//to keep it between 0.0f - 1.0f range, will divide it with 2.0
|
||||||
|
return gammaValue / 2.0f; |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
|
||||||
|
+ "varying vec2 vTextureCoord;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ "float gamma=" + gammaValue + ";\n" |
||||||
|
|
||||||
|
+ "void main() {\n" |
||||||
|
|
||||||
|
+ "vec4 textureColor = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ "gl_FragColor = vec4(pow(textureColor.rgb, vec3(gamma)), textureColor.w);\n" |
||||||
|
|
||||||
|
+ "}\n"; |
||||||
|
|
||||||
|
return shader; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,98 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
import java.util.Date; |
||||||
|
import java.util.Random; |
||||||
|
|
||||||
|
/** |
||||||
|
* Applies film grain effect to preview. |
||||||
|
*/ |
||||||
|
public class GrainFilter extends Filter { |
||||||
|
private float strength = 0.5f; |
||||||
|
private Random mRandom; |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public GrainFilter() { |
||||||
|
mRandom = new Random(new Date().getTime()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* setDistortionStrength |
||||||
|
* |
||||||
|
* @param strength Float, between 0.0f and 1.0. Zero means no distortion, while 1 |
||||||
|
* indicates the maximum amount of adjustment. |
||||||
|
*/ |
||||||
|
public void setDistortionStrength(float strength) { |
||||||
|
if (strength < 0.0f) |
||||||
|
strength = 0.0f; |
||||||
|
else if (strength > 1.0f) |
||||||
|
strength = 1.0f; |
||||||
|
this.strength = strength; |
||||||
|
} |
||||||
|
|
||||||
|
public float getStrength() { |
||||||
|
return strength; |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
float seed[] = {mRandom.nextFloat(), mRandom.nextFloat()}; |
||||||
|
String scaleString = "scale = " + strength + ";\n"; |
||||||
|
String seedString[] = new String[2]; |
||||||
|
seedString[0] = "seed[0] = " + seed[0] + ";\n"; |
||||||
|
seedString[1] = "seed[1] = " + seed[1] + ";\n"; |
||||||
|
String stepX = "stepX = " + 0.5f / mPreviewingViewWidth + ";\n"; |
||||||
|
String stepY = "stepY = " + 0.5f / mPreviewingViewHeight + ";\n"; |
||||||
|
|
||||||
|
// locString[1] = "loc[1] = loc[1]+" + seedString[1] + ";\n";
|
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ " vec2 seed;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" |
||||||
|
+ "uniform samplerExternalOES tex_sampler_0;\n" |
||||||
|
+ "uniform samplerExternalOES tex_sampler_1;\n" |
||||||
|
+ "float scale;\n" |
||||||
|
+ " float stepX;\n" |
||||||
|
+ " float stepY;\n" |
||||||
|
+ "float rand(vec2 loc) {\n" |
||||||
|
+ " float theta1 = dot(loc, vec2(0.9898, 0.233));\n" |
||||||
|
+ " float theta2 = dot(loc, vec2(12.0, 78.0));\n" |
||||||
|
+ " float value = cos(theta1) * sin(theta2) + sin(theta1) * cos(theta2);\n" |
||||||
|
+ |
||||||
|
// keep value of part1 in range: (2^-14 to 2^14).
|
||||||
|
" float temp = mod(197.0 * value, 1.0) + value;\n" |
||||||
|
+ " float part1 = mod(220.0 * temp, 1.0) + temp;\n" |
||||||
|
+ " float part2 = value * 0.5453;\n" |
||||||
|
+ " float part3 = cos(theta1 + theta2) * 0.43758;\n" |
||||||
|
+ " float sum = (part1 + part2 + part3);\n" |
||||||
|
+ " return fract(sum)*scale;\n" |
||||||
|
+ "}\n" |
||||||
|
+ "void main() {\n" |
||||||
|
// Parameters that were created above
|
||||||
|
+ seedString[0] |
||||||
|
+ seedString[1] |
||||||
|
+ scaleString |
||||||
|
+ stepX |
||||||
|
+ stepY |
||||||
|
+ " float noise = texture2D(tex_sampler_1, vTextureCoord + vec2(-stepX, -stepY)).r * 0.224;\n" |
||||||
|
+ " noise += texture2D(tex_sampler_1, vTextureCoord + vec2(-stepX, stepY)).r * 0.224;\n" |
||||||
|
+ " noise += texture2D(tex_sampler_1, vTextureCoord + vec2(stepX, -stepY)).r * 0.224;\n" |
||||||
|
+ " noise += texture2D(tex_sampler_1, vTextureCoord + vec2(stepX, stepY)).r * 0.224;\n" |
||||||
|
+ " noise += 0.4448;\n" |
||||||
|
+ " noise *= scale;\n" |
||||||
|
+ " vec4 color = texture2D(tex_sampler_0, vTextureCoord);\n" |
||||||
|
+ " float energy = 0.33333 * color.r + 0.33333 * color.g + 0.33333 * color.b;\n" |
||||||
|
+ " float mask = (1.0 - sqrt(energy));\n" |
||||||
|
+ " float weight = 1.0 - 1.333 * mask * noise;\n" |
||||||
|
+ " gl_FragColor = vec4(color.rgb * weight, color.a);\n" |
||||||
|
+ " gl_FragColor = gl_FragColor+vec4(rand(vTextureCoord + seed), rand(vTextureCoord + seed),rand(vTextureCoord + seed),1);\n" |
||||||
|
+ "}\n"; |
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Converts preview to GreyScale. |
||||||
|
*/ |
||||||
|
public class GreyScaleFilter extends Filter { |
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public GreyScaleFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" + "void main() {\n" |
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " float y = dot(color, vec4(0.299, 0.587, 0.114, 0));\n" |
||||||
|
+ " gl_FragColor = vec4(y, y, y, color.a);\n" + "}\n"; |
||||||
|
; |
||||||
|
|
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Apply Hue effect on the preview |
||||||
|
*/ |
||||||
|
public class HueFilter extends Filter { |
||||||
|
float hueValue = 0.0f; |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public HueFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Hue value chart - https://cloud.githubusercontent.com/assets/2201511/21810115/b99ac22a-d74a-11e6-9f6c-ef74d15c88c7.jpg"
|
||||||
|
* |
||||||
|
* @param hueDegrees Range of value should be between 0 to 360 degrees as described in the image above |
||||||
|
*/ |
||||||
|
public void setHueDegreeValue(float hueDegrees) { |
||||||
|
// manipulating input value so that we can map it on 360 degree circle
|
||||||
|
hueValue = ((hueDegrees - 45) / 45f + 0.5f) * -1; |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
|
||||||
|
+ "varying vec2 vTextureCoord;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ "float hue=" + hueValue + ";\n" |
||||||
|
|
||||||
|
+ "void main() {\n" |
||||||
|
|
||||||
|
+ "vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);\n" |
||||||
|
+ "vec4 kRGBToI = vec4 (0.595716, -0.274453, -0.321263, 0.0);\n" |
||||||
|
+ "vec4 kRGBToQ = vec4 (0.211456, -0.522591, 0.31135, 0.0);\n" |
||||||
|
|
||||||
|
+ "vec4 kYIQToR = vec4 (1.0, 0.9563, 0.6210, 0.0);\n" |
||||||
|
+ "vec4 kYIQToG = vec4 (1.0, -0.2721, -0.6474, 0.0);\n" |
||||||
|
+ "vec4 kYIQToB = vec4 (1.0, -1.1070, 1.7046, 0.0);\n" |
||||||
|
|
||||||
|
|
||||||
|
+ "vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
|
||||||
|
+ "float YPrime = dot(color, kRGBToYPrime);\n" |
||||||
|
+ "float I = dot(color, kRGBToI);\n" |
||||||
|
+ "float Q = dot(color, kRGBToQ);\n" |
||||||
|
|
||||||
|
+ "float chroma = sqrt (I * I + Q * Q);\n" |
||||||
|
|
||||||
|
+ "Q = chroma * sin (hue);\n" |
||||||
|
|
||||||
|
+ "I = chroma * cos (hue);\n" |
||||||
|
|
||||||
|
+ "vec4 yIQ = vec4 (YPrime, I, Q, 0.0);\n" |
||||||
|
|
||||||
|
+ "color.r = dot (yIQ, kYIQToR);\n" |
||||||
|
+ "color.g = dot (yIQ, kYIQToG);\n" |
||||||
|
+ "color.b = dot (yIQ, kYIQToB);\n" |
||||||
|
+ "gl_FragColor = color;\n" |
||||||
|
|
||||||
|
+ "}\n"; |
||||||
|
|
||||||
|
return shader; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Inverts the preview colors. This can also be known as negative Effect. |
||||||
|
*/ |
||||||
|
public class InvertColorsFilter extends Filter { |
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public InvertColorsFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" + "void main() {\n" |
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " float colorR = (1.0 - color.r) / 1.0;\n" |
||||||
|
+ " float colorG = (1.0 - color.g) / 1.0;\n" |
||||||
|
+ " float colorB = (1.0 - color.b) / 1.0;\n" |
||||||
|
+ " gl_FragColor = vec4(colorR, colorG, colorB, color.a);\n" |
||||||
|
+ "}\n"; |
||||||
|
|
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,143 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
import java.util.Date; |
||||||
|
import java.util.Random; |
||||||
|
|
||||||
|
/** |
||||||
|
* Applies lomo-camera style effect to preview. |
||||||
|
*/ |
||||||
|
public class LamoishFilter extends Filter { |
||||||
|
private Random mRandom; |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public LamoishFilter() { |
||||||
|
mRandom = new Random(new Date().getTime()); |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
float scale[] = new float[2]; |
||||||
|
if (mPreviewingViewWidth > mPreviewingViewHeight) { |
||||||
|
scale[0] = 1f; |
||||||
|
scale[1] = ((float) mPreviewingViewHeight) / mPreviewingViewWidth; |
||||||
|
} else { |
||||||
|
scale[0] = ((float) mPreviewingViewWidth) / mPreviewingViewHeight; |
||||||
|
scale[1] = 1f; |
||||||
|
} |
||||||
|
float max_dist = ((float) Math.sqrt(scale[0] * scale[0] + scale[1] |
||||||
|
* scale[1])) * 0.5f; |
||||||
|
|
||||||
|
float seed[] = {mRandom.nextFloat(), mRandom.nextFloat()}; |
||||||
|
|
||||||
|
String scaleString[] = new String[2]; |
||||||
|
String seedString[] = new String[2]; |
||||||
|
|
||||||
|
scaleString[0] = "scale[0] = " + scale[0] + ";\n"; |
||||||
|
scaleString[1] = "scale[1] = " + scale[1] + ";\n"; |
||||||
|
|
||||||
|
seedString[0] = "seed[0] = " + seed[0] + ";\n"; |
||||||
|
seedString[1] = "seed[1] = " + seed[1] + ";\n"; |
||||||
|
|
||||||
|
String inv_max_distString = "inv_max_dist = " + 1.0f / max_dist + ";\n"; |
||||||
|
String stepsizeString = "stepsize = " + 1.0f / 255.0f + ";\n"; |
||||||
|
String stepsizeXString = "stepsizeX = " + 1.0f / mPreviewingViewWidth + ";\n"; |
||||||
|
String stepsizeYString = "stepsizeY = " + 1.0f / mPreviewingViewHeight + ";\n"; |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ " vec2 seed;\n" |
||||||
|
+ " float stepsizeX;\n" |
||||||
|
+ " float stepsizeY;\n" |
||||||
|
+ " float stepsize;\n" |
||||||
|
+ " vec2 scale;\n" |
||||||
|
+ " float inv_max_dist;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" |
||||||
|
+ "float rand(vec2 loc) {\n" |
||||||
|
+ " float theta1 = dot(loc, vec2(0.9898, 0.233));\n" |
||||||
|
+ " float theta2 = dot(loc, vec2(12.0, 78.0));\n" |
||||||
|
+ " float value = cos(theta1) * sin(theta2) + sin(theta1) * cos(theta2);\n" |
||||||
|
+ |
||||||
|
// keep value of part1 in range: (2^-14 to 2^14).
|
||||||
|
" float temp = mod(197.0 * value, 1.0) + value;\n" |
||||||
|
+ " float part1 = mod(220.0 * temp, 1.0) + temp;\n" |
||||||
|
+ " float part2 = value * 0.5453;\n" |
||||||
|
+ " float part3 = cos(theta1 + theta2) * 0.43758;\n" |
||||||
|
+ " return fract(part1 + part2 + part3);\n" + "}\n" |
||||||
|
+ "void main() {\n" |
||||||
|
// Parameters that were created above
|
||||||
|
+ scaleString[0] |
||||||
|
+ scaleString[1] |
||||||
|
+ seedString[0] |
||||||
|
+ seedString[1] |
||||||
|
+ inv_max_distString |
||||||
|
+ stepsizeString |
||||||
|
+ stepsizeXString |
||||||
|
+ stepsizeYString |
||||||
|
// sharpen
|
||||||
|
+ " vec3 nbr_color = vec3(0.0, 0.0, 0.0);\n" |
||||||
|
+ " vec2 coord;\n" |
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " coord.x = vTextureCoord.x - 0.5 * stepsizeX;\n" |
||||||
|
+ " coord.y = vTextureCoord.y - stepsizeY;\n" |
||||||
|
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n" |
||||||
|
+ " coord.x = vTextureCoord.x - stepsizeX;\n" |
||||||
|
+ " coord.y = vTextureCoord.y + 0.5 * stepsizeY;\n" |
||||||
|
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n" |
||||||
|
+ " coord.x = vTextureCoord.x + stepsizeX;\n" |
||||||
|
+ " coord.y = vTextureCoord.y - 0.5 * stepsizeY;\n" |
||||||
|
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n" |
||||||
|
+ " coord.x = vTextureCoord.x + stepsizeX;\n" |
||||||
|
+ " coord.y = vTextureCoord.y + 0.5 * stepsizeY;\n" |
||||||
|
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n" |
||||||
|
+ " vec3 s_color = vec3(color.rgb + 0.3 * nbr_color);\n" |
||||||
|
+ |
||||||
|
// cross process
|
||||||
|
" vec3 c_color = vec3(0.0, 0.0, 0.0);\n" |
||||||
|
+ " float value;\n" |
||||||
|
+ " if (s_color.r < 0.5) {\n" |
||||||
|
+ " value = s_color.r;\n" |
||||||
|
+ " } else {\n" |
||||||
|
+ " value = 1.0 - s_color.r;\n" |
||||||
|
+ " }\n" |
||||||
|
+ " float red = 4.0 * value * value * value;\n" |
||||||
|
+ " if (s_color.r < 0.5) {\n" |
||||||
|
+ " c_color.r = red;\n" |
||||||
|
+ " } else {\n" |
||||||
|
+ " c_color.r = 1.0 - red;\n" |
||||||
|
+ " }\n" |
||||||
|
+ " if (s_color.g < 0.5) {\n" |
||||||
|
+ " value = s_color.g;\n" |
||||||
|
+ " } else {\n" |
||||||
|
+ " value = 1.0 - s_color.g;\n" |
||||||
|
+ " }\n" |
||||||
|
+ " float green = 2.0 * value * value;\n" |
||||||
|
+ " if (s_color.g < 0.5) {\n" |
||||||
|
+ " c_color.g = green;\n" |
||||||
|
+ " } else {\n" |
||||||
|
+ " c_color.g = 1.0 - green;\n" |
||||||
|
+ " }\n" |
||||||
|
+ " c_color.b = s_color.b * 0.5 + 0.25;\n" |
||||||
|
+ |
||||||
|
// blackwhite
|
||||||
|
" float dither = rand(vTextureCoord + seed);\n" |
||||||
|
+ " vec3 xform = clamp((c_color.rgb - 0.15) * 1.53846, 0.0, 1.0);\n" |
||||||
|
+ " vec3 temp = clamp((color.rgb + stepsize - 0.15) * 1.53846, 0.0, 1.0);\n" |
||||||
|
+ " vec3 bw_color = clamp(xform + (temp - xform) * (dither - 0.5), 0.0, 1.0);\n" |
||||||
|
+ |
||||||
|
// vignette
|
||||||
|
" coord = vTextureCoord - vec2(0.5, 0.5);\n" |
||||||
|
+ " float dist = length(coord * scale);\n" |
||||||
|
+ " float lumen = 0.85 / (1.0 + exp((dist * inv_max_dist - 0.73) * 20.0)) + 0.15;\n" |
||||||
|
+ " gl_FragColor = vec4(bw_color * lumen, color.a);\n" + "}\n"; |
||||||
|
; |
||||||
|
|
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
public class NoFilter extends Filter { |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
return mFragmentShader; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Applies Posterization effect to Preview. |
||||||
|
*/ |
||||||
|
public class PosterizeFilter extends Filter { |
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public PosterizeFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" + "void main() {\n" |
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " vec3 pcolor;\n" |
||||||
|
+ " pcolor.r = (color.r >= 0.5) ? 0.75 : 0.25;\n" |
||||||
|
+ " pcolor.g = (color.g >= 0.5) ? 0.75 : 0.25;\n" |
||||||
|
+ " pcolor.b = (color.b >= 0.5) ? 0.75 : 0.25;\n" |
||||||
|
+ " gl_FragColor = vec4(pcolor, color.a);\n" + "}\n"; |
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,102 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Adjusts color saturation of preview. |
||||||
|
*/ |
||||||
|
public class SaturationFilter extends Filter { |
||||||
|
private float scale = 1.0f; |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public SaturationFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param value Float, between 0.0 and 1. 0 means no change, while 0.0 indicates |
||||||
|
* full desaturated, i.e. grayscale. |
||||||
|
* and 1.0 indicates full saturation |
||||||
|
*/ |
||||||
|
public void setSaturationValue(float value) { |
||||||
|
if (value < 0.0f) |
||||||
|
value = 0.0f; |
||||||
|
else if (value > 1.0f) |
||||||
|
value = 1.0f; |
||||||
|
|
||||||
|
//since the shader excepts a range of -1.0 to 1.0
|
||||||
|
//will multiply it by 2.0f and subtract 1.0 to every value
|
||||||
|
this.scale = (2.0f * value) - 1.0f; |
||||||
|
} |
||||||
|
|
||||||
|
public float getSaturationValue() { |
||||||
|
//since the shader excepts a range of -1.0 to 1.0
|
||||||
|
//will add 1.0 to every value and divide it by 2.0f
|
||||||
|
return (scale + 1.0f) / 2.0f; |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
float shift = 1.0f / 255.0f; |
||||||
|
float weights[] = {2f / 8f, 5f / 8f, 1f / 8f}; |
||||||
|
float exponents[] = new float[3]; |
||||||
|
|
||||||
|
String weightsString[] = new String[3]; |
||||||
|
String exponentsString[] = new String[3]; |
||||||
|
exponentsString[0] = ""; |
||||||
|
exponentsString[1] = ""; |
||||||
|
exponentsString[2] = ""; |
||||||
|
String scaleString = ""; |
||||||
|
|
||||||
|
if (scale > 0.0f) { |
||||||
|
exponents[0] = (0.9f * scale) + 1.0f; |
||||||
|
exponents[1] = (2.1f * scale) + 1.0f; |
||||||
|
exponents[2] = (2.7f * scale) + 1.0f; |
||||||
|
exponentsString[0] = "exponents[0] = " + exponents[0] + ";\n"; |
||||||
|
exponentsString[1] = "exponents[1] = " + exponents[1] + ";\n"; |
||||||
|
exponentsString[2] = "exponents[2] = " + exponents[2] + ";\n"; |
||||||
|
} else |
||||||
|
scaleString = "scale = " + (1.0f + scale) + ";\n"; |
||||||
|
|
||||||
|
weightsString[0] = "weights[0] = " + weights[0] + ";\n"; |
||||||
|
weightsString[1] = "weights[1] = " + weights[1] + ";\n"; |
||||||
|
weightsString[2] = "weights[2] = " + weights[2] + ";\n"; |
||||||
|
String shiftString = "shift = " + shift + ";\n"; |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" + " float scale;\n" |
||||||
|
+ " float shift;\n" + " vec3 weights;\n" + " vec3 exponents;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" + "void main() {\n" |
||||||
|
// Parameters that were created above
|
||||||
|
+ weightsString[0] |
||||||
|
+ weightsString[1] |
||||||
|
+ weightsString[2] |
||||||
|
+ shiftString |
||||||
|
+ scaleString |
||||||
|
+ " vec4 oldcolor = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " float kv = dot(oldcolor.rgb, weights) + shift;\n" |
||||||
|
+ " vec3 new_color = scale * oldcolor.rgb + (1.0 - scale) * kv;\n" |
||||||
|
+ " gl_FragColor= vec4(new_color, oldcolor.a);\n" |
||||||
|
// Parameters that were created above
|
||||||
|
+ weightsString[0] |
||||||
|
+ weightsString[1] |
||||||
|
+ weightsString[2] |
||||||
|
+ exponentsString[0] |
||||||
|
+ exponentsString[1] |
||||||
|
+ exponentsString[2] |
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " float de = dot(color.rgb, weights);\n" |
||||||
|
+ " float inv_de = 1.0 / de;\n" |
||||||
|
+ " vec3 verynew_color = de * pow(color.rgb * inv_de, exponents);\n" |
||||||
|
+ " float max_color = max(max(max(verynew_color.r, verynew_color.g), verynew_color.b), 1.0);\n" |
||||||
|
+ " gl_FragColor = gl_FragColor+vec4(verynew_color / max_color, color.a);\n" |
||||||
|
+ "}\n"; |
||||||
|
|
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Converts preview to Sepia tone. |
||||||
|
*/ |
||||||
|
public class SepiaFilter extends Filter { |
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public SepiaFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
float weights[] = {805.0f / 2048.0f, 715.0f / 2048.0f, |
||||||
|
557.0f / 2048.0f, 1575.0f / 2048.0f, 1405.0f / 2048.0f, |
||||||
|
1097.0f / 2048.0f, 387.0f / 2048.0f, 344.0f / 2048.0f, |
||||||
|
268.0f / 2048.0f}; |
||||||
|
String matrixString[] = new String[9]; |
||||||
|
|
||||||
|
matrixString[0] = " matrix[0][0]=" + weights[0] + ";\n"; |
||||||
|
matrixString[1] = " matrix[0][1]=" + weights[1] + ";\n"; |
||||||
|
matrixString[2] = " matrix[0][2]=" + weights[2] + ";\n"; |
||||||
|
matrixString[3] = " matrix[1][0]=" + weights[3] + ";\n"; |
||||||
|
matrixString[4] = " matrix[1][1]=" + weights[4] + ";\n"; |
||||||
|
matrixString[5] = " matrix[1][2]=" + weights[5] + ";\n"; |
||||||
|
matrixString[6] = " matrix[2][0]=" + weights[6] + ";\n"; |
||||||
|
matrixString[7] = " matrix[2][1]=" + weights[7] + ";\n"; |
||||||
|
matrixString[8] = " matrix[2][2]=" + weights[8] + ";\n"; |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" + " mat3 matrix;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" + "void main() {\n" |
||||||
|
+ matrixString[0] + matrixString[1] + matrixString[2] |
||||||
|
+ matrixString[3] + matrixString[4] + matrixString[5] |
||||||
|
+ matrixString[6] + matrixString[7] + matrixString[8] |
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " vec3 new_color = min(matrix * color.rgb, 1.0);\n" |
||||||
|
+ " gl_FragColor = vec4(new_color.rgb, color.a);\n" + "}\n"; |
||||||
|
|
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,75 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Sharpens the preview. |
||||||
|
*/ |
||||||
|
public class SharpnessFilter extends Filter { |
||||||
|
private float scale = 0.5f; |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public SharpnessFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param value Float, between 0 and 1. 0 means no change. |
||||||
|
*/ |
||||||
|
public void setSharpnessValue(float value) { |
||||||
|
if (value < 0.0f) |
||||||
|
value = 0.0f; |
||||||
|
else if (value > 1.0f) |
||||||
|
value = 1.0f; |
||||||
|
|
||||||
|
this.scale = value; |
||||||
|
} |
||||||
|
|
||||||
|
public float getSharpnessValue() { |
||||||
|
return scale; |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
|
||||||
|
String stepsizeXString = "stepsizeX = " + 1.0f / mPreviewingViewWidth + ";\n"; |
||||||
|
String stepsizeYString = "stepsizeY = " + 1.0f / mPreviewingViewHeight + ";\n"; |
||||||
|
String scaleString = "scale = " + scale + ";\n"; |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ " float scale;\n" |
||||||
|
+ " float stepsizeX;\n" |
||||||
|
+ " float stepsizeY;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" |
||||||
|
+ "void main() {\n" |
||||||
|
// Parameters that were created above
|
||||||
|
+ stepsizeXString |
||||||
|
+ stepsizeYString |
||||||
|
+ scaleString |
||||||
|
+ " vec3 nbr_color = vec3(0.0, 0.0, 0.0);\n" |
||||||
|
+ " vec2 coord;\n" |
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " coord.x = vTextureCoord.x - 0.5 * stepsizeX;\n" |
||||||
|
+ " coord.y = vTextureCoord.y - stepsizeY;\n" |
||||||
|
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n" |
||||||
|
+ " coord.x = vTextureCoord.x - stepsizeX;\n" |
||||||
|
+ " coord.y = vTextureCoord.y + 0.5 * stepsizeY;\n" |
||||||
|
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n" |
||||||
|
+ " coord.x = vTextureCoord.x + stepsizeX;\n" |
||||||
|
+ " coord.y = vTextureCoord.y - 0.5 * stepsizeY;\n" |
||||||
|
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n" |
||||||
|
+ " coord.x = vTextureCoord.x + stepsizeX;\n" |
||||||
|
+ " coord.y = vTextureCoord.y + 0.5 * stepsizeY;\n" |
||||||
|
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n" |
||||||
|
+ " gl_FragColor = vec4(color.rgb - 2.0 * scale * nbr_color, color.a);\n" |
||||||
|
+ "}\n"; |
||||||
|
|
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* Adjusts color temperature of the preview. |
||||||
|
*/ |
||||||
|
public class TemperatureFilter extends Filter { |
||||||
|
private float scale = 0f; |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public TemperatureFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param scale Float, between 0 and 1, with 0 indicating cool, and 1 |
||||||
|
* indicating warm. A value of of 0.5 indicates no change. |
||||||
|
*/ |
||||||
|
public void setTemperatureScale(float scale) { |
||||||
|
if (scale < 0.0f) |
||||||
|
scale = 0.0f; |
||||||
|
else if (scale > 1.0f) |
||||||
|
scale = 1.0f; |
||||||
|
this.scale = scale; |
||||||
|
} |
||||||
|
|
||||||
|
public float getTemperatureScale() { |
||||||
|
return scale; |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
|
||||||
|
String scaleString = "scale = " + (2.0f * scale - 1.0f) + ";\n"; |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ " float scale;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" |
||||||
|
+ "void main() {\n" // Parameters that were created above
|
||||||
|
+ scaleString |
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " vec3 new_color = color.rgb;\n" |
||||||
|
+ " new_color.r = color.r + color.r * ( 1.0 - color.r) * scale;\n" |
||||||
|
+ " new_color.b = color.b - color.b * ( 1.0 - color.b) * scale;\n" |
||||||
|
+ " if (scale > 0.0) { \n" |
||||||
|
+ " new_color.g = color.g + color.g * ( 1.0 - color.g) * scale * 0.25;\n" |
||||||
|
+ " }\n" |
||||||
|
+ " float max_value = max(new_color.r, max(new_color.g, new_color.b));\n" |
||||||
|
+ " if (max_value > 1.0) { \n" |
||||||
|
+ " new_color /= max_value;\n" + " } \n" |
||||||
|
+ " gl_FragColor = vec4(new_color, color.a);\n" + "}\n"; |
||||||
|
|
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,66 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import android.graphics.Color; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Tints the preview with specified color.. |
||||||
|
*/ |
||||||
|
public class TintFilter extends Filter { |
||||||
|
private int mTint = 0xFFFF0000; |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public TintFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
public void setTintColor(int color) { |
||||||
|
this.mTint = color; |
||||||
|
} |
||||||
|
|
||||||
|
public int getTintColor() { |
||||||
|
return mTint; |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
float color_ratio[] = {0.21f, 0.71f, 0.07f}; |
||||||
|
String color_ratioString[] = new String[3]; |
||||||
|
color_ratioString[0] = "color_ratio[0] = " + color_ratio[0] + ";\n"; |
||||||
|
color_ratioString[1] = "color_ratio[1] = " + color_ratio[1] + ";\n"; |
||||||
|
color_ratioString[2] = "color_ratio[2] = " + color_ratio[2] + ";\n"; |
||||||
|
|
||||||
|
float tint_color[] = {Color.red(mTint) / 255f, |
||||||
|
Color.green(mTint) / 255f, Color.blue(mTint) / 255f}; |
||||||
|
|
||||||
|
String tintString[] = new String[3]; |
||||||
|
tintString[0] = "tint[0] = " + tint_color[0] + ";\n"; |
||||||
|
tintString[1] = "tint[1] = " + tint_color[1] + ";\n"; |
||||||
|
tintString[2] = "tint[2] = " + tint_color[2] + ";\n"; |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ " vec3 tint;\n" |
||||||
|
+ " vec3 color_ratio;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" |
||||||
|
+ "void main() {\n" |
||||||
|
// Parameters that were created above
|
||||||
|
+ color_ratioString[0] |
||||||
|
+ color_ratioString[1] |
||||||
|
+ color_ratioString[2] |
||||||
|
+ tintString[0] |
||||||
|
+ tintString[1] |
||||||
|
+ tintString[2] |
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " float avg_color = dot(color_ratio, color.rgb);\n" |
||||||
|
+ " vec3 new_color = min(0.8 * avg_color + 0.2 * tint, 1.0);\n" |
||||||
|
+ " gl_FragColor = vec4(new_color.rgb, color.a);\n" + "}\n"; |
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,99 @@ |
|||||||
|
package com.otaliastudios.cameraview.filters; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Applies lomo-camera style effect to your preview. |
||||||
|
*/ |
||||||
|
public class VignetteFilter extends Filter { |
||||||
|
private float mScale = 0.85f; |
||||||
|
private float mShade = 0.5f; |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize Effect |
||||||
|
*/ |
||||||
|
public VignetteFilter() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* setVignetteEffectScale |
||||||
|
* |
||||||
|
* @param scale Float, between 0.0 and 1. 0 |
||||||
|
*/ |
||||||
|
public void setVignetteEffectScale(float scale) { |
||||||
|
if (scale < 0.0f) |
||||||
|
scale = 0.0f; |
||||||
|
else if (scale > 1.0f) |
||||||
|
scale = 1.0f; |
||||||
|
this.mScale = scale; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* setVignetteEffectShade |
||||||
|
* |
||||||
|
* @param shade Float, between 0.0 and 1. 0 |
||||||
|
*/ |
||||||
|
public void setVignetteEffectShade(float shade) { |
||||||
|
if (shade < 0.0f) |
||||||
|
shade = 0.0f; |
||||||
|
else if (shade > 1.0f) |
||||||
|
shade = 1.0f; |
||||||
|
this.mShade = shade; |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String getFragmentShader() { |
||||||
|
float scale[] = new float[2]; |
||||||
|
if (mPreviewingViewWidth > mPreviewingViewHeight) { |
||||||
|
scale[0] = 1f; |
||||||
|
scale[1] = ((float) mPreviewingViewHeight) / mPreviewingViewWidth; |
||||||
|
} else { |
||||||
|
scale[0] = ((float) mPreviewingViewWidth) / mPreviewingViewHeight; |
||||||
|
scale[1] = 1f; |
||||||
|
} |
||||||
|
float max_dist = ((float) Math.sqrt(scale[0] * scale[0] + scale[1] |
||||||
|
* scale[1])) * 0.5f; |
||||||
|
|
||||||
|
String scaleString[] = new String[2]; |
||||||
|
|
||||||
|
scaleString[0] = "scale[0] = " + scale[0] + ";\n"; |
||||||
|
scaleString[1] = "scale[1] = " + scale[1] + ";\n"; |
||||||
|
String inv_max_distString = "inv_max_dist = " + 1.0f / max_dist + ";\n"; |
||||||
|
String shadeString = "shade = " + mShade + ";\n"; |
||||||
|
|
||||||
|
// The 'range' is between 1.3 to 0.6. When scale is zero then range is
|
||||||
|
// 1.3
|
||||||
|
// which means no vignette at all because the luminousity difference is
|
||||||
|
// less than 1/256 and will cause nothing.
|
||||||
|
String rangeString = "range = " |
||||||
|
+ (1.30f - (float) Math.sqrt(mScale) * 0.7f) + ";\n"; |
||||||
|
|
||||||
|
String shader = "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ " float range;\n" |
||||||
|
+ " float inv_max_dist;\n" |
||||||
|
+ " float shade;\n" |
||||||
|
+ " vec2 scale;\n" |
||||||
|
+ "varying vec2 vTextureCoord;\n" |
||||||
|
+ "void main() {\n" |
||||||
|
// Parameters that were created above
|
||||||
|
+ scaleString[0] |
||||||
|
+ scaleString[1] |
||||||
|
+ inv_max_distString |
||||||
|
+ shadeString |
||||||
|
+ rangeString |
||||||
|
+ " const float slope = 20.0;\n" |
||||||
|
+ " vec2 coord = vTextureCoord - vec2(0.5, 0.5);\n" |
||||||
|
+ " float dist = length(coord * scale);\n" |
||||||
|
+ " float lumen = shade / (1.0 + exp((dist * inv_max_dist - range) * slope)) + (1.0 - shade);\n" |
||||||
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
||||||
|
+ " gl_FragColor = vec4(color.rgb * lumen, color.a);\n" |
||||||
|
+ "}\n"; |
||||||
|
|
||||||
|
return shader; |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
<vector android:height="24dp" android:viewportHeight="480.3" |
||||||
|
android:viewportWidth="480.3" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
<path android:fillColor="#FFFFFF" android:pathData="M254.15,234.1V13.5c0,-7.5 -6,-13.5 -13.5,-13.5s-13.5,6 -13.5,13.5v220.6c-31.3,6.3 -55,34 -55,67.2s23.7,60.9 55,67.2v98.2c0,7.5 6,13.5 13.5,13.5s13.5,-6 13.5,-13.5v-98.2c31.3,-6.3 55,-34 55,-67.2C309.15,268.2 285.55,240.4 254.15,234.1zM240.65,342.8c-22.9,0 -41.5,-18.6 -41.5,-41.5s18.6,-41.5 41.5,-41.5s41.5,18.6 41.5,41.5S263.55,342.8 240.65,342.8z"/> |
||||||
|
<path android:fillColor="#FFFFFF" android:pathData="M88.85,120.9V13.5c0,-7.5 -6,-13.5 -13.5,-13.5s-13.5,6 -13.5,13.5v107.4c-31.3,6.3 -55,34 -55,67.2s23.7,60.9 55,67.2v211.4c0,7.5 6,13.5 13.5,13.5s13.5,-6 13.5,-13.5V255.2c31.3,-6.3 55,-34 55,-67.2S120.15,127.2 88.85,120.9zM75.35,229.6c-22.9,0 -41.5,-18.6 -41.5,-41.5s18.6,-41.5 41.5,-41.5s41.5,18.6 41.5,41.5S98.15,229.6 75.35,229.6z"/> |
||||||
|
<path android:fillColor="#FFFFFF" android:pathData="M418.45,120.9V13.5c0,-7.5 -6,-13.5 -13.5,-13.5s-13.5,6 -13.5,13.5v107.4c-31.3,6.3 -55,34 -55,67.2s23.7,60.9 55,67.2v211.5c0,7.5 6,13.5 13.5,13.5s13.5,-6 13.5,-13.5V255.2c31.3,-6.3 55,-34 55,-67.2S449.85,127.2 418.45,120.9zM404.95,229.6c-22.9,0 -41.5,-18.6 -41.5,-41.5s18.6,-41.5 41.5,-41.5s41.5,18.6 41.5,41.5S427.85,229.6 404.95,229.6z"/> |
||||||
|
</vector> |
Loading…
Reference in new issue