65 lines
2.4 KiB
TypeScript
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 输出');
|
|
}
|