Skip to content

Instantly share code, notes, and snippets.

@nildopontes
Last active February 27, 2025 10:31
Show Gist options
  • Save nildopontes/223899c9c2892561c9de56dc7f42bc69 to your computer and use it in GitHub Desktop.
Save nildopontes/223899c9c2892561c9de56dc7f42bc69 to your computer and use it in GitHub Desktop.
class ePNG {
constructor(data, w, h){
if(data.length != (w * h * 4)) return console.error(`Corrupted samples.`);
this.buffer = new Uint8Array(w * h * 4 + h);
for(let i = 0; i < h; i++){
this.buffer.set(data.slice(i * w * 4, (i + 1) * w * 4), i * w * 4 + 1 + i);
}
this.makeCRCTable();
this.ihdr = new Uint8Array([0, 0, 0, 13, 73, 72, 68, 82, ...this.set32bit(w), ...this.set32bit(h), 8, 6, 0, 0, 0, 0, 0, 0, 0]);
this.ihdr.set(this.getCRC32(this.ihdr.slice(4, 21)), 21);
}
set32bit(v){
return [v >> 24 & 255, v >> 16 & 255, v >> 8 & 255, v & 255];
}
makeCRCTable(){
let c, a = [];
for(let n = 0; n < 256; n++){
c = n;
for(let k = 0; k < 8; k++){
c = c & 1 ? 0xEDB88320 ^ c >>> 1 : c >>> 1;
}
a.push(c);
}
this.crcTable = a;
}
getCRC32(data){
let crc = -1;
data.map(v => crc = crc >>> 8 ^ this.crcTable[(crc ^ v) & 255]);
return this.set32bit(crc ^ -1 >>> 0);
}
compress(input){
let cs = new CompressionStream('deflate');
let writer = cs.writable.getWriter();
writer.write(input);
writer.close();
return new Response(cs.readable).bytes();
}
encode(){
return new Promise((resolve, reject) => {
this.compress(this.buffer).then(c => {
let idat = new Uint8Array([...this.set32bit(c.length), 73, 68, 65, 84, ...c, ...this.getCRC32([73, 68, 65, 84, ...c])]);
resolve(new Blob([new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]), this.ihdr, idat, new Uint8Array([0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130])], {type: "image/png"}));
});
});
}
}
/* EXEMPLO DE USO
window.addEventListener('load', e => {
let colors = [], d = [];
for(let c = 0; c < 256; c++) colors.push([parseInt(Math.random() * 255, 10), parseInt(Math.random() * 255, 10), parseInt(Math.random() * 255, 10), 255]);
for(let i = 0; i < 500; i++){
let color = parseInt(Math.random() * 255, 10);
for(let j = 0; j < 500; j++){
d.push(...colors[color]);
}
}
let t0 = Date.now();
png = new ePNG(d, 500, 500);
png.encode().then(b => {
let url = window.URL.createObjectURL(b);
document.body.innerHTML += `<br><hr><br><br><span>Tamanho: ${parseInt(b.size / 1024, 10)} KB</span><br><span>Tempo decorrido: ${Date.now() - t0} milissegundos</span><br><img src="${url}">`;
});
});
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment