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, Adobe Gain Maps & UltraHDR 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
- Read and write both Adobe Gain Map JPEGs and Ultra HDR JPEGS (Android compatible.)
- Tone mappers (ACES, Khronos Neutral, AgX and Reinhart)
- 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 viewing: https://hdrify.benhouston3d.com
- hdrify CLI
pnpm add hdrifyAll 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';
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';
const buffer = fs.readFileSync('image.hdr');
const imageData = readHdr(new Uint8Array(buffer));
console.log(`Image: ${imageData.width}x${imageData.height}`);import { readJpegGainMap } from 'hdrify';
const buffer = fs.readFileSync('image.jpg');
const imageData = readJpegGainMap(new Uint8Array(buffer));
console.log(`Image: ${imageData.width}x${imageData.height}`);
// imageData.data is linear HDR Float32Array RGBA; metadata.format is 'ultrahdr' or 'adobe-gainmap'import { encodeGainMap, readExr, writeExr, readHdr, writeHdr, writeJpegGainMap } from 'hdrify';
// 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, and JPEG gain map (Ultra HDR / Adobe) files. See packages/cli/README.md for full CLI documentation, or install from npm:
pnpm add -g hdrify-cli| Command | Description |
|---|---|
hdrify convert <input> <output> |
Convert between EXR, HDR, JPEG gain map, PNG, WebP, and JPEG |
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 (Ultra HDR, default)
hdrify convert input.exr output.jpg --format adobe-gainmap # Adobe gain map format
hdrify convert input.jpg output.exr # Read JPEG gain map as input
hdrify info input.exr
hdrify info input.jpg # JPEG gain map (Ultra HDR / Adobe)
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, Sponsored by Land of Assets
This project would not have been possible without these two projects which were used a reference:
- Three.js - tone mapping, UltraHDR loader, EXR loader, example images.
- Gainmap.js - UltraHDR loading, saving, example images.
- OpenEXR - EXR encoding/decoding for all the various compression formats, example images.
