TEST(EXR, BasicRoundTrip) { int width = 289; int height = 1 + 65536 / width; float *buf = new float[width * height]; for (int i = 0; i < 65536; ++i) { FP16 half; half.u = i; buf[i] = half_to_float_full(half).f; } for (int i = 65536; i < width * height; ++i) buf[i] = 0; EXRImage image; image.num_channels = 1; const char *channels[] = { "R" }; image.channel_names = channels; unsigned char *images[] = { (unsigned char *)buf }; image.images = images; int pixel_types[] = { TINYEXR_PIXELTYPE_HALF }; image.pixel_types = pixel_types; image.width = width; image.height = height; const char *err = nullptr; EXPECT_EQ(0, SaveMultiChannelEXRToFile(&image, "test.exr", &err)) << err; EXRImage readImage; EXPECT_EQ(0, LoadMultiChannelEXRFromFile(&readImage, "test.exr", &err)) << err; CompareImages(image, readImage, false); }
TEST(EXR, Randoms) { int width = 1024; int height = 1024; RNG rng; float *buf = new float[4 * width * height]; for (int i = 0; i < 4 * width * height; ++i) { buf[i] = -20 + 20. * rng.UniformFloat(); } EXRImage image; image.num_channels = 4; const char *channels[] = { "B", "G", "R", "A" }; image.channel_names = channels; unsigned char *images[] = { (unsigned char *)buf, (unsigned char *)(buf + width * height), (unsigned char *)(buf + 2 * width * height), (unsigned char *)(buf + 3 * width * height) }; image.images = images; int pixel_types[] = { TINYEXR_PIXELTYPE_HALF, TINYEXR_PIXELTYPE_HALF, TINYEXR_PIXELTYPE_HALF, TINYEXR_PIXELTYPE_HALF }; image.pixel_types = pixel_types; image.width = width; image.height = height; const char *err = nullptr; EXPECT_EQ(0, SaveMultiChannelEXRToFile(&image, "test.exr", &err)) << err; EXRImage readImage; EXPECT_EQ(0, LoadMultiChannelEXRFromFile(&readImage, "test.exr", &err)) << err; CompareImages(image, readImage, true); }
static RGBSpectrum *ReadImageEXR(const std::string &name, int *width, int *height) { EXRImage img; const char *err = nullptr; if (ParseMultiChannelEXRHeaderFromFile(&img, name.c_str(), &err) != 0) { Error("Unable to read \"%s\": %s", name.c_str(), err); return nullptr; } for (int i = 0; i < img.num_channels; ++i) { if (img.requested_pixel_types[i] == TINYEXR_PIXELTYPE_HALF) img.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; } if (LoadMultiChannelEXRFromFile(&img, name.c_str(), &err) != 0) { Error("Unable to read \"%s\": %s", name.c_str(), err); return nullptr; } *width = img.width; *height = img.height; int idxR = -1, idxG = -1, idxB = -1; for (int c = 0; c < img.num_channels; c++) { if (strcmp(img.channel_names[c], "R") == 0) { idxR = c; } else if (strcmp(img.channel_names[c], "G") == 0) { idxG = c; } else if (strcmp(img.channel_names[c], "B") == 0) { idxB = c; } } RGBSpectrum *ret = new RGBSpectrum[img.width * img.height]; int offset = 0; for (int y = 0; y < img.height; ++y) { for (int x = 0; x < img.width; ++x, ++offset) { if (img.num_channels == 1) ret[offset] = convert(img.images[0], offset, img.pixel_types[0]); else { Float rgb[3] = { convert(img.images[idxR], offset, img.pixel_types[idxR]), convert(img.images[idxG], offset, img.pixel_types[idxG]), convert(img.images[idxB], offset, img.pixel_types[idxB]) }; ret[offset] = RGBSpectrum::FromRGB(rgb); } } } FreeEXRImage(&img); return ret; }
ImageSourceFileTinyExr::ImageSourceFileTinyExr( DataSourceRef dataSource, ImageSource::Options /*options*/ ) { mExrImage.reset( new EXRImage ); const char *error; InitEXRImage( mExrImage.get() ); int status = 0; if( dataSource->isFilePath() ) { status = ParseMultiChannelEXRHeaderFromFile( mExrImage.get(), dataSource->getFilePath().string().c_str(), &error ); if( status != 0 ) throw ImageIoExceptionFailedLoadTinyExr( string( "Failed to parse OpenEXR header; Error message: " ) + error ); status = LoadMultiChannelEXRFromFile( mExrImage.get(), dataSource->getFilePath().string().c_str(), &error ); if( status != 0 ) throw ImageIoExceptionFailedLoadTinyExr( string( "Failed to parse OpenEXR file; Error message: " ) + error ); } else { BufferRef buffer = dataSource->getBuffer(); status = ParseMultiChannelEXRHeaderFromMemory( mExrImage.get(), (const unsigned char*)buffer->getData(), &error ); if( status != 0 ) throw ImageIoExceptionFailedLoadTinyExr( string( "Failed to parse OpenEXR header; Error message: " ) + error ); status = LoadMultiChannelEXRFromMemory( mExrImage.get(), (const unsigned char*)buffer->getData(), &error ); if( status != 0 ) throw ImageIoExceptionFailedLoadTinyExr( string( "Failed to parse OpenEXR file; Error message: " ) + error ); } // verify that the channels are all the same size; currently we don't support variably sized channels int pixelType = mExrImage->pixel_types[0]; for( int c = 1; c < mExrImage->num_channels; ++c ) { if( pixelType != mExrImage->pixel_types[c] ) throw ImageIoExceptionFailedLoadTinyExr( "TinyExr: heterogneous channel data types not supported" ); } switch( pixelType ) { case TINYEXR_PIXELTYPE_HALF: setDataType( ImageIo::FLOAT16 ); break; case TINYEXR_PIXELTYPE_FLOAT: setDataType( ImageIo::FLOAT32 ); break; default: throw ImageIoExceptionFailedLoadTinyExr( "TinyExr: Unknown data type" ); break; } setSize( mExrImage->width, mExrImage->height ); switch( mExrImage->num_channels ) { case 3: setColorModel( ImageIo::CM_RGB ); setChannelOrder( ImageIo::ChannelOrder::RGB ); break; case 4: setColorModel( ImageIo::CM_RGB ); setChannelOrder( ImageIo::ChannelOrder::RGBA ); break; default: throw ImageIoExceptionFailedLoadTinyExr( "TinyExr: Unsupported number of channels (" + to_string( mExrImage->num_channels ) + ")" ); } }
/* The gateway function */ void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { /* check for proper number of arguments */ if(nrhs != 1) { mexErrMsgIdAndTxt("HDRToolbox:write_exr:nrhs", "One input is required."); } char *nameFile; mwSize buflen; int status; buflen = mxGetN(prhs[0])*sizeof(mxChar)+1; nameFile = (char*) mxMalloc(buflen); /* Copy the string data into buf. */ status = mxGetString(prhs[0], nameFile, buflen); /* call the computational routine */ EXRImage image; InitEXRImage(&image); const char* err; int ret = ParseMultiChannelEXRHeaderFromFile(&image, nameFile, &err); if (ret != 0) { printf("Parse EXR error: %s\n", err); return; } int width = image.width; int height = image.height; int channels = image.num_channels; //Allocate into memory mwSize dims[3]; dims[0] = height; dims[1] = width; dims[2] = channels; plhs[0] = mxCreateNumericArray(channels, dims, mxDOUBLE_CLASS, mxREAL); double *outMatrix = mxGetPr(plhs[0]); for (int i = 0; i < image.num_channels; i++) { if (image.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) { image.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; } } ret = LoadMultiChannelEXRFromFile(&image, nameFile, &err); if (ret != 0) { printf("Load EXR error: %s\n", err); return; } float **images = (float**) image.images; int nPixels = width * height; int nPixels2 = nPixels * 2; if(channels == 1) { nPixels = 0; nPixels2 = 0; } if(channels == 2) { nPixels2 = 0; } for (int i = 0; i < width; i++){ for (int j = 0; j < height; j++){ int index = i * height + j; int indexOut = j * width + i; outMatrix[index ] = images[2][indexOut]; outMatrix[index + nPixels] = images[1][indexOut]; outMatrix[index + nPixels2] = images[0][indexOut]; } } FreeEXRImage(&image); }