FabricJS Levels Filter

by codingdude

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.6/fabric.js"></script>
<canvas width="600" height="400" id="c"></canvas>
<img style="display:none" src="https://images.unsplash.com/photo-1534809027769-b00d750a6bac?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjU1MjA5fQ&w=2333.3333333333&name=unsplash-Model - Kenagonio https://www.instagram.com/kenagonio/
Photographer - Judeus Samson https://www.instagram.com/judeus.samson.jpg" id="my-image" crossorigin="anonymous">

Black Point: <input name="blackPoint" value="0" type="range" min="0" max="255"><br/>
White Point: <input name="whitePoint" value="255" type="range" min="0" max="255"><br/>

Mid Point: <input name="midPoint" type="range" value="0" min="-100" max="100"><br/>

Min Output: <input name="minOutput" type="range" value="0" min="0" max="255"><br/>
Max Output: <input name="maxOutput" type="range" value="255" min="0" max="255"><br/>

JavaScript

/*FabricJS Plugin Template*/

fabric.textureSize = 4096;//for filters on large images
/*
  options:
    filterName - name of the filter
    mainParameter - main parameter name
    fragmentSource - code for the fragment shader
    uniforms
    sendUniformData(gl,uniformLocations)
*/
function setupFilter(options){
  fabric.Image.filters[options.filterName] = fabric.util.createClass(fabric.Image.filters.BaseFilter, Object.assign({

    type: options.filterName,

    applyTo2d: function(options) {
      alert("This filter only works on browsers that support webgl");
    },
    getUniformLocations: function(gl, program) {
        return options.uniforms(gl,program);
      },
    sendUniformData: function(gl, uniformLocations) {
        options.sendUniformData(gl, uniformLocations);
    },
    isNeutralState:function(){
    	return false;//this.callSuper('isNeutralState');
    }
  },options));

  fabric.Image.filters[options.filterName].fromObject = fabric.Image.filters.BaseFilter.fromObject;
}

////////////Template end////////////////////

var options={
    filterName: "MyLevels",
    mainParameter: "blackPoint",
    blackPoint:0,
    whitePoint:255,
    middlePoint:128,
    uniforms:function(gl,program){
    	return {
      	uBlackPoint:gl.getUniformLocation(program, 'uBlackPoint'),
        uMiddlePoint:gl.getUniformLocation(program, 'uMiddlePoint'),
      	uWhitePoint:gl.getUniformLocation(program, 'uWhitePoint'),
        uMinOutput:gl.getUniformLocation(program, 'uMinOutput'),
        uMaxOutput:gl.getUniformLocation(program, 'uMaxOutput')
      };
    },
    sendUniformData:function(gl,uniformLocations){
    	gl.uniform1f(uniformLocations.uBlackPoint, this.blackPoint);
      gl.uniform1f(uniformLocations.uMiddlePoint, this.middlePoint);
      gl.uniform1f(uniformLocations.uWhitePoint, this.whitePoint);
      gl.uniform1f(uniformLocations.uMinOutput, this.minOutput);
      gl.uniform1f(uniformLocations.uMaxOutput, this.maxOutput);
    },
    fragmentSource: `
   ...