This provides Rust and JavaScript wrappers around the C libjpegxr / jxrlib codec open-sourced by Microsoft. The code is included in-tree as it's no longer actively maintained, and the Codeplex source downloads may not last.
Currently only decoding is supported, but adding an encoder interface should be straightforward.
The wrapped C JPEG XR library was written by many fine folks at Microsoft!
Rust and JS code wrapping it, and tweaks to the C code, are by Brooke Vibber <bvibber@pobox.com>
.
BSD-style license; see license.md
or the headers in source files.
use fs;
use jpegxr::{ImageDecode, PixelInfo};
// ...
let input = File::open(filename)?;
let mut decoder = ImageDecode::with_reader(input)?;
let (width, height) = decoder.get_size()?;
let info = PixelInfo::from_format(get_pixel_format()?);
let stride = width * info.bytes_per_pixel() / 8;
let size = stride * height;
let buffer = Vec::<u8>::with_capacity(size);
buffer.resize(size, 0);
decoder.copy_all(&mut buffer, stride)?;
// now do stuff with the data
Quick start:
let fs = require('fs');
let jpegxr = require('jpegxr');
let bytes = fs.readFileSync(filename);
jpegxr().then((codec) => {
let image = codec.decode(bytes);
let stride = image.width * image.pixelInfo.bitsPerPixel / 8;
// do stuff with image.bytes
});
The jpegxr
module exports a factory function which asynchronously prepares the WebAssembly modules and returns an API wrapper object via a Promise
.
Call its decode
method with a Uint8Array
of input bytes to get back an object with the following structure:
{
width: number,
height: number,
pixelInfo: {
channels: number, // 3, 4 etc
colorFormat: string, // "RGB" etc
bitDepth: string, // "8", "32Float" etc
bitsPerPixel: number, // 24, 32, 128 etc
hasAlpha: boolean,
premultipliedAlpha: boolean,
bgr: boolean, // indicates RGB has blue channel first, not red
},
bytes: Uint8Array
}
Exceptions may be thrown in case of invalid data. The bytes
array is standalone and backed by its own buffer, and does not need to be manually freed -- however this all incurs the cost of a single copy of both input and output data in/out of the WebAssembly module.
Currently sports the ability to read basic image format (width/height/pixel format) from a JPEG XR image and decode its data to memory. Plan to add encoding, all the pieces are there, just haven't set it up yet.
In Rust API you can ask for a subset of the image, which should allow progressive display during decoding, or to save time decoding unused macroblocks on a cropped view.
HDR images with 32-bit floating point RGBA elements, as saved from the NVIDIA game screen capture tool, appear to decode correctly.
- add encoder interface
- more testing of obscure stuff
Building the JS via emscripten should work on macOS and Linux. On Windows I recommend using WSL to set up a Linux environment.
Install the emscripten SDK and set it up in PATH
. Either run make
directly, or npm run-script build
which runs make
itself.
Run npm test
to run a verification script which loads a sample floating point HDR screenshot and calculates average red, green, and blue intensities to prove it loaded correctly. Results should look something like this, with no exceptions thrown:
% make test
node wasm/test.js
{ decode: [Function: decode] }
{
width: 3440,
height: 1440,
pixelInfo: {
channels: 4,
colorFormat: 'RGB',
bitDepth: '32Float',
bitsPerPixel: 128,
hasAlpha: true,
premultipledAlpha: false,
bgr: false
},
bytes: Uint8Array(79257600) [
0, 0, 136, 58, 0, 0, 250, 58, 0, 0, 63, 59,
0, 0, 0, 0, 0, 0, 136, 58, 0, 0, 250, 58,
0, 0, 63, 59, 0, 0, 0, 0, 0, 0, 136, 58,
0, 0, 248, 58, 0, 0, 63, 59, 0, 0, 0, 0,
0, 0, 136, 58, 0, 0, 246, 58, 0, 0, 62, 59,
0, 0, 0, 0, 0, 0, 136, 58, 0, 0, 250, 58,
0, 0, 63, 59, 0, 0, 0, 0, 0, 0, 136, 58,
0, 0, 250, 58, 0, 0, 63, 59, 0, 0, 0, 0,
0, 0, 136, 58,
... 79257500 more items
]
}
average red brightness: 1.4860534716607372
average green brightness: 2.4572176722254246
average blue brightness: 3.867482314063597