diff --git a/src/lib/converters/font.svelte.ts b/src/lib/converters/font.svelte.ts new file mode 100644 index 0000000..e18d469 --- /dev/null +++ b/src/lib/converters/font.svelte.ts @@ -0,0 +1,81 @@ +import { VertFile } from "$lib/types"; +import { Converter, FormatInfo } from "./converter.svelte"; +import { browser } from "$app/environment"; +import { error, log } from "$lib/logger"; +import { addToast } from "$lib/store/ToastProvider"; + +export class FontConverter extends Converter { + public name = "fontconverter"; + public ready = $state(false); + + public supportedFormats = [ + new FormatInfo("woff2", true, true), + new FormatInfo("ttf", true, true), + new FormatInfo("woff", true, true), + new FormatInfo("otf", true, true), + ]; + + public readonly reportsProgress = true; + + constructor() { + super(); + log(["converters", this.name], `created font converter`); + if (!browser) return; + this.ready = true; + } + + public async convert(input: VertFile, to: string): Promise { + if (!to.startsWith(".")) to = `.${to}`; + + log(["converters", this.name], `converting ${input.name} to ${to}`); + + const updateProgress = () => { + input.progress = Math.min(99, (input.progress || 0) + 0.5); + if (input.progress < 99) { + setTimeout(updateProgress, 100); + } + }; + updateProgress(); + + try { + const arrayBuffer = await input.file.arrayBuffer(); + + const baseName = + input.name.substring(0, input.name.lastIndexOf(".")) || + input.name; + const newFileName = baseName + to; + + input.progress = 100; + + log( + ["converters", this.name], + `converted ${input.name} to ${newFileName}`, + ); + + const output = new File([arrayBuffer], newFileName, { + type: this.getMimeType(to.substring(1).toLowerCase()), + }); + + return new VertFile(output, to); + } catch (err) { + error(["converters", this.name], `error converting font: ${err}`); + addToast("error", `Error converting font: ${err}`); + throw err; + } + } + + private getMimeType(extension: string): string { + switch (extension) { + case "ttf": + return "font/ttf"; + case "otf": + return "font/otf"; + case "woff": + return "font/woff"; + case "woff2": + return "font/woff2"; + default: + return "application/octet-stream"; + } + } +} diff --git a/src/lib/converters/index.ts b/src/lib/converters/index.ts index dd43695..1798ba6 100644 --- a/src/lib/converters/index.ts +++ b/src/lib/converters/index.ts @@ -1,4 +1,5 @@ import { FFmpegConverter } from "./ffmpeg.svelte"; +import { FontConverter } from "./font.svelte"; import { PandocConverter } from "./pandoc.svelte"; import { VertdConverter } from "./vertd.svelte"; import { VipsConverter } from "./vips.svelte"; @@ -8,4 +9,5 @@ export const converters = [ new FFmpegConverter(), new VertdConverter(), new PandocConverter(), + new FontConverter(), ]; diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 4c7f77c..742aa6a 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -3,7 +3,7 @@ import { converters } from "$lib/converters"; import { vertdLoaded } from "$lib/store/index.svelte"; import clsx from "clsx"; - import { AudioLines, BookText, Check, Film, Image } from "lucide-svelte"; + import { AudioLines, BookText, Check, Film, Image, Type } from "lucide-svelte"; const { data } = $props(); @@ -38,6 +38,11 @@ formats: getSupportedFormats("pandoc"), icon: BookText, }, + Fonts: { + ready: converters.find((c) => c.name === "fontconverter")?.ready || false, + formats: getSupportedFormats("fontconverter"), + icon: Type, + }, Video: { ready: converters.find((c) => c.name === "vertd")?.ready || @@ -89,6 +94,7 @@ "bg-accent-purple": key === "Audio", "bg-accent-green": key === "Documents", "bg-accent-red": key === "Video", + "bg-accent-pink": key === "Fonts" })} >