{"version":3,"file":"Extract.mjs","sources":["../src/Extract.ts"],"sourcesContent":["import { extensions, ExtensionType, MSAA_QUALITY, Rectangle, RenderTexture, utils } from 'pixijs/core';\n\nimport type { ExtensionMetadata, ICanvas, ISystem, Renderer } from 'pixijs/core';\nimport type { DisplayObject } from 'pixijs/display';\n\nconst TEMP_RECT = new Rectangle();\nconst BYTES_PER_PIXEL = 4;\n\nexport interface IExtract\n{\n    image(target: DisplayObject | RenderTexture, format?: string, quality?: number): Promise<HTMLImageElement>;\n    base64(target: DisplayObject | RenderTexture, format?: string, quality?: number): Promise<string>;\n    canvas(target?: DisplayObject | RenderTexture, frame?: Rectangle): ICanvas;\n    pixels(target: DisplayObject | RenderTexture, frame?: Rectangle): Uint8Array | Uint8ClampedArray;\n}\n\n/**\n * This class provides renderer-specific plugins for exporting content from a renderer.\n * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).\n *\n * Do not instantiate these plugins directly. It is available from the `renderer.extract` property.\n * @example\n * import { Application, Graphics } from 'pixijs/browser';\n *\n * // Create a new application (extract will be auto-added to renderer)\n * const app = new Application();\n *\n * // Draw a red circle\n * const graphics = new Graphics()\n *     .beginFill(0xFF0000)\n *     .drawCircle(0, 0, 50);\n *\n * // Render the graphics as an HTMLImageElement\n * const image = await app.renderer.extract.image(graphics);\n * document.body.appendChild(image);\n * @memberof PIXI\n */\n\nexport class Extract implements ISystem, IExtract\n{\n    /** @ignore */\n    static extension: ExtensionMetadata = {\n        name: 'extract',\n        type: ExtensionType.RendererSystem,\n    };\n\n    private renderer: Renderer;\n\n    /**\n     * @param renderer - A reference to the current renderer\n     */\n    constructor(renderer: Renderer)\n    {\n        this.renderer = renderer;\n    }\n\n    /**\n     * Will return a HTML Image of the target\n     * @param target - A displayObject or renderTexture\n     *  to convert. If left empty will use the main renderer\n     * @param format - Image format, e.g. \"image/jpeg\" or \"image/webp\".\n     * @param quality - JPEG or Webp compression from 0 to 1. Default is 0.92.\n     * @returns - HTML Image of the target\n     */\n    public async image(target: DisplayObject | RenderTexture, format?: string, quality?: number): Promise<HTMLImageElement>\n    {\n        const image = new Image();\n\n        image.src = await this.base64(target, format, quality);\n\n        return image;\n    }\n\n    /**\n     * Will return a base64 encoded string of this target. It works by calling\n     *  `Extract.getCanvas` and then running toDataURL on that.\n     * @param target - A displayObject or renderTexture\n     *  to convert. If left empty will use the main renderer\n     * @param format - Image format, e.g. \"image/jpeg\" or \"image/webp\".\n     * @param quality - JPEG or Webp compression from 0 to 1. Default is 0.92.\n     * @returns - A base64 encoded string of the texture.\n     */\n    public async base64(target: DisplayObject | RenderTexture, format?: string, quality?: number): Promise<string>\n    {\n        const canvas = this.canvas(target);\n\n        if (canvas.toDataURL !== undefined)\n        {\n            return canvas.toDataURL(format, quality);\n        }\n        if (canvas.convertToBlob !== undefined)\n        {\n            const blob = await canvas.convertToBlob({ type: format, quality });\n\n            return await new Promise<string>((resolve) =>\n            {\n                const reader = new FileReader();\n\n                reader.onload = () => resolve(reader.result as string);\n                reader.readAsDataURL(blob);\n            });\n        }\n\n        throw new Error('Extract.base64() requires ICanvas.toDataURL or ICanvas.convertToBlob to be implemented');\n    }\n\n    /**\n     * Creates a Canvas element, renders this target to it and then returns it.\n     * @param target - A displayObject or renderTexture\n     *  to convert. If left empty will use the main renderer\n     * @param frame - The frame the extraction is restricted to.\n     * @returns - A Canvas element with the texture rendered on.\n     */\n    public canvas(target?: DisplayObject | RenderTexture, frame?: Rectangle): ICanvas\n    {\n        const { pixels, width, height, flipY } = this._rawPixels(target, frame);\n\n        let canvasBuffer = new utils.CanvasRenderTarget(width, height, 1);\n\n        // Add the pixels to the canvas\n        const canvasData = canvasBuffer.context.getImageData(0, 0, width, height);\n\n        Extract.arrayPostDivide(pixels, canvasData.data);\n\n        canvasBuffer.context.putImageData(canvasData, 0, 0);\n\n        // Flipping pixels\n        if (flipY)\n        {\n            const target = new utils.CanvasRenderTarget(canvasBuffer.width, canvasBuffer.height, 1);\n\n            target.context.scale(1, -1);\n\n            // We can't render to itself because we should be empty before render.\n            target.context.drawImage(canvasBuffer.canvas, 0, -height);\n\n            canvasBuffer.destroy();\n            canvasBuffer = target;\n        }\n\n        // Send the canvas back\n        return canvasBuffer.canvas;\n    }\n\n    /**\n     * Will return a one-dimensional array containing the pixel data of the entire texture in RGBA\n     * order, with integer values between 0 and 255 (included).\n     * @param target - A displayObject or renderTexture\n     *  to convert. If left empty will use the main renderer\n     * @param frame - The frame the extraction is restricted to.\n     * @returns - One-dimensional array containing the pixel data of the entire texture\n     */\n    public pixels(target?: DisplayObject | RenderTexture, frame?: Rectangle): Uint8Array\n    {\n        const { pixels } = this._rawPixels(target, frame);\n\n        Extract.arrayPostDivide(pixels, pixels);\n\n        return pixels;\n    }\n\n    private _rawPixels(target?: DisplayObject | RenderTexture, frame?: Rectangle): {\n        pixels: Uint8Array, width: number, height: number, flipY: boolean,\n    }\n    {\n        const renderer = this.renderer;\n        let resolution;\n        let flipY = false;\n        let renderTexture;\n        let generated = false;\n\n        if (target)\n        {\n            if (target instanceof RenderTexture)\n            {\n                renderTexture = target;\n            }\n            else\n            {\n                const multisample = renderer.context.webGLVersion >= 2 ? renderer.multisample : MSAA_QUALITY.NONE;\n\n                renderTexture = this.renderer.generateTexture(target, { multisample });\n\n                if (multisample !== MSAA_QUALITY.NONE)\n                {\n                    // Resolve the multisampled texture to a non-multisampled texture\n                    const resolvedTexture = RenderTexture.create({\n                        width: renderTexture.width,\n                        height: renderTexture.height,\n                    });\n\n                    renderer.framebuffer.bind(renderTexture.framebuffer);\n                    renderer.framebuffer.blit(resolvedTexture.framebuffer);\n                    renderer.framebuffer.bind(null);\n\n                    renderTexture.destroy(true);\n                    renderTexture = resolvedTexture;\n                }\n\n                generated = true;\n            }\n        }\n\n        if (renderTexture)\n        {\n            resolution = renderTexture.baseTexture.resolution;\n            frame = frame ?? renderTexture.frame;\n            flipY = false;\n            renderer.renderTexture.bind(renderTexture);\n        }\n        else\n        {\n            resolution = renderer.resolution;\n\n            if (!frame)\n            {\n                frame = TEMP_RECT;\n                frame.width = renderer.width;\n                frame.height = renderer.height;\n            }\n\n            flipY = true;\n            renderer.renderTexture.bind(null);\n        }\n\n        const width = Math.round(frame.width * resolution);\n        const height = Math.round(frame.height * resolution);\n\n        const pixels = new Uint8Array(BYTES_PER_PIXEL * width * height);\n\n        // Read pixels to the array\n        const gl = renderer.gl;\n\n        gl.readPixels(\n            Math.round(frame.x * resolution),\n            Math.round(frame.y * resolution),\n            width,\n            height,\n            gl.RGBA,\n            gl.UNSIGNED_BYTE,\n            pixels\n        );\n\n        if (generated)\n        {\n            renderTexture.destroy(true);\n        }\n\n        return { pixels, width, height, flipY };\n    }\n\n    /** Destroys the extract. */\n    public destroy(): void\n    {\n        this.renderer = null;\n    }\n\n    /**\n     * Takes premultiplied pixel data and produces regular pixel data\n     * @private\n     * @param pixels - array of pixel data\n     * @param out - output array\n     */\n    static arrayPostDivide(\n        pixels: number[] | Uint8Array | Uint8ClampedArray, out: number[] | Uint8Array | Uint8ClampedArray\n    ): void\n    {\n        for (let i = 0; i < pixels.length; i += 4)\n        {\n            const alpha = out[i + 3] = pixels[i + 3];\n\n            if (alpha !== 0)\n            {\n                out[i] = Math.round(Math.min(pixels[i] * 255.0 / alpha, 255.0));\n                out[i + 1] = Math.round(Math.min(pixels[i + 1] * 255.0 / alpha, 255.0));\n                out[i + 2] = Math.round(Math.min(pixels[i + 2] * 255.0 / alpha, 255.0));\n            }\n            else\n            {\n                out[i] = pixels[i];\n                out[i + 1] = pixels[i + 1];\n                out[i + 2] = pixels[i + 2];\n            }\n        }\n    }\n}\n\nextensions.add(Extract);\n"],"names":[],"mappings":";;AAKA,MAAM,SAAA,GAAY,IAAI,SAAU,EAAA,CAAA;AAChC,MAAM,eAAkB,GAAA,CAAA,CAAA;AAgCjB,MAAM,WAAN,MACP;AAAA,EAYI,YAAY,QACZ,EAAA;AACI,IAAA,IAAA,CAAK,QAAW,GAAA,QAAA,CAAA;AAAA,GACpB;AAAA,EAUA,MAAa,KAAA,CAAM,MAAuC,EAAA,MAAA,EAAiB,OAC3E,EAAA;AACI,IAAM,MAAA,KAAA,GAAQ,IAAI,KAAM,EAAA,CAAA;AAExB,IAAA,KAAA,CAAM,MAAM,MAAM,IAAA,CAAK,MAAO,CAAA,MAAA,EAAQ,QAAQ,OAAO,CAAA,CAAA;AAErD,IAAO,OAAA,KAAA,CAAA;AAAA,GACX;AAAA,EAWA,MAAa,MAAA,CAAO,MAAuC,EAAA,MAAA,EAAiB,OAC5E,EAAA;AACI,IAAM,MAAA,MAAA,GAAS,IAAK,CAAA,MAAA,CAAO,MAAM,CAAA,CAAA;AAEjC,IAAI,IAAA,MAAA,CAAO,cAAc,KACzB,CAAA,EAAA;AACI,MAAO,OAAA,MAAA,CAAO,SAAU,CAAA,MAAA,EAAQ,OAAO,CAAA,CAAA;AAAA,KAC3C;AACA,IAAI,IAAA,MAAA,CAAO,kBAAkB,KAC7B,CAAA,EAAA;AACI,MAAM,MAAA,IAAA,GAAO,MAAM,MAAO,CAAA,aAAA,CAAc,EAAE,IAAM,EAAA,MAAA,EAAQ,SAAS,CAAA,CAAA;AAEjE,MAAA,OAAO,MAAM,IAAI,OAAgB,CAAA,CAAC,OAClC,KAAA;AACI,QAAM,MAAA,MAAA,GAAS,IAAI,UAAW,EAAA,CAAA;AAE9B,QAAA,MAAA,CAAO,MAAS,GAAA,MAAM,OAAQ,CAAA,MAAA,CAAO,MAAgB,CAAA,CAAA;AACrD,QAAA,MAAA,CAAO,cAAc,IAAI,CAAA,CAAA;AAAA,OAC5B,CAAA,CAAA;AAAA,KACL;AAEA,IAAM,MAAA,IAAI,MAAM,wFAAwF,CAAA,CAAA;AAAA,GAC5G;AAAA,EASO,MAAO,CAAA,MAAA,EAAwC,KACtD,EAAA;AACI,IAAM,MAAA,EAAE,QAAQ,KAAO,EAAA,MAAA,EAAQ,UAAU,IAAK,CAAA,UAAA,CAAW,QAAQ,KAAK,CAAA,CAAA;AAEtE,IAAA,IAAI,eAAe,IAAI,KAAA,CAAM,kBAAmB,CAAA,KAAA,EAAO,QAAQ,CAAC,CAAA,CAAA;AAGhE,IAAA,MAAM,aAAa,YAAa,CAAA,OAAA,CAAQ,aAAa,CAAG,EAAA,CAAA,EAAG,OAAO,MAAM,CAAA,CAAA;AAExE,IAAQ,QAAA,CAAA,eAAA,CAAgB,MAAQ,EAAA,UAAA,CAAW,IAAI,CAAA,CAAA;AAE/C,IAAA,YAAA,CAAa,OAAQ,CAAA,YAAA,CAAa,UAAY,EAAA,CAAA,EAAG,CAAC,CAAA,CAAA;AAGlD,IAAA,IAAI,KACJ,EAAA;AACI,MAAM,MAAA,OAAA,GAAS,IAAI,KAAM,CAAA,kBAAA,CAAmB,aAAa,KAAO,EAAA,YAAA,CAAa,QAAQ,CAAC,CAAA,CAAA;AAEtF,MAAO,OAAA,CAAA,OAAA,CAAQ,KAAM,CAAA,CAAA,EAAG,CAAE,CAAA,CAAA,CAAA;AAG1B,MAAA,OAAA,CAAO,QAAQ,SAAU,CAAA,YAAA,CAAa,MAAQ,EAAA,CAAA,EAAG,CAAC,MAAM,CAAA,CAAA;AAExD,MAAA,YAAA,CAAa,OAAQ,EAAA,CAAA;AACrB,MAAe,YAAA,GAAA,OAAA,CAAA;AAAA,KACnB;AAGA,IAAA,OAAO,YAAa,CAAA,MAAA,CAAA;AAAA,GACxB;AAAA,EAUO,MAAO,CAAA,MAAA,EAAwC,KACtD,EAAA;AACI,IAAA,MAAM,EAAE,MAAA,EAAA,GAAW,IAAK,CAAA,UAAA,CAAW,QAAQ,KAAK,CAAA,CAAA;AAEhD,IAAQ,QAAA,CAAA,eAAA,CAAgB,QAAQ,MAAM,CAAA,CAAA;AAEtC,IAAO,OAAA,MAAA,CAAA;AAAA,GACX;AAAA,EAEQ,UAAW,CAAA,MAAA,EAAwC,KAG3D,EAAA;AACI,IAAA,MAAM,WAAW,IAAK,CAAA,QAAA,CAAA;AACtB,IAAI,IAAA,UAAA,CAAA;AACJ,IAAA,IAAI,KAAQ,GAAA,KAAA,CAAA;AACZ,IAAI,IAAA,aAAA,CAAA;AACJ,IAAA,IAAI,SAAY,GAAA,KAAA,CAAA;AAEhB,IAAA,IAAI,MACJ,EAAA;AACI,MAAA,IAAI,kBAAkB,aACtB,EAAA;AACI,QAAgB,aAAA,GAAA,MAAA,CAAA;AAAA,OAGpB,MAAA;AACI,QAAA,MAAM,cAAc,QAAS,CAAA,OAAA,CAAQ,gBAAgB,CAAI,GAAA,QAAA,CAAS,cAAc,YAAa,CAAA,IAAA,CAAA;AAE7F,QAAA,aAAA,GAAgB,KAAK,QAAS,CAAA,eAAA,CAAgB,MAAQ,EAAA,EAAE,aAAa,CAAA,CAAA;AAErE,QAAI,IAAA,WAAA,KAAgB,aAAa,IACjC,EAAA;AAEI,UAAM,MAAA,eAAA,GAAkB,cAAc,MAAO,CAAA;AAAA,YACzC,OAAO,aAAc,CAAA,KAAA;AAAA,YACrB,QAAQ,aAAc,CAAA,MAAA;AAAA,WACzB,CAAA,CAAA;AAED,UAAS,QAAA,CAAA,WAAA,CAAY,IAAK,CAAA,aAAA,CAAc,WAAW,CAAA,CAAA;AACnD,UAAS,QAAA,CAAA,WAAA,CAAY,IAAK,CAAA,eAAA,CAAgB,WAAW,CAAA,CAAA;AACrD,UAAS,QAAA,CAAA,WAAA,CAAY,KAAK,IAAI,CAAA,CAAA;AAE9B,UAAA,aAAA,CAAc,QAAQ,IAAI,CAAA,CAAA;AAC1B,UAAgB,aAAA,GAAA,eAAA,CAAA;AAAA,SACpB;AAEA,QAAY,SAAA,GAAA,IAAA,CAAA;AAAA,OAChB;AAAA,KACJ;AAEA,IAAA,IAAI,aACJ,EAAA;AACI,MAAA,UAAA,GAAa,cAAc,WAAY,CAAA,UAAA,CAAA;AACvC,MAAA,KAAA,GAAQ,SAAS,aAAc,CAAA,KAAA,CAAA;AAC/B,MAAQ,KAAA,GAAA,KAAA,CAAA;AACR,MAAS,QAAA,CAAA,aAAA,CAAc,KAAK,aAAa,CAAA,CAAA;AAAA,KAG7C,MAAA;AACI,MAAA,UAAA,GAAa,QAAS,CAAA,UAAA,CAAA;AAEtB,MAAA,IAAI,CAAC,KACL,EAAA;AACI,QAAQ,KAAA,GAAA,SAAA,CAAA;AACR,QAAA,KAAA,CAAM,QAAQ,QAAS,CAAA,KAAA,CAAA;AACvB,QAAA,KAAA,CAAM,SAAS,QAAS,CAAA,MAAA,CAAA;AAAA,OAC5B;AAEA,MAAQ,KAAA,GAAA,IAAA,CAAA;AACR,MAAS,QAAA,CAAA,aAAA,CAAc,KAAK,IAAI,CAAA,CAAA;AAAA,KACpC;AAEA,IAAA,MAAM,KAAQ,GAAA,IAAA,CAAK,KAAM,CAAA,KAAA,CAAM,QAAQ,UAAU,CAAA,CAAA;AACjD,IAAA,MAAM,MAAS,GAAA,IAAA,CAAK,KAAM,CAAA,KAAA,CAAM,SAAS,UAAU,CAAA,CAAA;AAEnD,IAAA,MAAM,MAAS,GAAA,IAAI,UAAW,CAAA,eAAA,GAAkB,QAAQ,MAAM,CAAA,CAAA;AAG9D,IAAA,MAAM,KAAK,QAAS,CAAA,EAAA,CAAA;AAEpB,IAAA,EAAA,CAAG,WACC,IAAK,CAAA,KAAA,CAAM,MAAM,CAAI,GAAA,UAAU,GAC/B,IAAK,CAAA,KAAA,CAAM,MAAM,CAAI,GAAA,UAAU,GAC/B,KACA,EAAA,MAAA,EACA,GAAG,IACH,EAAA,EAAA,CAAG,eACH,MACJ,CAAA,CAAA;AAEA,IAAA,IAAI,SACJ,EAAA;AACI,MAAA,aAAA,CAAc,QAAQ,IAAI,CAAA,CAAA;AAAA,KAC9B;AAEA,IAAA,OAAO,EAAE,MAAA,EAAQ,KAAO,EAAA,MAAA,EAAQ,KAAM,EAAA,CAAA;AAAA,GAC1C;AAAA,EAGA,OACA,GAAA;AACI,IAAA,IAAA,CAAK,QAAW,GAAA,IAAA,CAAA;AAAA,GACpB;AAAA,EAQA,OAAO,eACH,CAAA,MAAA,EAAmD,GAEvD,EAAA;AACI,IAAA,KAAA,IAAS,IAAI,CAAG,EAAA,CAAA,GAAI,MAAO,CAAA,MAAA,EAAQ,KAAK,CACxC,EAAA;AACI,MAAA,MAAM,KAAQ,GAAA,GAAA,CAAI,CAAI,GAAA,CAAA,CAAA,GAAK,OAAO,CAAI,GAAA,CAAA,CAAA,CAAA;AAEtC,MAAA,IAAI,UAAU,CACd,EAAA;AACI,QAAI,GAAA,CAAA,CAAA,CAAA,GAAK,IAAK,CAAA,KAAA,CAAM,IAAK,CAAA,GAAA,CAAI,OAAO,CAAK,CAAA,GAAA,GAAA,GAAQ,KAAO,EAAA,GAAK,CAAC,CAAA,CAAA;AAC9D,QAAA,GAAA,CAAI,CAAI,GAAA,CAAA,CAAA,GAAK,IAAK,CAAA,KAAA,CAAM,IAAK,CAAA,GAAA,CAAI,MAAO,CAAA,CAAA,GAAI,CAAK,CAAA,GAAA,GAAA,GAAQ,KAAO,EAAA,GAAK,CAAC,CAAA,CAAA;AACtE,QAAA,GAAA,CAAI,CAAI,GAAA,CAAA,CAAA,GAAK,IAAK,CAAA,KAAA,CAAM,IAAK,CAAA,GAAA,CAAI,MAAO,CAAA,CAAA,GAAI,CAAK,CAAA,GAAA,GAAA,GAAQ,KAAO,EAAA,GAAK,CAAC,CAAA,CAAA;AAAA,OAG1E,MAAA;AACI,QAAA,GAAA,CAAI,KAAK,MAAO,CAAA,CAAA,CAAA,CAAA;AAChB,QAAI,GAAA,CAAA,CAAA,GAAI,CAAK,CAAA,GAAA,MAAA,CAAO,CAAI,GAAA,CAAA,CAAA,CAAA;AACxB,QAAI,GAAA,CAAA,CAAA,GAAI,CAAK,CAAA,GAAA,MAAA,CAAO,CAAI,GAAA,CAAA,CAAA,CAAA;AAAA,OAC5B;AAAA,KACJ;AAAA,GACJ;AACJ,CAAA,CAAA;AAvPO,IAAM,OAAN,GAAA,SAAA;AAAM,QAGF,SAA+B,GAAA;AAAA,EAClC,IAAM,EAAA,SAAA;AAAA,EACN,MAAM,aAAc,CAAA,cAAA;AACxB,CAAA,CAAA;AAmPJ,UAAA,CAAW,IAAI,OAAO,CAAA;;;;"}