import type { ParticleSystem } from '../store/particleStore' import { collectSpineExportImages } from './spineConnectorClient' import { createZipArchive } from './zipArchive' import { translate } from '../i18n' function decodeBase64(value: string) { const binary = atob(value) const bytes = new Uint8Array(binary.length) for (let index = 0; index < binary.length; index++) bytes[index] = binary.charCodeAt(index) return bytes } function imagesDirectory(value: string) { const path = String(value || './images/').replace(/\\/g, '/').replace(/^\.\//, '').replace(/^\/+|\/+$/g, '') const parts = path.split('/').filter(Boolean) if (!parts.length || parts.some((part) => part === '..' || /^[a-z]+:/i.test(part))) return 'images' return parts.join('/') } function safeFileName(value: string) { const name = String(value || 'SpineParticle').replace(/\.json$/i, '').replace(/[\\/:*?"<>|]+/g, '_').replace(/^\.+/, '') return name || 'SpineParticle' } export async function buildSpineImagesArchive(input: { systems: ParticleSystem[]; imagesPath: string }) { const images = await collectSpineExportImages(input.systems) if (!images.length) throw new Error(translate('errors.noExportableImages')) const folder = imagesDirectory(input.imagesPath) const blob = createZipArchive(images.map((image) => ({ name: `${folder}/${image.path}`, data: decodeBase64(image.dataBase64), }))) return { blob, imageCount: images.length, folder } } export function downloadSpineImagesArchive(blob: Blob, exportFileName: string) { const fileName = `${safeFileName(exportFileName)}-images.zip` const url = URL.createObjectURL(blob) const anchor = document.createElement('a') anchor.href = url anchor.download = fileName anchor.style.display = 'none' document.body.appendChild(anchor) anchor.click() anchor.remove() setTimeout(() => URL.revokeObjectURL(url), 1000) return fileName }