Search code examples
javajavax.imageiohdr

imageIO to open .HDR file


I need to open an .hdr file and work on it, but imageIO doesn't supports that format.

The problem is that I need to keep the information loss as little as possible: 32bpc is perfect, 16 is fine and less the 16 won't work.

There are 3 possible solutions I came up to:

  1. Find a plugin that allow me to open .HDR file. I've been searching for it a lot but without luck;
  2. Find a way to convert the .HDR file to a format I can find a plugin for. Tiff maybe? Tried this too but still no luck;
  3. Reduce the dynamic range from 32bpc to 16bpc and then convert it to png. This is tricky because once I have a png file I win, but it's not that easy to cut the range without killing the image..

What would you recommend me to do? Do you know a way to make one of those 3 options works? Or do you have a better idea?


Solution

  • You can now read .HDR using ImageIO. :-)

    This is a first version, so it might be a little rough around the edges, but should work for standard (default settings) Radiance RGBE .HDR files.

    The returned image will be a custom BufferedImage with a DataBufferFloat backing (ie., samples will be in 3 samples, 32-bit float interleaved RGB format).

    By default, a simple global tone-mapping is applied, and all RGB values will be normalized to range [0...1] (this allows anyone to just use ImageIO.read(hdrFile) and the image will look somewhat reasonable, in a very reasonable time).

    It is also possible to pass an HDRImageReadParam to the ImageReader instance with a NullToneMapper. This is even faster, but the float values will be unnormalized, and might exceed the max value. This allows you to do custom, more sophisticated tone-mapping on the image data, before converting to something more displayable.

    Something like:

    // Create input stream
    ImageInputStream input = ImageIO.createImageInputStream(hdrFile);
    
    try {
        // Get the reader
        Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
    
        if (!readers.hasNext()) {
            throw new IllegalArgumentException("No reader for: " + hdrFile);
        }
    
        ImageReader reader = readers.next();
    
        try {
            reader.setInput(input);
    
            // Disable default tone mapping
            HDRImageReadParam param = (HDRImageReadParam) reader.getDefaultReadParam();
            param.setToneMapper(new NullToneMapper());
    
            // Read the image, using settings from param
            BufferedImage image = reader.read(0, param);
        }
        finally {
            // Dispose reader in finally block to avoid memory leaks
            reader.dispose();
        }
    }
    finally {
        // Close stream in finally block to avoid resource leaks
        input.close();
    }
    
    // Get float data
    float[] rgb = ((DataBufferFloat) image.getRaster().getDataBuffer()).getData();
    
    // TODO: Custom tone mapping on float RGB data
    
    // Convert the image to something easily displayable
    BufferedImage converted = new ColorConvertOp(null).filter(image, new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB));
    
    // Optionally write as JPEG or other format
    ImageIO.write(converted, "JPEG", new File(...));