- T5 待实现:WebP / PNG 导出,模板保存与加载
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 导出 {{ size.width }}×{{ size.height }}px 全分辨率(预览缩放不影响),
+ 下载为 {{ exportTarget }}。
+
+
+
+ ⚠ {{ exportError }}
+
+
+
+
+
+
+ {{ templateMsg }}
+
+
+ ⚠ 该模板用了本机字体:{{ missingFontsNow.join("、") }}。当前机器没有这些字体,
+ 会退回系统字体显示,文字排版可能对不上。
+
+
+ 已存模板({{ templates.length }})
+
+
+ 还没有模板。调好一张封面后点上面的「保存」,之后就能一键加载复用。
+
+
+
diff --git a/src/io/export.ts b/src/io/export.ts
new file mode 100644
index 0000000..36bae59
--- /dev/null
+++ b/src/io/export.ts
@@ -0,0 +1,88 @@
+import type { CanvasSize, ExportFormat, ExportOptions } from "@/types";
+
+/**
+ * 【T5】导出:WebP(默认,带质量)/ PNG(无损),走浏览器下载到下载文件夹。
+ * **不上传图床、不写 frontmatter**——这两条明确不做。
+ */
+
+/**
+ * 传给 fabric `canvas.toBlob()` 的参数。
+ *
+ * `multiplier` 恒为 1:画布 backstore 始终是逻辑尺寸(导出像素,如 1200×630),
+ * `useEditor().displayScale` / `fitTo()` 只改 CSS 尺寸。所以 `toBlob` 默认就已经
+ * 是全分辨率,**不要再乘一次 1/displayScale 去“补偿”预览缩放**,那会导出成两倍大小。
+ */
+export interface ExportRequest {
+ format: ExportFormat;
+ multiplier: number;
+ /** 0–1,只对 webp 生效。 */
+ quality?: number;
+ /** 导出像素尺寸 = 画布逻辑尺寸;只作展示/自检用,不进 toBlob。 */
+ width: number;
+ height: number;
+}
+
+function clampQuality(q: number): number {
+ if (!Number.isFinite(q)) return 0.85;
+ return Math.min(1, Math.max(0, q));
+}
+
+/** 纯函数:把画布逻辑尺寸 + 面板选项解析成该传给 `toDataURL`/`toBlob` 的参数。 */
+export function resolveExportRequest(
+ size: CanvasSize,
+ options: Pick