Files
armorpaint/base/Sources/ParserExr.ts
T
luboslenco ee67b50c0f Use ts
2024-01-17 18:53:31 +01:00

324 lines
6.0 KiB
TypeScript

// Based on miniexr.cpp - public domain - 2013 Aras Pranckevicius / Unity Technologies
// https://github.com/aras-p/miniexr
// https://www.openexr.com/documentation/openexrfilelayout.pdf
class ParserExr {
static writeString = (out: i32[], str: string) => {
for (let i = 0; i < str.length; ++i) {
out.push(str.charCodeAt(i));
}
}
static run = (width: i32, height: i32, src: ArrayBuffer, bits = 16, type = 1, off = 0): ArrayBuffer => {
let out = [];
out.push(0x76); // magic
out.push(0x2f);
out.push(0x31);
out.push(0x01);
out.push(2); // version, scanline
out.push(0);
out.push(0);
out.push(0);
ParserExr.writeString(out, "channels");
out.push(0);
ParserExr.writeString(out, "chlist");
out.push(0);
out.push(55);
out.push(0);
out.push(0);
out.push(0);
let attrib = bits == 16 ? 1 : 2; // half, float
out.push("B".charCodeAt(0)); // B
out.push(0);
out.push(attrib);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(1);
out.push(0);
out.push(0);
out.push(0);
out.push(1);
out.push(0);
out.push(0);
out.push(0);
out.push("G".charCodeAt(0)); // G
out.push(0);
out.push(attrib);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(1);
out.push(0);
out.push(0);
out.push(0);
out.push(1);
out.push(0);
out.push(0);
out.push(0);
out.push("R".charCodeAt(0)); // R
out.push(0);
out.push(attrib);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(1);
out.push(0);
out.push(0);
out.push(0);
out.push(1);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
ParserExr.writeString(out, "compression");
out.push(0);
ParserExr.writeString(out, "compression");
out.push(0);
out.push(1);
out.push(0);
out.push(0);
out.push(0);
out.push(0); // no compression
ParserExr.writeString(out, "dataWindow");
out.push(0);
ParserExr.writeString(out, "box2i");
out.push(0);
out.push(16);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
let ww = width - 1;
let hh = height - 1;
out.push(ww & 0xff);
out.push((ww >> 8) & 0xff);
out.push((ww >> 16) & 0xff);
out.push((ww >> 24) & 0xff);
out.push(hh & 0xff);
out.push((hh >> 8) & 0xff);
out.push((hh >> 16) & 0xff);
out.push((hh >> 24) & 0xff);
ParserExr.writeString(out, "displayWindow");
out.push(0);
ParserExr.writeString(out, "box2i");
out.push(0);
out.push(16);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(ww & 0xff);
out.push((ww >> 8) & 0xff);
out.push((ww >> 16) & 0xff);
out.push((ww >> 24) & 0xff);
out.push(hh & 0xff);
out.push((hh >> 8) & 0xff);
out.push((hh >> 16) & 0xff);
out.push((hh >> 24) & 0xff);
ParserExr.writeString(out, "lineOrder");
out.push(0);
ParserExr.writeString(out, "lineOrder");
out.push(0);
out.push(1);
out.push(0);
out.push(0);
out.push(0);
out.push(0); // increasing Y
ParserExr.writeString(out, "pixelAspectRatio");
out.push(0);
ParserExr.writeString(out, "float");
out.push(0);
out.push(4);
out.push(0);
out.push(0);
out.push(0);
out.push(0); // 1.0f
out.push(0);
out.push(0x80);
out.push(0x3f);
ParserExr.writeString(out, "screenWindowCenter");
out.push(0);
ParserExr.writeString(out, "v2f");
out.push(0);
out.push(8);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
ParserExr.writeString(out, "screenWindowWidth");
out.push(0);
ParserExr.writeString(out, "float");
out.push(0);
out.push(4);
out.push(0);
out.push(0);
out.push(0);
out.push(0); // 1.0f
out.push(0);
out.push(0x80);
out.push(0x3f);
out.push(0); // end of header
let channels = 4;
let byteSize = bits == 16 ? 2 : 4;
let kHeaderSize = out.length;
let kScanlineTableSize = 8 * height;
let pixelRowSize = width * 3 * byteSize;
let fullRowSize = pixelRowSize + 8;
// line offset table
let ofs = kHeaderSize + kScanlineTableSize;
for (let y = 0; y < height; ++y) {
out.push(ofs & 0xff);
out.push((ofs >> 8) & 0xff);
out.push((ofs >> 16) & 0xff);
out.push((ofs >> 24) & 0xff);
out.push(0);
out.push(0);
out.push(0);
out.push(0);
ofs += fullRowSize;
}
// scanline data
let stride = channels * byteSize;
let pos = 0;
let srcView = new DataView(src);
let writeLine16 = (bytePos: i32) => {
for (let x = 0; x < width; ++x) {
out.push(srcView.getUint8(bytePos ));
out.push(srcView.getUint8(bytePos + 1));
bytePos += stride;
}
}
let writeLine32 = (bytePos: i32) => {
for (let x = 0; x < width; ++x) {
out.push(srcView.getUint8(bytePos ));
out.push(srcView.getUint8(bytePos + 1));
out.push(srcView.getUint8(bytePos + 2));
out.push(srcView.getUint8(bytePos + 3));
bytePos += stride;
}
}
let writeLine = bits == 16 ? writeLine16 : writeLine32;
let writeBGR = (off: i32) => {
writeLine(pos + byteSize * 2);
writeLine(pos + byteSize);
writeLine(pos);
}
let writeSingle = (off: i32) => {
writeLine(pos + off * byteSize);
writeLine(pos + off * byteSize);
writeLine(pos + off * byteSize);
}
let writeData = type == 1 ? writeBGR : writeSingle;
for (let y = 0; y < height; ++y) {
// coordinate
out.push(y & 0xff);
out.push((y >> 8) & 0xff);
out.push((y >> 16) & 0xff);
out.push((y >> 24) & 0xff);
// data size
out.push(pixelRowSize & 0xff);
out.push((pixelRowSize >> 8) & 0xff);
out.push((pixelRowSize >> 16) & 0xff);
out.push((pixelRowSize >> 24) & 0xff);
// data
writeData(off);
pos += width * stride;
}
return Uint8Array.from(out).buffer;
}
}