@ankhzet/goo
Version:
Elegoo .goo file format reader/writer
221 lines (220 loc) • 8.94 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { assert, rgba8888Buffer, formatBytes } from './utils.js';
import { GOO_VERSION, GOO_MAGIC, GOO_DELIMITER } from './magics.js';
import { rleDecode } from './rle/index.js';
import { CRC8 } from './CRC8.js';
export class GooReader {
constructor(reader) {
this.reader = reader;
}
read() {
return __awaiter(this, void 0, void 0, function* () {
const version = yield this.reader.string(4);
assert(version === GOO_VERSION, `Version "${version}" is not supported`);
yield this.reader.assert(GOO_MAGIC, 'File signature mismatch');
const header = yield this.readHeader();
const layers = [];
let i = header.layers;
while (i-- > 0) {
layers.push(yield this.readLayer());
}
assert((yield this.reader.u24()) === 0, 'File tail signature mismatch');
yield this.reader.assert(GOO_MAGIC, 'File tail signature mismatch');
return {
header,
layers,
};
});
}
readHeader() {
return __awaiter(this, void 0, void 0, function* () {
const generator = yield this.reader.struct({}, {
description: () => this.reader.string(32),
version: () => this.reader.string(24),
});
const date = new Date(yield this.reader.string(24));
const printJob = yield this.reader.struct({ grayscale: true }, {
name: () => this.reader.string(32),
type: () => this.reader.string(32),
resinProfile: () => this.reader.string(32),
antialiasing: () => this.reader.u16(),
gray: () => this.reader.u16(),
blur: () => this.reader.u16(),
});
const previews = [];
for (const size of [116, 290]) {
previews.push(yield this.readPreview({ x: size, y: size }));
}
const layers = yield this.reader.u32();
const printer = yield this.reader.struct(printJob, {
resolution: () => this.reader.struct({}, {
x: () => this.reader.u16(),
y: () => this.reader.u16(),
}),
mirror: () => this.reader.struct({}, {
x: () => this.reader.bool(),
y: () => this.reader.bool(),
}),
platform: () => this.reader.struct({}, {
x: () => this.reader.f32(),
y: () => this.reader.f32(),
z: () => this.reader.f32(),
})
});
const layerConfig = yield this.readLayerConfig();
const summary = yield this.readSummary();
const next = yield this.reader.u32();
printer.grayscale = yield this.reader.bool();
layerConfig.transitionLayers = yield this.reader.u16();
return {
date,
generator,
printer,
previews,
layers,
layerConfig,
summary,
next,
};
});
}
readLayerConfig() {
return __awaiter(this, void 0, void 0, function* () {
return this.reader.struct({ transitionLayers: 0 }, {
thickness: () => this.reader.f32(),
commonExposure: () => this.reader.f32(),
exposureDelay: () => this.reader.bool(),
turnOffTime: () => this.reader.f32(),
timings: () => this.readGlobalConfig(() => this.readMotionTimes()),
bottomExposure: () => this.reader.f32(),
bottomLayers: () => this.reader.u32(),
motions: () => this.readMotions(() => (this.readLiftRetract(() => (this.readGlobalConfig(() => this.readMotionConfig()))))),
pwm: () => this.reader.struct({}, {
bottom: () => this.reader.u16(),
common: () => this.reader.u16(),
}),
advance: () => this.reader.bool(),
});
});
}
readSummary() {
return __awaiter(this, void 0, void 0, function* () {
return this.reader.struct({}, {
time: () => this.reader.u32(),
volume: () => this.reader.f32(),
weight: () => this.reader.f32(),
price: () => this.reader.f32(),
currency: () => this.reader.string(8),
});
});
}
readGlobalConfig(map) {
return __awaiter(this, void 0, void 0, function* () {
return {
bottom: yield map(),
common: yield map(),
};
});
}
readMotions(map) {
return __awaiter(this, void 0, void 0, function* () {
return {
first: yield map(),
second: yield map(),
};
});
}
readLiftRetract(map) {
return __awaiter(this, void 0, void 0, function* () {
return {
lift: yield map(),
retract: yield map(),
};
});
}
readMotionTimes() {
return __awaiter(this, void 0, void 0, function* () {
return this.reader.struct({}, {
before: () => this.reader.struct({}, {
lift: () => this.reader.f32(),
}),
after: () => this.reader.struct({}, {
lift: () => this.reader.f32(),
retract: () => this.reader.f32(),
}),
});
});
}
readMotionConfig() {
return __awaiter(this, void 0, void 0, function* () {
return {
distance: yield this.reader.f32(),
speed: yield this.reader.f32(),
};
});
}
readPreview(dimensions) {
return __awaiter(this, void 0, void 0, function* () {
const { buffer } = yield this.reader.binary(2 * dimensions.x * dimensions.y);
yield this.readDelimiter();
return {
dimensions,
input: {
buffer: rgba8888Buffer(buffer),
channels: 4,
},
};
});
}
readDelimiter() {
return __awaiter(this, void 0, void 0, function* () {
assert((yield this.reader.u16()) === GOO_DELIMITER, 'Delimiter expected');
});
}
readLayer() {
return __awaiter(this, void 0, void 0, function* () {
const definition = yield this.readLayerDefinition();
const offset = yield this.reader.u32();
const marker = yield this.reader.u8();
assert(marker === 0x55, `Layer data marker expected, got ${formatBytes(marker)}`);
const { buffer } = yield this.reader.binary(offset - 2);
const crc = yield this.reader.u8();
const checksum = (new CRC8()).checksum(buffer);
yield this.readDelimiter();
assert(checksum === crc, `CRC mismatch, expected ${formatBytes(crc)}, got ${formatBytes(checksum)}`);
return {
definition,
slice: {
buffer: rleDecode(buffer),
channels: 1,
},
};
});
}
readLayerDefinition() {
return __awaiter(this, void 0, void 0, function* () {
const definition = yield this.reader.struct({}, {
pause: () => this.reader.struct({}, {
mode: () => this.reader.u16(),
z: () => this.reader.f32(),
}),
z: () => this.reader.f32(),
exposure: () => this.reader.f32(),
offTime: () => this.reader.f32(),
times: () => this.readMotionTimes(),
motions: () => this.readLiftRetract(() => (this.readMotions(() => (this.readMotionConfig())))),
pwm: () => this.reader.u16(),
});
yield this.readDelimiter();
return definition;
});
}
}