🎞️ GIF 帧提取工具 · 本地优先版

自动加载 /dist 目录库文件 | 手动上传后备 | 完全离线可用

📚 核心库加载(自动加载 /dist 文件夹,也可手动上传)
🔧 gifuct-js 未加载
📥 下载库文件 📁 放置于 /dist/ 目录可自动加载
📦 JSZip 未加载
📥 下载库文件 📁 放置于 /dist/ 目录可自动加载
✨ 提示:优先尝试从网站 /dist 文件夹自动加载库文件,若失败请手动上传。完全本地处理,无隐私风险。
等待核心库加载完成…
请确保 gifuct-js 和 JSZip 库已就绪(自动或手动)
🛡️ 安全校验:GIF文件头 + 内容解析 未选择文件
`; } function showHtmlModal() { const code = generateHtmlWithFrames(); if (!code) return alert('无帧数据'); htmlCodeBlock.textContent = code; modal.style.display = 'flex'; } function resetUI() { framesData = []; framesGrid.innerHTML = ''; actionButtons.style.display = 'none'; fileInfoSpan.innerText = '未选择文件'; currentGifName = ''; } async function processGif(file) { if (!libsReady) { alert('核心库未就绪,请等待库加载完成或手动上传'); return; } try { resetUI(); loadingIndicator.style.display = 'block'; validateFileSecurity(file); await validateGifHeader(file); fileInfoSpan.innerText = `📁 ${file.name} 安全校验通过,解析中...`; currentGifName = file.name; const frames = await extractGifFrames(file); framesData = frames; renderFrames(framesData); actionButtons.style.display = 'flex'; fileInfoSpan.innerHTML = `✅ 成功 | ${framesData.length} 帧 | ${file.name}`; } catch (err) { fileInfoSpan.innerHTML = `❌ ${err.message}`; framesGrid.innerHTML = `
${err.message}
`; actionButtons.style.display = 'none'; framesData = []; } finally { loadingIndicator.style.display = 'none'; } } function bindEvents() { uploadZone.addEventListener('click', () => { if (libsReady) gifInput.click(); }); gifInput.addEventListener('change', (e) => { if (e.target.files[0] && libsReady) processGif(e.target.files[0]); gifInput.value = ''; }); uploadZone.addEventListener('dragover', (e) => { e.preventDefault(); if(libsReady) uploadZone.style.borderColor='#1f6e8c'; }); uploadZone.addEventListener('dragleave', () => { uploadZone.style.borderColor='#cbd5e1'; }); uploadZone.addEventListener('drop', (e) => { e.preventDefault(); uploadZone.style.borderColor='#cbd5e1'; if(!libsReady) return alert('库未就绪'); const file = e.dataTransfer.files[0]; if(file && file.type === 'image/gif') processGif(file); else alert('请拖入GIF文件'); }); downloadAllBtn.addEventListener('click', downloadAllFramesAsZip); generateHtmlBtn.addEventListener('click', showHtmlModal); clearBtn.addEventListener('click', resetUI); closeModalSpan.addEventListener('click', () => modal.style.display = 'none'); window.addEventListener('click', (e) => { if (e.target === modal) modal.style.display = 'none'; }); copyHtmlCodeBtn.addEventListener('click', async () => { const txt = htmlCodeBlock.textContent; if(txt) { await navigator.clipboard.writeText(txt); alert('已复制HTML代码'); } else alert('无内容'); }); } // 初始化:先尝试自动加载 /dist 目录库,同时绑定事件 (async function init() { bindEvents(); await autoLoadFromDist(); if (!gifuctLoaded || !jszipLoaded) { showManualMsg('部分库自动加载失败,请手动上传对应文件', 'warning'); } updateLibUI(); })();