Files
HDR/scripts/generate-real-starfield-image.mjs

83 lines
2.3 KiB
JavaScript

import { mkdir, rm } from 'node:fs/promises';
import { dirname, resolve } from 'node:path';
import { spawn } from 'node:child_process';
import { once } from 'node:events';
const root = resolve(import.meta.dirname, '..');
const sourceUrl = 'https://esahubble.org/media/archives/images/large/heic1509a.jpg';
const sourcePath = resolve(root, 'media/.hubble-westerlund-2-source.jpg');
const outputPath = resolve(root, 'media/hubble-westerlund-2-hdr.png');
async function run(command, args, options = {}) {
const child = spawn(command, args, { stdio: 'inherit', ...options });
const [code] = await once(child, 'close');
if (code !== 0) throw new Error(`${command} exited with code ${code}`);
}
function capture(command, args) {
return new Promise((resolveBuffer, reject) => {
const child = spawn(command, args, { stdio: ['ignore', 'pipe', 'inherit'] });
const chunks = [];
child.stdout.on('data', (chunk) => chunks.push(chunk));
child.on('error', reject);
child.on('close', (code) => {
if (code !== 0) {
reject(new Error(`${command} exited with code ${code}`));
return;
}
resolveBuffer(Buffer.concat(chunks));
});
});
}
await mkdir(dirname(outputPath), { recursive: true });
await run('curl', [
'-L',
'--fail',
'--silent',
'--show-error',
sourceUrl,
'-o',
sourcePath
]);
const frame = await capture('ffmpeg', [
'-hide_banner',
'-loglevel',
'error',
'-i', sourcePath,
'-vf',
'scale=2560:1440:force_original_aspect_ratio=increase,crop=2560:1440,eq=contrast=1.06:saturation=1.12:brightness=-0.02',
'-f', 'rawvideo',
'-pix_fmt', 'rgba64le',
'pipe:1'
]);
const encode = spawn('ffmpeg', [
'-y',
'-f', 'rawvideo',
'-pix_fmt', 'rgba64le',
'-s:v', '2560x1440',
'-i', 'pipe:0',
'-vf',
'setparams=range=full:color_primaries=bt2020:color_trc=smpte2084:colorspace=gbr',
'-frames:v', '1',
'-update', '1',
'-c:v', 'png',
'-pix_fmt', 'rgba64be',
'-pred', 'mixed',
'-color_primaries', 'bt2020',
'-color_trc', 'smpte2084',
outputPath
], { stdio: ['pipe', 'inherit', 'inherit'] });
encode.stdin.end(frame);
const [encodeCode] = await once(encode, 'close');
if (encodeCode !== 0) throw new Error(`ffmpeg png exited with code ${encodeCode}`);
await rm(sourcePath, { force: true });
console.log(`Wrote ${outputPath}`);
console.log('Source: NASA/ESA Hubble Westerlund 2, heic1509a');