NoteCardPreview - Web
%
`; preview.srcdoc = doc; } htmlInput.addEventListener('input', updatePreview); btnPaste.addEventListener('click', async()=>{ try{ const t=await navigator.clipboard.readText(); if(t){ htmlInput.value=t; updatePreview(); } }catch{} }); btnClear.addEventListener('click', ()=>{ htmlInput.value=''; updatePreview(); }); async function waitReady(){ await new Promise(r=>requestAnimationFrame(()=>requestAnimationFrame(r))); const idoc = preview.contentDocument; if(!idoc) return; try{ await Promise.race([idoc.fonts?.ready ?? Promise.resolve(), new Promise(r=>setTimeout(r,800))]); }catch{} const imgs=[...idoc.images]; await Promise.all(imgs.map(i=> i.complete&&i.naturalWidth?Promise.resolve():new Promise(res=>{i.addEventListener('load',res,{once:true});i.addEventListener('error',res,{once:true});}))); await new Promise(r=>requestAnimationFrame(()=>requestAnimationFrame(r))); } // 使用 html2canvas 直接渲染 iframe 内的内容 async function captureFullArea() { const idoc = preview.contentDocument; if(!idoc || !idoc.body) return null; if(typeof html2canvas !== 'function') return null; await waitReady(); let baseCanvas; try { const zm = parseInt(imgZEl.value||'100',10); const zf = Math.max(0.5, Math.min(5, (Number.isFinite(zm)?zm:100)/100)); const baseScale = (window.devicePixelRatio || 1) * zf; baseCanvas = await html2canvas(idoc.body, { backgroundColor: '#fff', useCORS: true, scale: Math.max(1, Math.min(5, baseScale)) }); } catch (e) { console.error('html2canvas capture failed', e); return null; } let out = baseCanvas; // 尺寸/比例调整,与原应用逻辑保持一致 try{ const wRaw = (imgWEl.value||'').trim(); const ratioRaw = (imgREl.value||'').trim(); const tW = parseInt(wRaw,10); const wantW = Number.isFinite(tW)&&tW>0; let rw=null,rh=null; const m = ratioRaw.match(/^\s*(\d+(?:\.\d+)?)\s*:\s*(\d+(?:\.\d+)?)\s*$/); if(m){ rw=parseFloat(m[1]); rh=parseFloat(m[2]); if(!(rw>0&&rh>0)){rw=rh=null;} } if(wantW && rw && rh){ const dw=tW, dh=Math.max(1, Math.round(tW*(rh/rw))); const cvs=document.createElement('canvas'); cvs.width=dw; cvs.height=dh; const c=cvs.getContext('2d',{alpha:false}); c.imageSmoothingEnabled=true; c.imageSmoothingQuality='high'; c.fillStyle='#fff'; c.fillRect(0,0,dw,dh); const s=Math.min(dw/out.width, dh/out.height); const drawW=Math.max(1,Math.round(out.width*s)); const drawH=Math.max(1,Math.round(out.height*s)); const dx=Math.floor((dw-drawW)/2), dy=Math.floor((dh-drawH)/2); c.drawImage(out,0,0,out.width,out.height,dx,dy,drawW,drawH); out = document.createElement('canvas'); out.width=cvs.width; out.height=cvs.height; out.getContext('2d').drawImage(cvs,0,0); } else if (wantW) { const dw=tW, dh=Math.max(1, Math.round(out.height*(tW/out.width))); const cvs=document.createElement('canvas'); cvs.width=dw; cvs.height=dh; cvs.getContext('2d',{alpha:false}).drawImage(out,0,0,out.width,out.height,0,0,dw,dh); out = document.createElement('canvas'); out.width=cvs.width; out.height=cvs.height; out.getContext('2d').drawImage(cvs,0,0); } else if (rw && rh) { const dw=out.width, dh=Math.max(1, Math.round(out.width*(rh/rw))); const cvs=document.createElement('canvas'); cvs.width=dw; cvs.height=dh; const c=cvs.getContext('2d',{alpha:false}); c.imageSmoothingEnabled=true; c.imageSmoothingQuality='high'; c.fillStyle='#fff'; c.fillRect(0,0,dw,dh); const s=Math.min(dw/out.width, dh/out.height); const drawW=Math.max(1,Math.round(out.width*s)); const drawH=Math.max(1,Math.round(out.height*s)); const dx=Math.floor((dw-drawW)/2), dy=Math.floor((dh-drawH)/2); c.drawImage(out,0,0,out.width,out.height,dx,dy,drawW,drawH); out = document.createElement('canvas'); out.width=cvs.width; out.height=cvs.height; out.getContext('2d').drawImage(cvs,0,0); } }catch(e){ console.error('resize failed', e); } const blob = await new Promise((res)=> out.toBlob(b=>res(b),'image/png')); return blob; } btnExport.addEventListener('click', async()=>{ if(!htmlInput.value.trim()) return; btnExport.disabled=true; btnExport.textContent='⏳ 导出中...'; const blob = await captureFullArea(); if(!blob){ alert('自动截图不可用,请检查浏览器控制台错误或尝试更换浏览器'); btnExport.disabled=false; btnExport.textContent='⚡ 一键导出(100%)'; return; } const url=URL.createObjectURL(blob); const a=document.createElement('a'); a.href=url; a.download=`html-preview-shot-${Date.now()}.png`; document.body.appendChild(a); a.click(); document.body.removeChild(a); setTimeout(()=>URL.revokeObjectURL(url),200); btnExport.disabled=false; btnExport.textContent='⚡ 一键导出(100%)'; }); updatePreview();