I'm sure that they are saved and loaded as TINYEXR_PIXELTYPE_FLOAT. When I load a demo EXR file off the internet, it works fine. When I save and reload that same image, the corruption in the final row of pixels shows up. However, the re-saved image still shows up fine in EXR viewers. Perhaps the EXR viewers I tried are more tolerant of faulty files, or perhaps there's an issue with my save/load code, although it's copied as nearly as I can manage from tinyEXR's docs. I've assembled a self-sufficient test case for you to take a look at when you have time.
import org.lwjgl.BufferUtils;
import org.lwjgl.PointerBuffer;
import org.lwjgl.util.tinyexr.*;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import static org.lwjgl.util.tinyexr.TinyEXR.*;
public class EXRTest {
public static void tinyEXRTest() {
String path = ""; //insert file path here
//create a simple raster
float[] raster = new float[] {
1f, 2f, 3f, 4f, 1f, 2f, 3f, 4f, 1f, 2f, 3f, 4f,
1f, 2f, 3f, 4f, 1f, 2f, 3f, 4f, 1f, 2f, 3f, 4f,
1f, 2f, 3f, 4f, 1f, 2f, 3f, 4f, 1f, 2f, 3f, 4f,
};
//save EXR to disk: no errors, looks fine in EXR viewer program
save(pathExr, 3, 3, raster);
//load EXR and get FloatBuffers for each channel
FloatBuffer[] fbs = load(pathExr);
for (int i = 0; i < 3*3; i++) {
System.out.print(fbs[0].get(i) + ", ");
System.out.print(fbs[1].get(i) + ", ");
System.out.print(fbs[2].get(i) + ", ");
System.out.println(fbs[3].get(i));
}
// Output:
// 1.0, 2.0, 3.0, 4.0
// 1.0, 2.0, 3.0, 4.0
// 1.0, 2.0, 3.0, 4.0
// 1.0, 2.0, 3.0, 4.0
// 1.0, 2.0, 3.0, 4.0
// 1.0, 2.0, 3.0, 4.0
// 133169.11, 4.611403E27, 2.626384E32, 1.172696E-39
// 1.18026E-40, 2.070413E-19, 2.4149792E8, 3.0353178E-31
// 1.1429877E33, 7.715514E31, 4.7423467E30, 8538626.0
}
private static ByteBuffer strBB(String s) {
byte[] bytes = s.getBytes();
ByteBuffer bb = BufferUtils.createByteBuffer(bytes.length);
bb.put(bytes);
bb.flip();
return bb;
}
private static void save(String path, int width, int height, float[] rgba) {
EXRHeader exr_header = EXRHeader.create();
InitEXRHeader(exr_header);
EXRImage exr_image = EXRImage.create();
InitEXRImage(exr_image);
exr_image.num_channels(4);
exr_header.num_channels(4);
float[][] images = new float[4][width * height];
int x = 0;
int y = 0;
for (int i = 0; i < width * height; i++) {
images[0][i] = rgba[4*i+0];
images[1][i] = rgba[4*i+1];
images[2][i] = rgba[4*i+2];
images[3][i] = rgba[4*i+3];
}
FloatBuffer red = BufferUtils.createFloatBuffer(width * height);
red.put(images[0]);
red.flip();
FloatBuffer green = BufferUtils.createFloatBuffer(width * height);
green.put(images[1]);
green.flip();
FloatBuffer blue = BufferUtils.createFloatBuffer(width * height);
blue.put(images[2]);
blue.flip();
FloatBuffer alpha = BufferUtils.createFloatBuffer(width * height);
alpha.put(images[3]);
alpha.flip();
PointerBuffer imagesPtr = BufferUtils.createPointerBuffer(4);
imagesPtr.put(red);
imagesPtr.put(green);
imagesPtr.put(blue);
imagesPtr.put(alpha);
imagesPtr.flip();
exr_image.images(imagesPtr);
exr_image.width(width);
exr_image.height(height);
EXRChannelInfo.Buffer channelInfos = EXRChannelInfo.create(exr_header.num_channels());
exr_header.channels(channelInfos);
channelInfos.get(0).name(strBB("R\0"));
channelInfos.get(1).name(strBB("G\0"));
channelInfos.get(2).name(strBB("B\0"));
channelInfos.get(3).name(strBB("A\0"));
IntBuffer pixelTypes = BufferUtils.createIntBuffer(exr_header.num_channels());
IntBuffer requestedPixelTypes = BufferUtils.createIntBuffer(exr_header.num_channels());
exr_header.pixel_types(pixelTypes);
exr_header.requested_pixel_types(requestedPixelTypes);
for (int i = 0; i < exr_header.num_channels(); i++) {
pixelTypes.put(i, TINYEXR_PIXELTYPE_FLOAT);
requestedPixelTypes.put(i, TINYEXR_PIXELTYPE_FLOAT);
}
PointerBuffer err = BufferUtils.createPointerBuffer(1);
int ret = SaveEXRImageToFile(exr_image, exr_header, path, err);
if (ret != TINYEXR_SUCCESS) {
System.out.println("EXR err: " + err.get(0));
}
System.out.println("EXR saved at " + path);
}
private static FloatBuffer[] load(String path) {
EXRVersion exr_version = EXRVersion.create();
int ret = ParseEXRVersionFromFile(exr_version, path);
if (ret != TINYEXR_SUCCESS) {
System.out.println("Invalid EXR file: " + path);
return null;
}
if (exr_version.multipart()) {
System.out.println("Multipart unsupported");
return null;
}
EXRHeader exr_header = EXRHeader.create();
InitEXRHeader(exr_header);
PointerBuffer err = BufferUtils.createPointerBuffer(1);
ret = ParseEXRHeaderFromFile(exr_header, exr_version, path, err);
if (ret != TINYEXR_SUCCESS) {
System.out.println("EXR parse error: " + err.get(0));
return null;
}
// Read HALF channel as FLOAT.
for (int i = 0; i < exr_header.num_channels(); i++) {
if (exr_header.pixel_types().get(i) == TINYEXR_PIXELTYPE_HALF) {
exr_header.requested_pixel_types().put(i, TINYEXR_PIXELTYPE_FLOAT);
}
}
EXRImage exr_image = EXRImage.create();
InitEXRImage(exr_image);
ret = LoadEXRImageFromFile(exr_image, exr_header, path, err);
if (ret != TINYEXR_SUCCESS) {
System.out.println("EXR load errror: " + err.get(0));
return null;
}
PointerBuffer images = exr_image.images();
int w = exr_image.width();
int h = exr_image.height();
return new FloatBuffer[] {
images.getFloatBuffer(0, w * h),
images.getFloatBuffer(1, w * h),
images.getFloatBuffer(2, w * h),
images.getFloatBuffer(3, w * h)
};
}
}