19 lines
1.2 KiB
JavaScript
19 lines
1.2 KiB
JavaScript
import sharp from 'sharp';
|
|
import { readdirSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
const [,, dir, out, colsArg = '4', wArg = '360'] = process.argv;
|
|
const cols = Number(colsArg), w = Number(wArg), h = Math.round(w * 0.66);
|
|
const files = readdirSync(dir).filter(f => /\.(jpe?g|png|webp)$/i.test(f)).sort();
|
|
const tiles = [];
|
|
for (const [i, f] of files.entries()) {
|
|
try {
|
|
const buf = await sharp(join(dir, f)).resize(w, h, { fit: 'cover' }).toBuffer();
|
|
const label = Buffer.from(`<svg width="${w}" height="24"><rect width="${w}" height="24" fill="black" opacity="0.6"/><text x="6" y="17" font-family="sans-serif" font-size="14" fill="white">${i}: ${f.slice(0, 40)}</text></svg>`);
|
|
const tile = await sharp(buf).composite([{ input: label, top: h - 24, left: 0 }]).toBuffer();
|
|
tiles.push({ input: tile, left: (i % cols) * w, top: Math.floor(i / cols) * h });
|
|
} catch (e) { console.error('skip', f, e.message); }
|
|
}
|
|
const rows = Math.ceil(tiles.length / cols);
|
|
await sharp({ create: { width: cols * w, height: rows * h, channels: 3, background: '#222' } }).composite(tiles).jpeg({ quality: 80 }).toFile(out);
|
|
console.log('wrote', out, files.length, 'images');
|