diff --git a/apps/docs/docs/image-svg.md b/apps/docs/docs/image-svg.md index e936634779..b94afabf68 100644 --- a/apps/docs/docs/image-svg.md +++ b/apps/docs/docs/image-svg.md @@ -22,6 +22,8 @@ If the root dimensions are in absolute units, the width/height properties have n The `ImageSVG` component doesn't follow the same painting rules as other components. [see applying effects](#applying-effects). +On Web, the Current Transformation Matrix (CTM) won't be applied to `ImageSVG` because the component relies on browser SVG rendering instead of CanvasKit. The SVG is rendered as a hidden image element and then imported as image data. This means transformations need to be prepared beforehand or applied through the `Group` component with explicit transform matrices. + ::: ### Example diff --git a/apps/remotion/src/Playground/Playground.tsx b/apps/remotion/src/Playground/Playground.tsx index f2c1a78586..4468546694 100644 --- a/apps/remotion/src/Playground/Playground.tsx +++ b/apps/remotion/src/Playground/Playground.tsx @@ -1,4 +1,12 @@ import React from "react"; +import { + fitbox, + Group, + ImageSVG, + rect, + Skia, + useSVG, +} from "@shopify/react-native-skia"; import { Background, Canvas } from "../components"; import { makeAnimation, wait } from "../components/animations/Animations"; @@ -11,7 +19,21 @@ const state = makeAnimation(function* ({}) { export const durationInFrames = state.duration; +const SVG_URL = + "https://upload.wikimedia.org/wikipedia/commons/f/fd/Ghostscript_Tiger.svg"; + export const Playground = () => { + const svg = useSVG(SVG_URL); + const svg2 = Skia.SVG.MakeFromString( + ` + + + + ` + )!; + + const src = rect(0, 0, svg2.width(), svg2.height()); + const dst = rect(0, 0, 400, 400); return ( <> { images={{}} > + + + + ); diff --git a/packages/skia/src/skia/core/SVG.web.ts b/packages/skia/src/skia/core/SVG.web.ts index c0de0a8bdc..cbb72ea002 100644 --- a/packages/skia/src/skia/core/SVG.web.ts +++ b/packages/skia/src/skia/core/SVG.web.ts @@ -1,36 +1,46 @@ +import { useEffect, useState } from "react"; + import { Skia } from "../Skia"; -import type { DataSourceParam } from "../types"; +import type { DataSourceParam, SkSVG } from "../types"; export const useSVG = ( source: DataSourceParam, onError?: (err: Error) => void ) => { + const [svg, setSVG] = useState(null); if (source === null || source === undefined) { throw new Error(`Invalid svg data source. Got: ${source}`); } - let src: string; - if (typeof source === "string") { - src = source; - } else if ( - typeof source === "object" && - "default" in source && - typeof source.default === "string" - ) { - src = source.default; - } else if (typeof source === "object" && "uri" in source) { - src = source.uri; - } else { - throw new Error( - `Invalid svg data source. Make sure that the source resolves to a string. Got: ${JSON.stringify( - source, - null, - 2 - )}` - ); - } - const svg = Skia.SVG.MakeFromString(src); - if (svg === null && onError !== undefined) { - onError(new Error("Failed to create SVG from source.")); - } + useEffect(() => { + (async () => { + let src: string; + if (typeof source === "string") { + src = source; + } else if ( + typeof source === "object" && + "default" in source && + typeof source.default === "string" + ) { + src = source.default; + } else if (typeof source === "object" && "uri" in source) { + src = source.uri; + } else { + throw new Error( + `Invalid svg data source. Make sure that the source resolves to a string. Got: ${JSON.stringify( + source, + null, + 2 + )}` + ); + } + const result = await fetch(src); + const svgStr = await result.text(); + const newSvg = Skia.SVG.MakeFromString(svgStr); + setSVG(newSvg); + if (newSvg === null && onError !== undefined) { + onError(new Error("Failed to create SVG from source.")); + } + })(); + }, [onError, source]); return svg; }; diff --git a/packages/skia/src/skia/web/JsiSkCanvas.ts b/packages/skia/src/skia/web/JsiSkCanvas.ts index 988bbc353b..63d147ba57 100644 --- a/packages/skia/src/skia/web/JsiSkCanvas.ts +++ b/packages/skia/src/skia/web/JsiSkCanvas.ts @@ -305,7 +305,9 @@ export class JsiSkCanvas ); } - drawSvg(svg: SkSVG, _width?: number, _height?: number) { + drawSvg(svg: SkSVG, width?: number, height?: number) { + const ctm = this.ref.getLocalToDevice(); + console.log({ ctm, width, height }); const image = this.CanvasKit.MakeImageFromCanvasImageSource( (svg as JsiSkSVG).ref );