Skip to content

Commit

Permalink
Document applying image filter to SVG image (#1576)
Browse files Browse the repository at this point in the history
  • Loading branch information
wcandillon authored May 19, 2023
1 parent 7a26237 commit b0b9475
Show file tree
Hide file tree
Showing 4 changed files with 836 additions and 21 deletions.
48 changes: 46 additions & 2 deletions docs/docs/image-svg.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,13 @@ export const SVG = () => {

As mentionned above, if the root dimensions are in absolute units, the width/height properties have no effect since the initial viewport is fixed. However you can access these values and use the fitbox function.

```tsx
### Example

In the example below we scale the SVG to the canvas width and height.

```tsx twoslash
import React from "react";
import { Canvas, ImageSVG, Skia, rect, fitbox } from "@shopify/react-native-skia";
import { Canvas, ImageSVG, Skia, rect, fitbox, Group } from "@shopify/react-native-skia";

const svg = Skia.SVG.MakeFromString(
`<svg viewBox='0 0 20 20' width="20" height="20" xmlns='http://www.w3.org/2000/svg'>
Expand All @@ -101,8 +105,48 @@ export const SVG = () => {
};
```

### Result

<img src={require("/static/img/svg.png").default} width="256" height="256" />

## Applying Filters

The `ImageSVG` component doesn't follow the same painting rules as other components.
This is because behind the scene, we use the SVG module from Skia.
However you can apply image filters using the `layer` property.

### Example

In the example below we apply a blur image filter to the SVG.

```tsx twoslash
import React from "react";
import { Canvas, ImageSVG, Skia, rect, fitbox, useSVG, Group, Paint, Blur } from "@shopify/react-native-skia";

const width = 256;
const height = 256;

export const SVG = () => {
const tiger = useSVG(require("./tiger.svg"));
if (!tiger) {
return null;
}
const src = rect(0, 0, tiger.width(), tiger.height());
const dst = rect(0, 0, width, height);
return (
<Canvas style={{ flex: 1 }}>
<Group transform={fitbox("contain", src, dst)} layer={<Paint><Blur blur={10} /></Paint>}>
<ImageSVG svg={tiger} x={0} y={0} width={800} height={800} />
</Group>
</Canvas>
);
};
```

### Result

<img src={require("/static/img/blurred-tiger.png").default} width="256" height="256" />

## SVG Support

The [SVG module from Skia](https://github.com/google/skia/tree/main/modules/svg) displays SVGs as images.
Expand Down
Binary file added docs/static/img/blurred-tiger.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
85 changes: 66 additions & 19 deletions package/src/renderer/__tests__/e2e/SVG.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,50 @@
import fs from "fs";

import React from "react";

import { checkImage, docPath, itRunsE2eOnly } from "../../../__tests__/setup";
import { importSkia, surface } from "../setup";
import { Fill, Group, ImageSVG, fitbox } from "../../components";
import { Blur, Fill, Group, ImageSVG, Paint, fitbox } from "../../components";
import type { SkSVG } from "../../../skia/types";

// Because SkSVG doesn't exist on web,
// this instance is just to send the svg over the wire
class SVGAsset implements SkSVG {
__typename__ = "SVG" as const;
constructor(
private _source: string,
private _width: number,
private _height: number
) {}

dispose() {}

source() {
return this._source;
}

// Because SkSVG doesn't exist on web
// This instance is just to send the svg over the wire
const svgWithSize = {
__typename__: "SVG" as const,
width() {
return 20;
},
return this._width;
}

height() {
return 20;
},
dispose() {},
source() {
return `<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='#00FFFF'/>
</svg>`;
},
};
return this._height;
}
}

const circle = new SVGAsset(
`<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='#00FFFF'/>
</svg>`,
20,
20
);

const tiger = new SVGAsset(
fs.readFileSync("src/skia/__tests__/assets/tiger.svg", "utf-8"),
800,
800
);

const svgWithoutSize = {
__typename__: "SVG" as const,
Expand All @@ -42,14 +66,13 @@ describe("Displays SVGs", () => {
itRunsE2eOnly("should render the SVG scaled properly", async () => {
const { rect } = importSkia();
const { width, height } = surface;

const src = rect(0, 0, svgWithSize.width(), svgWithSize.height());
const src = rect(0, 0, circle.width(), circle.height());
const dst = rect(0, 0, width, height);
const image = await surface.draw(
<>
<Fill color="white" />
<Group transform={fitbox("contain", src, dst)}>
<ImageSVG svg={svgWithSize} />
<ImageSVG svg={circle} />
</Group>
</>
);
Expand Down Expand Up @@ -101,4 +124,28 @@ describe("Displays SVGs", () => {
checkImage(image, docPath("svg2.png"));
}
);

itRunsE2eOnly("should apply an image filter to the svg", async () => {
const { rect } = importSkia();
const { width, height } = surface;

const src = rect(0, 0, tiger.width(), tiger.height());
const dst = rect(0, 0, width, height);
const image = await surface.draw(
<>
<Fill color="white" />
<Group
transform={fitbox("contain", src, dst)}
layer={
<Paint>
<Blur blur={10} />
</Paint>
}
>
<ImageSVG svg={tiger} x={0} y={0} width={800} height={800} />
</Group>
</>
);
checkImage(image, docPath("blurred-tiger.png"));
});
});
Loading

0 comments on commit b0b9475

Please sign in to comment.