{"version":3,"file":"Convolute.min.mjs","names":[],"sources":["../../../src/filters/Convolute.ts"],"sourcesContent":["import { BaseFilter } from './BaseFilter';\nimport type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';\nimport { classRegistry } from '../ClassRegistry';\nimport { fragmentSource } from './shaders/convolute';\n\nexport type ConvoluteOwnProps = {\n  opaque: boolean;\n  matrix: number[];\n};\n\nexport const convoluteDefaultValues: ConvoluteOwnProps = {\n  opaque: false,\n  matrix: [0, 0, 0, 0, 1, 0, 0, 0, 0],\n};\n\n/**\n * Adapted from <a href=\"http://www.html5rocks.com/en/tutorials/canvas/imagefilters/\">html5rocks article</a>\n * @example <caption>Sharpen filter</caption>\n * const filter = new Convolute({\n *   matrix: [ 0, -1,  0,\n *            -1,  5, -1,\n *             0, -1,  0 ]\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n * canvas.renderAll();\n * @example <caption>Blur filter</caption>\n * const filter = new Convolute({\n *   matrix: [ 1/9, 1/9, 1/9,\n *             1/9, 1/9, 1/9,\n *             1/9, 1/9, 1/9 ]\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n * canvas.renderAll();\n * @example <caption>Emboss filter</caption>\n * const filter = new Convolute({\n *   matrix: [ 1,   1,  1,\n *             1, 0.7, -1,\n *            -1,  -1, -1 ]\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n * canvas.renderAll();\n * @example <caption>Emboss filter with opaqueness</caption>\n * const filter = new Convolute({\n *   opaque: true,\n *   matrix: [ 1,   1,  1,\n *             1, 0.7, -1,\n *            -1,  -1, -1 ]\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n * canvas.renderAll();\n */\nexport class Convolute extends BaseFilter<'Convolute', ConvoluteOwnProps> {\n  /*\n   * Opaque value (true/false)\n   */\n  declare opaque: ConvoluteOwnProps['opaque'];\n\n  /*\n   * matrix for the filter, max 9x9\n   */\n  declare matrix: ConvoluteOwnProps['matrix'];\n\n  static type = 'Convolute';\n\n  static defaults = convoluteDefaultValues;\n\n  static uniformLocations = ['uMatrix', 'uOpaque', 'uHalfSize', 'uSize'];\n\n  getCacheKey() {\n    return `${this.type}_${Math.sqrt(this.matrix.length)}_${\n      this.opaque ? 1 : 0\n    }` as keyof typeof fragmentSource;\n  }\n\n  getFragmentSource() {\n    return fragmentSource[this.getCacheKey()];\n  }\n\n  /**\n   * Apply the Brightness operation to a Uint8ClampedArray representing the pixels of an image.\n   *\n   * @param {Object} options\n   * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n   */\n  applyTo2d(options: T2DPipelineState) {\n    const imageData = options.imageData,\n      data = imageData.data,\n      weights = this.matrix,\n      side = Math.round(Math.sqrt(weights.length)),\n      halfSide = Math.floor(side / 2),\n      sw = imageData.width,\n      sh = imageData.height,\n      output = options.ctx.createImageData(sw, sh),\n      dst = output.data,\n      // go through the destination image pixels\n      alphaFac = this.opaque ? 1 : 0;\n    let r, g, b, a, dstOff, scx, scy, srcOff, wt, x, y, cx, cy;\n\n    for (y = 0; y < sh; y++) {\n      for (x = 0; x < sw; x++) {\n        dstOff = (y * sw + x) * 4;\n        // calculate the weighed sum of the source image pixels that\n        // fall under the convolution matrix\n        r = 0;\n        g = 0;\n        b = 0;\n        a = 0;\n\n        for (cy = 0; cy < side; cy++) {\n          for (cx = 0; cx < side; cx++) {\n            scy = y + cy - halfSide;\n            scx = x + cx - halfSide;\n\n            if (scy < 0 || scy >= sh || scx < 0 || scx >= sw) {\n              continue;\n            }\n\n            srcOff = (scy * sw + scx) * 4;\n            wt = weights[cy * side + cx];\n\n            r += data[srcOff] * wt;\n            g += data[srcOff + 1] * wt;\n            b += data[srcOff + 2] * wt;\n\n            if (!alphaFac) {\n              a += data[srcOff + 3] * wt;\n            }\n          }\n        }\n        dst[dstOff] = r;\n        dst[dstOff + 1] = g;\n        dst[dstOff + 2] = b;\n        if (!alphaFac) {\n          dst[dstOff + 3] = a;\n        } else {\n          dst[dstOff + 3] = data[dstOff + 3];\n        }\n      }\n    }\n    options.imageData = output;\n  }\n\n  /**\n   * Send data from this filter to its shader program's uniforms.\n   *\n   * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n   * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n   */\n  sendUniformData(\n    gl: WebGLRenderingContext,\n    uniformLocations: TWebGLUniformLocationMap,\n  ) {\n    gl.uniform1fv(uniformLocations.uMatrix, this.matrix);\n  }\n\n  /**\n   * Returns object representation of an instance\n   * @return {Object} Object representation of an instance\n   */\n  toObject() {\n    return {\n      ...super.toObject(),\n      opaque: this.opaque,\n      matrix: [...this.matrix],\n    };\n  }\n}\n\nclassRegistry.setClass(Convolute);\n"],"mappings":"sRAuDA,IAAa,EAAb,cAA+B,CAAA,CAiB7B,aAAA,CACE,MAAO,GAAG,KAAK,KAAA,GAAQ,KAAK,KAAK,KAAK,OAAO,OAAA,CAAA,GAC3C,KAAK,OAAS,EAAI,IAItB,mBAAA,CACE,OAAO,EAAe,KAAK,aAAA,EAS7B,UAAU,EAAA,CACR,IAAM,EAAY,EAAQ,UACxB,EAAO,EAAU,KACjB,EAAU,KAAK,OACf,EAAO,KAAK,MAAM,KAAK,KAAK,EAAQ,OAAA,CAAA,CACpC,EAAW,KAAK,MAAM,EAAO,EAAA,CAC7B,EAAK,EAAU,MACf,EAAK,EAAU,OACf,EAAS,EAAQ,IAAI,gBAAgB,EAAI,EAAA,CACzC,EAAM,EAAO,KAEb,EAAW,KAAK,OAAS,EAAI,EAC3B,EAAG,EAAG,EAAG,EAAG,EAAQ,EAAK,EAAK,EAAQ,EAAI,EAAG,EAAG,EAAI,EAExD,IAAK,EAAI,EAAG,EAAI,EAAI,IAClB,IAAK,EAAI,EAAG,EAAI,EAAI,IAAK,CASvB,IARA,EAAwB,GAAd,EAAI,EAAK,GAGnB,EAAI,EACJ,EAAI,EACJ,EAAI,EACJ,EAAI,EAEC,EAAK,EAAG,EAAK,EAAM,IACtB,IAAK,EAAK,EAAG,EAAK,EAAM,IACtB,EAAM,EAAI,EAAK,EACf,EAAM,EAAI,EAAK,EAEX,EAAM,GAAK,GAAO,GAAM,EAAM,GAAK,GAAO,IAI9C,EAA4B,GAAlB,EAAM,EAAK,GACrB,EAAK,EAAQ,EAAK,EAAO,GAEzB,GAAK,EAAK,GAAU,EACpB,GAAK,EAAK,EAAS,GAAK,EACxB,GAAK,EAAK,EAAS,GAAK,EAEnB,IACH,GAAK,EAAK,EAAS,GAAK,IAI9B,EAAI,GAAU,EACd,EAAI,EAAS,GAAK,EAClB,EAAI,EAAS,GAAK,EAIhB,EAAI,EAAS,GAHV,EAGe,EAAK,EAAS,GAFd,EAMxB,EAAQ,UAAY,EAStB,gBACE,EACA,EAAA,CAEA,EAAG,WAAW,EAAiB,QAAS,KAAK,OAAA,CAO/C,UAAA,CACE,MAAO,CAAA,GACF,MAAM,UAAA,CACT,OAAQ,KAAK,OACb,OAAQ,CAAA,GAAI,KAAK,OAAA,CAAA,GAAA,EAAA,EArGd,OAAO,YAAA,CAAA,EAAA,EAEP,WA1DgD,CACvD,OAAA,CAAQ,EACR,OAAQ,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAA,CAAA,CAAA,CAAA,EAAA,EA0D1B,mBAAmB,CAAC,UAAW,UAAW,YAAa,QAAA,CAAA,CAsGhE,EAAc,SAAS,EAAA,CAAA,OAAA,KAAA"}