-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcompress_zopfli.html
95 lines (95 loc) · 2.89 KB
/
compress_zopfli.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Compress with Zopfli</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
html{height:100%;font:4vmin monospace;background:#222;color:#eee}
body{min-height:100%;padding:1rem;display:grid;place-items:center}
main{text-align:center}
body.dragover::before{
content:'';
position:absolute;
inset:1rem;
background:rgba(200,200,200,.1);
border:2px solid rgba(200,200,200,.25);
}
main a{color:#adf}
main:not(:empty){font-size:67%}
main.ready:not(.busy):empty::before{
content:'Drag a file here';
font-style:italic;
opacity:.5;
}
main.busy::before{
content:'';
display:inline-block;
width:2rem;height:2rem;
border-radius:50%;
border:.1rem solid rgba(200,200,200,.5);
border-top-color:rgb(200,200,200);
animation:spin 1s ease-in-out infinite;
will-change:transform;
}
@keyframes spin{
to{transform:rotate(360deg)}
}
</style>
</head>
<body>
<main></main>
</body>
<script type="module">
import {zopfli,gunzip} from './zopfli_worker.mjs';
const main=document.querySelector('main');
main.classList.add('ready');
['dragenter','dragover','dragleave','drop'].forEach(it=>{
window.addEventListener(it,e=>{
e.preventDefault();e.stopPropagation();document.body.classList.remove('dragover');
},false);
});
const dragListener=e=>{
e.dataTransfer.dropEffect='copy';
document.body.classList.add('dragover');
};
window.addEventListener('dragover',dragListener,false);
const read=file=>new Promise(r=>{
const reader=new FileReader();
reader.onloadend=()=>r(new Uint8Array(reader.result));
reader.readAsArrayBuffer(file);
});
const dropListener=async e=>{
main.textContent='';
main.classList.add('busy');
window.removeEventListener('dragover',dragListener);
window.removeEventListener('drop',dropListener);
const file=e.dataTransfer.files.item(0);
console.log(file.size);
const uncompressed=await read(file);
const hash=new Uint8Array(await crypto.subtle.digest('SHA-256',uncompressed));
const compressed=await zopfli(uncompressed,10);
const decompressed=await gunzip(compressed);
new Uint8Array(await crypto.subtle.digest('SHA-256',decompressed)).forEach((it,i)=>{
if(it!==hash[i]) throw new Error('Verification failed.');
});
const blob=new Blob([compressed],{type:'octet/stream'});
const url=await new Promise((resolve,reject)=>{
const reader=new FileReader();
reader.addEventListener('load',e=>resolve(e.target.result));
reader.addEventListener('error',reject);
reader.readAsDataURL(blob);
});
const a=document.createElement('a');
a.download=`${file.name}.gz`;
a.href=url;
a.innerHTML=`${file.name}.gz`;
main.classList.remove('busy');
main.appendChild(a);
main.innerHTML+=`<br>(${compressed.byteLength} B)`;
window.addEventListener('dragover',dragListener,false);
window.addEventListener('drop',dropListener,false);
};
window.addEventListener('drop',dropListener,false);
</script>
</html>