HDRify implements comprehensive support for high dynamic range imaging with support for HDR (Radiance RGBE), EXR (OpenEXR), and JPEG with gain maps (JPEG-R / Ultra HDR) reading and writing in pure JavaScript. No native bindings—works in Node.js and browsers.
→ Online demo — HDR, EXR, and Ultra HDR (JPEG-R) viewer and converter (the demos/web-converter from this repo). Try it in your browser.
- Read and write RGB EXR files (PIZ, PXR24, ZIP, ZIPS, and RLE compression)
- Read and write HDR (Radiance RGBE) files
- Write JPEGs with gain maps (JPEG-R / Ultra HDR) — a new, highly compressible HDR format. Convert EXR or HDR to JPEG-R for efficient storage and broad compatibility (modern browsers, mobile).
- Tone mapping utilities for easing conversion of HDR to LDR images
- Full TypeScript support
- No DOM or Node.js dependencies (works in browser, web workers, and node.js)
- Written in a functional style to support tree-shaking
- Web app example of HDR, EXR and Ultra HDR conversion and vieweing: https://hdrify.benhouston3d.com
- hdrify CLI
pnpm add hdrify| Function | Description |
|---|---|
readHdr(hdrBuffer: Uint8Array) |
Parse Radiance RGBE HDR file → FloatImageData |
writeHdr(imageData: FloatImageData) |
Encode FloatImageData → HDR bytes |
readExr(exrBuffer: Uint8Array) |
Parse OpenEXR file (PIZ, ZIP, RLE) → FloatImageData |
writeExr(imageData, options?) |
Encode FloatImageData → EXR bytes |
writeJpegGainMap(encodingResult, options?) |
Encode HDR as JPEG-R (JPEG with gain map) for highly compressible storage |
All read functions return FloatImageData, and all write functions accept it (or derived types). This is the universal intermediate format used across the library.
interface FloatImageData {
width: number; // Image width in pixels
height: number; // Image height in pixels
data: Float32Array; // RGBA pixel data: [R, G, B, A, R, G, B, A, ...]
metadata?: Record<string, unknown>; // Format-specific header metadata (e.g. compression, exposure)
}import { readExr } from 'hdrify';
import * as fs from 'node:fs';
const buffer = fs.readFileSync('image.exr');
const imageData = readExr(new Uint8Array(buffer));
console.log(`Image: ${imageData.width}x${imageData.height}`);
// imageData.data is a Float32Array with RGBA valuesimport { readHdr } from 'hdrify';
import * as fs from 'node:fs';
const buffer = fs.readFileSync('image.hdr');
const imageData = readHdr(new Uint8Array(buffer));
console.log(`Image: ${imageData.width}x${imageData.height}`);import { encodeGainMap, readExr, writeExr, readHdr, writeHdr, writeJpegGainMap } from 'hdrify';
import * as fs from 'node:fs';
// Convert EXR to HDR
const exrBuffer = fs.readFileSync('input.exr');
const imageData = readExr(new Uint8Array(exrBuffer));
fs.writeFileSync('output.hdr', writeHdr(imageData));
// Convert HDR to EXR
const hdrBuffer2 = fs.readFileSync('input.hdr');
const imageData2 = readHdr(new Uint8Array(hdrBuffer2));
fs.writeFileSync('output.exr', writeExr(imageData2));
// Convert EXR or HDR to JPEG-R (JPEG with gain map—highly compressible HDR)
const imageData3 = readExr(new Uint8Array(fs.readFileSync('input.exr')));
const encoding = encodeGainMap(imageData3, { toneMapping: 'reinhard' });
fs.writeFileSync('output.jpg', writeJpegGainMap(encoding, { quality: 90 }));import { readExr } from 'hdrify';
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', async (e) => {
const file = (e.target as HTMLInputElement).files?.[0];
if (!file) return;
const arrayBuffer = await file.arrayBuffer();
const buffer = new Uint8Array(arrayBuffer);
const imageData = readExr(buffer);
// Use imageData.data to render to canvas, etc.
});The hdrify-cli package is a companion command-line tool for converting and inspecting EXR/HDR files:
pnpm add -g hdrify-cli| Command | Description |
|---|---|
hdrify convert <input> <output> |
Convert between EXR, HDR, PNG, WebP, and JPEG (JPEG-R gain map when output is .jpg) |
hdrify info <file> |
Display metadata (format, dimensions, compression) |
hdrify reference <output> |
Create synthetic reference test images |
hdrify convert input.exr output.hdr
hdrify convert input.hdr output.exr
hdrify convert input.exr output.jpg # JPEG-R with gain map (highly compressible HDR)
hdrify info input.exr
hdrify reference output.exr --compression zip
hdrify convert input.exr output.exr --compression pxr24See the online demo link at the top. To run the web-converter locally (demos/web-converter, drag-and-drop and exposure slider):
cd demos/web-converter
pnpm install
pnpm devOpen http://localhost:3000 and drag-and-drop EXR or HDR files.
Check out this git project and run:
# install dependencies
pnpm install
# build packages (hdrify, hdrify-cli)
pnpm build
# run tests
pnpm test
# type-check
pnpm tsgo
# lint
pnpm check
# clean build artifacts
pnpm clean
# publish the npm packages
pnpm make-release:hdrify
pnpm make-release:hdrify-cliMIT
Ben Houston neuralsoft@gmail.com (https://benhouston3d.com), Sponsored by Land of Assets
