AcademySoftwareFoundation / AcademySoftwareFoundation/openexr
OpenEXRCore 3.1.1 - A detailed writing example
- Dominant language
- C
- Stars
- 1.8k
- Forks
- 700
- Avg merge
- 3d 12h
- Merged PRs (30d)
- 29
Description
I'm working on a function that writes EXRs using Core only and what I have below does the job except all pixels have the same value (i.e. we get a constant color image) eventually. The value in questions seems to be the the RGBA value of the upper left most pixel. I couldn't find a detailed exr write example in the documentation, so I looked at the src of the EXR tests which helped a lot to get to the function here:
```
void writeEXR(Image *image, char *filename) {
int pixel_count = image->width * image->height;
size_t total_size = pixel_count * 4 * sizeof(float);
// PREPARE RAW IMAGE DATA
uint8_t *data = malloc(total_size);
memset(data, 0, total_size);
for (int y = 0; y < image->height; y++) { // Iterate over the lines
for (int x = 0; x < image->width; x++) { // Iterate over the line pixels
unsigned index = (y * image->width + x) * sizeof(float);
printf("%d ", index);
// This should give us planar layout (e.g. 4x1 px):
// 0__________________ 1__________________ 2__________________ 3__________________
// 0___ 4___ 8___ 12__ 0___ 4___ 8___ 12__ 0___ 4___ 8___ 12__ 0___ 4___ 8___ 12__
// RRRR RRRR RRRR RRRR | GGGG GGGG GGGG GGGG | BBBB BBBB BBBB BBBB | AAAA AAAA AAAA AAAA
memcpy(data + (pixel_count * 0 * sizeof(float) + index), &image->pixels[y][x].color.r, sizeof(float));
memcpy(data + (pixel_count * 1 * sizeof(float) + index), &image->pixels[y][x].color.g, sizeof(float));
memcpy(data + (pixel_count * 2 * sizeof(float) + index), &image->pixels[y][x].color.b, sizeof(float));
memcpy(data + (pixel_count * 3 * sizeof(float) + index), &image->pixels[y][x].alpha, sizeof(float));
}
}
// INIT EXR
exr_context_initializer_t ctxinit = EXR_DEFAULT_CONTEXT_INITIALIZER;
ctxinit.max_image_width = image->width;
ctxinit.max_image_height = image->height;
exr_context_t out;
int partidx = 0;
exr_start_write(&out, filename, EXR_WRITE_FILE_DIRECTLY, &ctxinit);
exr_get_count(out, &partidx);
assert(partidx == 0);
exr_add_part(out, "Ci", EXR_STORAGE_SCANLINE, &partidx);
assert(partidx == 0);
exr_initialize_required_attr_simple(out, partidx, image->width, image->height, EXR_COMPRESSION_ZIPS);
exr_add_channel(out, partidx, "A", EXR_PIXEL_FLOAT, EXR_PERCEPTUALLY_LINEAR, 1, 1);
exr_add_channel(out, partidx, "B", EXR_PIXEL_FLOAT, EXR_PERCEPTUALLY_LOGARITHMIC, 1, 1);
exr_add_channel(out, partidx, "G", EXR_PIXEL_FLOAT, EXR_PERCEPTUALLY_LOGARITHMIC, 1, 1);
exr_add_channel(out, partidx, "R", EXR_PIXEL_FLOAT, EXR_PERCEPTUALLY_LOGARITHMIC, 1, 1);
exr_attr_set_user(out, partidx, "user", "mytype", 4, "foo");
exr_write_header(out);
int nchunks = 0;
exr_get_chunk_count(out, partidx, &nchunks);
exr_chunk_info_t cinfo;
exr_encode_pipeline_t encoder;
exr_write_scanline_chunk_info(out, partidx, 0, &cinfo);
exr_encoding_initialize(out, partidx, &cinfo, &encoder);
encoder.channels[0].channel_name = "A";
encoder.channels[0].encode_from_ptr = &data[pixel_count * sizeof(float) * 3];
encoder.channels[0].user_data_type = EXR_PIXEL_FLOAT;
encoder.channels[0].user_pixel_stride = 1 * sizeof(float);
encoder.channels[0].user_line_stride = sizeof(float) * image->width;
encoder.channels[0].user_bytes_per_element = sizeof(float);
encoder.channels[1].channel_name = "B";
encoder.channels[1].encode_from_ptr = &data[pixel_count * sizeof(float) * 2];
encoder.channels[1].user_data_type = EXR_PIXEL_FLOAT;
encoder.channels[1].user_pixel_stride = 1 * sizeof(float);
encoder.channels[1].user_line_stride = sizeof(float) * image->width;
encoder.channels[1].user_bytes_per_element = sizeof(float);
encoder.channels[2].channel_name = "G";
encoder.channels[2].encode_from_ptr = &data[pixel_count * sizeof(float) * 1];
encoder.channels[2].user_data_type = EXR_PIXEL_FLOAT;
encoder.channels[2].user_pixel_stride = 1 * sizeof(float);
encoder.channels[2].user_line_stride = sizeof(float) * image->width;
encoder.channels[2].user_bytes_per_element = sizeof(float);
encoder.channels[3].channel_name = "R";
encoder.channels[3].encode_from_ptr = &data[pixel_count * sizeof(float) * 0];
encoder.channels[3].user_data_type = EXR_PIXEL_FLOAT;
encoder.channels[3].user_pixel_stride = 1 * sizeof(float);
encoder.channels[3].user_line_stride = sizeof(float) * image->width;
encoder.channels[3].user_bytes_per_element = 4;
exr_encoding_choose_default_routines(out, partidx, &encoder);
for (int y = 0; y < nchunks; y++) {
if (y > 0) {
exr_write_scanline_chunk_info(out, partidx, y, &cinfo);
exr_encoding_update(out, partidx, &cinfo, &encoder);
}
exr_encoding_run(out, partidx, &encoder);
}
exr_encoding_destroy(out, &encoder);
exr_finish(&out);
}
```
Yet, I must be doing something wrong. Can anybody spot the problem? A nudge in the right direction would be awesome! Thanks!
Contributor guide
Research direction
Start with the EXR tests referenced in the issue and compare their OpenEXRCore write flow with the supplied writeEXR function, especially the channel buffers and scanline handling. Done means providing a detailed, verified writing example in the documentation that produces varying pixel values rather than a constant-color image.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- computer-graphics
- Issue type
- Documentation
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100