mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-19 02:48:12 +08:00
Break apart and improve the JS for rasterizing SVGs and downloading files (#786)
It now uses a blob URL instead of a data URL in the download process, which is cleaner and better performance.
This commit is contained in:
@@ -1,23 +1,27 @@
|
||||
export function downloadBlob(url: string, filename: string): void {
|
||||
export function downloadFileURL(filename: string, url: string): void {
|
||||
const element = document.createElement("a");
|
||||
|
||||
element.href = url;
|
||||
element.setAttribute("download", filename);
|
||||
element.style.display = "none";
|
||||
|
||||
element.click();
|
||||
}
|
||||
|
||||
export function download(filename: string, fileData: string): void {
|
||||
const type = filename.endsWith(".svg") ? "image/svg+xml;charset=utf-8" : "text/plain;charset=utf-8";
|
||||
const blob = new Blob([fileData], { type });
|
||||
export function downloadFileBlob(filename: string, blob: Blob): void {
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
downloadBlob(url, filename);
|
||||
downloadFileURL(filename, url);
|
||||
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
export function downloadFileText(filename: string, text: string): void {
|
||||
const type = filename.endsWith(".svg") ? "image/svg+xml;charset=utf-8" : "text/plain;charset=utf-8";
|
||||
|
||||
const blob = new Blob([text], { type });
|
||||
downloadFileBlob(filename, blob);
|
||||
}
|
||||
|
||||
export async function upload<T extends "text" | "data">(acceptedExtensions: string, textOrData: T): Promise<UploadResult<T>> {
|
||||
return new Promise<UploadResult<T>>((resolve, _) => {
|
||||
const element = document.createElement("input");
|
||||
|
||||
44
frontend/src/utility-functions/rasterization.ts
Normal file
44
frontend/src/utility-functions/rasterization.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
// Rasterize the string of an SVG document at a given width and height and turn it into the blob data of an image file matching the given MIME type
|
||||
export function rasterizeSVG(svg: string, width: number, height: number, mime: string, backgroundColor?: string): Promise<Blob> {
|
||||
let promiseResolve: (value: Blob | PromiseLike<Blob>) => void | undefined;
|
||||
let promiseReject: () => void | undefined;
|
||||
const promise = new Promise<Blob>((resolve, reject) => {
|
||||
promiseResolve = resolve;
|
||||
promiseReject = reject;
|
||||
});
|
||||
|
||||
// A canvas to render our svg to in order to get a raster image
|
||||
// https://stackoverflow.com/questions/3975499/convert-svg-to-image-jpeg-png-etc-in-the-browser
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
const context = canvas.getContext("2d");
|
||||
if (!context) return Promise.reject();
|
||||
|
||||
// Apply a background fill color if one is given
|
||||
if (backgroundColor) {
|
||||
context.fillStyle = backgroundColor;
|
||||
context.fillRect(0, 0, width, height);
|
||||
}
|
||||
|
||||
// Create a blob URL for our SVG
|
||||
const image = new Image();
|
||||
const svgBlob = new Blob([svg], { type: "image/svg+xml;charset=utf-8" });
|
||||
const url = URL.createObjectURL(svgBlob);
|
||||
image.onload = (): void => {
|
||||
// Draw our SVG to the canvas
|
||||
context?.drawImage(image, 0, 0, width, height);
|
||||
|
||||
// Clean up the SVG blob URL (once the URL is revoked, the SVG blob data itself is garbage collected after `svgBlob` goes out of scope)
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
// Convert the canvas to an image of the correct MIME type
|
||||
canvas.toBlob((blob) => {
|
||||
if (blob !== null) promiseResolve(blob);
|
||||
else promiseReject();
|
||||
}, mime);
|
||||
};
|
||||
image.src = url;
|
||||
|
||||
return promise;
|
||||
}
|
||||
Reference in New Issue
Block a user