OpenJPH
Open-source implementation of JPEG2000 Part-15
ojph_img_io.cpp
Go to the documentation of this file.
1//***************************************************************************/
2// This software is released under the 2-Clause BSD license, included
3// below.
4//
5// Copyright (c) 2019, Aous Naman
6// Copyright (c) 2019, Kakadu Software Pty Ltd, Australia
7// Copyright (c) 2019, The University of New South Wales, Australia
8//
9// Redistribution and use in source and binary forms, with or without
10// modification, are permitted provided that the following conditions are
11// met:
12//
13// 1. Redistributions of source code must retain the above copyright
14// notice, this list of conditions and the following disclaimer.
15//
16// 2. Redistributions in binary form must reproduce the above copyright
17// notice, this list of conditions and the following disclaimer in the
18// documentation and/or other materials provided with the distribution.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
26// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31//***************************************************************************/
32// This file is part of the OpenJPH software implementation.
33// File: ojph_img_io.cpp
34// Author: Aous Naman
35// Date: 28 August 2019
36//***************************************************************************/
37
38
39#include <cstdlib>
40#include <cstring>
41
42#include "ojph_file.h"
43#include "ojph_img_io.h"
44#include "ojph_mem.h"
45#include "ojph_message.h"
46
47namespace ojph {
48
50 // Static functions
52
54 static
55 ui16 be2le(const ui16 v)
56 {
57 return (ui16)((v<<8) | (v>>8));
58 }
59
61 static inline
62 ui32 be2le(const ui32 t)
63 {
64 ui32 u = be2le((ui16)(t & 0xFFFFu));
65 u <<= 16;
66 u |= be2le((ui16)(t >> 16));
67 return u;
68 }
69
71 static
72 void eat_white_spaces(FILE *fh)
73 {
74 int c = fgetc(fh);
75 while(1)
76 {
77 if (c == ' ' || c == '\r' || c == '\n' || c == '\t')
78 c = fgetc(fh);
79 else if (c == '#')
80 {
81 while (c != '\n') c = fgetc(fh);
82 }
83 else
84 {
85 ungetc(c, fh);
86 break;
87 }
88 }
89 }
90
92 //
93 //
94 // Accelerators -- non-accelerating
95 //
96 //
98
99 void gen_cvrt_32b1c_to_8ub1c(const line_buf *ln0, const line_buf *ln1,
100 const line_buf *ln2, void *dp,
101 ui32 bit_depth, ui32 count)
102 {
103 ojph_unused(ln1);
104 ojph_unused(ln2);
105
106 int max_val = (1 << bit_depth) - 1;
107 const si32 *sp = ln0->i32;
108 ui8* p = (ui8 *)dp;
109 for ( ; count > 0; --count)
110 {
111 int val = *sp++;
112 val = val >= 0 ? val : 0;
113 val = val <= max_val ? val : max_val;
114 *p++ = (ui8)val;
115 }
116 }
117
118 void gen_cvrt_32b3c_to_8ub3c(const line_buf *ln0, const line_buf *ln1,
119 const line_buf *ln2, void *dp,
120 ui32 bit_depth, ui32 count)
121 {
122 int max_val = (1<<bit_depth) - 1;
123 const si32 *sp0 = ln0->i32;
124 const si32 *sp1 = ln1->i32;
125 const si32 *sp2 = ln2->i32;
126 ui8* p = (ui8 *)dp;
127 for (; count > 0; --count)
128 {
129 int val;
130 val = *sp0++;
131 val = val >= 0 ? val : 0;
132 val = val <= max_val ? val : max_val;
133 *p++ = (ui8) val;
134 val = *sp1++;
135 val = val >= 0 ? val : 0;
136 val = val <= max_val ? val : max_val;
137 *p++ = (ui8) val;
138 val = *sp2++;
139 val = val >= 0 ? val : 0;
140 val = val <= max_val ? val : max_val;
141 *p++ = (ui8) val;
142 }
143 }
144
145 void gen_cvrt_32b1c_to_16ub1c_le(const line_buf *ln0, const line_buf *ln1,
146 const line_buf *ln2, void *dp,
147 ui32 bit_depth, ui32 count)
148 {
149 ojph_unused(ln1);
150 ojph_unused(ln2);
151 int max_val = (1<<bit_depth) - 1;
152 const si32 *sp = ln0->i32;
153 ui16* p = (ui16*)dp;
154 for (; count > 0; --count)
155 {
156 int val = *sp++;
157 val = val >= 0 ? val : 0;
158 val = val <= max_val ? val : max_val;
159 *p++ = (ui16) val;
160 }
161 }
162
163 void gen_cvrt_32b3c_to_16ub3c_le(const line_buf *ln0, const line_buf *ln1,
164 const line_buf *ln2, void *dp,
165 ui32 bit_depth, ui32 count)
166 {
167 int max_val = (1<<bit_depth) - 1;
168 const si32 *sp0 = ln0->i32;
169 const si32 *sp1 = ln1->i32;
170 const si32 *sp2 = ln2->i32;
171 ui16* p = (ui16*)dp;
172 for (; count > 0; --count)
173 {
174 int val;
175 val = *sp0++;
176 val = val >= 0 ? val : 0;
177 val = val <= max_val ? val : max_val;
178 *p++ = (ui16) val;
179 val = *sp1++;
180 val = val >= 0 ? val : 0;
181 val = val <= max_val ? val : max_val;
182 *p++ = (ui16) val;
183 val = *sp2++;
184 val = val >= 0 ? val : 0;
185 val = val <= max_val ? val : max_val;
186 *p++ = (ui16) val;
187 }
188 }
189
190 void gen_cvrt_32b1c_to_16ub1c_be(const line_buf *ln0, const line_buf *ln1,
191 const line_buf *ln2, void *dp,
192 ui32 bit_depth, ui32 count)
193 {
194 ojph_unused(ln1);
195 ojph_unused(ln2);
196 int max_val = (1<<bit_depth) - 1;
197 const si32 *sp = ln0->i32;
198 ui16* p = (ui16*)dp;
199 for (; count > 0; --count)
200 {
201 int val = *sp++;
202 val = val >= 0 ? val : 0;
203 val = val <= max_val ? val : max_val;
204 *p++ = be2le((ui16) val);
205 }
206 }
207
208 void gen_cvrt_32b3c_to_16ub3c_be(const line_buf *ln0, const line_buf *ln1,
209 const line_buf *ln2, void *dp,
210 ui32 bit_depth, ui32 count)
211 {
212 int max_val = (1<<bit_depth) - 1;
213 const si32 *sp0 = ln0->i32;
214 const si32 *sp1 = ln1->i32;
215 const si32 *sp2 = ln2->i32;
216 ui16* p = (ui16*)dp;
217 for (; count > 0; --count)
218 {
219 int val;
220 val = *sp0++;
221 val = val >= 0 ? val : 0;
222 val = val <= max_val ? val : max_val;
223 *p++ = be2le((ui16) val);
224 val = *sp1++;
225 val = val >= 0 ? val : 0;
226 val = val <= max_val ? val : max_val;
227 *p++ = be2le((ui16) val);
228 val = *sp2++;
229 val = val >= 0 ? val : 0;
230 val = val <= max_val ? val : max_val;
231 *p++ = be2le((ui16) val);
232 }
233 }
234
235
237 //
238 //
239 //
240 //
241 //
243
245 void ppm_in::open(const char *filename)
246 {
247 assert(fh == 0);
248 fh = fopen(filename, "rb");
249 if (fh == 0)
250 OJPH_ERROR(0x030000001, "Unable to open file %s", filename);
251 fname = filename;
252
253 // read magic number
254 char t[2];
255 if (fread(t, 1, 2, fh) != 2)
256 {
257 close();
258 OJPH_ERROR(0x030000002, "Error reading file %s", filename);
259 }
260
261 // check magic number
262 if (t[0] != 'P' || (t[1] != '5' && t[1] != '6'))
263 {
264 close();
265 OJPH_ERROR(0x030000003, "unknown file type for file %s", filename);
266 }
267
268 size_t len = strlen(filename);
269 if (t[1] == '5' && strncmp(filename + len - 4, ".pgm", 4) != 0)
270 {
271 close();
272 OJPH_ERROR(0x030000004, "wrong file extension, a file with "
273 "keyword P5 must have a .pgm extension for file %s", filename);
274 }
275 if (t[1] == '6' && strncmp(filename + len - 4, ".ppm", 4) != 0)
276 {
277 close();
278 OJPH_ERROR(0x030000005, "wrong file extension, a file with keyword P6 "
279 "must have a .ppm extension fir file %s", filename);
280 }
281
282 // set number of components based on file-type
283 num_comps = t[1] == '5' ? 1 : 3;
285
286 // read width, height and max value in header
287 if (fscanf(fh, "%d %d %d", &width, &height, &max_val) != 3)
288 {
289 close();
290 OJPH_ERROR(0x030000006, "error in file format for file %s", filename);
291 }
293 bytes_per_sample = max_val > 255 ? 2 : 1;
296 fgetc(fh);
298
299 // allocate linebuffer to hold a line of image data
301 {
302 if (alloc_p == NULL)
303 {
305 void* t = temp_buf;
306 if (temp_buf)
308 else
310 if (temp_buf == NULL) { // failed to allocate memory
311 if (t) free(t); // the original buffer is still valid
312 OJPH_ERROR(0x030000007, "error allocating mmeory");
313 }
314 }
315 else
316 {
317 assert(temp_buf_byte_size == 0); //cannot reallocate the buffer
320 }
321 }
322 cur_line = 0;
323 }
324
327 {
328 if (alloc_p == NULL)
329 return;
330
331 if (bytes_per_sample == 1)
333 else
335 }
336
338 ui32 ppm_in::read(const line_buf* line, ui32 comp_num)
339 {
340 assert(temp_buf_byte_size != 0 && fh != 0 && comp_num < num_comps);
341 assert(line->size >= width);
342
343 if (planar || comp_num == 0)
344 {
345 size_t result = fread(
347 if (result != num_ele_per_line)
348 {
349 close();
350 OJPH_ERROR(0x030000011, "not enough data in file %s", fname);
351 }
352 if (++cur_line >= height)
353 {
354 cur_line = 0;
355 ojph_fseek(fh, start_of_data, SEEK_SET); //handles plannar reading
356 }
357 }
358
359 if (bytes_per_sample == 1)
360 {
361 const ui8* sp = (ui8*)temp_buf + comp_num;
362 si32* dp = line->i32;
363 for (ui32 i = width; i > 0; --i, sp+=num_comps)
364 *dp++ = (si32)*sp;
365 }
366 else
367 {
368 const ui16* sp = (ui16*)temp_buf + comp_num;
369 si32* dp = line->i32;
370 for (ui32 i = width; i > 0; --i, sp+=num_comps)
371 *dp++ = (si32)be2le(*sp);
372 }
373
374 return width;
375 }
376
378 //
379 //
380 //
381 //
382 //
384
386 void ppm_out::open(char* filename)
387 {
388 assert(fh == NULL && buffer == NULL);
389 if (num_components == 1)
390 {
391 size_t len = strlen(filename);
392 if (len >= 4)
393 {
394 if (strncmp(".ppm", filename + len - 4, 4) == 0)
395 {
396 filename[len - 2] = 'g';
397 OJPH_WARN(0x03000001, "file was renamed %s\n", filename);
398 }
399 if (strncmp(".PPM", filename + len - 4, 4) == 0)
400 {
401 filename[len - 2] = 'G';
402 OJPH_WARN(0x03000002, "file was renamed %s\n", filename);
403 }
404 }
405 fh = fopen(filename, "wb");
406 if (fh == NULL)
407 OJPH_ERROR(0x030000021,
408 "unable to open file %s for writing", filename);
409
410 fprintf(fh, "P5\n%d %d\n%d\n", width, height, (1 << bit_depth) - 1);
412 buffer = (ui8*)malloc(buffer_size);
413 }
414 else
415 {
416 size_t len = strlen(filename);
417 if (len >= 4)
418 {
419 if (strncmp(".pgm", filename + len - 4, 4) == 0)
420 {
421 filename[len - 2] = 'p';
422 OJPH_WARN(0x03000003, "file was renamed %s\n", filename);
423 }
424 if (strncmp(".PGM", filename + len - 4, 4) == 0)
425 {
426 filename[len - 2] = 'P';
427 OJPH_WARN(0x03000004, "file was renamed %s\n", filename);
428 }
429 }
430 fh = fopen(filename, "wb");
431 if (fh == NULL)
432 OJPH_ERROR(0x030000022,
433 "unable to open file %s for writing", filename);
434 int result = //the number of written characters
435 fprintf(fh, "P6\n%d %d\n%d\n", width, height, (1 << bit_depth) - 1);
436 if (result == 0)
437 OJPH_ERROR(0x030000023, "error writing to file %s", filename);
439 buffer = (ui8*)malloc(buffer_size);
440 }
441 fname = filename;
442 cur_line = 0;
443 }
444
446 void ppm_out::configure(ui32 width, ui32 height, ui32 num_components,
447 ui32 bit_depth)
448 {
449 assert(fh == NULL); //configure before opening
450 if (num_components != 1 && num_components != 3)
451 OJPH_ERROR(0x030000031,
452 "ppm supports 3 colour components, while pgm supports 1");
453 this->width = width;
454 this->height = height;
455 this->num_components = num_components;
456 this->bit_depth = bit_depth;
457 bytes_per_sample = 1 + (bit_depth > 8 ? 1 : 0);
460
461 if (bytes_per_sample == 1) {
462 if (num_components == 1)
464 else
466 }
467 else {
468 if (num_components == 1)
470 else
472 }
473
474#ifndef OJPH_DISABLE_INTEL_SIMD
475
477 if (bytes_per_sample == 1) {
478 if (num_components == 1)
480 else
482 }
483 else {
484 if (num_components == 1)
486 else
488 }
489 }
490
492 if (bytes_per_sample == 1) {
493 if (num_components == 1)
495 else
497 }
498 else {
499 if (num_components == 1)
501 else
502 { } // did not find an implementation better than sse41
503 }
504 }
505
506#endif
507 }
508
510 ui32 ppm_out::write(const line_buf* line, ui32 comp_num)
511 {
512 assert(fh);
513
514 lptr[comp_num] = line;
515 if (comp_num == num_components - 1)
516 {
517 assert(lptr[0] != lptr[1]);
518 assert((lptr[1]!=lptr[2] && num_components==3) || num_components==1);
520 size_t result = fwrite(buffer,
522 if (result != samples_per_line)
523 OJPH_ERROR(0x030000042, "error writing to file %s", fname);
524 }
525 return 0;
526 }
527
529 //
530 //
531 //
532 //
533 //
535#ifdef OJPH_ENABLE_TIFF_SUPPORT
537 void tif_in::open(const char* filename)
538 {
539 tiff_handle = NULL;
540 if ((tiff_handle = TIFFOpen(filename, "r")) == NULL)
541 OJPH_ERROR(0x0300000B1, "Unable to open file %s", filename);
542 fname = filename;
543
544 ui32 tiff_width = 0;
545 ui32 tiff_height = 0;
546 TIFFGetField(tiff_handle, TIFFTAG_IMAGEWIDTH, &tiff_width);
547 TIFFGetField(tiff_handle, TIFFTAG_IMAGELENGTH, &tiff_height);
548
549 ui16 tiff_bits_per_sample = 0;
550 ui16 tiff_samples_per_pixel = 0;
551 TIFFGetField(tiff_handle, TIFFTAG_BITSPERSAMPLE, &tiff_bits_per_sample);
552 TIFFGetField(tiff_handle, TIFFTAG_SAMPLESPERPIXEL, &tiff_samples_per_pixel);
553 // some TIFs have tiff_samples_per_pixel=0 when it is a single channel
554 // image - set to 1
555 tiff_samples_per_pixel =
556 (tiff_samples_per_pixel < 1) ? 1 : tiff_samples_per_pixel;
557
558 ui16 tiff_planar_configuration = 0;
559 ui16 tiff_photometric = 0;
560 TIFFGetField(tiff_handle, TIFFTAG_PLANARCONFIG, &tiff_planar_configuration);
561 TIFFGetField(tiff_handle, TIFFTAG_PHOTOMETRIC, &tiff_photometric);
562
563 planar_configuration = tiff_planar_configuration;
564
565 ui16 tiff_compression = 0;
566 ui32 tiff_rows_per_strip = 0;
567 TIFFGetField(tiff_handle, TIFFTAG_COMPRESSION, &tiff_compression);
568 TIFFGetField(tiff_handle, TIFFTAG_ROWSPERSTRIP, &tiff_rows_per_strip);
569
570 if (tiff_planar_configuration == PLANARCONFIG_SEPARATE)
571 {
572 bytes_per_line = tiff_samples_per_pixel * TIFFScanlineSize64(tiff_handle);
573 }
574 else
575 {
576 bytes_per_line = TIFFScanlineSize64(tiff_handle);
577 }
578 // allocate linebuffer to hold a line of image data
579 line_buffer = malloc(bytes_per_line);
580 if (NULL == line_buffer)
581 OJPH_ERROR(0x0300000B2, "Unable to allocate %d bytes for line_buffer[] "
582 "for file %s", bytes_per_line, filename);
583
584 cur_line = 0;
585
586 // Error on known incompatilbe input formats
587 if( tiff_bits_per_sample != 8 && tiff_bits_per_sample != 16 )
588 {
589 OJPH_ERROR(0x0300000B3, "\nTIFF IO is currently limited to file limited"
590 " to files with TIFFTAG_BITSPERSAMPLE=8 and TIFFTAG_BITSPERSAMPLE=16 \n"
591 "input file = %s has TIFFTAG_BITSPERSAMPLE=%d",
592 filename, tiff_bits_per_sample);
593 }
594
595 if( TIFFIsTiled( tiff_handle ) )
596 {
597 OJPH_ERROR(0x0300000B4, "\nTIFF IO is currently limited to TIF files "
598 "without tiles. \nInput file %s has been detected as tiled", filename);
599 }
600
601 if(PHOTOMETRIC_RGB != tiff_photometric &&
602 PHOTOMETRIC_MINISBLACK != tiff_photometric )
603 {
604 OJPH_ERROR(0x0300000B5, "\nTIFF IO is currently limited to "
605 "TIFFTAG_PHOTOMETRIC=PHOTOMETRIC_MINISBLACK=%d and "
606 "PHOTOMETRIC_RGB=%d. \nInput file %s has been detected "
607 "TIFFTAG_PHOTOMETRIC=%d",
608 PHOTOMETRIC_MINISBLACK, PHOTOMETRIC_RGB, filename, tiff_photometric);
609 }
610
611 if( tiff_samples_per_pixel > 4 )
612 {
613 OJPH_ERROR(0x0300000B6, "\nTIFF IO is currently limited to "
614 "TIFFTAG_SAMPLESPERPIXEL=4 \nInput file %s has been detected with "
615 "TIFFTAG_SAMPLESPERPIXEL=%d",
616 filename, tiff_samples_per_pixel);
617 }
618
619 // set number of components based on tiff_samples_per_pixel
620 width = tiff_width;
621 height = tiff_height;
622 num_comps = tiff_samples_per_pixel;
623 bytes_per_sample = (tiff_bits_per_sample + 7) / 8;
624 for (ui32 comp_num = 0; comp_num < num_comps; comp_num++)
625 bit_depth[comp_num] = tiff_bits_per_sample;
626
627 // allocate intermediate linebuffers to hold a line of a single component
628 // of image data
629 if (tiff_planar_configuration == PLANARCONFIG_SEPARATE &&
630 bytes_per_sample == 1)
631 {
632 line_buffer_for_planar_support_uint8 =
633 (uint8_t*)calloc(width, sizeof(uint8_t));
634 if (NULL == line_buffer_for_planar_support_uint8)
635 OJPH_ERROR(0x0300000B7, "Unable to allocate %d bytes for "
636 "line_buffer_for_planar_support_uint8[] for file %s",
637 width * sizeof(uint8_t), filename);
638 }
639 if (tiff_planar_configuration == PLANARCONFIG_SEPARATE &&
640 bytes_per_sample == 2)
641 {
642 line_buffer_for_planar_support_uint16 =
643 (uint16_t*)calloc(width, sizeof(uint16_t));
644 if (NULL == line_buffer_for_planar_support_uint16)
645 OJPH_ERROR(0x0300000B8, "Unable to allocate %d bytes for "
646 "line_buffer_for_planar_support_uint16[] for file %s",
647 width * sizeof(uint16_t), filename);
648 }
649 }
650
652
654 void tif_in::set_bit_depth(ui32 num_bit_depths, ui32* bit_depth)
655 {
656 if (num_bit_depths < 1)
657 OJPH_ERROR(0x030000B9, "one or more bit_depths must be provided");
658 ui32 last_bd_idx = 0;
659 for (ui32 i = 0; i < 4; ++i)
660 {
661 ui32 bd = bit_depth[i < num_bit_depths ? i : last_bd_idx];
662 last_bd_idx += last_bd_idx + 1 < num_bit_depths ? 1 : 0;
663
664 if (bd > 32 || bd < 1)
665 {
666 OJPH_ERROR(0x0300000BA,
667 "bit_depth = %d, this must be an integer from 1-32", bd);
668 }
669 this->bit_depth[i] = bd;
670 }
671 }
672
674 ui32 tif_in::read(const line_buf* line, ui32 comp_num)
675 {
676 assert(bytes_per_line != 0 && tiff_handle != 0 && comp_num < num_comps);
677 assert((ui32)line->size >= width);
678
679 // do a read from the file if this is the first component and therefore
680 // the first time trying to access this line
681 if (PLANARCONFIG_SEPARATE == planar_configuration && 0 == comp_num )
682 {
683 for (unsigned short color = 0; color < num_comps; color++)
684 {
685 if (bytes_per_sample == 1)
686 {
687 TIFFReadScanline(tiff_handle, line_buffer_for_planar_support_uint8,
688 cur_line, color);
689 ui32 x = color;
690 uint8_t* line_buffer_of_interleaved_components =
691 (uint8_t*)line_buffer;
692 for (ui32 i = 0; i < width; i++, x += num_comps)
693 {
694 line_buffer_of_interleaved_components[x] =
695 line_buffer_for_planar_support_uint8[i];
696 }
697 }
698 else if (bytes_per_sample == 2)
699 {
700 TIFFReadScanline(tiff_handle, line_buffer_for_planar_support_uint16,
701 cur_line, color);
702 ui32 x = color;
703 ui16* line_buffer_of_interleaved_components = (ui16*)line_buffer;
704 for (ui32 i = 0; i < width; i++, x += num_comps)
705 {
706 line_buffer_of_interleaved_components[x] =
707 line_buffer_for_planar_support_uint16[i];
708 }
709 }
710 }
711 cur_line++;
712
713 }
714 else if (planar_configuration == PLANARCONFIG_CONTIG && 0 == comp_num)
715 {
716 TIFFReadScanline(tiff_handle, line_buffer, cur_line++);
717 }
718 if (cur_line >= height)
719 {
720 cur_line = 0;
721 }
722
723 if (bytes_per_sample == 1)
724 {
725 const ui8* sp = (ui8*)line_buffer + comp_num;
726 si32* dp = line->i32;
727 if (bit_depth[comp_num] == 8)
728 {
729 for (ui32 i = width; i > 0; --i, sp += num_comps)
730 *dp++ = (si32)*sp;
731 }
732 else if (bit_depth[comp_num] < 8)
733 {
734 // read the desired precision from the MSBs
735 const int bits_to_shift = 8 - (int)bit_depth[comp_num];
736 const int bit_mask = (1 << bit_depth[comp_num]) - 1;
737 for (ui32 i = width; i > 0; --i, sp += num_comps)
738 *dp++ = (si32) (((*sp) >> bits_to_shift) & bit_mask);
739 }
740 else if (bit_depth[comp_num] > 8)
741 {
742 const int bits_to_shift = (int)bit_depth[comp_num] - 8;
743 const int bit_mask = (1 << bit_depth[comp_num]) - 1;
744 for (ui32 i = width; i > 0; --i, sp += num_comps)
745 *dp++ = (si32)(((*sp) << bits_to_shift) & bit_mask);
746 }
747 }
748 else if(bytes_per_sample == 2)
749 {
750 if (bit_depth[comp_num] == 16)
751 {
752 const ui16* sp = (ui16*)line_buffer + comp_num;
753 si32* dp = line->i32;
754 for (ui32 i = width; i > 0; --i, sp += num_comps)
755 *dp++ = (si32)*sp;
756 }
757 else if (bit_depth[comp_num] < 16)
758 {
759 // read the desired precision from the MSBs
760 const int bits_to_shift = 16 - (int)bit_depth[comp_num];
761 const int bit_mask = (1 << bit_depth[comp_num]) - 1;
762 const ui16* sp = (ui16*)line_buffer + comp_num;
763 si32* dp = line->i32;
764 for (ui32 i = width; i > 0; --i, sp += num_comps)
765 *dp++ = (si32)(((*sp) >> bits_to_shift) & bit_mask);
766 }
767 else if (bit_depth[comp_num] > 16)
768 {
769 const int bits_to_shift = (int)bit_depth[comp_num] - 16;
770 const int bit_mask = (1 << bit_depth[comp_num]) - 1;
771 const ui16* sp = (ui16*)line_buffer + comp_num;
772 si32* dp = line->i32;
773 for (ui32 i = width; i > 0; --i, sp += num_comps)
774 *dp++ = (si32)(((*sp) << bits_to_shift) & bit_mask);
775 }
776
777 }
778
779 return width;
780 }
781
783 //
784 //
785 //
786 //
787 //
789
791 void tif_out::open(char* filename)
792 {
793 // Error on known incompatilbe output formats
794 ui32 max_bitdepth = 0;
795 for (ui32 c = 0; c < num_components; c++)
796 {
797 if (bit_depth_of_data[c] > max_bitdepth)
798 max_bitdepth = bit_depth_of_data[c];
799 }
800 if (max_bitdepth > 16)
801 {
802 OJPH_WARN(0x0300000C2, "TIFF output is currently limited to files "
803 "with max_bitdepth = 16, the source codestream has max_bitdepth=%d"
804 ", the decoded data will be truncated to 16 bits", max_bitdepth);
805 }
806 if (num_components > 4)
807 {
808 OJPH_ERROR(0x0300000C3, "TIFF IO is currently limited to files with "
809 "num_components=1 to 4");
810 }
811
812 assert(tiff_handle == NULL && buffer == NULL);
813 if ((tiff_handle = TIFFOpen(filename, "w")) == NULL)
814 {
815 OJPH_ERROR(0x0300000C1, "unable to open file %s for writing", filename);
816 }
817
818 buffer_size = width * num_components * bytes_per_sample;
819 buffer = (ui8*)malloc(buffer_size);
820 fname = filename;
821 cur_line = 0;
822
823 // set tiff fields
824
825 // Write the tiff tags to the file
826 TIFFSetField(tiff_handle, TIFFTAG_IMAGEWIDTH, width);
827 TIFFSetField(tiff_handle, TIFFTAG_IMAGELENGTH, height);
828
829 TIFFSetField(tiff_handle, TIFFTAG_BITSPERSAMPLE, bytes_per_sample * 8);
830 TIFFSetField(tiff_handle, TIFFTAG_SAMPLESPERPIXEL, num_components);
831
832 planar_configuration = PLANARCONFIG_CONTIG;
833 TIFFSetField(tiff_handle, TIFFTAG_PLANARCONFIG, planar_configuration);
834
835 if (num_components == 1)
836 {
837 TIFFSetField(tiff_handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
838 }
839 else if (num_components == 2)
840 {
841 TIFFSetField(tiff_handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
842 // possible values are EXTRASAMPLE_UNSPECIFIED = 0;
843 // EXTRASAMPLE_ASSOCALPHA = 1; EXTRASAMPLE_UNASSALPHA = 2;
844 const ui16 extra_samples_description[1] = { EXTRASAMPLE_ASSOCALPHA };
845 TIFFSetField(tiff_handle, TIFFTAG_EXTRASAMPLES, (uint16_t)1,
846 &extra_samples_description);
847 }
848 else if (num_components == 3)
849 {
850 TIFFSetField(tiff_handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
851 }
852 else if (num_components == 4)
853 {
854 TIFFSetField(tiff_handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
855 // possible values are EXTRASAMPLE_UNSPECIFIED = 0;
856 // EXTRASAMPLE_ASSOCALPHA = 1; EXTRASAMPLE_UNASSALPHA = 2;
857 const ui16 extra_samples_description[1] = { EXTRASAMPLE_ASSOCALPHA };
858 TIFFSetField(tiff_handle, TIFFTAG_EXTRASAMPLES, (uint16_t)1,
859 &extra_samples_description);
860 }
861
862 TIFFSetField(tiff_handle, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
863 TIFFSetField(tiff_handle, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
864 //TIFFSetField(tiff_handle, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
865 TIFFSetField(tiff_handle, TIFFTAG_ROWSPERSTRIP, height);
866
867 }
868
870 void tif_out::configure(ui32 width, ui32 height, ui32 num_components,
871 ui32 *bit_depth)
872 {
873 assert(tiff_handle == NULL); //configure before opening
874
875 this->width = width;
876 this->height = height;
877 this->num_components = num_components;
878 ui32 max_bitdepth = 0;
879 for (ui32 c = 0; c < num_components; c++)
880 {
881 this->bit_depth_of_data[c] = bit_depth[c];
882 if (bit_depth[c] > max_bitdepth)
883 max_bitdepth = bit_depth[c];
884 }
885
886 bytes_per_sample = (max_bitdepth + 7) / 8; // round up
887 if (bytes_per_sample > 2)
888 {
889 // TIFF output is currently limited to files with max_bitdepth = 16,
890 // the decoded data will be truncated to 16 bits
891 bytes_per_sample = 2;
892 }
893 samples_per_line = num_components * width;
894 bytes_per_line = bytes_per_sample * samples_per_line;
895
896 }
897
899 ui32 tif_out::write(const line_buf* line, ui32 comp_num)
900 {
901 assert(tiff_handle);
902
903 if (bytes_per_sample == 1)
904 {
905 int max_val = (1 << bit_depth_of_data[comp_num]) - 1;
906 const si32* sp = line->i32;
907 ui8* dp = buffer + comp_num;
908 if (bit_depth_of_data[comp_num] == 8)
909 {
910 for (ui32 i = width; i > 0; --i, dp += num_components)
911 {
912 // clamp the decoded sample to the allowed range
913 int val = *sp++;
914 val = val >= 0 ? val : 0;
915 val = val <= max_val ? val : max_val;
916 *dp = (ui8)val;
917 }
918 }
919 else if (bit_depth_of_data[comp_num] < 8)
920 {
921 const int bits_to_shift = 8 - (int)bit_depth_of_data[comp_num];
922 const int bit_mask = (1 << bit_depth_of_data[comp_num]) - 1;
923 for (ui32 i = width; i > 0; --i, dp += num_components)
924 {
925 // clamp the decoded sample to the allowed range
926 int val = *sp++;
927 val = val >= 0 ? val : 0;
928 val = val <= max_val ? val : max_val;
929 // shift the decoded data so the data's MSB is aligned with the
930 // 8 bit MSB
931 *dp = (ui8)((val & bit_mask) << bits_to_shift);
932 }
933 }
934 else if (bit_depth_of_data[comp_num] > 8)
935 {
936 const int bits_to_shift = (int)bit_depth_of_data[comp_num] - 8;
937 const int bit_mask = (1 << bit_depth_of_data[comp_num]) - 1;
938 for (ui32 i = width; i > 0; --i, dp += num_components)
939 {
940 // clamp the decoded sample to the allowed range
941 int val = *sp++;
942 val = val >= 0 ? val : 0;
943 val = val <= max_val ? val : max_val;
944 // shift the decoded data so the data's MSB is aligned with the
945 // 8 bit MSB
946 *dp = (ui8)((val >> bits_to_shift) & bit_mask);
947 }
948 }
949
950 }
951 else if(bytes_per_sample == 2)
952 {
953 int max_val = (1 << bit_depth_of_data[comp_num]) - 1;
954 const si32* sp = line->i32;
955 ui16* dp = (ui16*)buffer + comp_num;
956
957 if (bit_depth_of_data[comp_num] == 16)
958 {
959 for (ui32 i = width; i > 0; --i, dp += num_components)
960 {
961 // clamp the decoded sample to the allowed range
962 int val = *sp++;
963 val = val >= 0 ? val : 0;
964 val = val <= max_val ? val : max_val;
965 *dp = (ui16)val;
966 }
967 }
968 else if (bit_depth_of_data[comp_num] < 16)
969 {
970 const int bits_to_shift = 16 - (int)bit_depth_of_data[comp_num];
971 const int bit_mask = (1 << bit_depth_of_data[comp_num]) - 1;
972 for (ui32 i = width; i > 0; --i, dp += num_components)
973 {
974 // clamp the decoded sample to the allowed range
975 int val = *sp++;
976 val = val >= 0 ? val : 0;
977 val = val <= max_val ? val : max_val;
978
979 // shift the decoded data so the data's MSB is aligned with the
980 // 16 bit MSB
981 *dp = (ui16)((val & bit_mask) << bits_to_shift);
982 }
983 }
984 else if (bit_depth_of_data[comp_num] > 16)
985 {
986 const int bits_to_shift = (int)bit_depth_of_data[comp_num] - 16;
987 const int bit_mask = (1 << bit_depth_of_data[comp_num]) - 1;
988 for (ui32 i = width; i > 0; --i, dp += num_components)
989 {
990 // clamp the decoded sample to the allowed range
991 int val = *sp++;
992 val = val >= 0 ? val : 0;
993 val = val <= max_val ? val : max_val;
994
995 // shift the decoded data so the data's MSB is aligned with the
996 // 16 bit MSB
997 *dp = (ui16)((val >> bits_to_shift) & bit_mask);
998 }
999 }
1000
1001 }
1002 // write scanline when the last component is reached
1003 if (comp_num == num_components-1)
1004 {
1005 int result = TIFFWriteScanline(tiff_handle, buffer, cur_line++);
1006 if (result != 1)
1007 OJPH_ERROR(0x0300000C4, "error writing to file %s", fname);
1008 }
1009 return 0;
1010 }
1011 #endif /* OJPH_ENABLE_TIFF_SUPPORT */
1012
1014 //
1015 //
1016 //
1017 //
1018 //
1020
1022 void yuv_in::open(const char* filename)
1023 {
1024 assert(fh == NULL);
1025 fh = fopen(filename, "rb");
1026 if (fh == 0)
1027 OJPH_ERROR(0x03000051, "Unable to open file %s", filename);
1028
1029 //need to extract info from filename
1030
1031 assert(num_com == 1 || num_com == 3);
1032 for (ui32 i = 0; i < num_com; ++i)
1033 bytes_per_sample[i] = bit_depth[i] > 8 ? 2 : 1;
1034 ui32 max_byte_width = width[0] * bytes_per_sample[0];
1035 comp_address[0] = 0;
1036 for (ui32 i = 1; i < num_com; ++i)
1037 {
1038 comp_address[i] = comp_address[i - 1];
1039 comp_address[i] += width[i-1] * height[i-1] * bytes_per_sample[i-1];
1040 max_byte_width = ojph_max(max_byte_width, width[i]*bytes_per_sample[i]);
1041 }
1042 temp_buf = malloc(max_byte_width);
1043 fname = filename;
1044 }
1045
1047 ui32 yuv_in::read(const line_buf* line, ui32 comp_num)
1048 {
1049 assert(comp_num < num_com);
1050 size_t result = fread(temp_buf, bytes_per_sample[comp_num],
1051 width[comp_num], fh);
1052 if (result != width[comp_num])
1053 {
1054 close();
1055 OJPH_ERROR(0x03000061, "not enough data in file %s", fname);
1056 }
1057
1058 if (bytes_per_sample[comp_num] == 1)
1059 {
1060 const ui8* sp = (ui8*)temp_buf;
1061 si32* dp = line->i32;
1062 for (ui32 i = width[comp_num]; i > 0; --i, ++sp)
1063 *dp++ = (si32)*sp;
1064 }
1065 else
1066 {
1067 const ui16* sp = (ui16*)temp_buf;
1068 si32* dp = line->i32;
1069 for (ui32 i = width[comp_num]; i > 0; --i, ++sp)
1070 *dp++ = (si32)*sp;
1071 }
1072
1073 return width[comp_num];
1074 }
1075
1077 void yuv_in::set_img_props(const size& s, ui32 num_components,
1078 ui32 num_downsamplings, const point *subsampling)
1079 {
1080 if (num_components != 1 && num_components !=3)
1081 OJPH_ERROR(0x03000071, "yuv_in support 1 or 3 components");
1082 this->num_com = num_components;
1083
1084 if (num_downsamplings < 1)
1085 OJPH_ERROR(0x03000072, "one or more downsampling must be provided");
1086
1087 ui32 last_downsamp_idx = 0;
1088 for (ui32 i = 0; i < num_components; ++i)
1089 {
1090 point cp_ds = subsampling[i<num_downsamplings ? i : last_downsamp_idx];
1091 last_downsamp_idx += last_downsamp_idx + 1 < num_downsamplings ? 1 : 0;
1092
1093 this->subsampling[i] = cp_ds;
1094 }
1095
1096 for (ui32 i = 0; i < num_components; ++i)
1097 {
1098 width[i] = ojph_div_ceil(s.w, this->subsampling[i].x);
1099 height[i] = ojph_div_ceil(s.h, this->subsampling[i].y);
1100 }
1101 }
1102
1104 void yuv_in::set_bit_depth(ui32 num_bit_depths, ui32* bit_depth)
1105 {
1106 if (num_bit_depths < 1)
1107 OJPH_ERROR(0x03000081, "one or more bit_depths must be provided");
1108 ui32 last_bd_idx = 0;
1109 for (ui32 i = 0; i < 3; ++i)
1110 {
1111 ui32 bd = bit_depth[i < num_bit_depths ? i : last_bd_idx];
1112 last_bd_idx += last_bd_idx + 1 < num_bit_depths ? 1 : 0;
1113
1114 this->bit_depth[i] = bd;
1115 }
1116 }
1117
1119 //
1120 //
1121 //
1122 //
1123 //
1125
1128 {
1129 close();
1130 if (buffer)
1131 {
1132 free(buffer);
1133 buffer = NULL;
1134 buffer_size = 0;
1135 }
1136 if (comp_width)
1137 {
1138 delete [] comp_width;
1139 comp_width = NULL;
1140 }
1141 }
1142
1144 void yuv_out::open(char *filename)
1145 {
1146 assert(fh == NULL); //configure before open
1147 fh = fopen(filename, "wb");
1148 if (fh == 0)
1149 OJPH_ERROR(0x03000091, "Unable to open file %s", filename);
1150 fname = filename;
1151 }
1152
1154 void yuv_out::configure(ui32 bit_depth, ui32 num_components,
1155 ui32* comp_width)
1156 {
1157 assert(fh == NULL);
1158 this->num_components = num_components;
1159 this->bit_depth = bit_depth;
1160 this->comp_width = new ui32[num_components];
1161 ui32 tw = 0;
1162 for (ui32 i = 0; i < num_components; ++i)
1163 {
1164 this->comp_width[i] = comp_width[i];
1165 tw = ojph_max(tw, this->comp_width[i]);
1166 }
1167 this->width = tw;
1168 buffer_size = tw * (bit_depth > 8 ? 2 : 1);
1169 buffer = (ui8*)malloc(buffer_size);
1170 }
1171
1173 ui32 yuv_out::write(const line_buf* line, ui32 comp_num)
1174 {
1175 assert(fh);
1176 assert(comp_num < num_components);
1177
1178 int max_val = (1<<bit_depth) - 1;
1179 ui32 w = comp_width[comp_num];
1180 if (bit_depth > 8)
1181 {
1182 const si32 *sp = line->i32;
1183 ui16 *dp = (ui16 *)buffer;
1184 for (ui32 i = w; i > 0; --i)
1185 {
1186 int val = *sp++;
1187 val = val >= 0 ? val : 0;
1188 val = val <= max_val ? val : max_val;
1189 *dp++ = (ui16)val;
1190 }
1191 if (fwrite(buffer, 2, w, fh) != w)
1192 OJPH_ERROR(0x030000A1, "unable to write to file %s", fname);
1193 }
1194 else
1195 {
1196 const si32 *sp = line->i32;
1197 ui8 *dp = (ui8 *)buffer;
1198 for (ui32 i = w; i > 0; --i)
1199 {
1200 int val = *sp++;
1201 val = val >= 0 ? val : 0;
1202 val = val <= max_val ? val : max_val;
1203 *dp++ = (ui8)val;
1204 }
1205 if (fwrite(buffer, 1, w, fh) != w)
1206 OJPH_ERROR(0x030000A2, "unable to write to file %s", fname);
1207 }
1208
1209 return w;
1210 }
1211
1213 //
1214 //
1215 //
1216 //
1217 //
1219
1221 void raw_in::open(const char* filename)
1222 {
1223 assert(fh == NULL);
1224 fh = fopen(filename, "rb");
1225 if (fh == NULL)
1226 OJPH_ERROR(0x030000C1, "Unable to open file %s", filename);
1227
1228 cur_line = 0;
1229 bytes_per_sample = (bit_depth + 7) >> 3;
1231 buffer = (ui8*)malloc(buffer_size);
1232 fname = filename;
1233 }
1234
1236 ui32 raw_in::read(const line_buf* line, ui32 comp_num)
1237 {
1238 ojph_unused(comp_num);
1239 assert(comp_num == 0);
1240 size_t result = fread(buffer, bytes_per_sample, width, fh);
1241 if (result != width)
1242 {
1243 close();
1244 OJPH_ERROR(0x030000C2, "not enough data in file %s", fname);
1245 }
1246
1247 if (bytes_per_sample > 3)
1248 {
1249 si32* dp = line->i32;
1250 if (is_signed) {
1251 const si32* sp = (si32*)buffer;
1252 for (ui32 i = width; i > 0; --i, ++sp)
1253 *dp++ = *sp;
1254 }
1255 else {
1256 si32* dp = line->i32;
1257 const ui32* sp = (ui32*)buffer;
1258 for (ui32 i = width; i > 0; --i, ++sp)
1259 *dp++ = (si32)*sp;
1260 }
1261 }
1262 else if (bytes_per_sample > 2)
1263 {
1264 si32* dp = line->i32;
1265 if (is_signed) {
1266 const si32* sp = (si32*)buffer;
1267 for (ui32 i = width; i > 0; --i) {
1268 si32 val = *sp & 0xFFFFFF;
1269 val |= (val & 0x800000) ? 0xFF000000 : 0;
1270 *dp++ = val;
1271 // this only works for little endian architecture
1272 sp = (si32*)((si8*)sp + 3);
1273 }
1274 }
1275 else {
1276 const ui32* sp = (ui32*)buffer;
1277 for (ui32 i = width; i > 0; --i) {
1278 *dp++ = (si32)(*sp & 0xFFFFFFu);
1279 // this only works for little endian architecture
1280 sp = (ui32*)((ui8*)sp + 3);
1281 }
1282 }
1283 }
1284 else if (bytes_per_sample > 1)
1285 {
1286 si32* dp = line->i32;
1287 if (is_signed) {
1288 const si16* sp = (si16*)buffer;
1289 for (ui32 i = width; i > 0; --i, ++sp)
1290 *dp++ = *sp;
1291 }
1292 else {
1293 const ui16* sp = (ui16*)buffer;
1294 for (ui32 i = width; i > 0; --i, ++sp)
1295 *dp++ = (si32)*sp;
1296 }
1297 }
1298 else
1299 {
1300 si32* dp = line->i32;
1301 if (is_signed) {
1302 const si8* sp = (si8*)buffer;
1303 for (ui32 i = width; i > 0; --i, ++sp)
1304 *dp++ = *sp;
1305 }
1306 else {
1307 const ui8* sp = (ui8*)buffer;
1308 for (ui32 i = width; i > 0; --i, ++sp)
1309 *dp++ = (si32)*sp;
1310 }
1311 }
1312
1313 return width;
1314 }
1315
1317 void raw_in::set_img_props(const size& s, ui32 bit_depth, bool is_signed)
1318 {
1319 assert(fh == NULL);
1320 //need to extract this info from filename
1321 this->width = s.w;
1322 this->height = s.h;
1323 this->bit_depth = bit_depth;
1324 this->is_signed = is_signed;
1325 }
1326
1328 //
1329 //
1330 //
1331 //
1332 //
1334
1337 {
1338 close();
1339 if (buffer)
1340 {
1341 free(buffer);
1342 buffer = NULL;
1343 buffer_size = 0;
1344 }
1345 }
1346
1348 void raw_out::open(char *filename)
1349 {
1350 assert(fh == NULL); //configure before open
1351 fh = fopen(filename, "wb");
1352 if (fh == 0)
1353 OJPH_ERROR(0x03000091, "Unable to open file %s", filename);
1354 fname = filename;
1355 }
1356
1358 void raw_out::configure(bool is_signed, ui32 bit_depth, ui32 width)
1359 {
1360 assert(fh == NULL);
1361 this->is_signed = is_signed;
1362 this->bit_depth = bit_depth;
1363 this->width = width;
1364
1365 if (is_signed) {
1366 upper_val = (1 << (bit_depth - 1));
1367 lower_val = -(1 << (bit_depth - 1));
1368 } else {
1369 upper_val = 1 << bit_depth;
1370 lower_val = 0;
1371 }
1372
1373 bytes_per_sample = (bit_depth + 7) >> 3;
1375 buffer = (ui8*)malloc(buffer_size);
1376 }
1377
1379 ui32 raw_out::write(const line_buf* line, ui32 comp_num)
1380 {
1381 ojph_unused(comp_num);
1382 assert(fh);
1383 assert(comp_num == 0);
1384
1385 if (bytes_per_sample > 3)
1386 {
1387 const si32* sp = line->i32;
1388 ui32* dp = (ui32*)buffer;
1389 for (ui32 i = width; i > 0; --i)
1390 {
1391 int val = *sp++;
1392 val = val < upper_val ? val : upper_val;
1393 val = val >= lower_val ? val : lower_val;
1394 *dp++ = (ui32)val;
1395 }
1396 if (fwrite(buffer, bytes_per_sample, width, fh) != width)
1397 OJPH_ERROR(0x030000B1, "unable to write to file %s", fname);
1398 }
1399 else if (bytes_per_sample > 2)
1400 {
1401 const si32* sp = line->i32;
1402 ui32* dp = (ui32*)buffer;
1403 for (ui32 i = width; i > 0; --i)
1404 {
1405 int val = *sp++;
1406 val = val < upper_val ? val : upper_val;
1407 val = val >= lower_val ? val : lower_val;
1408 *dp = (ui32)val;
1409 // this only works for little endian architecture
1410 dp = (ui32*)((ui8*)dp + 3);
1411 }
1412 if (fwrite(buffer, bytes_per_sample, width, fh) != width)
1413 OJPH_ERROR(0x030000B2, "unable to write to file %s", fname);
1414 }
1415 else if (bytes_per_sample > 1)
1416 {
1417 const si32* sp = line->i32;
1418 ui16* dp = (ui16*)buffer;
1419 for (ui32 i = width; i > 0; --i)
1420 {
1421 int val = *sp++;
1422 val = val < upper_val ? val : upper_val;
1423 val = val >= lower_val ? val : lower_val;
1424 *dp++ = (ui16)val;
1425 }
1426 if (fwrite(buffer, bytes_per_sample, width, fh) != width)
1427 OJPH_ERROR(0x030000B3, "unable to write to file %s", fname);
1428 }
1429 else
1430 {
1431 const si32* sp = line->i32;
1432 ui8* dp = (ui8*)buffer;
1433 for (ui32 i = width; i > 0; --i)
1434 {
1435 int val = *sp++;
1436 val = val < upper_val ? val : upper_val;
1437 val = val >= lower_val ? val : lower_val;
1438 *dp++ = (ui8)val;
1439 }
1440 if (fwrite(buffer, bytes_per_sample, width, fh) != width)
1441 OJPH_ERROR(0x030000B4, "unable to write to file %s", fname);
1442 }
1443
1444 return width;
1445 }
1446
1447
1449 //
1450 //
1451 //
1452 //
1453 //
1455
1457
1458 void dpx_in::open(const char* filename)
1459 {
1460 assert(file_handle == 0);
1461 file_handle = fopen(filename, "rb");
1462 if (0 == file_handle)
1463 OJPH_ERROR(0x0300000D1, "Unable to open file %s", filename);
1464 fname = filename;
1465
1466 // read magic number
1467 ui32 magic_number;
1468 if (fread(&magic_number, sizeof(ui32), 1, file_handle) != 1)
1469 {
1470 close();
1471 OJPH_ERROR(0x0300000D2, "Error reading file %s", filename);
1472 }
1473
1474 // check magic number
1475 const ui32 dpx_magic_number = 0x53445058;
1476 if (dpx_magic_number == magic_number)
1477 {
1478 // magic number is a match - no byte swapping necessary
1480 }
1481 else if (dpx_magic_number == be2le(magic_number))
1482 {
1483 // magic number is a match after bytes swapping -
1484 // the data read from this file needs byte swapping
1486 }
1487 else
1488 {
1489 close();
1490 OJPH_ERROR(0x0300000D3, "Error reading file %s - this does not appear "
1491 "to be a valid DPX file. It has magic number = 0x%08X. The magic "
1492 "number of a DPX file is 0x%08X.", filename, magic_number,
1493 dpx_magic_number);
1494 }
1495
1496 // read offset to data
1497 if (fread(&offset_to_image_data_in_bytes, sizeof(ui32), 1, file_handle)
1498 != 1)
1499 {
1500 close();
1501 OJPH_ERROR(0x0300000D4, "Error reading file %s", filename);
1502 }
1505 // read version
1506 if (fread(version, sizeof(uint8_t), 8, file_handle) != 8)
1507 {
1508 close();
1509 OJPH_ERROR(0x0300000D5, "Error reading file %s", filename);
1510 }
1511 // read image file size in bytes
1512 if (fread(&total_image_file_size_in_bytes, sizeof(ui32), 1, file_handle)
1513 != 1)
1514 {
1515 close();
1516 OJPH_ERROR(0x0300000D6, "Error reading file %s", filename);
1517 }
1520
1521 // seek to image info header
1522 if (fseek(file_handle,768, SEEK_SET) != 0)
1523 {
1524 close();
1525 OJPH_ERROR(0x0300000D7, "Error reading file %s", filename);
1526 }
1527
1528 // read image_orientation
1529 if (fread(&image_orientation, sizeof(uint16_t), 1, file_handle) != 1)
1530 {
1531 close();
1532 OJPH_ERROR(0x0300000D8, "Error reading file %s", filename);
1533 }
1536
1537 // read number of image elements
1538 if (fread(&number_of_image_elements, sizeof(uint16_t), 1, file_handle)
1539 != 1)
1540 {
1541 close();
1542 OJPH_ERROR(0x0300000D9, "Error reading file %s", filename);
1543 }
1546
1547 // read pixels per line
1548 if (fread(&pixels_per_line, sizeof(ui32), 1, file_handle) != 1)
1549 {
1550 close();
1551 OJPH_ERROR(0x0300000DA, "Error reading file %s", filename);
1552 }
1555
1556 // read lines per image element
1557 if (fread(&lines_per_image_element, sizeof(ui32), 1, file_handle) != 1)
1558 {
1559 close();
1560 OJPH_ERROR(0x0300000DB, "Error reading file %s", filename);
1561 }
1564
1565 // seek to data structure for image element 1
1566 if (fseek(file_handle, 780, SEEK_SET) != 0)
1567 {
1568 close();
1569 OJPH_ERROR(0x0300000DC, "Error reading file %s", filename);
1570 }
1571
1572 // read data sign for image element
1573 if (fread(&data_sign_for_image_element_1, sizeof(ui32), 1, file_handle)
1574 != 1)
1575 {
1576 close();
1577 OJPH_ERROR(0x0300000DE, "Error reading file %s", filename);
1578 }
1581
1582 // seek to core data elements in image element 1
1583 if (fseek(file_handle, 800, SEEK_SET) != 0)
1584 {
1585 close();
1586 OJPH_ERROR(0x0300000DF, "Error reading file %s", filename);
1587 }
1588
1589 // read descriptor
1590 if (fread(&descriptor_for_image_element_1, sizeof(uint8_t), 1, file_handle)
1591 != 1)
1592 {
1593 close();
1594 OJPH_ERROR(0x0300000E0, "Error reading file %s", filename);
1595 }
1596
1597 // read transfer characteristic
1598 if (fread(&transfer_characteristic_for_image_element_1, sizeof(uint8_t),
1599 1, file_handle) != 1)
1600 {
1601 close();
1602 OJPH_ERROR(0x0300000E1, "Error reading file %s", filename);
1603 }
1604
1605 // read colorimetric specification
1606 if (fread(&colormetric_specification_for_image_element_1, sizeof(uint8_t),
1607 1, file_handle) != 1)
1608 {
1609 close();
1610 OJPH_ERROR(0x0300000E2, "Error reading file %s", filename);
1611 }
1612
1613 // read bit depth
1614 if (fread(&bitdepth_for_image_element_1, sizeof(uint8_t), 1, file_handle)
1615 != 1)
1616 {
1617 close();
1618 OJPH_ERROR(0x0300000E3, "Error reading file %s", filename);
1619 }
1620
1621 // read packing
1622 if (fread(&packing_for_image_element_1, sizeof(uint16_t), 1, file_handle)
1623 != 1)
1624 {
1625 close();
1626 OJPH_ERROR(0x0300000E4, "Error reading file %s", filename);
1627 }
1630
1631 // read encoding
1632 if (fread(&encoding_for_image_element_1, sizeof(uint16_t), 1, file_handle)
1633 != 1)
1634 {
1635 close();
1636 OJPH_ERROR(0x0300000E5, "Error reading file %s", filename);
1637 }
1640
1641 // read offset to data
1642 if (fread(&offset_to_data_for_image_element_1, sizeof(ui32), 1,
1643 file_handle) != 1)
1644 {
1645 close();
1646 OJPH_ERROR(0x0300000E6, "Error reading file %s", filename);
1647 }
1651
1652 // set to starting point of image data
1653 if (fseek(file_handle, (long)offset_to_image_data_in_bytes, SEEK_SET) != 0)
1654 {
1655 close();
1656 OJPH_ERROR(0x0300000E7, "Error reading file %s", filename);
1657 }
1658
1659 // set ojph properties
1662 num_comps = 3; // descriptor field can indicate 1, 3, or 4 comps
1663 for ( ojph::ui32 c = 0; c < get_num_components(); c++)
1664 {
1666 is_signed[c] = false;
1667 subsampling[c] = point(1,1);
1668 }
1669
1670 // handle DPX image data packing in file
1671 ui32 number_of_samples_per_32_bit_word = 32 / bitdepth_for_image_element_1;
1674 (number_of_samples_per_line + (number_of_samples_per_32_bit_word - 1))
1675 / number_of_samples_per_32_bit_word;
1676
1677 cur_line = 0;
1678
1679 // allocate linebuffer to hold a line of image data from the file
1681 if (NULL == line_buffer)
1682 OJPH_ERROR(0x0300000E8, "Unable to allocate %d bytes for line_buffer[] "
1683 "for file %s",
1684 number_of_32_bit_words_per_line * sizeof(ui32), filename);
1685
1686 // allocate line_buffer_16bit_samples to hold a line of image data in memory
1688 (ui16*) malloc(width * num_comps * sizeof(ui16));
1689 if (NULL == line_buffer_16bit_samples)
1690 OJPH_ERROR(0x0300000E9, "Unable to allocate %d bytes for "
1691 "line_buffer_16bit_samples[] for file %s",
1692 width * num_comps * sizeof(ui16), filename);
1693
1694 cur_line = 0;
1695
1696 return;
1697 }
1698
1700 ui32 dpx_in::read(const line_buf* line, ui32 comp_num)
1701 {
1702 assert(file_handle != 0 && comp_num < num_comps);
1703 assert((ui32)line->size >= width);
1704
1705 // read from file if trying to read the first component
1706 if (0 == comp_num)
1707 {
1710 {
1711 close();
1712 OJPH_ERROR(0x0300000F1, "Error reading file %s", fname);
1713 }
1714
1715 if (true == is_byte_swapping_necessary)
1716 {
1718 {
1719 ui16* line_buffer_ptr = (ui16*)line_buffer;
1720 for (size_t i = 0; i < 2*number_of_32_bit_words_per_line; i++)
1721 {
1722 line_buffer_ptr[i] = be2le(line_buffer_ptr[i]);
1723 }
1724 }
1725 else
1726 {
1727 ui32* line_buffer_ptr = (ui32*)line_buffer;
1728 for (size_t i = 0; i < number_of_32_bit_words_per_line; i++)
1729 {
1730 line_buffer_ptr[i] = be2le(line_buffer_ptr[i]);
1731 }
1732 }
1733 }
1734
1735 // extract samples from 32bit words from file read into
1736 // RGB ordered buffer
1737 ui32 word_index = 0;
1738 if (10 == bitdepth_for_image_element_1 && 3 == num_comps
1740 {
1741 ui32* line_buffer_ptr = (ui32*)line_buffer;
1742 for (ui32 i = 0; i < number_of_samples_per_line; i += 3)
1743 {
1744 // R
1746 (ui16) ((line_buffer_ptr[word_index] & 0xFFC00000) >> 22);
1747 // G
1749 (ui16) ((line_buffer_ptr[word_index] & 0x003FF000) >> 12);
1750 // B
1752 (ui16) ((line_buffer_ptr[word_index] & 0x00000FFC) >> 2);
1753 word_index++;
1754 }
1755 }
1756 else if (16 == bitdepth_for_image_element_1 && 3 == num_comps)
1757 {
1758 ui16* line_buffer_ptr = (ui16*)line_buffer;
1759 for (ui32 i = 0; i < number_of_samples_per_line; i++)
1760 {
1761 line_buffer_16bit_samples[i] = line_buffer_ptr[i];
1762 }
1763 }
1764 else
1765 {
1766 OJPH_ERROR(0x0300000F2, "file %s uses DPX image formats that are not "
1767 "yet supported by this software\n bitdepth_for_image_element_1 = "
1768 "%d\n num_comps=%d\npacking_for_image_element_1=%d\n "
1769 "descriptor_for_image_element_1=%d", fname,
1772 }
1773
1774 cur_line++;
1775 }
1776
1777 // copy sample data from the unpacked line buffer into a
1778 // single-component buffer to be used by the openjph core
1779 const ui16* sp = (ui16*)line_buffer_16bit_samples + comp_num;
1780 si32* dp = line->i32;
1781 for (ui32 i = width; i > 0; --i, sp += num_comps)
1782 *dp++ = (si32)*sp;
1783
1784 return width;
1785 }
1786
1787}
ui32 get_num_components()
Definition: ojph_img_io.h:284
void * line_buffer
Definition: ojph_img_io.h:302
size_t number_of_32_bit_words_per_line
Definition: ojph_img_io.h:336
void open(const char *filename)
ui16 packing_for_image_element_1
Definition: ojph_img_io.h:332
ui8 descriptor_for_image_element_1
Definition: ojph_img_io.h:328
ui32 offset_to_data_for_image_element_1
Definition: ojph_img_io.h:334
ui32 total_image_file_size_in_bytes
Definition: ojph_img_io.h:320
FILE * file_handle
Definition: ojph_img_io.h:299
ui32 pixels_per_line
Definition: ojph_img_io.h:324
point subsampling[4]
Definition: ojph_img_io.h:309
ui16 number_of_image_elements
Definition: ojph_img_io.h:323
ui8 bitdepth_for_image_element_1
Definition: ojph_img_io.h:331
virtual ui32 read(const line_buf *line, ui32 comp_num)
ui16 * line_buffer_16bit_samples
Definition: ojph_img_io.h:313
char version[8]
Definition: ojph_img_io.h:319
ui32 offset_to_image_data_in_bytes
Definition: ojph_img_io.h:318
ui16 encoding_for_image_element_1
Definition: ojph_img_io.h:333
ui32 number_of_samples_per_line
Definition: ojph_img_io.h:311
ui8 transfer_characteristic_for_image_element_1
Definition: ojph_img_io.h:329
ui8 colormetric_specification_for_image_element_1
Definition: ojph_img_io.h:330
ui32 lines_per_image_element
Definition: ojph_img_io.h:325
ui16 image_orientation
Definition: ojph_img_io.h:322
bool is_signed[4]
Definition: ojph_img_io.h:308
const char * fname
Definition: ojph_img_io.h:301
void close()
Definition: ojph_img_io.h:275
ui32 bit_depth[4]
Definition: ojph_img_io.h:307
bool is_byte_swapping_necessary
Definition: ojph_img_io.h:316
ui32 data_sign_for_image_element_1
Definition: ojph_img_io.h:327
void pre_alloc_data(size_t num_ele, ui32 pre_size)
Definition: ojph_mem.h:66
T * post_alloc_data(size_t num_ele, ui32 pre_size)
Definition: ojph_mem.h:89
void open(const char *filename)
ui32 num_ele_per_line
Definition: ojph_img_io.h:133
ui32 bytes_per_sample
Definition: ojph_img_io.h:133
ui32 max_val_num_bits
Definition: ojph_img_io.h:132
const char * fname
Definition: ojph_img_io.h:129
void finalize_alloc()
ui32 temp_buf_byte_size
Definition: ojph_img_io.h:134
void * temp_buf
Definition: ojph_img_io.h:131
void close()
Definition: ojph_img_io.h:112
mem_fixed_allocator * alloc_p
Definition: ojph_img_io.h:130
si64 start_of_data
Definition: ojph_img_io.h:137
ui32 bit_depth[3]
Definition: ojph_img_io.h:139
virtual ui32 read(const line_buf *line, ui32 comp_num)
ui32 num_components
Definition: ojph_img_io.h:559
const char * fname
Definition: ojph_img_io.h:558
void open(char *filename)
virtual ui32 write(const line_buf *line, ui32 comp_num)
ui32 bytes_per_line
Definition: ojph_img_io.h:563
ui32 bytes_per_sample
Definition: ojph_img_io.h:560
const line_buf * lptr[3]
Definition: ojph_img_io.h:565
conversion_fun converter
Definition: ojph_img_io.h:564
void configure(ui32 width, ui32 height, ui32 num_components, ui32 bit_depth)
ui32 samples_per_line
Definition: ojph_img_io.h:563
void close()
Definition: ojph_img_io.h:431
ui32 bytes_per_sample
Definition: ojph_img_io.h:442
void * buffer
Definition: ojph_img_io.h:445
void set_img_props(const size &s, ui32 bit_depth, bool is_signed)
size_t buffer_size
Definition: ojph_img_io.h:446
const char * fname
Definition: ojph_img_io.h:440
void open(const char *filename)
virtual ui32 read(const line_buf *line, ui32 comp_num=0)
void open(char *filename)
void configure(bool is_signed, ui32 bit_depth, ui32 width)
virtual void close()
Definition: ojph_img_io.h:694
virtual ~raw_out()
const char * fname
Definition: ojph_img_io.h:698
virtual ui32 write(const line_buf *line, ui32 comp_num=0)
ui32 bytes_per_sample
Definition: ojph_img_io.h:700
ui32 width[3]
Definition: ojph_img_io.h:391
virtual ui32 read(const line_buf *line, ui32 comp_num)
ui32 height[3]
Definition: ojph_img_io.h:391
void open(const char *filename)
void * temp_buf
Definition: ojph_img_io.h:390
const char * fname
Definition: ojph_img_io.h:389
void set_img_props(const size &s, ui32 num_components, ui32 num_downsampling, const point *downsampling)
void set_bit_depth(ui32 num_bit_depths, ui32 *bit_depth)
ui32 bytes_per_sample[3]
Definition: ojph_img_io.h:392
point subsampling[3]
Definition: ojph_img_io.h:398
void close()
Definition: ojph_img_io.h:377
ui32 bit_depth[3]
Definition: ojph_img_io.h:397
ui32 comp_address[3]
Definition: ojph_img_io.h:393
const char * fname
Definition: ojph_img_io.h:659
void open(char *filename)
ui32 * comp_width
Definition: ojph_img_io.h:663
ui32 num_components
Definition: ojph_img_io.h:661
void configure(ui32 bit_depth, ui32 num_components, ui32 *comp_width)
virtual void close()
Definition: ojph_img_io.h:655
virtual ~yuv_out()
virtual ui32 write(const line_buf *line, ui32 comp_num)
void sse41_cvrt_32b3c_to_8ub3c(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, ui32 bit_depth, ui32 count)
int ojph_fseek(FILE *stream, si64 offset, int origin)
Definition: ojph_file.h:61
static void eat_white_spaces(FILE *fh)
Definition: ojph_img_io.cpp:72
si64 ojph_ftell(FILE *stream)
Definition: ojph_file.h:66
void gen_cvrt_32b3c_to_16ub3c_le(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, ui32 bit_depth, ui32 count)
void avx2_cvrt_32b3c_to_8ub3c(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, ui32 bit_depth, ui32 count)
int8_t si8
Definition: ojph_defs.h:51
@ X86_CPU_EXT_LEVEL_AVX2
Definition: ojph_arch.h:104
@ X86_CPU_EXT_LEVEL_SSE41
Definition: ojph_arch.h:101
uint16_t ui16
Definition: ojph_defs.h:52
void gen_cvrt_32b1c_to_16ub1c_le(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, ui32 bit_depth, ui32 count)
void sse41_cvrt_32b1c_to_16ub1c_be(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, ui32 bit_depth, ui32 count)
void avx2_cvrt_32b1c_to_16ub1c_be(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, ui32 bit_depth, ui32 count)
void sse41_cvrt_32b1c_to_8ub1c(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, ui32 bit_depth, ui32 count)
void avx2_cvrt_32b1c_to_8ub1c(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, ui32 bit_depth, ui32 count)
void gen_cvrt_32b3c_to_16ub3c_be(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, ui32 bit_depth, ui32 count)
static ui16 be2le(const ui16 v)
Definition: ojph_img_io.cpp:55
OJPH_EXPORT int get_cpu_ext_level()
Definition: ojph_arch.cpp:184
static ui32 count_leading_zeros(ui32 val)
Definition: ojph_arch.h:130
void gen_cvrt_32b1c_to_8ub1c(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, ui32 bit_depth, ui32 count)
Definition: ojph_img_io.cpp:99
int32_t si32
Definition: ojph_defs.h:55
void sse41_cvrt_32b3c_to_16ub3c_be(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, ui32 bit_depth, ui32 count)
int16_t si16
Definition: ojph_defs.h:53
uint32_t ui32
Definition: ojph_defs.h:54
uint8_t ui8
Definition: ojph_defs.h:50
void gen_cvrt_32b1c_to_16ub1c_be(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, ui32 bit_depth, ui32 count)
void gen_cvrt_32b3c_to_8ub3c(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, ui32 bit_depth, ui32 count)
#define ojph_max(a, b)
Definition: ojph_defs.h:73
#define ojph_div_ceil(a, b)
Definition: ojph_defs.h:70
#define ojph_unused(x)
Definition: ojph_defs.h:78
#define OJPH_ERROR(t,...)
Definition: ojph_message.h:131
#define OJPH_WARN(t,...)
Definition: ojph_message.h:128
size_t size
Definition: ojph_mem.h:152
si32 * i32
Definition: ojph_mem.h:155
ui32 w
Definition: ojph_base.h:50
ui32 h
Definition: ojph_base.h:51