Skip to content

Quickstart

You need:

  • Node.js 22 or later for the Node path.
  • Any modern browser for the BlobReader and HttpRangeReader paths.
Terminal window
npm install @fits-js/core

Everything comes from the same entry. Pick the reader that fits the byte source.

import { NodeFileReader, openFits, readImage } from "@fits-js/core";
const reader = await NodeFileReader.open("data/image.fits");
try {
const { hdus } = await openFits(reader);
const primary = hdus[0];
const region = { start: [0, 0], shape: [16, 16] };
const { data } = await readImage(primary, reader, { region });
console.log(data.slice(0, 8));
} finally {
await reader.close();
}

openFits enumerates HDUs and reads only header blocks. readImage with a region only reads the bytes that region covers, so a small cutout from a multi-gigabyte cube stays cheap.

import { HttpRangeReader, openFits, readImage } from "@fits-js/core";
const reader = new HttpRangeReader("https://example.test/cube.fits");
const { hdus } = await openFits(reader);
const primary = hdus[0];
const region = { start: [0, 0], shape: [8, 8] };
const { data } = await readImage(primary, reader, { region });

HttpRangeReader issues HTTP Range requests for the bytes openFits and readImage ask for, and fetches are page-granular. Measured on a 1.2 MB archive file with five image extensions, enumeration costs about 320 KB at the default 64 KiB pageSize, and an 8x8 cutout from the first extension then costs nothing more, because its bytes land in pages the enumeration already cached. A smaller pageSize trades more requests for fewer bytes. The HTTP guide covers the tuning.

If the server answers the initial bytes=0-0 probe with 200 (ignoring the range), the reader falls back to fetching the whole body once and serving later reads from memory.

import { BlobReader, openFits, readImage } from "@fits-js/core";
const input = document.querySelector<HTMLInputElement>("input[type=file]")!;
input.addEventListener("change", async () => {
const file = input.files?.[0];
if (!file) return;
const reader = new BlobReader(file);
const { hdus } = await openFits(reader);
const primary = hdus[0];
const { data } = await readImage(primary, reader);
// ...render or analyze
});

The same code path works for File (from a picker) and Blob (from fetch, IndexedDB, or any other Web source).

None of the snippets above ever read more than they need.

  • openFits(reader) reads only the 2880-byte header blocks for each HDU.
  • readImage(primary, reader, { region }) reads only the bytes the region spans.
  • Reading without a region returns the full image.

A 4 GB cube with a tiny region cutout still costs kilobytes, not gigabytes, which is the point. See examples/http-range for a complete program that prints the byte counts.