{"version":3,"file":"loadSVG.mjs","sources":["../../../../../src/assets/loader/parsers/textures/loadSVG.ts"],"sourcesContent":["import { DOMAdapter } from '../../../../environment/adapter';\nimport { type ImageLike } from '../../../../environment/ImageLike';\nimport { ExtensionType } from '../../../../extensions/Extensions';\nimport { ImageSource } from '../../../../rendering/renderers/shared/texture/sources/ImageSource';\nimport { GraphicsContext } from '../../../../scene/graphics/shared/GraphicsContext';\nimport { getResolutionOfUrl } from '../../../../utils/network/getResolutionOfUrl';\nimport { checkDataUrl } from '../../../utils/checkDataUrl';\nimport { checkExtension } from '../../../utils/checkExtension';\nimport { type LoaderParser, LoaderParserPriority } from '../LoaderParser';\nimport { createTexture } from './utils/createTexture';\n\nimport type { TextureSourceOptions } from '../../../../rendering/renderers/shared/texture/sources/TextureSource';\nimport type { Texture } from '../../../../rendering/renderers/shared/texture/Texture';\nimport type { ResolvedAsset } from '../../../types';\nimport type { Loader } from '../../Loader';\n\n/**\n * Configuration for the {@link loadSvg} plugin.\n * @see loadSvg\n * @category assets\n * @advanced\n */\nexport interface LoadSVGConfig\n{\n    /**\n     * The crossOrigin value to use for loading the SVG as an image.\n     * @default 'anonymous'\n     */\n    crossOrigin: ImageLike['crossOrigin'];\n    /**\n     * When set to `true`, loading and decoding images will happen with `new Image()`,\n     * @default false\n     */\n    parseAsGraphicsContext: boolean;\n}\n\n/**\n * Regular expression for SVG XML document.\n * @example &lt;?xml version=\"1.0\" encoding=\"utf-8\" ?&gt;&lt;!-- image/svg --&gt;&lt;svg\n * @readonly\n */\nconst validSVGExtension = '.svg';\nconst validSVGMIME = 'image/svg+xml';\n\n/**\n * A loader plugin for loading SVG data as textures or graphics contexts.\n * @category assets\n * @advanced\n */\nexport const loadSvg: LoaderParser<Texture | GraphicsContext, TextureSourceOptions & LoadSVGConfig, LoadSVGConfig> = {\n    extension: {\n        type: ExtensionType.LoadParser,\n        priority: LoaderParserPriority.Low,\n        name: 'loadSVG',\n    },\n\n    /** used for deprecation purposes */\n    name: 'loadSVG',\n    id: 'svg',\n\n    config: {\n        crossOrigin: 'anonymous',\n        parseAsGraphicsContext: false,\n    },\n\n    test(url: string): boolean\n    {\n        return checkDataUrl(url, validSVGMIME) || checkExtension(url, validSVGExtension);\n    },\n\n    async load(\n        url: string,\n        asset: ResolvedAsset<TextureSourceOptions & LoadSVGConfig>,\n        loader: Loader\n    ): Promise<Texture | GraphicsContext>\n    {\n        if (asset.data?.parseAsGraphicsContext ?? this.config.parseAsGraphicsContext)\n        {\n            return loadAsGraphics(url);\n        }\n\n        return loadAsTexture(url, asset, loader, this.config.crossOrigin);\n    },\n\n    unload(asset: Texture | GraphicsContext): void\n    {\n        asset.destroy(true);\n    }\n\n};\n\nasync function loadAsTexture(\n    url: string,\n    asset: ResolvedAsset<TextureSourceOptions & LoadSVGConfig>,\n    loader: Loader,\n    crossOrigin: ImageLike['crossOrigin']\n): Promise<Texture>\n{\n    const response = await DOMAdapter.get().fetch(url);\n\n    const image = DOMAdapter.get().createImage();\n\n    image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(await response.text())}`;\n    image.crossOrigin = crossOrigin;\n    await image.decode();\n\n    // convert to canvas...\n    const width = asset.data?.width ?? image.width;\n    const height = asset.data?.height ?? image.height;\n    const resolution = asset.data?.resolution || getResolutionOfUrl(url);\n\n    // Ensure canvas dimensions are integers to prevent edge trimming\n    const canvasWidth = Math.ceil(width * resolution);\n    const canvasHeight = Math.ceil(height * resolution);\n\n    const canvas = DOMAdapter.get().createCanvas(canvasWidth, canvasHeight);\n    const context = canvas.getContext('2d');\n\n    // Improve rendering quality for decimal resolutions\n    context.imageSmoothingEnabled = true;\n    context.imageSmoothingQuality = 'high';\n\n    // Draw image with exact scaled dimensions to prevent trimming\n    context.drawImage(image as CanvasImageSource, 0, 0, width * resolution, height * resolution);\n\n    const { parseAsGraphicsContext: _p, ...rest } = asset.data ?? {};\n    const base = new ImageSource({\n        resource: canvas,\n        alphaMode: 'premultiply-alpha-on-upload',\n        resolution,\n        ...rest,\n    });\n\n    return createTexture(base, loader, url);\n}\n\nasync function loadAsGraphics(url: string): Promise<GraphicsContext>\n{\n    const response = await DOMAdapter.get().fetch(url);\n    const svgSource = await response.text();\n\n    const context = new GraphicsContext();\n\n    context.svg(svgSource);\n\n    return context;\n}\n"],"names":[],"mappings":"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"}