import { writePsd } from 'ag-psd'; import { filterSvgByColors } from './svgFilter'; async function renderSvgToCanvas(svgEl, width, height) { const serializer = new XMLSerializer(); const svgString = serializer.serializeToString(svgEl); const blob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' }); const url = URL.createObjectURL(blob); const img = new Image(); await new Promise((resolve, reject) => { img.onload = resolve; img.onerror = reject; img.src = url; }); const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, width, height); ctx.drawImage(img, 0, 0, width, height); URL.revokeObjectURL(url); return canvas; } export async function exportPSD(svgDoc, groups, uniqueColors, onProgress) { const svgEl = svgDoc.querySelector('svg'); let width, height; const vb = svgEl.getAttribute('viewBox'); if (vb) { const parts = vb.split(/[\s,]+/).map(Number); width = parts[2]; height = parts[3]; } else { width = parseFloat(svgEl.getAttribute('width')) || 512; height = parseFloat(svgEl.getAttribute('height')) || 512; } const maxDim = 4096; if (width > maxDim || height > maxDim) { const scale = maxDim / Math.max(width, height); width = Math.round(width * scale); height = Math.round(height * scale); } else { width = Math.round(width); height = Math.round(height); } const total = groups.length; const children = []; for (let gi = 0; gi < total; gi++) { onProgress?.('レイヤーをレンダリング中...', `${gi + 1} / ${total}`, Math.round((gi / (total + 1)) * 100)); await new Promise((r) => setTimeout(r, 0)); const groupColors = new Set(groups[gi].map((ci) => uniqueColors[ci].hex)); const filteredSvg = svgEl.cloneNode(true); filterSvgByColors(filteredSvg, groupColors); const canvas = await renderSvgToCanvas(filteredSvg, width, height); children.push({ name: `Group ${gi + 1} (${groups[gi].map((ci) => uniqueColors[ci].hex).join(', ')})`, canvas, transparencyProtected: false, hidden: false, opacity: 255, blendMode: 'normal', }); } onProgress?.('PSDを生成中...', '', 90); await new Promise((r) => setTimeout(r, 0)); const buffer = writePsd({ width, height, channels: 4, bitsPerChannel: 8, colorMode: 3, children }); onProgress?.('ダウンロード中...', '', 100); await new Promise((r) => setTimeout(r, 0)); const blob = new Blob([buffer], { type: 'application/octet-stream' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'color_groups.psd'; a.click(); URL.revokeObjectURL(url); }