package com.marshalchen.common.uimodule.imageprocessing.filter.colour;
import com.marshalchen.common.uimodule.imageprocessing.filter.BasicFilter;
import android.opengl.GLES20;
/**
* A image levels filter extension of BasicFilter.
* This filter works like the levels filter in photoshop and can be use to adjust histographs as well
* as gamma levels.
* Values for min and max levels of both input and output should be in [0, 1].
* The gamma value works like the {@link GammaFilter} and should be in [0, 3] for normal use case.
* @author Chris Batt
*/
public class LevelsFilter extends BasicFilter {
private static final String UNIFORM_GAMMA = "u_Gamma";
private static final String UNIFORM_MAXIN = "u_MaxIn";
private static final String UNIFORM_MAXOUT = "u_MaxOut";
private static final String UNIFORM_MININ = "u_MinIn";
private static final String UNIFORM_MINOUT = "u_MinOut";
private float gamma;
private float minIn;
private float maxIn;
private float minOut;
private float maxOut;
private int gammaHandle;
private int minInHandle;
private int maxInHandle;
private int minOutHandle;
private int maxOutHandle;
/**
* Creates a ImageLevelsFilter with the given min, gamma, max input levels and min and max output levels.
* @param minIn
* The minimum level of the input image.
* @param maxIn
* The maximum level of the input image.
* @param gamma
* The gamma adjust value.
* @param minOut
* The minimum level of the output image.
* @param maxOut
* The maximum level of the output image.
*/
public LevelsFilter(float minIn, float maxIn, float gamma, float minOut, float maxOut) {
if(gamma < 0) {
gamma = 0;
}
this.gamma = gamma;
this.minIn = minIn;
this.minOut = minOut;
this.maxIn = maxIn;
this.maxOut = maxOut;
}
/*
** Levels control (input (+gamma), output)
** Details: http://blog.mouaif.org/2009/01/28/levels-control-shader/
*/
@Override
protected String getFragmentShader() {
return
"#define GammaCorrection(color, gamma) pow(color, 1.0 / gamma)\n"
+"#define LevelsControlInputRange(color, minInput, maxInput) min(max(color - minInput, vec3(0.0)) / (maxInput - minInput), vec3(1.0))\n"
+"#define LevelsControlInput(color, minInput, gamma, maxInput) GammaCorrection(LevelsControlInputRange(color, minInput, maxInput), gamma)\n"
+"#define LevelsControlOutputRange(color, minOutput, maxOutput) mix(minOutput, maxOutput, color)\n"
+"#define LevelsControl(color, minInput, gamma, maxInput, minOutput, maxOutput) LevelsControlOutputRange(LevelsControlInput(color, minInput, gamma, maxInput), minOutput, maxOutput)\n"
+"precision mediump float;\n"
+"uniform sampler2D "+UNIFORM_TEXTURE0+";\n"
+"varying vec2 "+VARYING_TEXCOORD+";\n"
+"uniform float "+UNIFORM_GAMMA+";\n"
+"uniform float "+UNIFORM_MININ+";\n"
+"uniform float "+UNIFORM_MAXIN+";\n"
+"uniform float "+UNIFORM_MINOUT+";\n"
+"uniform float "+UNIFORM_MAXOUT+";\n"
+"void main(){\n"
+" vec4 color = texture2D("+UNIFORM_TEXTURE0+", "+VARYING_TEXCOORD+");\n"
+" gl_FragColor = vec4(LevelsControl(color.rgb, vec3("+UNIFORM_MININ+"), vec3("+UNIFORM_GAMMA+"), vec3("+UNIFORM_MAXIN+"), vec3("+UNIFORM_MINOUT+"), vec3("+UNIFORM_MAXOUT+")), color.a);\n"
+"}\n";
}
@Override
protected void initShaderHandles() {
super.initShaderHandles();
gammaHandle = GLES20.glGetUniformLocation(programHandle, UNIFORM_GAMMA);
minInHandle = GLES20.glGetUniformLocation(programHandle, UNIFORM_MININ);
maxInHandle = GLES20.glGetUniformLocation(programHandle, UNIFORM_MAXIN);
minOutHandle = GLES20.glGetUniformLocation(programHandle, UNIFORM_MINOUT);
maxOutHandle = GLES20.glGetUniformLocation(programHandle, UNIFORM_MAXOUT);
}
/*
** Gamma correction
** Details: http://blog.mouaif.org/2009/01/22/photoshop-gamma-correction-shader/
*/
@Override
protected void passShaderValues() {
super.passShaderValues();
GLES20.glUniform1f(gammaHandle, gamma);
GLES20.glUniform1f(minInHandle, minIn);
GLES20.glUniform1f(maxInHandle, maxIn);
GLES20.glUniform1f(minOutHandle, minOut);
GLES20.glUniform1f(maxOutHandle, maxOut);
}
}