fits-js
fits-js parses FITS files in TypeScript. It runs in Node, browsers, Bun, and Deno from a single browser-safe core. Opening a file reads only the header blocks, and a small cutout from a 4 GB cube reads only the bytes that cutout covers.
Install
Section titled “Install”npm install @fits-js/corepnpm add @fits-js/coreyarn add @fits-js/corebun add @fits-js/coreZero runtime dependencies. Node 22 or later. In the browser, any environment
with fetch, Blob, and TypedArray works.
The code that renders the image above
Section titled “The code that renders the image above”import { BytesReader, openFits, readImage } from "@fits-js/core";
const bytes = new Uint8Array(await (await fetch("/horsehead.fits")).arrayBuffer());const reader = new BytesReader(bytes);const { hdus } = await openFits(reader);const primary = hdus[0];
const { data } = await readImage(primary, reader);const w = primary.header.getNumber("NAXIS1")!;const h = primary.header.getNumber("NAXIS2")!;
const finite = new Float64Array(data.length);let n = 0;for (let i = 0; i < data.length; i++) { const v = Number(data[i]); if (Number.isFinite(v)) finite[n++] = v;}const sorted = finite.subarray(0, n).sort();const lo = sorted[Math.floor(n * 0.005)];const hi = sorted[Math.floor(n * 0.995)];const scale = 255 / (hi - lo);
const canvas = document.getElementById("horsehead") as HTMLCanvasElement;canvas.width = h;canvas.height = w;const ctx = canvas.getContext("2d")!;const img = ctx.createImageData(h, w);for (let cy = 0; cy < w; cy++) { for (let cx = 0; cx < h; cx++) { const i1 = w - 1 - cy; const i2 = h - 1 - cx; const v = Number(data[i2 * w + i1]); const norm = Number.isFinite(v) ? Math.max(0, Math.min(255, (v - lo) * scale)) : 0; const k = (cy * h + cx) * 4; img.data[k] = img.data[k + 1] = img.data[k + 2] = norm; img.data[k + 3] = 255; }}ctx.putImageData(img, 0, 0);The percentile clip drops outlier pixels. The pixel mapping flips Y (FITS stores row 0 at the bottom, the canvas paints top-down) and rotates 90 degrees to match the orientation the Horsehead is usually shown in.
The Quickstart covers NodeFileReader, HttpRangeReader,
and a few cutout patterns.