-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
3 lines (3 loc) · 3.55 KB
/
Copy pathscript.js
File metadata and controls
3 lines (3 loc) · 3.55 KB
1
2
3
const $=id=>document.getElementById(id);const input=$('fileInput'),drop=$('dropZone'),results=$('results'),quality=$('quality'),format=$('format'),maxWidth=$('maxWidth'),suffix=$('suffix');let outputFiles=[];$('year').textContent=new Date().getFullYear();quality.oninput=()=>$('qualityText').textContent=quality.value+'%';$('pickFiles').onclick=()=>input.click();input.onchange=e=>handleFiles([...e.target.files]);['dragenter','dragover'].forEach(ev=>drop.addEventListener(ev,e=>{e.preventDefault();drop.classList.add('drag')}));['dragleave','drop'].forEach(ev=>drop.addEventListener(ev,e=>{e.preventDefault();drop.classList.remove('drag')}));drop.addEventListener('drop',e=>handleFiles([...e.dataTransfer.files].filter(f=>f.type.startsWith('image/')||/\.tiff?$/i.test(f.name))));function fmt(n){return n>1048576?(n/1048576).toFixed(2)+' MB':(n/1024).toFixed(1)+' KB'}function ext(m){return m==='image/jpeg'?'jpg':m==='image/png'?'png':m==='image/webp'?'webp':'webp'}function newName(name,m){return name.replace(/\.[^.]+$/,'')+(suffix.value||'-compressed')+'.'+ext(m)}async function handleFiles(files){for(const file of files)compress(file);}
async function compress(file){const row=document.createElement('tr');row.innerHTML=`<td class="p-4"><div class="h-14 w-14 animate-pulse rounded-xl bg-white/10"></div></td><td class="p-4 max-w-[220px] truncate">${file.name}</td><td class="p-4">${fmt(file.size)}</td><td class="p-4">Working...</td><td class="p-4">--</td><td class="p-4">--</td>`;results.prepend(row);try{const bitmap=await createImageBitmap(file);let w=bitmap.width,h=bitmap.height,mw=parseInt(maxWidth.value||'0',10);if(mw&&w>mw){h=Math.round(h*mw/w);w=mw}const canvas=document.createElement('canvas');canvas.width=w;canvas.height=h;const ctx=canvas.getContext('2d',{alpha:true});ctx.drawImage(bitmap,0,0,w,h);let mime=format.value==='same'&&['image/jpeg','image/png','image/webp'].includes(file.type)?file.type:format.value==='same'?'image/webp':format.value;let blob=await new Promise(r=>canvas.toBlob(r,mime,Number(quality.value)/100));if(!blob)throw new Error('Unsupported output');const url=URL.createObjectURL(blob),saved=Math.max(0,100-(blob.size/file.size*100));outputFiles.push({name:newName(file.name,mime),blob});row.innerHTML=`<td class="p-4"><img src="${url}" class="h-14 w-14 rounded-xl object-cover" alt="compressed preview"></td><td class="p-4 max-w-[220px] truncate">${file.name}<div class="text-xs text-slate-500">${w}×${h}</div></td><td class="p-4">${fmt(file.size)}</td><td class="p-4 font-bold text-cyan-200">${fmt(blob.size)}</td><td class="p-4 font-bold text-emerald-300">${saved.toFixed(1)}%</td><td class="p-4"><a class="rounded-xl bg-white px-4 py-2 font-bold text-ink" href="${url}" download="${newName(file.name,mime)}">Download</a></td>`;updateStats()}catch(err){row.innerHTML=`<td class="p-4">⚠️</td><td class="p-4">${file.name}</td><td class="p-4">${fmt(file.size)}</td><td class="p-4 text-red-300" colspan="3">Could not compress this image in your browser.</td>`}}
function updateStats(){const original=[...results.querySelectorAll('tr')].length;$('totalFiles').textContent=outputFiles.length;$('downloadZip').disabled=outputFiles.length===0;let saved=0,orig=0;outputFiles.forEach(f=>saved+=f.blob.size);document.querySelectorAll('tbody tr').forEach(()=>{});$('savedPercent').textContent=outputFiles.length? 'Ready':'0%'}$('downloadZip').onclick=async()=>{const zip=new JSZip();outputFiles.forEach(f=>zip.file(f.name,f.blob));const blob=await zip.generateAsync({type:'blob'});const a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='compressed-images.zip';a.click()};