Skip to content

Commit 1aa4da8

Browse files
Feature/preserve exr standard attributes (data window, display window, etc) (#192)
* support reading exr files with non-trivial data window, closes #190 * copy standard attributes (data window, display window, etc) from input exr to output exr, allow different compression option using -compression command-line option
1 parent 223fd90 commit 1aa4da8

File tree

12 files changed

+170
-21
lines changed

12 files changed

+170
-21
lines changed

.github/workflows/codeql.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ jobs:
5858
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
5959
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
6060
steps:
61+
62+
- name: run apt-get update
63+
run: sudo apt-get -y update
6164

6265
- name: Checkout repository
6366
uses: actions/checkout@v4

.github/workflows/ubuntu_address_sanitizer.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ jobs:
2727

2828
steps:
2929

30+
- name: run apt-get update
31+
run: sudo apt-get -y update
32+
3033
- name: remove openexr
3134
run: sudo apt-get --purge remove libopenexr-dev -y
3235

@@ -70,6 +73,9 @@ jobs:
7073

7174
steps:
7275

76+
- name: run apt-get update
77+
run: sudo apt-get -y update
78+
7379
- name: remove openexr
7480
run: sudo apt-get --purge remove libopenexr-dev -y
7581

.github/workflows/ubuntu_arm_debug.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ jobs:
2727

2828
steps:
2929

30+
- name: run apt-get update
31+
run: sudo apt-get -y update
32+
3033
- name: install ilmbase
3134
run: sudo apt-get -y install libilmbase-dev
3235

@@ -52,6 +55,9 @@ jobs:
5255

5356
steps:
5457

58+
- name: run apt-get update
59+
run: sudo apt-get -y update
60+
5561
- name: remove ilmbase
5662
run: sudo apt-get --purge remove libilmbase-dev -y
5763

@@ -108,6 +114,9 @@ jobs:
108114

109115
steps:
110116

117+
- name: run apt-get update
118+
run: sudo apt-get -y update
119+
111120
- name: remove ilmbase
112121
run: sudo apt-get --purge remove libilmbase-dev -y
113122

.github/workflows/ubuntu_arm_release.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ jobs:
5858

5959
steps:
6060

61+
- name: run apt-get update
62+
run: sudo apt-get -y update
63+
6164
- name: remove ilmbase
6265
run: sudo apt-get --purge remove libilmbase-dev -y
6366

@@ -102,6 +105,9 @@ jobs:
102105

103106
steps:
104107

108+
- name: run apt-get update
109+
run: sudo apt-get -y update
110+
105111
- name: remove ilmbase
106112
run: sudo apt-get --purge remove libilmbase-dev -y
107113

@@ -157,6 +163,9 @@ jobs:
157163

158164
steps:
159165

166+
- name: run apt-get update
167+
run: sudo apt-get -y update
168+
160169
- name: remove ilmbase
161170
run: sudo apt-get --purge remove libilmbase-dev -y
162171

@@ -212,6 +221,9 @@ jobs:
212221

213222
steps:
214223

224+
- name: run apt-get update
225+
run: sudo apt-get -y update
226+
215227
- name: remove ilmbase
216228
run: sudo apt-get --purge remove libilmbase-dev -y
217229

.github/workflows/ubuntu_debug.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ jobs:
2727

2828
steps:
2929

30+
- name: run apt-get update
31+
run: sudo apt-get -y update
32+
3033
- name: install ilmbase
3134
run: sudo apt-get -y install libilmbase-dev
3235

@@ -52,6 +55,9 @@ jobs:
5255

5356
steps:
5457

58+
- name: run apt-get update
59+
run: sudo apt-get -y update
60+
5561
- name: remove ilmbase
5662
run: sudo apt-get --purge remove libilmbase-dev -y
5763

@@ -108,6 +114,9 @@ jobs:
108114

109115
steps:
110116

117+
- name: run apt-get update
118+
run: sudo apt-get -y update
119+
111120
- name: remove ilmbase
112121
run: sudo apt-get --purge remove libilmbase-dev -y
113122

.github/workflows/ubuntu_no_libtiff.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ jobs:
2727

2828
steps:
2929

30+
- name: run apt-get update
31+
run: sudo apt-get -y update
32+
3033
- name: remove libtiff
3134
run: sudo apt-get --purge remove libtiff-dev -y
3235

@@ -52,6 +55,9 @@ jobs:
5255

5356
steps:
5457

58+
- name: run apt-get update
59+
run: sudo apt-get -y update
60+
5561
- name: remove libtiff-dev
5662
run: sudo apt-get --purge remove libtiff-dev -y
5763

.github/workflows/ubuntu_release.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ jobs:
2727

2828
steps:
2929

30+
- name: run apt-get update
31+
run: sudo apt-get -y update
32+
3033
- name: install libtiff
3134
run: sudo apt-get -y install libtiff-dev
3235

@@ -55,6 +58,9 @@ jobs:
5558

5659
steps:
5760

61+
- name: run apt-get update
62+
run: sudo apt-get -y update
63+
5864
- name: remove ilmbase
5965
run: sudo apt-get --purge remove libilmbase-dev -y
6066

@@ -98,6 +104,9 @@ jobs:
98104
runs-on: ubuntu-latest
99105

100106
steps:
107+
108+
- name: run apt-get update
109+
run: sudo apt-get -y update
101110

102111
- name: remove ilmbase
103112
run: sudo apt-get --purge remove libilmbase-dev -y
@@ -154,6 +163,9 @@ jobs:
154163

155164
steps:
156165

166+
- name: run apt-get update
167+
run: sudo apt-get -y update
168+
157169
- name: remove ilmbase
158170
run: sudo apt-get --purge remove libilmbase-dev -y
159171

@@ -209,6 +221,9 @@ jobs:
209221

210222
steps:
211223

224+
- name: run apt-get update
225+
run: sudo apt-get -y update
226+
212227
- name: remove ilmbase
213228
run: sudo apt-get --purge remove libilmbase-dev -y
214229

ctlrender/exr_file.cc

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,20 @@
6464
#include <ImfChannelList.h>
6565
#include <Iex.h>
6666

67+
void exr_read_standard_attributes(Imf::InputFile *file, format_t *format)
68+
{
69+
format->exr_standard_attributes.dataWindow = file->header().dataWindow();
70+
format->exr_standard_attributes.displayWindow = file->header().displayWindow();
71+
format->exr_standard_attributes.pixelAspectRatio = file->header().pixelAspectRatio();
72+
format->exr_standard_attributes.screenWindowCenter = file->header().screenWindowCenter();
73+
format->exr_standard_attributes.screenWindowWidth = file->header().screenWindowWidth();
74+
format->exr_standard_attributes.lineOrder = file->header().lineOrder();
75+
format->exr_standard_attributes.compression = file->header().compression();
76+
77+
format->is_exr_standard_attributes_set = true;
78+
return;
79+
}
80+
6781
bool exr_read(const char *name, float scale, ctl::dpx::fb<float> *pixels,
6882
format_t *format) {
6983
std::ifstream ins;
@@ -92,7 +106,9 @@ bool exr_read(const char *name, float scale, ctl::dpx::fb<float> *pixels,
92106
//////////////////////////
93107

94108
Imf::InputFile file(name);
95-
Imath::Box2i dw = file.header().dataWindow();
109+
// read the exr standard attributes for potential later use in exr_write()
110+
exr_read_standard_attributes(&file, format);
111+
Imath::Box2i dw = format->exr_standard_attributes.dataWindow;
96112

97113
if (file.header().channels().begin().channel().type == Imf::HALF)
98114
format->src_bps=16;
@@ -112,30 +128,34 @@ bool exr_read(const char *name, float scale, ctl::dpx::fb<float> *pixels,
112128

113129
Imf::FrameBuffer frameBuffer;
114130
frameBuffer.insert ("R",
115-
Imf::Slice (pixelType,
131+
Imf::Slice::Make (pixelType,
116132
(char *) pixels->ptr(),
133+
dw,
117134
xstride, ystride,
118135
1, 1,
119136
0.0));
120137

121138
frameBuffer.insert ("G",
122-
Imf::Slice (pixelType,
139+
Imf::Slice::Make (pixelType,
123140
(char *) (pixels->ptr()+1),
141+
dw,
124142
xstride, ystride,
125143
1, 1,
126144
0.0));
127145

128146
frameBuffer.insert ("B",
129-
Imf::Slice (pixelType,
147+
Imf::Slice::Make (pixelType,
130148
(char *) (pixels->ptr()+2),
149+
dw,
131150
xstride, ystride,
132151
1, 1,
133152
0.0));
134153

135154
if (has_alpha){
136155
frameBuffer.insert ("A",
137-
Imf::Slice (pixelType,
156+
Imf::Slice::Make (pixelType,
138157
(char *) (pixels->ptr()+3),
158+
dw,
139159
xstride, ystride,
140160
1, 1,
141161
1.0));
@@ -166,8 +186,8 @@ void exr_write(const char *name, float scale, const ctl::dpx::fb<float> &pixels,
166186
bool is_half = format->bps == 16 ? true : false;
167187

168188
int depth = pixels.depth();
169-
float width = pixels.width();
170-
float height = pixels.height();
189+
int width = pixels.width();
190+
int height = pixels.height();
171191
float const* pixelPtr = pixels.ptr();
172192

173193
// Do any scaling on a full float buffer
@@ -189,13 +209,33 @@ void exr_write(const char *name, float scale, const ctl::dpx::fb<float> &pixels,
189209
Imf::PixelType pixelType = is_half ? Imf::HALF : Imf::FLOAT;
190210

191211
Imf::Header header(width, height);
192-
header.compression() = (Imf::Compression)compression->exrCompressionScheme;
212+
213+
if (format->is_exr_standard_attributes_set) {
214+
header.dataWindow() = format->exr_standard_attributes.dataWindow;
215+
header.displayWindow() = format->exr_standard_attributes.displayWindow;
216+
header.pixelAspectRatio() = format->exr_standard_attributes.pixelAspectRatio;
217+
header.screenWindowCenter() = format->exr_standard_attributes.screenWindowCenter;
218+
header.screenWindowWidth() = format->exr_standard_attributes.screenWindowWidth;
219+
header.lineOrder() = format->exr_standard_attributes.lineOrder;
220+
if (true == format->is_compression_set) {
221+
// the user specified a specific compression type
222+
header.compression() = (Imf::Compression)compression->exrCompressionScheme;
223+
}
224+
else {
225+
header.compression() = format->exr_standard_attributes.compression;
226+
}
227+
}
228+
else {
229+
header.compression() = (Imf::Compression)compression->exrCompressionScheme;
230+
}
231+
Imath::Box2i dataWindow = header.dataWindow();
193232

194233
header.channels().insert("R", Imf::Channel(pixelType));
195234
header.channels().insert("G", Imf::Channel(pixelType));
196235
header.channels().insert("B", Imf::Channel(pixelType));
197-
if (depth == 4)
198-
header.channels().insert("A", Imf::Channel(pixelType));
236+
if (depth == 4) {
237+
header.channels().insert("A", Imf::Channel(pixelType));
238+
}
199239

200240
Imf::OutputFile file(name, header);
201241
Imf::FrameBuffer frameBuffer;
@@ -219,27 +259,32 @@ void exr_write(const char *name, float scale, const ctl::dpx::fb<float> &pixels,
219259
int ystride = sizeof(*halfPixelPtr) * depth * width;
220260

221261
// Insert the half buffer into the framebuffer
222-
frameBuffer.insert("R", Imf::Slice(pixelType, (char*)halfPixelPtr, xstride, ystride));
223-
frameBuffer.insert("G", Imf::Slice(pixelType, (char*)(halfPixelPtr + 1), xstride, ystride));
224-
frameBuffer.insert("B", Imf::Slice(pixelType, (char*)(halfPixelPtr + 2), xstride, ystride));
225-
if (depth == 4)
226-
frameBuffer.insert("A", Imf::Slice(pixelType, (char*)(halfPixelPtr + 3), xstride, ystride));
262+
frameBuffer.insert("R", Imf::Slice::Make(pixelType, (char*)(halfPixelPtr + 0), dataWindow, xstride, ystride));
263+
frameBuffer.insert("G", Imf::Slice::Make(pixelType, (char*)(halfPixelPtr + 1), dataWindow, xstride, ystride));
264+
frameBuffer.insert("B", Imf::Slice::Make(pixelType, (char*)(halfPixelPtr + 2), dataWindow, xstride, ystride));
265+
if (depth == 4) {
266+
frameBuffer.insert("A", Imf::Slice::Make(pixelType, (char*)(halfPixelPtr + 3), dataWindow, xstride, ystride));
267+
}
268+
227269
}
228270
else {
229271
// No conversion needed so insert the float buffer into the frambuffer
230272
int xstride = sizeof(*pixelPtr) * depth;
231273
int ystride = sizeof(*pixelPtr) * depth * width;
232274

233-
frameBuffer.insert("R", Imf::Slice(pixelType, (char*)pixelPtr, xstride, ystride));
234-
frameBuffer.insert("G", Imf::Slice(pixelType, (char*)(pixelPtr + 1), xstride, ystride));
235-
frameBuffer.insert("B", Imf::Slice(pixelType, (char*)(pixelPtr + 2), xstride, ystride));
236-
if (depth == 4)
237-
frameBuffer.insert("A", Imf::Slice(pixelType, (char*)(pixelPtr + 3), xstride, ystride));
275+
frameBuffer.insert("R", Imf::Slice::Make(pixelType, (char*)(pixelPtr + 0), dataWindow, xstride, ystride));
276+
frameBuffer.insert("G", Imf::Slice::Make(pixelType, (char*)(pixelPtr + 1), dataWindow, xstride, ystride));
277+
frameBuffer.insert("B", Imf::Slice::Make(pixelType, (char*)(pixelPtr + 2), dataWindow, xstride, ystride));
278+
if (depth == 4) {
279+
frameBuffer.insert("A", Imf::Slice::Make(pixelType, (char*)(pixelPtr + 3), dataWindow, xstride, ystride));
280+
}
281+
238282
}
239283

240284
file.setFrameBuffer(frameBuffer);
241-
file.writePixels(height);
285+
file.writePixels(dataWindow.max.y - dataWindow.min.y + 1);
242286

287+
return;
243288
}
244289

245290
#else

ctlrender/format.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,19 @@ format_t::format_t() {
5959
bps=0;
6060
squish=0;
6161
descriptor=0;
62+
is_compression_set = false;
63+
#if defined(HAVE_OPENEXR)
64+
is_exr_standard_attributes_set = false;
65+
#endif
6266
};
6367

6468
format_t::format_t(const char *_ext, uint8_t _bps) {
6569
ext=_ext;
6670
bps=_bps;
6771
squish=0;
6872
descriptor=0;
73+
is_compression_set = false;
74+
#if defined(HAVE_OPENEXR)
75+
is_exr_standard_attributes_set = false;
76+
#endif
6977
};

0 commit comments

Comments
 (0)