import { materialContentUrl } from "@/lib/client/asset-urls"; import type { PromptMaterial } from "@/lib/prompt/assembler"; import type { SeedreamAnnotation } from "@/lib/seedream/creation"; const markerColor = "#2563eb"; export async function createSeedreamMarkedFile( source: PromptMaterial, annotations: SeedreamAnnotation[], imageIndex: number ) { const strokes = annotations.filter((annotation) => annotation.kind === "stroke" && annotation.points && annotation.points.length > 1); if (!strokes.length) return null; const response = await fetch(materialContentUrl(source), { credentials: "same-origin" }); if (!response.ok) throw new Error(`读取图${imageIndex}失败,无法合成蓝色标记`); const bitmap = await createImageBitmap(await response.blob()); try { const canvas = document.createElement("canvas"); canvas.width = bitmap.width; canvas.height = bitmap.height; const context = canvas.getContext("2d"); if (!context) throw new Error("当前浏览器无法创建标记画布"); context.drawImage(bitmap, 0, 0); context.strokeStyle = markerColor; context.fillStyle = markerColor; context.lineCap = "round"; context.lineJoin = "round"; context.lineWidth = Math.max(5, Math.round(Math.min(bitmap.width, bitmap.height) * 0.012)); for (const stroke of strokes) { const points = stroke.points || []; if (!points.length) continue; context.beginPath(); context.moveTo(points[0].x / 1000 * bitmap.width, points[0].y / 1000 * bitmap.height); for (const point of points.slice(1)) { context.lineTo(point.x / 1000 * bitmap.width, point.y / 1000 * bitmap.height); } context.stroke(); } const blob = await canvasBlob(canvas, "image/png"); return new File([blob], `seedream-marked-image-${imageIndex}.png`, { type: "image/png" }); } finally { bitmap.close(); } } function canvasBlob(canvas: HTMLCanvasElement, type: string) { return new Promise((resolve, reject) => { canvas.toBlob((blob) => { if (blob) resolve(blob); else reject(new Error("生成标记图片失败")); }, type); }); }