{"version":3,"file":"BlendImage.min.mjs","names":[],"sources":["../../../src/filters/BlendImage.ts"],"sourcesContent":["import { FabricImage } from '../shapes/Image';\nimport { createCanvasElement } from '../util/misc/dom';\nimport { BaseFilter } from './BaseFilter';\nimport type {\n  T2DPipelineState,\n  TWebGLPipelineState,\n  TWebGLUniformLocationMap,\n} from './typedefs';\nimport type { WebGLFilterBackend } from './WebGLFilterBackend';\nimport { classRegistry } from '../ClassRegistry';\nimport { fragmentSource, vertexSource } from './shaders/blendImage';\n\nexport type TBlendImageMode = 'multiply' | 'mask';\n\ntype BlendImageOwnProps = {\n  mode: TBlendImageMode;\n  alpha: number;\n};\n\nexport const blendImageDefaultValues: BlendImageOwnProps = {\n  mode: 'multiply',\n  alpha: 1,\n};\n\n/**\n * Image Blend filter class\n * @example\n * const filter = new filters.BlendColor({\n *  color: '#000',\n *  mode: 'multiply'\n * });\n *\n * const filter = new BlendImage({\n *  image: fabricImageObject,\n *  mode: 'multiply'\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n * canvas.renderAll();\n */\nexport class BlendImage extends BaseFilter<'BlendImage', BlendImageOwnProps> {\n  /**\n   * Image to make the blend operation with.\n   **/\n  declare image: FabricImage;\n\n  /**\n   * Blend mode for the filter: either 'multiply' or 'mask'. 'multiply' will\n   * multiply the values of each channel (R, G, B, and A) of the filter image by\n   * their corresponding values in the base image. 'mask' will only look at the\n   * alpha channel of the filter image, and apply those values to the base\n   * image's alpha channel.\n   * @type String\n   **/\n  declare mode: BlendImageOwnProps['mode'];\n\n  /**\n   * alpha value. represent the strength of the blend image operation.\n   * not implemented.\n   **/\n  declare alpha: BlendImageOwnProps['alpha'];\n\n  static type = 'BlendImage';\n\n  static defaults = blendImageDefaultValues;\n\n  static uniformLocations = ['uTransformMatrix', 'uImage'];\n\n  getCacheKey() {\n    return `${this.type}_${this.mode}`;\n  }\n\n  getFragmentSource(): string {\n    return fragmentSource[this.mode];\n  }\n\n  getVertexSource(): string {\n    return vertexSource;\n  }\n\n  applyToWebGL(options: TWebGLPipelineState) {\n    const gl = options.context,\n      texture = this.createTexture(options.filterBackend, this.image);\n    this.bindAdditionalTexture(gl, texture!, gl.TEXTURE1);\n    super.applyToWebGL(options);\n    this.unbindAdditionalTexture(gl, gl.TEXTURE1);\n  }\n\n  createTexture(backend: WebGLFilterBackend, image: FabricImage) {\n    return backend.getCachedTexture(image.cacheKey, image.getElement());\n  }\n\n  /**\n   * Calculate a transformMatrix to adapt the image to blend over\n   * @param {Object} options\n   * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n   * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n   */\n  calculateMatrix() {\n    const image = this.image,\n      { width, height } = image.getElement();\n    return [\n      1 / image.scaleX,\n      0,\n      0,\n      0,\n      1 / image.scaleY,\n      0,\n      -image.left / width,\n      -image.top / height,\n      1,\n    ];\n  }\n\n  /**\n   * Apply the Blend 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({\n    imageData: { data, width, height },\n    filterBackend: { resources },\n  }: T2DPipelineState) {\n    const image = this.image;\n    if (!resources.blendImage) {\n      resources.blendImage = createCanvasElement();\n    }\n    const canvas1 = resources.blendImage;\n    const context = canvas1.getContext('2d')!;\n    if (canvas1.width !== width || canvas1.height !== height) {\n      canvas1.width = width;\n      canvas1.height = height;\n    } else {\n      context.clearRect(0, 0, width, height);\n    }\n    context.setTransform(\n      image.scaleX,\n      0,\n      0,\n      image.scaleY,\n      image.left,\n      image.top,\n    );\n    context.drawImage(image.getElement(), 0, 0, width, height);\n    const blendData = context.getImageData(0, 0, width, height).data;\n    for (let i = 0; i < data.length; i += 4) {\n      const r = data[i];\n      const g = data[i + 1];\n      const b = data[i + 2];\n      const a = data[i + 3];\n\n      const tr = blendData[i];\n      const tg = blendData[i + 1];\n      const tb = blendData[i + 2];\n      const ta = blendData[i + 3];\n\n      switch (this.mode) {\n        case 'multiply':\n          data[i] = (r * tr) / 255;\n          data[i + 1] = (g * tg) / 255;\n          data[i + 2] = (b * tb) / 255;\n          data[i + 3] = (a * ta) / 255;\n          break;\n        case 'mask':\n          data[i + 3] = ta;\n          break;\n      }\n    }\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    const matrix = this.calculateMatrix();\n    gl.uniform1i(uniformLocations.uImage, 1); // texture unit 1.\n    gl.uniformMatrix3fv(uniformLocations.uTransformMatrix, false, matrix);\n  }\n\n  /**\n   * Returns object representation of an instance\n   * TODO: Handle the possibility of missing image better.\n   * As of now a BlendImage filter without image can't be used with fromObject\n   * @return {Object} Object representation of an instance\n   */\n  toObject(): {\n    type: 'BlendImage';\n    image: ReturnType<FabricImage['toObject']>;\n  } & BlendImageOwnProps {\n    return {\n      ...super.toObject(),\n      image: this.image && this.image.toObject(),\n    };\n  }\n\n  /**\n   * Create filter instance from an object representation\n   * @param {object} object Object to create an instance from\n   * @param {object} [options]\n   * @param {AbortSignal} [options.signal] handle aborting image loading, see https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal\n   * @returns {Promise<BlendImage>}\n   */\n  static async fromObject(\n    { type, image, ...filterOptions }: Record<string, any>,\n    options: { signal: AbortSignal },\n  ): Promise<BaseFilter<'BlendImage', BlendImageOwnProps>> {\n    return FabricImage.fromObject(image, options).then(\n      (enlivedImage) => new this({ ...filterOptions, image: enlivedImage }),\n    );\n  }\n}\n\nclassRegistry.setClass(BlendImage);\n"],"mappings":"8ZAwCA,IAAa,EAAb,cAAgC,CAAA,CA4B9B,aAAA,CACE,MAAO,GAAG,KAAK,KAAA,GAAQ,KAAK,OAG9B,mBAAA,CACE,OAAO,EAAe,KAAK,MAG7B,iBAAA,CACE,OAAO,EAGT,aAAa,EAAA,CACX,IAAM,EAAK,EAAQ,QACjB,EAAU,KAAK,cAAc,EAAQ,cAAe,KAAK,MAAA,CAC3D,KAAK,sBAAsB,EAAI,EAAU,EAAG,SAAA,CAC5C,MAAM,aAAa,EAAA,CACnB,KAAK,wBAAwB,EAAI,EAAG,SAAA,CAGtC,cAAc,EAA6B,EAAA,CACzC,OAAO,EAAQ,iBAAiB,EAAM,SAAU,EAAM,YAAA,CAAA,CASxD,iBAAA,CACE,IAAM,EAAQ,KAAK,MAAA,CACjB,MAAE,EAAA,OAAO,GAAW,EAAM,YAAA,CAC5B,MAAO,CACL,EAAI,EAAM,OACV,EACA,EACA,EACA,EAAI,EAAM,OACV,EAAA,CACC,EAAM,KAAO,EAAA,CACb,EAAM,IAAM,EACb,EAAA,CAUJ,UAAA,CACE,UAAA,CAAW,KAAE,EAAA,MAAM,EAAA,OAAO,GAC1B,cAAA,CAAe,UAAE,IAAA,CAEjB,IAAM,EAAQ,KAAK,MACd,EAAU,aACb,EAAU,WAAa,GAAA,EAEzB,IAAM,EAAU,EAAU,WACpB,EAAU,EAAQ,WAAW,KAAA,CAC/B,EAAQ,QAAU,GAAS,EAAQ,SAAW,GAChD,EAAQ,MAAQ,EAChB,EAAQ,OAAS,GAEjB,EAAQ,UAAU,EAAG,EAAG,EAAO,EAAA,CAEjC,EAAQ,aACN,EAAM,OACN,EACA,EACA,EAAM,OACN,EAAM,KACN,EAAM,IAAA,CAER,EAAQ,UAAU,EAAM,YAAA,CAAc,EAAG,EAAG,EAAO,EAAA,CACnD,IAAM,EAAY,EAAQ,aAAa,EAAG,EAAG,EAAO,EAAA,CAAQ,KAC5D,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,GAAK,EAAG,CACvC,IAAM,EAAI,EAAK,GACT,EAAI,EAAK,EAAI,GACb,EAAI,EAAK,EAAI,GACb,EAAI,EAAK,EAAI,GAEb,EAAK,EAAU,GACf,EAAK,EAAU,EAAI,GACnB,EAAK,EAAU,EAAI,GACnB,EAAK,EAAU,EAAI,GAEzB,OAAQ,KAAK,KAAb,CACE,IAAK,WACH,EAAK,GAAM,EAAI,EAAM,IACrB,EAAK,EAAI,GAAM,EAAI,EAAM,IACzB,EAAK,EAAI,GAAM,EAAI,EAAM,IACzB,EAAK,EAAI,GAAM,EAAI,EAAM,IACzB,MACF,IAAK,OACH,EAAK,EAAI,GAAK,IAYtB,gBACE,EACA,EAAA,CAEA,IAAM,EAAS,KAAK,iBAAA,CACpB,EAAG,UAAU,EAAiB,OAAQ,EAAA,CACtC,EAAG,iBAAiB,EAAiB,iBAAA,CAAkB,EAAO,EAAA,CAShE,UAAA,CAIE,MAAO,CAAA,GACF,MAAM,UAAA,CACT,MAAO,KAAK,OAAS,KAAK,MAAM,UAAA,CAAA,CAWpC,aAAA,WAAa,CACX,KAAE,EAAA,MAAM,EAAA,GAAU,GAClB,EAAA,CAEA,OAAO,EAAY,WAAW,EAAO,EAAA,CAAS,KAC3C,GAAiB,IAAI,KAAK,CAAA,GAAK,EAAe,MAAO,EAAA,CAAA,CAAA,GAAA,EAAA,EAxJnD,OAAO,aAAA,CAAA,EAAA,EAEP,WA7CkD,CACzD,KAAM,WACN,MAAO,EAAA,CAAA,CAAA,EAAA,EA6CA,mBAAmB,CAAC,mBAAoB,SAAA,CAAA,CAyJjD,EAAc,SAAS,EAAA,CAAA,OAAA,KAAA"}