Import
import { openEnvi, renderSpectralBand } from 'purejsimage/scientific'Minimal Node.js example
import { FileSource } from 'purejsimage'
import { openEnvi, renderSpectralBand } from 'purejsimage/scientific'
const dataset = await openEnvi({
header: await FileSource.open('scene.hdr'),
data: await FileSource.open('scene.img'),
maxInputBytes: 2_000_000_000,
})
const display = await renderSpectralBand(dataset, {
wavelength: 1648.7,
range: { mode: 'percentile', low: 1, high: 99 },
palette: 'viridis',
})
for await (const pixels of display.image.pixels) console.log(pixels.width, pixels.height)Minimal browser example
import { openEnvi } from 'purejsimage/scientific'
const headerInput = document.querySelector<HTMLInputElement>('#header')
const binaryInput = document.querySelector<HTMLInputElement>('#binary')
const header = headerInput?.files?.[0]
const data = binaryInput?.files?.[0]
if (!header || !data) throw new Error('Choose an ENVI header and binary file')
const dataset = await openEnvi({
header,
data,
maxInputBytes: data.size,
})
for await (const block of dataset.readPlane({
z: 0, c: 172, t: 0, x: 0, y: 0, width: 512, height: 512,
})) console.log(block.data)Supported features
| Feature | Support |
|---|---|
| ENVI Standard | Read |
| ENVI Classification | Read class names and exact RGB lookup colors; bounded categorical preview |
| Interleave | BSQ, BIL, BIP |
| Samples | uint8, int16, int32, float32, float64, uint16, uint32 |
| Byte order | Little-endian and big-endian |
| Spectral metadata | Band names, wavelength centers, units, FWHM, default bands |
Dataset mapping
ENVI samples map to X, lines map to Y, and bands map to C in MultidimensionalRasterDataset. Z and T are 1. Channel metadata retains each actual wavelength center. PureJsImage does not manufacture wavelengths between declared channels.
Bounded reads
The header is read eagerly because it is small. The binary source stays lazy. A browser File uses BlobSource and Blob.slice(). BSQ and BIL selections read the requested rows and bands. BIP reads the required interleaved row ranges. Opening a large file does not call File.arrayBuffer().
Display rendering
renderSpectralBand() selects the nearest actual wavelength channel. renderScientificPlane() selects a channel index directly. Display transfers run after the selected quantitative range is normalized: linear uses the normalized value; sqrt uses its square root; log uses log1p(999x) / log(1000); asinh uses asinh(10x) / asinh(10). Use measureScientificPlane() once and reuse its explicit range when only palette or transfer changes.
Classification maps
renderEnviClassification() uses the header's class lookup colors directly and nearest-neighbor sampling so categories are never blended. Callers must provide maximum output dimensions. The renderer reads one selected source row at a time, which allows the explorer to preview the 37,679 × 39,594 USGS Afghanistan mineral map without creating its roughly 6 GB full-resolution RGBA equivalent.
Unsupported features
Complex samples, 64-bit integer samples, other special ENVI file types, malformed headers, and mismatched binary lengths reject. ENVI writing and spectral-coordinate interpolation are not implemented.
Official specification
ENVI image files · ENVI header files
Scientific Raster Explorer · GSF guide · FITS guide · API · OME-TIFF