1 /*
2 ** SPDX-License-Identifier: BSD-3-Clause
3 ** Copyright Contributors to the OpenEXR Project.
4 */
5
6 #include "openexr_encode.h"
7
8 #include "internal_coding.h"
9 #include "internal_compress.h"
10 #include "internal_structs.h"
11 #include "internal_xdr.h"
12
13 /**************************************/
14
15 static exr_result_t
default_compress_chunk(exr_encode_pipeline_t * encode)16 default_compress_chunk (exr_encode_pipeline_t* encode)
17 {
18 exr_result_t rv;
19 EXR_PROMOTE_CONST_CONTEXT_AND_PART_OR_ERROR_NO_LOCK (
20 encode->context, encode->part_index);
21
22 rv = internal_encode_alloc_buffer (
23 encode,
24 EXR_TRANSCODE_BUFFER_COMPRESSED,
25 &(encode->compressed_buffer),
26 &(encode->compressed_alloc_size),
27 (((size_t) encode->packed_bytes) * (size_t) 110) / ((size_t) 100) +
28 65536);
29 if (rv != EXR_ERR_SUCCESS) return rv;
30
31 switch (part->comp_type)
32 {
33 case EXR_COMPRESSION_NONE:
34 return pctxt->report_error (
35 pctxt,
36 EXR_ERR_INVALID_ARGUMENT,
37 "no compresssion set but still trying to compress");
38
39 case EXR_COMPRESSION_RLE: rv = internal_exr_apply_rle (encode); break;
40 case EXR_COMPRESSION_ZIP:
41 case EXR_COMPRESSION_ZIPS: rv = internal_exr_apply_zip (encode); break;
42 case EXR_COMPRESSION_PIZ: rv = internal_exr_apply_piz (encode); break;
43 case EXR_COMPRESSION_PXR24:
44 rv = internal_exr_apply_pxr24 (encode);
45 break;
46 case EXR_COMPRESSION_B44: rv = internal_exr_apply_b44 (encode); break;
47 case EXR_COMPRESSION_B44A: rv = internal_exr_apply_b44a (encode); break;
48 case EXR_COMPRESSION_DWAA: rv = internal_exr_apply_dwaa (encode); break;
49 case EXR_COMPRESSION_DWAB: rv = internal_exr_apply_dwab (encode); break;
50 case EXR_COMPRESSION_LAST_TYPE:
51 default:
52 return pctxt->print_error (
53 pctxt,
54 EXR_ERR_INVALID_ARGUMENT,
55 "Compression technique 0x%02X invalid",
56 (int) part->comp_type);
57 }
58 return rv;
59 }
60
61 /**************************************/
62
63 static exr_result_t
default_yield(exr_encode_pipeline_t * encode)64 default_yield (exr_encode_pipeline_t* encode)
65 {
66 exr_result_t rv;
67 EXR_PROMOTE_CONST_CONTEXT_AND_PART_OR_ERROR (
68 encode->context, encode->part_index);
69
70 rv = internal_validate_next_chunk (encode, pctxt, part);
71
72 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (rv);
73 }
74
75 /**************************************/
76
77 static exr_result_t
default_write_chunk(exr_encode_pipeline_t * encode)78 default_write_chunk (exr_encode_pipeline_t* encode)
79 {
80 exr_result_t rv;
81
82 if (!encode) return EXR_ERR_INVALID_ARGUMENT;
83
84 switch (encode->chunk.type)
85 {
86 case EXR_STORAGE_SCANLINE:
87 rv = exr_write_scanline_chunk (
88 EXR_CONST_CAST (exr_context_t, encode->context),
89 encode->part_index,
90 encode->chunk.start_y,
91 encode->compressed_buffer,
92 encode->compressed_bytes);
93 break;
94 case EXR_STORAGE_TILED:
95 rv = exr_write_tile_chunk (
96 EXR_CONST_CAST (exr_context_t, encode->context),
97 encode->part_index,
98 encode->chunk.start_x,
99 encode->chunk.start_y,
100 encode->chunk.level_x,
101 encode->chunk.level_y,
102 encode->compressed_buffer,
103 encode->compressed_bytes);
104 break;
105 case EXR_STORAGE_DEEP_SCANLINE:
106 if (!encode->packed_sample_count_table ||
107 encode->packed_sample_count_bytes == 0)
108 return EXR_ERR_INVALID_ARGUMENT;
109 rv = exr_write_deep_scanline_chunk (
110 EXR_CONST_CAST (exr_context_t, encode->context),
111 encode->part_index,
112 encode->chunk.start_y,
113 encode->compressed_buffer,
114 encode->compressed_bytes,
115 encode->packed_bytes,
116 encode->packed_sample_count_table,
117 encode->packed_sample_count_bytes);
118 break;
119 case EXR_STORAGE_DEEP_TILED:
120 if (!encode->packed_sample_count_table ||
121 encode->packed_sample_count_bytes == 0)
122 return EXR_ERR_INVALID_ARGUMENT;
123 rv = exr_write_deep_tile_chunk (
124 EXR_CONST_CAST (exr_context_t, encode->context),
125 encode->part_index,
126 encode->chunk.start_x,
127 encode->chunk.start_y,
128 encode->chunk.level_x,
129 encode->chunk.level_y,
130 encode->compressed_buffer,
131 encode->compressed_bytes,
132 encode->packed_bytes,
133 encode->packed_sample_count_table,
134 encode->packed_sample_count_bytes);
135 break;
136 case EXR_STORAGE_LAST_TYPE:
137 default: rv = EXR_ERR_INVALID_ARGUMENT; break;
138 }
139 return rv;
140 }
141
142 /**************************************/
143
144 exr_result_t
exr_encoding_initialize(exr_const_context_t ctxt,int part_index,const exr_chunk_info_t * cinfo,exr_encode_pipeline_t * encode)145 exr_encoding_initialize (
146 exr_const_context_t ctxt,
147 int part_index,
148 const exr_chunk_info_t* cinfo,
149 exr_encode_pipeline_t* encode)
150 {
151 exr_result_t rv;
152 exr_encode_pipeline_t nil = { 0 };
153
154 EXR_PROMOTE_CONST_CONTEXT_AND_PART_OR_ERROR (ctxt, part_index);
155 if (!cinfo || !encode)
156 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (
157 pctxt->standard_error (pctxt, EXR_ERR_INVALID_ARGUMENT));
158
159 if (pctxt->mode != EXR_CONTEXT_WRITING_DATA)
160 {
161 if (pctxt->mode == EXR_CONTEXT_WRITE)
162 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (
163 pctxt->standard_error (pctxt, EXR_ERR_HEADER_NOT_WRITTEN));
164 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (
165 pctxt->standard_error (pctxt, EXR_ERR_NOT_OPEN_WRITE));
166 }
167
168 *encode = nil;
169
170 rv = internal_coding_fill_channel_info (
171 &(encode->channels),
172 &(encode->channel_count),
173 encode->_quick_chan_store,
174 cinfo,
175 pctxt,
176 part);
177
178 if (rv == EXR_ERR_SUCCESS)
179 {
180 encode->part_index = part_index;
181 encode->context = ctxt;
182 encode->chunk = *cinfo;
183 }
184 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (rv);
185 }
186
187 /**************************************/
188
189 exr_result_t
exr_encoding_choose_default_routines(exr_const_context_t ctxt,int part_index,exr_encode_pipeline_t * encode)190 exr_encoding_choose_default_routines (
191 exr_const_context_t ctxt, int part_index, exr_encode_pipeline_t* encode)
192 {
193 int32_t isdeep = 0;
194 EXR_PROMOTE_CONST_CONTEXT_AND_PART_OR_ERROR (ctxt, part_index);
195 if (!encode)
196 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (
197 pctxt->standard_error (pctxt, EXR_ERR_INVALID_ARGUMENT));
198
199 if (encode->context != ctxt || encode->part_index != part_index)
200 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (pctxt->print_error (
201 pctxt,
202 EXR_ERR_INVALID_ARGUMENT,
203 "Cross-wired request for default routines from different context / part"));
204
205 isdeep = (part->storage_mode == EXR_STORAGE_DEEP_SCANLINE ||
206 part->storage_mode == EXR_STORAGE_DEEP_TILED)
207 ? 1
208 : 0;
209
210 encode->convert_and_pack_fn = internal_exr_match_encode (encode, isdeep);
211 if (part->comp_type != EXR_COMPRESSION_NONE)
212 encode->compress_fn = &default_compress_chunk;
213 encode->yield_until_ready_fn = &default_yield;
214 encode->write_fn = &default_write_chunk;
215
216 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (EXR_ERR_SUCCESS);
217 }
218
219 /**************************************/
220
221 exr_result_t
exr_encoding_update(exr_const_context_t ctxt,int part_index,const exr_chunk_info_t * cinfo,exr_encode_pipeline_t * encode)222 exr_encoding_update (
223 exr_const_context_t ctxt,
224 int part_index,
225 const exr_chunk_info_t* cinfo,
226 exr_encode_pipeline_t* encode)
227 {
228 exr_result_t rv;
229
230 EXR_PROMOTE_CONST_CONTEXT_AND_PART_OR_ERROR (ctxt, part_index);
231 if (!cinfo || !encode)
232 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (
233 pctxt->standard_error (pctxt, EXR_ERR_INVALID_ARGUMENT));
234
235 if (encode->context != ctxt || encode->part_index != part_index)
236 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (pctxt->print_error (
237 pctxt,
238 EXR_ERR_INVALID_ARGUMENT,
239 "Cross-wired request for default routines from different context / part"));
240
241 if (encode->packed_buffer == encode->compressed_buffer)
242 encode->compressed_buffer = NULL;
243
244 encode->packed_bytes = 0;
245 encode->packed_sample_count_bytes = 0;
246 encode->compressed_bytes = 0;
247
248 rv = internal_coding_update_channel_info (
249 encode->channels, encode->channel_count, cinfo, pctxt, part);
250
251 if (rv == EXR_ERR_SUCCESS) encode->chunk = *cinfo;
252 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (rv);
253 }
254
255 /**************************************/
256
257 exr_result_t
exr_encoding_run(exr_const_context_t ctxt,int part_index,exr_encode_pipeline_t * encode)258 exr_encoding_run (
259 exr_const_context_t ctxt, int part_index, exr_encode_pipeline_t* encode)
260 {
261 exr_result_t rv = EXR_ERR_SUCCESS;
262 uint64_t packed_bytes = 0;
263 EXR_PROMOTE_CONST_CONTEXT_AND_PART_OR_ERROR (ctxt, part_index);
264
265 if (!encode)
266 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (
267 pctxt->standard_error (pctxt, EXR_ERR_INVALID_ARGUMENT));
268 if (encode->context != ctxt || encode->part_index != part_index)
269 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (pctxt->report_error (
270 pctxt,
271 EXR_ERR_INVALID_ARGUMENT,
272 "Invalid request for encoding update from different context / part"));
273
274 if (part->storage_mode == EXR_STORAGE_DEEP_SCANLINE ||
275 part->storage_mode == EXR_STORAGE_DEEP_TILED)
276 {
277 if (encode->sample_count_table == NULL ||
278 encode->sample_count_alloc_size !=
279 (((size_t) encode->chunk.width) *
280 ((size_t) encode->chunk.height) * sizeof (int32_t)))
281 {
282 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (pctxt->report_error (
283 pctxt,
284 EXR_ERR_INVALID_ARGUMENT,
285 "Invalid / missing sample count table for deep data"));
286 }
287 }
288
289 for (int c = 0; c < encode->channel_count; ++c)
290 {
291 const exr_coding_channel_info_t* encc = (encode->channels + c);
292
293 if (encc->height == 0) continue;
294
295 if (encc->width == 0)
296 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (pctxt->print_error (
297 pctxt,
298 EXR_ERR_INVALID_ARGUMENT,
299 "Unexpected 0-width chunk to encode"));
300 if (!encc->encode_from_ptr)
301 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (pctxt->print_error (
302 pctxt,
303 EXR_ERR_INVALID_ARGUMENT,
304 "Missing channel data pointer - must encode all channels"));
305
306 /*
307 * if a user specifies a bad pixel stride / line stride
308 * we can't know this realistically, and they may want to
309 * use 0 to cause things to collapse for testing purposes
310 * so only test the values we can
311 */
312 if (encc->user_bytes_per_element != 2 &&
313 encc->user_bytes_per_element != 4)
314 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (pctxt->print_error (
315 pctxt,
316 EXR_ERR_INVALID_ARGUMENT,
317 "Invalid / unsupported output bytes per element (%d) for channel %c (%s)",
318 (int) encc->user_bytes_per_element,
319 c,
320 encc->channel_name));
321
322 if (encc->user_data_type != (uint16_t) (EXR_PIXEL_HALF) &&
323 encc->user_data_type != (uint16_t) (EXR_PIXEL_FLOAT) &&
324 encc->user_data_type != (uint16_t) (EXR_PIXEL_UINT))
325 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (pctxt->print_error (
326 pctxt,
327 EXR_ERR_INVALID_ARGUMENT,
328 "Invalid / unsupported output data type (%d) for channel %c (%s)",
329 (int) encc->user_data_type,
330 c,
331 encc->channel_name));
332
333 packed_bytes +=
334 ((uint64_t) (encc->height) * (uint64_t) (encc->width) *
335 (uint64_t) (encc->bytes_per_element));
336 }
337
338 encode->packed_bytes = 0;
339 if (encode->convert_and_pack_fn)
340 {
341 if (packed_bytes > 0)
342 {
343 rv = internal_encode_alloc_buffer (
344 encode,
345 EXR_TRANSCODE_BUFFER_PACKED,
346 &(encode->packed_buffer),
347 &(encode->packed_alloc_size),
348 packed_bytes);
349
350 if (rv == EXR_ERR_SUCCESS)
351 rv = encode->convert_and_pack_fn (encode);
352 }
353 }
354 else if (!encode->packed_buffer || packed_bytes != encode->compressed_bytes)
355 {
356 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (pctxt->report_error (
357 pctxt,
358 EXR_ERR_INVALID_ARGUMENT,
359 "Encode pipeline has no packing function declared and packed buffer is null or appears to need packing"));
360 }
361 EXR_UNLOCK_WRITE (pctxt);
362
363 if ((part->storage_mode == EXR_STORAGE_DEEP_SCANLINE ||
364 part->storage_mode == EXR_STORAGE_DEEP_TILED) &&
365 encode->sample_count_table != NULL)
366 {
367 priv_from_native32 (
368 encode->sample_count_table,
369 encode->chunk.width * encode->chunk.height);
370 }
371
372 if (rv == EXR_ERR_SUCCESS)
373 {
374 if (encode->compress_fn && encode->packed_bytes > 0)
375 {
376 rv = encode->compress_fn (encode);
377 }
378 else
379 {
380 internal_encode_free_buffer (
381 encode,
382 EXR_TRANSCODE_BUFFER_COMPRESSED,
383 &(encode->compressed_buffer),
384 &(encode->compressed_alloc_size));
385
386 internal_encode_free_buffer (
387 encode,
388 EXR_TRANSCODE_BUFFER_PACKED_SAMPLES,
389 &(encode->packed_sample_count_table),
390 &(encode->packed_sample_count_alloc_size));
391
392 encode->compressed_buffer = encode->packed_buffer;
393 encode->compressed_bytes = encode->packed_bytes;
394 encode->compressed_alloc_size = 0;
395
396 encode->packed_sample_count_table = encode->sample_count_table;
397 encode->packed_sample_count_alloc_size = 0;
398 encode->packed_sample_count_bytes =
399 (((size_t) encode->chunk.width) *
400 ((size_t) encode->chunk.height) * sizeof (int32_t));
401 }
402 }
403
404 if (rv == EXR_ERR_SUCCESS && encode->yield_until_ready_fn)
405 rv = encode->yield_until_ready_fn (encode);
406
407 if (rv == EXR_ERR_SUCCESS && encode->write_fn)
408 rv = encode->write_fn (encode);
409
410 if ((part->storage_mode == EXR_STORAGE_DEEP_SCANLINE ||
411 part->storage_mode == EXR_STORAGE_DEEP_TILED) &&
412 encode->sample_count_table != NULL)
413 {
414 priv_to_native32 (
415 encode->sample_count_table,
416 encode->chunk.width * encode->chunk.height);
417 }
418
419 return rv;
420 }
421
422 /**************************************/
423
424 exr_result_t
exr_encoding_destroy(exr_const_context_t ctxt,exr_encode_pipeline_t * encode)425 exr_encoding_destroy (exr_const_context_t ctxt, exr_encode_pipeline_t* encode)
426 {
427 INTERN_EXR_PROMOTE_CONST_CONTEXT_OR_ERROR (ctxt);
428 if (encode)
429 {
430 exr_encode_pipeline_t nil = { 0 };
431 if (encode->channels != encode->_quick_chan_store)
432 pctxt->free_fn (encode->channels);
433
434 internal_encode_free_buffer (
435 encode,
436 EXR_TRANSCODE_BUFFER_PACKED,
437 &(encode->packed_buffer),
438 &(encode->packed_alloc_size));
439 internal_encode_free_buffer (
440 encode,
441 EXR_TRANSCODE_BUFFER_COMPRESSED,
442 &(encode->compressed_buffer),
443 &(encode->compressed_alloc_size));
444 internal_encode_free_buffer (
445 encode,
446 EXR_TRANSCODE_BUFFER_SCRATCH1,
447 &(encode->scratch_buffer_1),
448 &(encode->scratch_alloc_size_1));
449 internal_encode_free_buffer (
450 encode,
451 EXR_TRANSCODE_BUFFER_SCRATCH2,
452 &(encode->scratch_buffer_2),
453 &(encode->scratch_alloc_size_2));
454 internal_encode_free_buffer (
455 encode,
456 EXR_TRANSCODE_BUFFER_PACKED_SAMPLES,
457 &(encode->packed_sample_count_table),
458 &(encode->packed_sample_count_alloc_size));
459 *encode = nil;
460 }
461 return EXR_UNLOCK_WRITE_AND_RETURN_PCTXT (EXR_ERR_SUCCESS);
462 }
463