Files
wordcloud/frontend/src/lib/designPreview.ts
T

65 lines
2.4 KiB
TypeScript

import type { CanvasDocument, StickerAsset } from '../types';
import { serializeDocument } from './svgExport';
const PNG_TYPE = 'image/png';
/**
* Render the full visible canvas document to a PNG Blob. WebKit returns the
* Blob directly from toBlob; the standard-track callback form and the
* data-URL fallback keep other browsers working.
*/
export async function createDesignPreviewBlob(
document: CanvasDocument,
stickers: Map<string, StickerAsset>,
): Promise<Blob> {
const width = Math.max(1, Math.floor(document.width || 0));
const height = Math.max(1, Math.floor(document.height || 0));
const svgMarkup = await serializeDocument(document, stickers, { includeBackground: true });
const svgBlob = new Blob([svgMarkup], { type: 'image/svg+xml;charset=utf-8' });
const objectUrl = URL.createObjectURL(svgBlob);
try {
const image: HTMLImageElement =
typeof Image === 'function' ? new Image() : globalThis.document.createElement('img');
image.src = objectUrl;
await image.decode();
const canvas = globalThis.document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
if (!ctx) throw new Error('设计预览画布上下文不可用');
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
const pngBlob = await canvasToPngBlob(canvas);
if (pngBlob.type !== PNG_TYPE || pngBlob.size === 0) {
throw new Error('设计预览未生成有效的 PNG 输出');
}
return pngBlob;
} finally {
URL.revokeObjectURL(objectUrl);
}
}
async function canvasToPngBlob(canvas: HTMLCanvasElement): Promise<Blob> {
if (typeof canvas.toBlob === 'function') {
try {
const direct = (canvas.toBlob as unknown as (type: string) => Blob | undefined)('image/png');
if (direct) return direct;
} catch {
// Non-WebKit browsers wait for the callback form below.
}
return new Promise<Blob>((resolve, reject) => {
canvas.toBlob(blob => {
if (blob) resolve(blob);
else reject(new Error('设计预览画布未生成 PNG Blob'));
}, 'image/png');
});
}
if (typeof canvas.toDataURL === 'function') {
const res = await fetch(canvas.toDataURL('image/png'));
if (!res.ok) throw new Error('设计预览 PNG 输出读取失败');
return res.blob();
}
throw new Error('当前浏览器不支持设计预览 PNG 输出');
}