tools: preserve HTML deck exporter
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env node
|
||||
// Assemble rendered slide PNGs into a 16:9 PPTX: one full-bleed image per slide,
|
||||
// native speaker notes, document metadata.
|
||||
//
|
||||
// Usage:
|
||||
// node build.mjs <pngdir> <out.pptx> [--notes notes.json] [--title T] [--author A] [--subject S]
|
||||
import { createRequire } from 'node:module';
|
||||
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const PptxGenJS = require('pptxgenjs');
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
if (!args[0] || !args[1]) {
|
||||
console.error(
|
||||
'usage: node build.mjs <pngdir> <out.pptx> [--notes notes.json] [--title T] [--author A] [--subject S]',
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const invocationDir = process.env.INIT_CWD || process.cwd();
|
||||
const dir = path.resolve(invocationDir, args[0]);
|
||||
const out = path.resolve(invocationDir, args[1]);
|
||||
const opt = (flag, fallback) => {
|
||||
const index = args.indexOf(flag);
|
||||
return index >= 0 ? args[index + 1] : fallback;
|
||||
};
|
||||
|
||||
const presentation = new PptxGenJS();
|
||||
presentation.layout = 'LAYOUT_WIDE'; // 13.333 x 7.5 in
|
||||
presentation.title = opt('--title', path.basename(out, '.pptx'));
|
||||
presentation.author = opt('--author', 'ThothII');
|
||||
presentation.subject = opt('--subject', '');
|
||||
|
||||
const notesOption = opt('--notes', null);
|
||||
const notesPath = notesOption
|
||||
? path.resolve(invocationDir, notesOption)
|
||||
: path.join(dir, 'notes.json');
|
||||
const notes = existsSync(notesPath)
|
||||
? JSON.parse(readFileSync(notesPath, 'utf8'))
|
||||
: {};
|
||||
|
||||
const pngs = readdirSync(dir)
|
||||
.filter(file => /^\d+\.png$/.test(file))
|
||||
.sort((left, right) => Number.parseInt(left, 10) - Number.parseInt(right, 10));
|
||||
if (pngs.length === 0) {
|
||||
console.error('no NN.png files in ' + dir);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
for (const file of pngs) {
|
||||
const slideNumber = Number.parseInt(file, 10);
|
||||
const slide = presentation.addSlide();
|
||||
slide.background = { color: 'FCFAFA' };
|
||||
slide.addImage({
|
||||
path: path.join(dir, file),
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 13.333,
|
||||
h: 7.5,
|
||||
});
|
||||
if (notes[slideNumber]) {
|
||||
slide.addNotes(notes[slideNumber]);
|
||||
}
|
||||
}
|
||||
|
||||
await presentation.writeFile({ fileName: out });
|
||||
console.log('built', out, '-', pngs.length, 'slides');
|
||||
Reference in New Issue
Block a user