Skip to content

Commit

Permalink
Introduce internal_images and internal_pixel_types field to ExrIm…
Browse files Browse the repository at this point in the history
…age.

Internal images are only non-zero for HALF pixel image channel. It stores original fp16 value.
For UINT and FLOAT pixel image channel, `internal_images[c]` is set to NULL.
  • Loading branch information
syoyo committed Jun 19, 2015
1 parent 191ab08 commit cdf93e6
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 12 deletions.
4 changes: 4 additions & 0 deletions test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ main(int argc, char** argv)
const char* outfilename = "output_test.exr";
const char* err;
EXRImage exrImage;
InitExrImage(&exrImage);

if (argc < 2) {
fprintf(stderr, "Needs input.exr.\n");
Expand Down Expand Up @@ -71,6 +72,7 @@ main(int argc, char** argv)
for (int i = 0; i < exrImage.num_channels; i++) {
printf("pixelType[%d]: %d\n", i, exrImage.pixel_types[i]);
printf("chan[%d] = %s\n", i, exrImage.channel_names[i]);
printf("internal_images[%d] = %p\n", i, exrImage.internal_images[i]);
}

// Uncomment to save image as float pixel type.
Expand All @@ -84,6 +86,8 @@ main(int argc, char** argv)
return ret;
}
printf("Saved exr file. [ %s ] \n", outfilename);

FreeExrImage(&exrImage);
#endif

return ret;
Expand Down
109 changes: 103 additions & 6 deletions tinyexr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6994,6 +6994,7 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
}

EXRImage exrImage;
InitExrImage(&exrImage);
int ret = LoadMultiChannelEXRFromFile(&exrImage, filename, err);
if (ret != 0) {
return ret;
Expand Down Expand Up @@ -7219,6 +7220,7 @@ int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory, const char *
}

EXRImage exrImage;
InitExrImage(&exrImage);
int ret = LoadMultiChannelEXRFromMemory(&exrImage, memory, err);
if (ret != 0) {
return ret;
Expand Down Expand Up @@ -7502,6 +7504,17 @@ int LoadMultiChannelEXRFromMemory(EXRImage *exrImage, const unsigned char *memor
dataHeight)); // enough to store float and uint pixel image
}

exrImage->internal_images = reinterpret_cast<unsigned char **>(
(unsigned short **)malloc(sizeof(unsigned short *) * numChannels));
for (int c = 0; c < numChannels; c++) {
exrImage->internal_images[c] = NULL;
}

exrImage->internal_pixel_types = (int *)malloc(sizeof(int) * numChannels);
for (int c = 0; c < numChannels; c++) {
exrImage->internal_pixel_types[c] = channels[c].pixelType;
}

