PDFIX / compress.html
Talha912's picture
Create compress.html
ed58949 verified
Raw History Blame Contribute Delete
17.1 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#f7f8ff" />
<meta name="description" content="Try reducing your PDF file size with PDFix. Process your document locally in your browser." />
<title>Compress PDF — PDFix</title>
<style>
:root{--bg:#f7f8ff;--ink:#17182d;--muted:#71738a;--line:#e7e8f2;--primary:#635bff;--primary-dark:#4c43e8;--green:#119b82;--danger:#d94765;--shadow:0 18px 55px rgba(47,43,112,.09)}
*{box-sizing:border-box}body{margin:0;min-height:100vh;color:var(--ink);font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;line-height:1.5;background:radial-gradient(circle at 85% 5%,rgba(177,171,255,.19),transparent 25rem),radial-gradient(circle at 4% 35%,rgba(115,221,211,.12),transparent 22rem),var(--bg)}
a{color:inherit;text-decoration:none}button,input,select{font:inherit}button{cursor:pointer}.container{width:min(1040px,calc(100% - 32px));margin:0 auto}
header{padding:20px 0}.nav{display:flex;align-items:center;justify-content:space-between;gap:18px}.brand{display:inline-flex;align-items:center;gap:10px;font-size:1.4rem;font-weight:850;letter-spacing:-1px}.brand-mark{width:39px;height:39px;display:grid;place-items:center;border-radius:13px;color:#fff;background:linear-gradient(145deg,#766dff,#4c43e8);box-shadow:0 8px 20px rgba(99,91,255,.25)}.brand-mark svg{width:23px;height:23px}.brand-name span{color:var(--primary)}.back-link{color:#65677d;font-weight:650;font-size:.92rem}.back-link:hover{color:var(--primary)}
main{padding:42px 0 70px}.intro{text-align:center;max-width:720px;margin:0 auto 28px}.eyebrow{display:inline-flex;gap:8px;align-items:center;padding:7px 12px;border:1px solid #e4e1ff;border-radius:99px;background:rgba(255,255,255,.8);color:#5a52e9;font-size:.82rem;font-weight:750}
h1{margin:18px 0 12px;font-size:clamp(2.4rem,5vw,4rem);line-height:1.06;letter-spacing:-2.7px}h1 span{color:var(--primary)}.intro p{margin:0;color:var(--muted);font-size:1.05rem}
.workspace{max-width:820px;margin:0 auto;border:1px solid rgba(99,91,255,.14);border-radius:24px;padding:12px;background:rgba(255,255,255,.9);box-shadow:var(--shadow)}
.dropzone{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:210px;padding:26px 18px;text-align:center;border:2px dashed #cbc8ff;border-radius:17px;background:linear-gradient(135deg,rgba(238,237,255,.72),rgba(239,253,251,.5));transition:.2s ease}.dropzone.dragover{border-color:var(--primary);background:#efedff;transform:scale(.995)}
.upload-icon{width:54px;height:54px;display:grid;place-items:center;margin-bottom:13px;border-radius:17px;color:var(--primary);background:#fff;box-shadow:0 7px 18px rgba(71,64,160,.1)}.upload-icon svg{width:28px;height:28px}.dropzone strong{font-size:1.1rem}.dropzone p{margin:5px 0 16px;color:var(--muted);font-size:.9rem}
.btn{border:0;display:inline-flex;align-items:center;justify-content:center;gap:9px;padding:12px 18px;border-radius:13px;font-weight:750;transition:.2s ease}.btn-primary{color:#fff;background:var(--primary);box-shadow:0 8px 18px rgba(99,91,255,.22)}.btn-primary:hover:not(:disabled){background:var(--primary-dark);transform:translateY(-1px)}.btn-light{color:#4b4d64;background:#fff;border:1px solid var(--line)}.btn-light:hover{border-color:#c9c5ff;color:var(--primary)}button:disabled{opacity:.5;cursor:not-allowed;box-shadow:none}input[type=file]{display:none}
.file-panel{display:none;padding:22px 10px 8px}.file-panel.visible{display:block}.file-row{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:12px;padding:13px;border:1px solid var(--line);border-radius:14px;background:#fff}.file-icon{width:42px;height:46px;display:grid;place-items:center;border-radius:11px;color:#e6536a;background:#fff0f2}.file-icon svg{width:23px;height:23px}.file-meta{min-width:0}.file-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:700;font-size:.92rem}.file-size{color:var(--muted);font-size:.8rem;margin-top:3px}
.field{margin-top:18px;padding:17px;border:1px solid var(--line);border-radius:15px;background:#fff}.field-title{font-size:.95rem;font-weight:800;margin-bottom:11px}.quality-options{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}.quality-option{display:block;position:relative}.quality-option input{position:absolute;opacity:0;pointer-events:none}.quality-option span{display:block;height:100%;padding:13px;border:1px solid var(--line);border-radius:13px;cursor:pointer;transition:.2s}.quality-option input:checked+span{border-color:var(--primary);background:#f1f0ff;box-shadow:0 0 0 2px rgba(99,91,255,.08)}.quality-option b{display:block;font-size:.9rem}.quality-option small{display:block;margin-top:4px;color:var(--muted);font-size:.78rem;line-height:1.4}.field-note{color:var(--muted);font-size:.82rem;margin:12px 0 0}
.panel-actions{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;margin-top:17px}.privacy{display:flex;align-items:center;gap:7px;color:var(--muted);font-size:.82rem}.privacy svg{width:17px;height:17px;color:var(--green);flex-shrink:0}
.status{display:none;margin-top:17px;padding:13px 15px;border-radius:12px;font-size:.9rem}.status.show{display:block}.status.info{background:#efedff;color:#4c43c9}.status.success{background:#e6fbf3;color:#087d68}.status.warning{background:#fff7df;color:#885e00}.status.error{background:#fff0f2;color:#b52b49}
.result{display:none;margin-top:16px;padding:17px;border:1px solid #c9f0e2;border-radius:15px;background:#f0fcf7}.result.visible{display:block}.result-top{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}.result h2{font-size:1rem;margin:0 0 4px}.result p{margin:0;color:#47796e;font-size:.85rem}.savings{font-size:1.2rem;font-weight:850;color:#087d68}
.tips{display:grid;grid-template-columns:repeat(3,1fr);gap:15px;max-width:820px;margin:24px auto 0}.tip{padding:18px;border:1px solid var(--line);border-radius:17px;background:rgba(255,255,255,.72)}.tip b{display:block;margin-bottom:5px;font-size:.92rem}.tip p{margin:0;color:var(--muted);font-size:.84rem}
footer{border-top:1px solid var(--line);padding:24px 0;color:var(--muted);font-size:.85rem}.footer-inner{display:flex;justify-content:space-between;align-items:center;gap:14px;flex-wrap:wrap}.toast{position:fixed;left:50%;bottom:22px;transform:translate(-50%,18px);opacity:0;pointer-events:none;padding:12px 17px;border-radius:13px;background:#20213a;color:#fff;box-shadow:var(--shadow);z-index:10;transition:.22s ease;max-width:calc(100% - 28px);text-align:center;font-size:.9rem}.toast.show{opacity:1;transform:translate(-50%,0)}
@media(max-width:650px){main{padding-top:30px}h1{letter-spacing:-1.8px}.tips{grid-template-columns:1fr}.quality-options{grid-template-columns:1fr}.panel-actions{align-items:stretch;flex-direction:column}.panel-actions .btn{width:100%}.file-row{grid-template-columns:auto minmax(0,1fr)}}
</style>
</head>
<body>
<header><div class="container nav">
<a class="brand" href="index.html" aria-label="PDFix homepage">
<span class="brand-mark"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M7 3.5h7l4 4V20a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 6 20V5A1.5 1.5 0 0 1 7.5 3.5Z" stroke="currentColor" stroke-width="1.8"/><path d="M14 3.8V8h4M8.5 12h7M8.5 15.5h7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg></span>
<span class="brand-name">PDF<span>ix</span></span>
</a>
<a class="back-link" href="index.html">← Back to all tools</a>
</div></header>
<main><div class="container">
<div class="intro">
<div class="eyebrow">✦ PDFix PDF tools</div>
<h1>Compress <span>PDF files</span></h1>
<p>Try to reduce your PDF file size before sharing or storing it. Choose a compression approach and download the processed file.</p>
</div>
<div class="workspace">
<div class="dropzone" id="dropzone" tabindex="0" role="button" aria-label="Choose or drop a PDF file">
<div class="upload-icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 16V4m0 0L7.5 8.5M12 4l4.5 4.5M5 14.5v4A1.5 1.5 0 0 0 6.5 20h11a1.5 1.5 0 0 0 1.5-1.5v-4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
<strong>Drop one PDF file here</strong><p>Select a PDF to check whether its size can be reduced.</p>
<button type="button" class="btn btn-primary" id="chooseFile">Select PDF file <span aria-hidden="true">↑</span></button>
<input id="fileInput" type="file" accept=".pdf,application/pdf" />
</div>
<div class="file-panel" id="filePanel">
<div class="file-row">
<div class="file-icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M6.5 3.5h8l4 4V20a1.5 1.5 0 0 1-1.5 1.5h-10A1.5 1.5 0 0 1 5.5 20V5A1.5 1.5 0 0 1 7 3.5Z" stroke="currentColor" stroke-width="1.7"/><path d="M14.5 3.8V8h4M8 12h8M8 15h6" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg></div>
<div class="file-meta"><div class="file-name" id="fileName">document.pdf</div><div class="file-size" id="fileSize"></div></div>
<button class="btn btn-light" id="changeFile" type="button">Change</button>
</div>
<div class="field">
<div class="field-title">Choose a processing level</div>
<div class="quality-options">
<label class="quality-option"><input type="radio" name="quality" value="light" checked><span><b>Light</b><small>Try to preserve the original document structure.</small></span></label>
<label class="quality-option"><input type="radio" name="quality" value="balanced"><span><b>Balanced</b><small>Re-save and clean up PDF objects where possible.</small></span></label>
<label class="quality-option"><input type="radio" name="quality" value="strong"><span><b>Strong attempt</b><small>Rebuild the PDF structure; results vary by file.</small></span></label>
</div>
<p class="field-note">Browser-only limitation: this version re-saves the PDF structure. It does not downsample embedded images or guarantee a smaller file. True image compression requires a more advanced PDF engine.</p>
</div>
<div class="panel-actions">
<div class="privacy"><svg viewBox="0 0 24 24" fill="none"><path d="M12 3 19 6v5c0 4.5-2.9 7.7-7 10-4.1-2.3-7-5.5-7-10V6l7-3Z" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="m9 12 2 2 4-4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg> Your PDF is processed in your browser.</div>
<button type="button" class="btn btn-primary" id="compressBtn" disabled>Process PDF <span aria-hidden="true">→</span></button>
</div>
<div class="status" id="status" role="status" aria-live="polite"></div>
<div class="result" id="result">
<div class="result-top"><div><h2>Your processed PDF is ready</h2><p id="resultDetails"></p></div><div class="savings" id="savings"></div></div>
<div style="margin-top:14px"><button type="button" class="btn btn-primary" id="downloadBtn">Download PDF ↓</button></div>
</div>
</div>
</div>
<div class="tips">
<article class="tip"><b>① Select your PDF</b><p>Choose one PDF file from your device.</p></article>
<article class="tip"><b>② Process locally</b><p>The browser re-saves the PDF without uploading it to a server.</p></article>
<article class="tip"><b>③ Check the result</b><p>Compare the original and processed sizes before using the new file.</p></article>
</div>
</div></main>
<footer><div class="container footer-inner"><a class="brand" href="index.html"><span class="brand-name">PDF<span>ix</span></span></a><span>© <span id="year"></span> PDFix · Your documents, made simple.</span></div></footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="https://unpkg.com/pdf-lib@1.17.1/dist/pdf-lib.min.js"></script>
<script>
const fileInput=document.getElementById('fileInput');
const dropzone=document.getElementById('dropzone');
const filePanel=document.getElementById('filePanel');
const compressBtn=document.getElementById('compressBtn');
const statusBox=document.getElementById('status');
const resultBox=document.getElementById('result');
const toast=document.getElementById('toast');
let selectedFile=null, outputBlob=null, outputName='pdfix-compressed.pdf', toastTimer;
document.getElementById('year').textContent=new Date().getFullYear();
function showToast(message){toast.textContent=message;toast.classList.add('show');clearTimeout(toastTimer);toastTimer=setTimeout(()=>toast.classList.remove('show'),3000)}
function setStatus(message,type='info'){statusBox.textContent=message;statusBox.className=`status show ${type}`}
function formatSize(bytes){if(bytes<1024)return `${bytes} B`;if(bytes<1024*1024)return `${(bytes/1024).toFixed(1)} KB`;return `${(bytes/(1024*1024)).toFixed(2)} MB`}
function choosePdf(files){
const file=Array.from(files||[]).find(f=>f.name.toLowerCase().endsWith('.pdf')||f.type==='application/pdf');
if(!file){showToast('Please select a PDF file.');return}
selectedFile=file;outputBlob=null;resultBox.classList.remove('visible');
document.getElementById('fileName').textContent=file.name;document.getElementById('fileName').title=file.name;
document.getElementById('fileSize').textContent=`Original size: ${formatSize(file.size)}`;
filePanel.style.display='block';filePanel.classList.add('visible');compressBtn.disabled=false;
statusBox.className='status';fileInput.value='';
}
document.getElementById('chooseFile').addEventListener('click',e=>{e.stopPropagation();fileInput.click()});
document.getElementById('changeFile').addEventListener('click',()=>fileInput.click());
dropzone.addEventListener('click',e=>{if(!e.target.closest('button'))fileInput.click()});
dropzone.addEventListener('keydown',e=>{if(e.key==='Enter'||e.key===' '){e.preventDefault();fileInput.click()}});
fileInput.addEventListener('change',()=>choosePdf(fileInput.files));
['dragenter','dragover'].forEach(type=>dropzone.addEventListener(type,e=>{e.preventDefault();dropzone.classList.add('dragover')}));
['dragleave','drop'].forEach(type=>dropzone.addEventListener(type,e=>{e.preventDefault();dropzone.classList.remove('dragover')}));
dropzone.addEventListener('drop',e=>choosePdf(e.dataTransfer.files));
compressBtn.addEventListener('click',async()=>{
if(!selectedFile)return;
if(!window.PDFLib){setStatus('The PDF library could not load. Check your internet connection and reload this page.','error');return}
const originalLabel=compressBtn.innerHTML;compressBtn.disabled=true;compressBtn.textContent='Processing…';resultBox.classList.remove('visible');
try{
setStatus('Reading and re-saving your PDF…','info');
const {PDFDocument}=window.PDFLib;
const level=document.querySelector('input[name="quality"]:checked').value;
const source=await PDFDocument.load(await selectedFile.arrayBuffer());
const saveOptions={useObjectStreams:level!=='light'};
const bytes=await source.save(saveOptions);
outputBlob=new Blob([bytes],{type:'application/pdf'});
outputName=selectedFile.name.replace(/\.pdf$/i,'')+'-compressed.pdf';
const before=selectedFile.size,after=outputBlob.size;
const delta=before-after;
document.getElementById('resultDetails').textContent=`Original: ${formatSize(before)} · Processed: ${formatSize(after)}`;
const savings=document.getElementById('savings');
if(delta>0){savings.textContent=`${((delta/before)*100).toFixed(1)}% smaller`;setStatus('Processing complete. Compare the sizes below; this method may not compress every PDF.','success')}
else if(delta<0){savings.textContent='Size increased';setStatus('The PDF was re-saved, but its file size increased. This browser-only method cannot compress all PDFs. You can still download it or try another level.','warning')}
else{savings.textContent='Same size';setStatus('The PDF was re-saved but the file size stayed about the same. Stronger compression may require image optimization or a backend engine.','warning')}
resultBox.classList.add('visible');
}catch(error){
console.error(error);
setStatus('Could not process this PDF. It may be damaged, password-protected, or use unsupported features.','error');
}finally{compressBtn.disabled=!selectedFile;compressBtn.innerHTML=originalLabel}
});
document.getElementById('downloadBtn').addEventListener('click',()=>{
if(!outputBlob)return;
const url=URL.createObjectURL(outputBlob);const link=document.createElement('a');link.href=url;link.download=outputName;document.body.appendChild(link);link.click();link.remove();setTimeout(()=>URL.revokeObjectURL(url),1500);
});
</script>
</body>
</html>