#!/usr/bin/env node const fs = require("fs") const zlib = require("zlib") function compressImg(fn) { const rgf = fs.readFileSync(fn) const width = rgf[0] const height = rgf[1] const expSz = ((width + 7) >> 3) * height + 2 console.log(`w=${width} h=${height} sz=${rgf.length} exp=${expSz}`) let crcTable function crc32(buf) { if (!crcTable) { crcTable = [] for (let i = 0; i < 256; i++) { let curr = i; for (let j = 0; j < 8; j++) { if (curr & 1) { curr = 0xedb88320 ^ (curr >>> 1); } else { curr = curr >>> 1; } } crcTable[i] = curr } } let crc = -1; for (var i = 0; i < buf.length; i++) { crc = crcTable[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8); } return (crc ^ -1) >>> 0; } /* Width 4 bytes Height 4 bytes Bit depth 1 byte Colour type 1 byte Compression method 1 byte Filter method 1 byte Interlace method 1 byte */ const chunks = [] function addChunk(mark, addsize) { const buf = Buffer.alloc(mark.length + addsize) for (let i = 0; i < mark.length; ++i) { buf[i] = mark.charCodeAt(i) } chunks.push(buf) return buf } const hd = addChunk("IHDR", 4 + 4 + 5) hd.writeInt32BE(width, 4) hd.writeInt32BE(height, 8) hd[12] = 1 // bit depth hd[13] = 0 // color type - grayscale hd[14] = 0 // compression - deflate hd[15] = 0 // filter method hd[16] = 0 // interlace method - no interlace const scanlines = [] const scanlen = (width + 7) >> 3 let srcptr = 2 let srcmask = 0x01 for (let y = 0; y < height; ++y) { const scan = Buffer.alloc(1 + scanlen) scanlines.push(scan) let dstptr = 1 let dstmask = 0x80 for (let x = 0; x < width; ++x) { if (!(rgf[srcptr] & srcmask)) { scan[dstptr] |= dstmask } dstmask >>= 1; if (dstmask == 0) { dstmask = 0x80 dstptr++ } srcmask <<= 1; if (srcmask > 0x80) { srcmask = 0x01 srcptr++ } } if (srcmask != 0x01) { srcmask = 0x01 srcptr++ } if (false) { // seems to increase file size scan[0] = 1 // sub let prev = 0 for (let i = 1; i < scan.length; ++i) { let p = scan[i] scan[i] = (p - prev) & 0xff prev = p } } } const dat = zlib.deflateSync(Buffer.concat(scanlines), { level: 9 }) const idat = addChunk("IDAT", dat.length) dat.copy(idat, 4) addChunk("IEND", 0) const output = [new Buffer([137, 80, 78, 71, 13, 10, 26, 10])] function intBuf(v) { let b = new Buffer(4) b.writeUInt32BE(v, 0) return b } for (let ch of chunks) { output.push(intBuf(ch.length - 4)) output.push(ch) output.push(intBuf(crc32(ch))) } let outp = Buffer.concat(output) return outp } let sz = 0 let bf let out = { "*": { namespace: "images", dataEncoding: "base64", mimeType: "image/png" } } let ts = "namespace images {\n" for (let i = 2; i < process.argv.length; ++i) { let fn = process.argv[i] let m = /([^\/]+\/[^/]+)\.rgf$/.exec(fn) let bn = m[1] bf = compressImg(fn) bn = bn.replace(/\//g, " ") .toLowerCase() .replace(/(\d)\s+/g, (f, n) => n) .replace(/\s+(.)/g, (f, l) => l.toUpperCase()) out[bn] = bf.toString("base64") sz += bf.length ts += ` //% fixedInstance jres\n` ts += ` export const ${bn} = screen.unpackPNG(hex\`\`);\n` } ts += `}\n` console.log("total " + sz) fs.writeFileSync("out.json", JSON.stringify(out, null, 4)) fs.writeFileSync("out.ts", ts) fs.writeFileSync("out.png", bf) //if (require("os").platform() == "darwin") // require('child_process').execSync("afplay out.wav") // TODO also play on Windows