Skip to content

Instantly share code, notes, and snippets.

@Daft-Freak
Created December 23, 2020 17:02
Show Gist options
  • Save Daft-Freak/81dcbf76f6ee8f37339c5efc42ae6b4c to your computer and use it in GitHub Desktop.
Save Daft-Freak/81dcbf76f6ee8f37339c5efc42ae6b4c to your computer and use it in GitHub Desktop.
function unpackImage(buf) {
const bytes = new Uint8Array(buf);
const byteCount = new Uint32Array(buf.slice(8, 12))[0];
const width = bytes[12] | (bytes[13] << 8);
const height = bytes[14] | (bytes[15] << 8);
const format = bytes[16];
const paletteEntryCount = bytes[17];
if(format != 2) // palette
return null;
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
const imageData = ctx.createImageData(width, height);
const palette = bytes.slice(18, 18 + paletteEntryCount * 4);
if(bytes[6] == 0x50 && bytes[7] == 0x4B) { // "PK"
const bitDepth = Math.ceil(Math.log2(paletteEntryCount));
let outOff = 0;
let offset = 18 + paletteEntryCount * 4;
let col = 0, bit = 0;
for(; offset < byteCount; offset++) {
for(let b = 0; b < 8; b++) {
col <<= 1;
col |= (bytes[offset] >> (7 - b)) & 1;
if(++bit == bitDepth) {
imageData.data[outOff++] = palette[col * 4 + 0];
imageData.data[outOff++] = palette[col * 4 + 1];
imageData.data[outOff++] = palette[col * 4 + 2];
imageData.data[outOff++] = palette[col * 4 + 3];
bit = 0; col = 0;
}
}
}
} else if(bytes[6] == 0x52 && bytes[7] == 0x4C) { // "RL"
const bitDepth = Math.ceil(Math.log2(paletteEntryCount));
let outOff = 0;
let offset = 18 + paletteEntryCount * 4;
let col = 0, bit = 0, count = 0;
let parseState = 0;
for(; offset < byteCount; offset++) {
for(let b = 0; b < 8; b++) {
switch(parseState) {
case 0: // flag
if(bytes[offset] & (0x80 >> b))
parseState = 1;
else
parseState = 2;
break;
case 1: // repeat count
count <<= 1;
count |= (bytes[offset] >> (7 - b)) & 1;
if(++bit == 8) {
parseState = 2;
bit = 0;
}
break;
case 2: // value
col <<= 1;
col |= (bytes[offset] >> (7 - b)) & 1;
if(++bit == bitDepth) {
for(let c = 0; c <= count; c++) {
imageData.data[outOff++] = palette[col * 4 + 0];
imageData.data[outOff++] = palette[col * 4 + 1];
imageData.data[outOff++] = palette[col * 4 + 2];
imageData.data[outOff++] = palette[col * 4 + 3];
}
bit = 0; col = 0; count = 0; parseState = 0;
}
break;
}
}
}
// else RW
} else
return null;
ctx.putImageData(imageData, 0, 0);
return canvas.toDataURL();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment