Skip to content

Commit

Permalink
Bugfix: Encoding von UTF-8 Text im Browser
Browse files Browse the repository at this point in the history
  • Loading branch information
phjardas committed Mar 23, 2024
1 parent f58ff78 commit fa28291
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 6 deletions.
8 changes: 8 additions & 0 deletions .changeset/thin-apes-juggle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"taktische-zeichen-core": patch
"taktische-zeichen-cli": patch
"taktische-zeichen-react": patch
"taktische-zeichen-web-component": patch
---

Bugfix: Encoding von UTF-8 Text im Browser
27 changes: 27 additions & 0 deletions packages/core/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
"format": "prettier --write src",
"statistics": "ts-node -P tsconfig-scripts.json scripts/statistics.ts"
},
"dependencies": {
"base64-js": "^1.5.1"
},
"devDependencies": {
"@types/jest": "^27.4.0",
"@types/node": "^20.11.5",
Expand Down
82 changes: 82 additions & 0 deletions packages/core/src/taktisches-zeichen.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { erzeugeTaktischesZeichen } from "./taktisches-zeichen";

describe("taktisches-zeichen", () => {
it("should render an SVG", () => {
const tz = erzeugeTaktischesZeichen({
grundzeichen: "taktische-formation",
organisation: "feuerwehr",
skipFontRegistration: true,
});

expect(tz.toString()).toMatchInlineSnapshot(`
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
<svg color=\\"#ffffff\\" fill=\\"transparent\\" stroke=\\"black\\" stroke-width=\\"2\\" viewBox=\\"0 0 75 45\\" xmlns=\\"http://www.w3.org/2000/svg\\"><defs><clipPath id=\\"tz_taktische-formation\\"><path d=\\"M1,1 H74 V44 H1 Z\\" /></clipPath></defs><path d=\\"M1,1 H74 V44 H1 Z\\" fill=\\"#cc0000\\" /></svg>"
`);
});

it("should render a data URL", () => {
const tz = erzeugeTaktischesZeichen({
grundzeichen: "taktische-formation",
organisation: "feuerwehr",
skipFontRegistration: true,
});

expect(tz.dataUrl).toMatchInlineSnapshot(
`"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjb2xvcj0iI2ZmZmZmZiIgZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0iYmxhY2siIHN0cm9rZS13aWR0aD0iMiIgdmlld0JveD0iMCAwIDc1IDQ1IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxjbGlwUGF0aCBpZD0idHpfdGFrdGlzY2hlLWZvcm1hdGlvbiI+PHBhdGggZD0iTTEsMSBINzQgVjQ0IEgxIFoiIC8+PC9jbGlwUGF0aD48L2RlZnM+PHBhdGggZD0iTTEsMSBINzQgVjQ0IEgxIFoiIGZpbGw9IiNjYzAwMDAiIC8+PC9zdmc+"`
);
});

it("should render an SVG with text", () => {
const tz = erzeugeTaktischesZeichen({
grundzeichen: "taktische-formation",
organisation: "feuerwehr",
name: "Test",
skipFontRegistration: true,
});

expect(tz.toString()).toMatchInlineSnapshot(`
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
<svg color=\\"#ffffff\\" fill=\\"transparent\\" stroke=\\"black\\" stroke-width=\\"2\\" viewBox=\\"0 0 75 45\\" xmlns=\\"http://www.w3.org/2000/svg\\"><defs><clipPath id=\\"tz_taktische-formation\\"><path d=\\"M1,1 H74 V44 H1 Z\\" /></clipPath></defs><path d=\\"M1,1 H74 V44 H1 Z\\" fill=\\"#cc0000\\" /><g clip-path=\\"url(#tz_taktische-formation)\\"><g transform=\\"translate(3,3) scale(0.27906976744186046)\\"><text fill=\\"currentColor\\" stroke=\\"none\\" style=\\"font-family:Roboto Slab;font-size:30px;font-weight:bold;letter-spacing:-1px\\" x=\\"0\\" y=\\"21.5\\"><![CDATA[Test]]></text></g></g></svg>"
`);
});

it("should render a data URL with text", () => {
const tz = erzeugeTaktischesZeichen({
grundzeichen: "taktische-formation",
organisation: "feuerwehr",
name: "Test",
skipFontRegistration: true,
});

expect(tz.dataUrl).toMatchInlineSnapshot(
`"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjb2xvcj0iI2ZmZmZmZiIgZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0iYmxhY2siIHN0cm9rZS13aWR0aD0iMiIgdmlld0JveD0iMCAwIDc1IDQ1IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxjbGlwUGF0aCBpZD0idHpfdGFrdGlzY2hlLWZvcm1hdGlvbiI+PHBhdGggZD0iTTEsMSBINzQgVjQ0IEgxIFoiIC8+PC9jbGlwUGF0aD48L2RlZnM+PHBhdGggZD0iTTEsMSBINzQgVjQ0IEgxIFoiIGZpbGw9IiNjYzAwMDAiIC8+PGcgY2xpcC1wYXRoPSJ1cmwoI3R6X3Rha3Rpc2NoZS1mb3JtYXRpb24pIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgzLDMpIHNjYWxlKDAuMjc5MDY5NzY3NDQxODYwNDYpIj48dGV4dCBmaWxsPSJjdXJyZW50Q29sb3IiIHN0cm9rZT0ibm9uZSIgc3R5bGU9ImZvbnQtZmFtaWx5OlJvYm90byBTbGFiO2ZvbnQtc2l6ZTozMHB4O2ZvbnQtd2VpZ2h0OmJvbGQ7bGV0dGVyLXNwYWNpbmc6LTFweCIgeD0iMCIgeT0iMjEuNSI+PCFbQ0RBVEFbVGVzdF1dPjwvdGV4dD48L2c+PC9nPjwvc3ZnPg=="`
);
});

it("should render an SVG with UTF-8 text", () => {
const tz = erzeugeTaktischesZeichen({
grundzeichen: "taktische-formation",
organisation: "feuerwehr",
name: "Täst",
skipFontRegistration: true,
});

expect(tz.toString()).toMatchInlineSnapshot(`
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
<svg color=\\"#ffffff\\" fill=\\"transparent\\" stroke=\\"black\\" stroke-width=\\"2\\" viewBox=\\"0 0 75 45\\" xmlns=\\"http://www.w3.org/2000/svg\\"><defs><clipPath id=\\"tz_taktische-formation\\"><path d=\\"M1,1 H74 V44 H1 Z\\" /></clipPath></defs><path d=\\"M1,1 H74 V44 H1 Z\\" fill=\\"#cc0000\\" /><g clip-path=\\"url(#tz_taktische-formation)\\"><g transform=\\"translate(3,3) scale(0.27906976744186046)\\"><text fill=\\"currentColor\\" stroke=\\"none\\" style=\\"font-family:Roboto Slab;font-size:30px;font-weight:bold;letter-spacing:-1px\\" x=\\"0\\" y=\\"21.5\\"><![CDATA[Täst]]></text></g></g></svg>"
`);
});

it("should render a data URL with UTF-8 text", () => {
const tz = erzeugeTaktischesZeichen({
grundzeichen: "taktische-formation",
organisation: "feuerwehr",
name: "Täst",
skipFontRegistration: true,
});

expect(tz.dataUrl).toMatchInlineSnapshot(
`"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjb2xvcj0iI2ZmZmZmZiIgZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0iYmxhY2siIHN0cm9rZS13aWR0aD0iMiIgdmlld0JveD0iMCAwIDc1IDQ1IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxjbGlwUGF0aCBpZD0idHpfdGFrdGlzY2hlLWZvcm1hdGlvbiI+PHBhdGggZD0iTTEsMSBINzQgVjQ0IEgxIFoiIC8+PC9jbGlwUGF0aD48L2RlZnM+PHBhdGggZD0iTTEsMSBINzQgVjQ0IEgxIFoiIGZpbGw9IiNjYzAwMDAiIC8+PGcgY2xpcC1wYXRoPSJ1cmwoI3R6X3Rha3Rpc2NoZS1mb3JtYXRpb24pIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgzLDMpIHNjYWxlKDAuMjc5MDY5NzY3NDQxODYwNDYpIj48dGV4dCBmaWxsPSJjdXJyZW50Q29sb3IiIHN0cm9rZT0ibm9uZSIgc3R5bGU9ImZvbnQtZmFtaWx5OlJvYm90byBTbGFiO2ZvbnQtc2l6ZTozMHB4O2ZvbnQtd2VpZ2h0OmJvbGQ7bGV0dGVyLXNwYWNpbmc6LTFweCIgeD0iMCIgeT0iMjEuNSI+PCFbQ0RBVEFbVMOkc3RdXT48L3RleHQ+PC9nPjwvZz48L3N2Zz4="`
);
});
});
19 changes: 13 additions & 6 deletions packages/core/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { SVG, Element } from "./svg";
import { fromByteArray } from "base64-js";
import { Element, SVG } from "./svg";
import type { Image, Padding, Point, Rect, Renderable } from "./types";

export type Parent = {
Expand Down Expand Up @@ -26,18 +27,24 @@ export class ImageImpl implements Image {
constructor(public readonly svg: SVG, public readonly size: Point) {}

get dataUrl() {
const data =
typeof window !== "undefined"
? btoa(this.toString())
: Buffer.from(this.toString()).toString("base64");
return `data:image/svg+xml;base64,${data}`;
return `data:image/svg+xml;base64,${toBase64(this.toString())}`;
}

toString() {
return this.svg.render();
}
}

function toBase64(string: string): string {
if (typeof Buffer !== "undefined") {
console.log("using Buffer to encode base64:", string);
return Buffer.from(string).toString("base64");
}

console.log("using Array to encode base64:", string);
return fromByteArray(new TextEncoder().encode(string));
}

export type Alignment = "center" | "start" | "end";

export type PlacedComponent = {
Expand Down

0 comments on commit fa28291

Please sign in to comment.