UNPKG

@ankhzet/goo

Version:

Elegoo .goo file format reader/writer

221 lines (220 loc) 8.94 kB
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; }); } }