std::vector<size_t> channelOffsetList(numChannels);
int pixelDataSize = 0;
size_t channelOffset = 0;
Expand All @@ -7510,6 +7523,8 @@ int LoadMultiChannelEXRFromMemory(EXRImage *exrImage, const unsigned char *memor
if (channels[c].pixelType == TINYEXR_PIXELTYPE_HALF) {
pixelDataSize += sizeof(unsigned short);
channelOffset += sizeof(unsigned short);
// Alloc internal image for half type.
exrImage->internal_images[c] = (unsigned char*)malloc(sizeof(unsigned short) * dataWidth * dataHeight);
} else if (channels[c].pixelType == TINYEXR_PIXELTYPE_FLOAT) {
pixelDataSize += sizeof(float);
channelOffset += sizeof(float);
Expand Down Expand Up @@ -7582,13 +7597,27 @@ int LoadMultiChannelEXRFromMemory(EXRImage *exrImage, const unsigned char *memor

FP32 f32 = half_to_float(hf);

float *image = reinterpret_cast<float **>(exrImage->images)[c];
if (lineOrder == 0) {
image += (lineNo + v) * dataWidth + u;
} else {
image += (dataHeight - 1 - (lineNo + v)) * dataWidth + u;
{
float *image = reinterpret_cast<float **>(exrImage->images)[c];
if (lineOrder == 0) {
image += (lineNo + v) * dataWidth + u;
} else {
image += (dataHeight - 1 - (lineNo + v)) * dataWidth + u;
}
*image = f32.f;
}

// Store fp16 value to internal_image
{
assert(exrImage->internal_images[c]);
unsigned short *internalImage = reinterpret_cast<unsigned short **>(exrImage->internal_images)[c];
if (lineOrder == 0) {
internalImage += (lineNo + v) * dataWidth + u;
} else {
internalImage += (dataHeight - 1 - (lineNo + v)) * dataWidth + u;
}
*internalImage = hf.u;
}
*image = f32.f;
}
}
} else if (channels[c].pixelType == TINYEXR_PIXELTYPE_UINT) {
Expand Down Expand Up @@ -7658,6 +7687,13 @@ int LoadMultiChannelEXRFromMemory(EXRImage *exrImage, const unsigned char *memor

const unsigned short *linePtr = reinterpret_cast<const unsigned short *>(
dataPtr + 8 + c * dataWidth * sizeof(unsigned short));

unsigned short *outLineInternal = reinterpret_cast<unsigned short **>(exrImage->internal_images)[c];
if (lineOrder == 0) {
outLineInternal += y * dataWidth;
} else {
outLineInternal += (dataHeight - 1 - y) * dataWidth;
}

for (int u = 0; u < dataWidth; u++) {
FP16 hf;
Expand All @@ -7671,6 +7707,9 @@ int LoadMultiChannelEXRFromMemory(EXRImage *exrImage, const unsigned char *memor
FP32 f32 = half_to_float(hf);

outLine[u] = f32.f;

// Also store fp16 value to internal_image
outLineInternal[u] = hf.u;
}
}
else if (channels[c].pixelType == TINYEXR_PIXELTYPE_FLOAT) {
Expand Down Expand Up @@ -8784,3 +8823,61 @@ int SaveDeepEXR(const DeepImage *deepImage, const char *filename,

return 0; // OK
}

void InitExrImage(EXRImage* exrImage) {
if (exrImage == NULL) {
return;
}

exrImage->num_channels = 0;
exrImage->channel_names = NULL;
exrImage->images = NULL;
exrImage->internal_images = NULL;
exrImage->pixel_types = NULL;
exrImage->internal_pixel_types = NULL;
}

int FreeExrImage(EXRImage* exrImage) {

if (exrImage == NULL) {
return -1; // Err
}

for (int i = 0; i < exrImage->num_channels; i++) {

if (exrImage->channel_names && exrImage->channel_names[i]) {
free((char*)exrImage->channel_names[i]); // remove const
}

if (exrImage->images && exrImage->images[i]) {
free(exrImage->images[i]);
}

if (exrImage->internal_images && exrImage->internal_images[i]) {
free(exrImage->internal_images[i]);
}

}

if (exrImage->channel_names) {
free(exrImage->channel_names);
}

if (exrImage->images) {
free(exrImage->images);
}

if (exrImage->internal_images) {
free(exrImage->internal_images);
}

if (exrImage->pixel_types) {
free(exrImage->pixel_types);
}

if (exrImage->internal_pixel_types) {
free(exrImage->internal_pixel_types);
}

return 0;
}
23 changes: 17 additions & 6 deletions tinyexr.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,13 @@ extern "C" {
typedef struct _EXRImage {
int num_channels;
const char **channel_names;
unsigned char **images; // image[channels][pixels]
int *pixel_types; // pixel type(TINYEXR_PIXELTYPE_*) for each channel

unsigned char **images; // image[channels][pixels]
int *pixel_types; // pixel type(TINYEXR_PIXELTYPE_*) of `images` for each channel

unsigned char **internal_images; // internal image data of half type. Only non-null for half type image channel.
int *internal_pixel_types; // internal pixel type(i.e. pixel type stored in .exr data) of `internal_images`

int width;
int height;
} EXRImage;
Expand All @@ -68,7 +73,6 @@ extern int LoadEXR(float **out_rgba, int *width, int *height,
// For emscripten.
// Parse single-frame OpenEXR header from memory.
// Return 0 if success
// Returns error string in `err` when there's an error
extern int ParseEXRHeaderFromMemory(int *width, int *height, const unsigned char *memory);

// For emscripten.
Expand Down Expand Up @@ -101,23 +105,23 @@ extern int LoadMultiChannelEXRFromMemory(EXRImage *image, const unsigned char *m

// Saves multi-channel, single-frame OpenEXR image to a file.
// Application must free EXRImage
// Return 0 if success
// Returns 0 if success
// Returns error string in `err` when there's an error
extern int SaveMultiChannelEXRToFile(const EXRImage *image,
const char *filename, const char **err);

// Saves multi-channel, single-frame OpenEXR image to a memory.
// Application must free EXRImage
// Return the number of bytes if succes.
// Retrun zero or negative number when failed.
// Retruns 0 if success, negative number when failed.
// Returns error string in `err` when there's an error
extern size_t SaveMultiChannelEXRToMemory(const EXRImage *image,
unsigned char **memory,
const char **err);

// Loads single-frame OpenEXR deep image.
// Application must free memory of variables in DeepImage(image, offset_table)
// Return 0 if success
// Returns 0 if success
// Returns error string in `err` when there's an error
extern int LoadDeepEXR(DeepImage *out_image, const char *filename,
const char **err);
Expand All @@ -136,6 +140,13 @@ extern int LoadDeepEXR(DeepImage *out_image, const char *filename,
// char *filename,
// const char **err);

// Initialize of EXRImage struct
extern void InitExrImage(EXRImage* exrImage);

// Free's internal data of EXRImage struct
// Returns 0 if success.
extern int FreeExrImage(EXRImage* exrImage);

#ifdef __cplusplus
}
#endif
Expand Down

0 comments on commit cdf93e6

Please sign in to comment.