UNPKG

tldraw

Version:

A tiny little drawing editor.

144 lines (143 loc) 3.99 kB
import { FileHelpers, Image, PngHelpers, debugFlags, exhaustiveSwitchError, sleep, tlenv } from "@tldraw/editor"; import { clampToBrowserMaxCanvasSize } from "../../shapes/shared/getBrowserCanvasMaxSize.mjs"; async function getSvgAsImage(editor, svgString, options) { const { type, width, height, quality = 1, pixelRatio = 2 } = options; let [clampedWidth, clampedHeight] = await clampToBrowserMaxCanvasSize( width * pixelRatio, height * pixelRatio ); clampedWidth = Math.floor(clampedWidth); clampedHeight = Math.floor(clampedHeight); const effectiveScale = clampedWidth / width; const svgUrl = await FileHelpers.blobToDataUrl(new Blob([svgString], { type: "image/svg+xml" })); const canvas = await new Promise((resolve) => { const image = Image(); image.crossOrigin = "anonymous"; image.onload = async () => { if (tlenv.isSafari) { await sleep(250); } const canvas2 = document.createElement("canvas"); const ctx = canvas2.getContext("2d"); canvas2.width = clampedWidth; canvas2.height = clampedHeight; ctx.imageSmoothingEnabled = true; ctx.imageSmoothingQuality = "high"; ctx.drawImage(image, 0, 0, clampedWidth, clampedHeight); URL.revokeObjectURL(svgUrl); resolve(canvas2); }; image.onerror = () => { resolve(null); }; image.src = svgUrl; }); if (!canvas) return null; const blob = await new Promise( (resolve) => canvas.toBlob( (blob2) => { if (!blob2 || debugFlags.throwToBlob.get()) { resolve(null); } resolve(blob2); }, "image/" + type, quality ) ); if (!blob) return null; if (type === "png") { const view = new DataView(await blob.arrayBuffer()); return PngHelpers.setPhysChunk(view, effectiveScale, { type: "image/" + type }); } else { return blob; } } async function getSvgString(editor, ids, opts) { const svg = await editor.getSvgString(ids?.length ? ids : [...editor.getCurrentPageShapeIds()], { scale: opts.scale ?? 1, background: editor.getInstanceState().exportBackground, ...opts }); if (!svg) { throw new Error("Could not construct SVG."); } return svg; } async function exportToString(editor, ids, format, opts = {}) { switch (format) { case "svg": { return (await getSvgString(editor, ids, opts))?.svg; } case "json": { const data = await editor.resolveAssetsInContent(editor.getContentFromCurrentPage(ids)); return JSON.stringify(data); } default: { exhaustiveSwitchError(format); } } } async function exportToBlob({ editor, ids, format, opts = {} }) { switch (format) { case "svg": return new Blob([await exportToString(editor, ids, "svg", opts)], { type: "text/plain" }); case "json": return new Blob([await exportToString(editor, ids, "json", opts)], { type: "text/plain" }); case "jpeg": case "png": case "webp": { const svgResult = await getSvgString(editor, ids, opts); if (!svgResult) throw new Error("Could not construct image."); const image = await getSvgAsImage(editor, svgResult.svg, { type: format, quality: opts.quality, pixelRatio: opts.pixelRatio, width: svgResult.width, height: svgResult.height }); if (!image) { throw new Error("Could not construct image."); } return image; } default: { exhaustiveSwitchError(format); } } } const mimeTypeByFormat = { jpeg: "image/jpeg", png: "image/png", webp: "image/webp", json: "text/plain", svg: "text/plain" }; function exportToBlobPromise(editor, ids, format, opts = {}) { return { blobPromise: exportToBlob({ editor, ids, format, opts }), mimeType: mimeTypeByFormat[format] }; } export { exportToBlob, exportToBlobPromise, exportToString, getSvgAsImage }; //# sourceMappingURL=export.mjs.map