UNPKG

@fdm-monster/server

Version:

FDM Monster is a bulk OctoPrint, Klipper, PrusaLink and BambuLab manager to set up, configure and monitor 3D printers. Our aim is to provide neat overview over your farm.

122 lines (121 loc) 3.01 kB
//#region src/utils/bgcode/qoi-decoder.ts const QOI_OP_INDEX = 0; const QOI_OP_DIFF = 64; const QOI_OP_LUMA = 128; const QOI_OP_RUN = 192; const QOI_OP_RGB = 254; const QOI_OP_RGBA = 255; const QOI_MAGIC = 1903126886; function hashColor(r, g, b, a) { return (r * 3 + g * 5 + b * 7 + a * 11) % 64; } function decodeQOI(buffer) { let pos = 0; if (buffer.length < 14) throw new Error("Invalid QOI file: too short"); const magic = buffer.readUInt32BE(pos); pos += 4; if (magic !== QOI_MAGIC) throw new Error(`Invalid QOI magic: expected ${QOI_MAGIC.toString(16)}, got ${magic.toString(16)}`); const width = buffer.readUInt32BE(pos); pos += 4; const height = buffer.readUInt32BE(pos); pos += 4; const channels = buffer.readUInt8(pos); pos += 1; const colorspace = buffer.readUInt8(pos); pos += 1; if (channels !== 3 && channels !== 4) throw new Error(`Invalid QOI channels: ${channels}`); const outputSize = width * height * 4; const output = Buffer.alloc(outputSize); const colorArray = new Array(64); for (let i = 0; i < 64; i++) colorArray[i] = [ 0, 0, 0, 0 ]; let r = 0; let g = 0; let b = 0; let a = 255; let outPos = 0; while (outPos < outputSize) { if (pos + 8 <= buffer.length) { let isEnd = true; for (let i = 0; i < 7; i++) if (buffer[pos + i] !== 0) { isEnd = false; break; } if (isEnd && buffer[pos + 7] === 1) break; } if (pos >= buffer.length) throw new Error("Unexpected end of QOI data"); const byte1 = buffer[pos++]; if (byte1 === QOI_OP_RGB) { r = buffer[pos++]; g = buffer[pos++]; b = buffer[pos++]; } else if (byte1 === QOI_OP_RGBA) { r = buffer[pos++]; g = buffer[pos++]; b = buffer[pos++]; a = buffer[pos++]; } else { const tag = byte1 & 192; if (tag === QOI_OP_INDEX) { const index = byte1 & 63; [r, g, b, a] = colorArray[index]; } else if (tag === QOI_OP_DIFF) { const dr = (byte1 >> 4 & 3) - 2; const dg = (byte1 >> 2 & 3) - 2; const db = (byte1 & 3) - 2; r = r + dr & 255; g = g + dg & 255; b = b + db & 255; } else if (tag === QOI_OP_LUMA) { const byte2 = buffer[pos++]; const dg = (byte1 & 63) - 32; const dr_dg = (byte2 >> 4 & 15) - 8; const db_dg = (byte2 & 15) - 8; g = g + dg & 255; r = r + dg + dr_dg & 255; b = b + dg + db_dg & 255; } else if (tag === QOI_OP_RUN) { const run = (byte1 & 63) + 1; for (let i = 0; i < run; i++) { output[outPos++] = r; output[outPos++] = g; output[outPos++] = b; output[outPos++] = a; } const hash = hashColor(r, g, b, a); colorArray[hash] = [ r, g, b, a ]; continue; } } output[outPos++] = r; output[outPos++] = g; output[outPos++] = b; output[outPos++] = a; const hash = hashColor(r, g, b, a); colorArray[hash] = [ r, g, b, a ]; } return { width, height, channels, colorspace, data: output }; } //#endregion export { decodeQOI }; //# sourceMappingURL=qoi-decoder.js.map