Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/docs/docs/image-svg.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 26 additions & 0 deletions apps/remotion/src/Playground/Playground.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -11,14 +19,32 @@ 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(
`
<svg viewBox='0 0 20 20' width="20" height="20" xmlns='http://www.w3.org/2000/svg'>
<circle cx='10' cy='10' r='10' fill='red'/>
</svg>
`
)!;

const src = rect(0, 0, svg2.width(), svg2.height());
const dst = rect(0, 0, 400, 400);
return (
<>
<Canvas
typefaces={{ RubikMedium: require("./assets/Rubik-Medium.otf") }}
images={{}}
>
<Background />
<ImageSVG svg={svg} width={256} height={256} />
<Group transform={fitbox("contain", src, dst)}>
<ImageSVG svg={svg2} x={0} y={0} width={20} height={20} />
</Group>
</Canvas>
</>
);
Expand Down
60 changes: 35 additions & 25 deletions packages/skia/src/skia/core/SVG.web.ts
Original file line number Diff line number Diff line change
@@ -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<SkSVG | null>(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;
};
4 changes: 3 additions & 1 deletion packages/skia/src/skia/web/JsiSkCanvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
Expand Down
Loading