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
62 void eat_white_spaces(FILE *fh)
63 {
64 int c = fgetc(fh);
65 while(1)
66 {
67 if (c == ' ' || c == '\r' || c == '\n' || c == '\t')
68 c = fgetc(fh);
69 else if (c == '#')
70 {
71 while (c != '\n') c = fgetc(fh);
72 }
73 else
74 {
75 ungetc(c, fh);
76 break;
77 }
78 }
79 }
80
82 //
83 //
84 // Accelerators -- non-accelerating
85 //
86 //
88
89 void gen_cvrt_32b1c_to_8ub1c(const line_buf *ln0, const line_buf *ln1,
90 const line_buf *ln2, void *dp,
91 int bit_depth, int count)
92 {
93 ojph_unused(ln1);
94 ojph_unused(ln2);
95
96 int max_val = (1 << bit_depth) - 1;
97 const si32 *sp = ln0->i32;
98 ui8* p = (ui8 *)dp;
99 for (ui32 i = count; i > 0; --i)
100 {
101 int val = *sp++;
102 val = val >= 0 ? val : 0;
103 val = val <= max_val ? val : max_val;
104 *p++ = (ui8)val;
105 }
106 }
107
108 void gen_cvrt_32b3c_to_8ub3c(const line_buf *ln0, const line_buf *ln1,
109 const line_buf *ln2, void *dp,
110 int bit_depth, int count)
111 {
112 int max_val = (1<<bit_depth) - 1;
113 const si32 *sp0 = ln0->i32;
114 const si32 *sp1 = ln1->i32;
115 const si32 *sp2 = ln2->i32;
116 ui8* p = (ui8 *)dp;
117 for (ui32 i = count; i > 0; --i)
118 {
119 int val;
120 val = *sp0++;
121 val = val >= 0 ? val : 0;
122 val = val <= max_val ? val : max_val;
123 *p++ = (ui8) val;
124 val = *sp1++;
125 val = val >= 0 ? val : 0;
126 val = val <= max_val ? val : max_val;
127 *p++ = (ui8) val;
128 val = *sp2++;
129 val = val >= 0 ? val : 0;
130 val = val <= max_val ? val : max_val;
131 *p++ = (ui8) val;
132 }
133 }
134
135 void gen_cvrt_32b1c_to_16ub1c_le(const line_buf *ln0, const line_buf *ln1,
136 const line_buf *ln2, void *dp,
137 int bit_depth, int count)
138 {
139 ojph_unused(ln1);
140 ojph_unused(ln2);
141 int max_val = (1<<bit_depth) - 1;
142 const si32 *sp = ln0->i32;
143 ui16* p = (ui16*)dp;
144 for (ui32 i = count; i > 0; --i)
145 {
146 int val = *sp++;
147 val = val >= 0 ? val : 0;
148 val = val <= max_val ? val : max_val;
149 *p++ = (ui16) val;
150 }
151 }
152
153 void gen_cvrt_32b3c_to_16ub3c_le(const line_buf *ln0, const line_buf *ln1,
154 const line_buf *ln2, void *dp,
155 int bit_depth, int count)
156 {
157 int max_val = (1<<bit_depth) - 1;
158 const si32 *sp0 = ln0->i32;
159 const si32 *sp1 = ln1->i32;
160 const si32 *sp2 = ln2->i32;
161 ui16* p = (ui16*)dp;
162 for (ui32 i = count; i > 0; --i)
163 {
164 int val;
165 val = *sp0++;
166 val = val >= 0 ? val : 0;
167 val = val <= max_val ? val : max_val;
168 *p++ = (ui16) val;
169 val = *sp1++;
170 val = val >= 0 ? val : 0;
171 val = val <= max_val ? val : max_val;
172 *p++ = (ui16) val;
173 val = *sp2++;
174 val = val >= 0 ? val : 0;
175 val = val <= max_val ? val : max_val;
176 *p++ = (ui16) val;
177 }
178 }
179
180 void gen_cvrt_32b1c_to_16ub1c_be(const line_buf *ln0, const line_buf *ln1,
181 const line_buf *ln2, void *dp,
182 int bit_depth, int count)
183 {
184 ojph_unused(ln1);
185 ojph_unused(ln2);
186 int max_val = (1<<bit_depth) - 1;
187 const si32 *sp = ln0->i32;
188 ui16* p = (ui16*)dp;
189 for (ui32 i = count; i > 0; --i)
190 {
191 int val = *sp++;
192 val = val >= 0 ? val : 0;
193 val = val <= max_val ? val : max_val;
194 *p++ = be2le((ui16) val);
195 }
196 }
197
198 void gen_cvrt_32b3c_to_16ub3c_be(const line_buf *ln0, const line_buf *ln1,
199 const line_buf *ln2, void *dp,
200 int bit_depth, int count)
201 {
202 int max_val = (1<<bit_depth) - 1;
203 const si32 *sp0 = ln0->i32;
204 const si32 *sp1 = ln1->i32;
205 const si32 *sp2 = ln2->i32;
206 ui16* p = (ui16*)dp;
207 for (ui32 i = count; i > 0; --i)
208 {
209 int val;
210 val = *sp0++;
211 val = val >= 0 ? val : 0;
212 val = val <= max_val ? val : max_val;
213 *p++ = be2le((ui16) val);
214 val = *sp1++;
215 val = val >= 0 ? val : 0;
216 val = val <= max_val ? val : max_val;
217 *p++ = be2le((ui16) val);
218 val = *sp2++;
219 val = val >= 0 ? val : 0;
220 val = val <= max_val ? val : max_val;
221 *p++ = be2le((ui16) val);
222 }
223 }
224
225
227 //
228 //
229 //
230 //
231 //
233
235 void ppm_in::open(const char *filename)
236 {
237 assert(fh == 0);
238 fh = fopen(filename, "rb");
239 if (fh == 0)
240 OJPH_ERROR(0x030000001, "Unable to open file %s", filename);
241 fname = filename;
242
243 // read magic number
244 char t[2];
245 if (fread(t, 1, 2, fh) != 2)
246 {
247 close();
248 OJPH_ERROR(0x030000002, "Error reading file %s", filename);
249 }
250
251 // check magic number
252 if (t[0] != 'P' || (t[1] != '5' && t[1] != '6'))
253 {
254 close();
255 OJPH_ERROR(0x030000003, "unknown file type for file %s", filename);
256 }
257
258 size_t len = strlen(filename);
259 if (t[1] == '5' && strncmp(filename + len - 4, ".pgm", 4) != 0)
260 {
261 close();
262 OJPH_ERROR(0x030000004, "wrong file extension, a file with "
263 "keyword P5 must have a .pgm extension for file %s", filename);
264 }
265 if (t[1] == '6' && strncmp(filename + len - 4, ".ppm", 4) != 0)
266 {
267 close();
268 OJPH_ERROR(0x030000005, "wrong file extension, a file with keyword P6 "
269 "must have a .ppm extension fir file %s", filename);
270 }
271
272 // set number of components based on file-type
273 num_comps = t[1] == '5' ? 1 : 3;
275
276 // read width, height and max value in header
277 if (fscanf(fh, "%d %d %d", &width, &height, &max_val) != 3)
278 {
279 close();
280 OJPH_ERROR(0x030000006, "error in file format for file %s", filename);
281 }
283 bytes_per_sample = max_val > 255 ? 2 : 1;
286 fgetc(fh);
288
289 // allocate linebuffer to hold a line of image data
291 {
292 if (alloc_p == NULL)
293 {
295 void* t = temp_buf;
296 if (temp_buf)
298 else
300 if (temp_buf == NULL) { // failed to allocate memory
301 if (t) free(t); // the original buffer is still valid
302 OJPH_ERROR(0x030000007, "error allocating mmeory");
303 }
304 }
305 else
306 {
307 assert(temp_buf_byte_size == 0); //cannot reallocate the buffer
310 }
311 }
312 cur_line = 0;
313 }
314
317 {
318 if (alloc_p == NULL)
319 return;
320
321 if (bytes_per_sample == 1)
323 else
325 }
326
328 ui32 ppm_in::read(const line_buf* line, ui32 comp_num)
329 {
330 assert(temp_buf_byte_size != 0 && fh != 0 && comp_num < num_comps);
331 assert(line->size >= width);
332
333 if (planar || comp_num == 0)
334 {
335 size_t result = fread(
337 if (result != num_ele_per_line)
338 {
339 close();
340 OJPH_ERROR(0x030000011, "not enough data in file %s", fname);
341 }
342 if (++cur_line >= height)
343 {
344 cur_line = 0;
345 ojph_fseek(fh, start_of_data, SEEK_SET); //handles plannar reading
346 }
347 }
348
349 if (bytes_per_sample == 1)
350 {
351 const ui8* sp = (ui8*)temp_buf + comp_num;
352 si32* dp = line->i32;
353 for (ui32 i = width; i > 0; --i, sp+=num_comps)
354 *dp++ = (si32)*sp;
355 }
356 else
357 {
358 const ui16* sp = (ui16*)temp_buf + comp_num;
359 si32* dp = line->i32;
360 for (ui32 i = width; i > 0; --i, sp+=num_comps)
361 *dp++ = (si32)be2le(*sp);
362 }
363
364 return width;
365 }
366
368 //
369 //
370 //
371 //
372 //
374
376 void ppm_out::open(char* filename)
377 {
378 assert(fh == NULL && buffer == NULL);
379 if (num_components == 1)
380 {
381 size_t len = strlen(filename);
382 if (len >= 4)
383 {
384 if (strncmp(".ppm", filename + len - 4, 4) == 0)
385 {
386 filename[len - 2] = 'g';
387 OJPH_WARN(0x03000001, "file was renamed %s\n", filename);
388 }
389 if (strncmp(".PPM", filename + len - 4, 4) == 0)
390 {
391 filename[len - 2] = 'G';
392 OJPH_WARN(0x03000002, "file was renamed %s\n", filename);
393 }
394 }
395 fh = fopen(filename, "wb");
396 if (fh == NULL)
397 OJPH_ERROR(0x030000021,
398 "unable to open file %s for writing", filename);
399
400 fprintf(fh, "P5\n%d %d\n%d\n", width, height, (1 << bit_depth) - 1);
402 buffer = (ui8*)malloc(buffer_size);
403 }
404 else
405 {
406 size_t len = strlen(filename);
407 if (len >= 4)
408 {
409 if (strncmp(".pgm", filename + len - 4, 4) == 0)
410 {
411 filename[len - 2] = 'p';
412 OJPH_WARN(0x03000003, "file was renamed %s\n", filename);
413 }
414 if (strncmp(".PGM", filename + len - 4, 4) == 0)
415 {
416 filename[len - 2] = 'P';
417 OJPH_WARN(0x03000004, "file was renamed %s\n", filename);
418 }
419 }
420 fh = fopen(filename, "wb");
421 if (fh == NULL)
422 OJPH_ERROR(0x030000022,
423 "unable to open file %s for writing", filename);
424 int result = //the number of written characters
425 fprintf(fh, "P6\n%d %d\n%d\n", width, height, (1 << bit_depth) - 1);
426 if (result == 0)
427 OJPH_ERROR(0x030000023, "error writing to file %s", filename);
429 buffer = (ui8*)malloc(buffer_size);
430 }
431 fname = filename;
432 cur_line = 0;
433 }
434
436 void ppm_out::configure(ui32 width, ui32 height, ui32 num_components,
437 ui32 bit_depth)
438 {
439 assert(fh == NULL); //configure before opening
440 if (num_components != 1 && num_components != 3)
441 OJPH_ERROR(0x030000031,
442 "ppm supports 3 colour components, while pgm supports 1");
443 this->width = width;
444 this->height = height;
445 this->num_components = num_components;
446 this->bit_depth = bit_depth;
447 bytes_per_sample = 1 + (bit_depth > 8 ? 1 : 0);
450
451 if (bytes_per_sample == 1) {
452 if (num_components == 1)
454 else
456 }
457 else {
458 if (num_components == 1)
460 else
462 }
463
464#ifndef OJPH_DISABLE_INTEL_SIMD
465
467 if (bytes_per_sample == 1) {
468 if (num_components == 1)
470 else
472 }
473 else {
474 if (num_components == 1)
476 else
478 }
479 }
480
482 if (bytes_per_sample == 1) {
483 if (num_components == 1)
485 else
487 }
488 else {
489 if (num_components == 1)
491 else
492 { } // did not find an implementation better than sse41
493 }
494 }
495
496#endif
497 }
498
500 ui32 ppm_out::write(const line_buf* line, ui32 comp_num)
501 {
502 assert(fh);
503
504 lptr[comp_num] = line;
505 if (comp_num == num_components - 1)
506 {
507 assert(lptr[0] != lptr[1]);
508 assert((lptr[1]!=lptr[2] && num_components==3) || num_components==1);
510 size_t result = fwrite(buffer,
512 if (result != samples_per_line)
513 OJPH_ERROR(0x030000042, "error writing to file %s", fname);
514 }
515 return 0;
516 }
517
519 //
520 //
521 //
522 //
523 //
525#ifdef OJPH_ENABLE_TIFF_SUPPORT
527 void tif_in::open(const char* filename)
528 {
529 tiff_handle = NULL;
530 if ((tiff_handle = TIFFOpen(filename, "r")) == NULL)
531 OJPH_ERROR(0x0300000B1, "Unable to open file %s", filename);
532 fname = filename;
533
534 ui32 tiff_width = 0;
535 ui32 tiff_height = 0;
536 TIFFGetField(tiff_handle, TIFFTAG_IMAGEWIDTH, &tiff_width);
537 TIFFGetField(tiff_handle, TIFFTAG_IMAGELENGTH, &tiff_height);
538
539 ui16 tiff_bits_per_sample = 0;
540 ui16 tiff_samples_per_pixel = 0;
541 TIFFGetField(tiff_handle, TIFFTAG_BITSPERSAMPLE, &tiff_bits_per_sample);
542 TIFFGetField(tiff_handle, TIFFTAG_SAMPLESPERPIXEL, &tiff_samples_per_pixel);
543 // some TIFs have tiff_samples_per_pixel=0 when it is a single channel
544 // image - set to 1
545 tiff_samples_per_pixel =
546 (tiff_samples_per_pixel < 1) ? 1 : tiff_samples_per_pixel;
547
548 ui16 tiff_planar_configuration = 0;
549 ui16 tiff_photometric = 0;
550 TIFFGetField(tiff_handle, TIFFTAG_PLANARCONFIG, &tiff_planar_configuration);
551 TIFFGetField(tiff_handle, TIFFTAG_PHOTOMETRIC, &tiff_photometric);
552
553 planar_configuration = tiff_planar_configuration;
554
555 ui16 tiff_compression = 0;
556 ui32 tiff_rows_per_strip = 0;
557 TIFFGetField(tiff_handle, TIFFTAG_COMPRESSION, &tiff_compression);
558 TIFFGetField(tiff_handle, TIFFTAG_ROWSPERSTRIP, &tiff_rows_per_strip);
559
560 if (tiff_planar_configuration == PLANARCONFIG_SEPARATE)
561 {
562 bytes_per_line = tiff_samples_per_pixel * TIFFScanlineSize64(tiff_handle);
563 }
564 else
565 {
566 bytes_per_line = TIFFScanlineSize64(tiff_handle);
567 }
568 // allocate linebuffer to hold a line of image data
569 line_buffer = malloc(bytes_per_line);
570 if (NULL == line_buffer)
571 OJPH_ERROR(0x0300000B2, "Unable to allocate %d bytes for line_buffer[] "
572 "for file %s", bytes_per_line, filename);
573
574 cur_line = 0;
575
576 // Error on known incompatilbe input formats
577 if( tiff_bits_per_sample != 8 && tiff_bits_per_sample != 16 )
578 {
579 OJPH_ERROR(0x0300000B3, "\nTIFF IO is currently limited to file limited"
580 " to files with TIFFTAG_BITSPERSAMPLE=8 and TIFFTAG_BITSPERSAMPLE=16 \n"
581 "input file = %s has TIFFTAG_BITSPERSAMPLE=%d",
582 filename, tiff_bits_per_sample);
583 }
584
585 if( TIFFIsTiled( tiff_handle ) )
586 {
587 OJPH_ERROR(0x0300000B4, "\nTIFF IO is currently limited to TIF files "
588 "without tiles. \nInput file %s has been detected as tiled", filename);
589 }
590
591 if(PHOTOMETRIC_RGB != tiff_photometric &&
592 PHOTOMETRIC_MINISBLACK != tiff_photometric )
593 {
594 OJPH_ERROR(0x0300000B5, "\nTIFF IO is currently limited to "
595 "TIFFTAG_PHOTOMETRIC=PHOTOMETRIC_MINISBLACK=%d and "
596 "PHOTOMETRIC_RGB=%d. \nInput file %s has been detected "
597 "TIFFTAG_PHOTOMETRIC=%d",
598 PHOTOMETRIC_MINISBLACK, PHOTOMETRIC_RGB, filename, tiff_photometric);
599 }
600
601 if( tiff_samples_per_pixel > 4 )
602 {
603 OJPH_ERROR(0x0300000B6, "\nTIFF IO is currently limited to "
604 "TIFFTAG_SAMPLESPERPIXEL=4 \nInput file %s has been detected with "
605 "TIFFTAG_SAMPLESPERPIXEL=%d",
606 filename, tiff_samples_per_pixel);
607 }
608
609 // set number of components based on tiff_samples_per_pixel
610 width = tiff_width;
611 height = tiff_height;
612 num_comps = tiff_samples_per_pixel;
613 bytes_per_sample = (tiff_bits_per_sample + 7) / 8;
614 for (ui32 comp_num = 0; comp_num < num_comps; comp_num++)
615 bit_depth[comp_num] = tiff_bits_per_sample;
616
617 // allocate intermediate linebuffers to hold a line of a single component
618 // of image data
619 if (tiff_planar_configuration == PLANARCONFIG_SEPARATE &&
620 bytes_per_sample == 1)
621 {
622 line_buffer_for_planar_support_uint8 =
623 (uint8_t*)calloc(width, sizeof(uint8_t));
624 if (NULL == line_buffer_for_planar_support_uint8)
625 OJPH_ERROR(0x0300000B7, "Unable to allocate %d bytes for "
626 "line_buffer_for_planar_support_uint8[] for file %s",
627 width * sizeof(uint8_t), filename);
628 }
629 if (tiff_planar_configuration == PLANARCONFIG_SEPARATE &&
630 bytes_per_sample == 2)
631 {
632 line_buffer_for_planar_support_uint16 =
633 (uint16_t*)calloc(width, sizeof(uint16_t));
634 if (NULL == line_buffer_for_planar_support_uint16)
635 OJPH_ERROR(0x0300000B8, "Unable to allocate %d bytes for "
636 "line_buffer_for_planar_support_uint16[] for file %s",
637 width * sizeof(uint16_t), filename);
638 }
639 }
640
642
644 void tif_in::set_bit_depth(ui32 num_bit_depths, ui32* bit_depth)
645 {
646 if (num_bit_depths < 1)
647 OJPH_ERROR(0x030000B9, "one or more bit_depths must be provided");
648 ui32 last_bd_idx = 0;
649 for (ui32 i = 0; i < 4; ++i)
650 {
651 ui32 bd = bit_depth[i < num_bit_depths ? i : last_bd_idx];
652 last_bd_idx += last_bd_idx + 1 < num_bit_depths ? 1 : 0;
653
654 if (bd > 32 || bd < 1)
655 {
656 OJPH_ERROR(0x0300000BA,
657 "bit_depth = %d, this must be an integer from 1-32", bd);
658 }
659 this->bit_depth[i] = bd;
660 }
661 }
662
664 ui32 tif_in::read(const line_buf* line, ui32 comp_num)
665 {
666 assert(bytes_per_line != 0 && tiff_handle != 0 && comp_num < num_comps);
667 assert((ui32)line->size >= width);
668
669 // do a read from the file if this is the first component and therefore
670 // the first time trying to access this line
671 if (PLANARCONFIG_SEPARATE == planar_configuration && 0 == comp_num )
672 {
673 for (unsigned short color = 0; color < num_comps; color++)
674 {
675 if (bytes_per_sample == 1)
676 {
677 TIFFReadScanline(tiff_handle, line_buffer_for_planar_support_uint8,
678 cur_line, color);
679 ui32 x = color;
680 uint8_t* line_buffer_of_interleaved_components =
681 (uint8_t*)line_buffer;
682 for (ui32 i = 0; i < width; i++, x += num_comps)
683 {
684 line_buffer_of_interleaved_components[x] =
685 line_buffer_for_planar_support_uint8[i];
686 }
687 }
688 else if (bytes_per_sample == 2)
689 {
690 TIFFReadScanline(tiff_handle, line_buffer_for_planar_support_uint16,
691 cur_line, color);
692 ui32 x = color;
693 ui16* line_buffer_of_interleaved_components = (ui16*)line_buffer;
694 for (ui32 i = 0; i < width; i++, x += num_comps)
695 {
696 line_buffer_of_interleaved_components[x] =
697 line_buffer_for_planar_support_uint16[i];
698 }
699 }
700 }
701 cur_line++;
702
703 }
704 else if (planar_configuration == PLANARCONFIG_CONTIG && 0 == comp_num)
705 {
706 TIFFReadScanline(tiff_handle, line_buffer, cur_line++);
707 }
708 if (cur_line >= height)
709 {
710 cur_line = 0;
711 }
712
713 if (bytes_per_sample == 1)
714 {
715 const ui8* sp = (ui8*)line_buffer + comp_num;
716 si32* dp = line->i32;
717 if (bit_depth[comp_num] == 8)
718 {
719 for (ui32 i = width; i > 0; --i, sp += num_comps)
720 *dp++ = (si32)*sp;
721 }
722 else if (bit_depth[comp_num] < 8)
723 {
724 // read the desired precision from the MSBs
725 const int bits_to_shift = 8 - (int)bit_depth[comp_num];
726 const int bit_mask = (1 << bit_depth[comp_num]) - 1;
727 for (ui32 i = width; i > 0; --i, sp += num_comps)
728 *dp++ = (si32) (((*sp) >> bits_to_shift) & bit_mask);
729 }
730 else if (bit_depth[comp_num] > 8)
731 {
732 const int bits_to_shift = (int)bit_depth[comp_num] - 8;
733 const int bit_mask = (1 << bit_depth[comp_num]) - 1;
734 for (ui32 i = width; i > 0; --i, sp += num_comps)
735 *dp++ = (si32)(((*sp) << bits_to_shift) & bit_mask);
736 }
737 }
738 else if(bytes_per_sample == 2)
739 {
740 if (bit_depth[comp_num] == 16)
741 {
742 const ui16* sp = (ui16*)line_buffer + comp_num;
743 si32* dp = line->i32;
744 for (ui32 i = width; i > 0; --i, sp += num_comps)
745 *dp++ = (si32)*sp;
746 }
747 else if (bit_depth[comp_num] < 16)
748 {
749 // read the desired precision from the MSBs
750 const int bits_to_shift = 16 - (int)bit_depth[comp_num];
751 const int bit_mask = (1 << bit_depth[comp_num]) - 1;
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) >> bits_to_shift) & bit_mask);
756 }
757 else if (bit_depth[comp_num] > 16)
758 {
759 const int bits_to_shift = (int)bit_depth[comp_num] - 16;
760 const int bit_mask = (1 << bit_depth[comp_num]) - 1;
761 const ui16* sp = (ui16*)line_buffer + comp_num;
762 si32* dp = line->i32;
763 for (ui32 i = width; i > 0; --i, sp += num_comps)
764 *dp++ = (si32)(((*sp) << bits_to_shift) & bit_mask);
765 }
766
767 }
768
769 return width;
770 }
771
773 //
774 //
775 //
776 //
777 //
779
781 void tif_out::open(char* filename)
782 {
783 // Error on known incompatilbe output formats
784 ui32 max_bitdepth = 0;
785 for (ui32 c = 0; c < num_components; c++)
786 {
787 if (bit_depth_of_data[c] > max_bitdepth)
788 max_bitdepth = bit_depth_of_data[c];
789 }
790 if (max_bitdepth > 16)
791 {
792 OJPH_WARN(0x0300000C2, "TIFF output is currently limited to files "
793 "with max_bitdepth = 16, the source codestream has max_bitdepth=%d"
794 ", the decoded data will be truncated to 16 bits", max_bitdepth);
795 }
796 if (num_components > 4)
797 {
798 OJPH_ERROR(0x0300000C3, "TIFF IO is currently limited to files with "
799 "num_components=1 to 4");
800 }
801
802 assert(tiff_handle == NULL && buffer == NULL);
803 if ((tiff_handle = TIFFOpen(filename, "w")) == NULL)
804 {
805 OJPH_ERROR(0x0300000C1, "unable to open file %s for writing", filename);
806 }
807
808 buffer_size = width * num_components * bytes_per_sample;
809 buffer = (ui8*)malloc(buffer_size);
810 fname = filename;
811 cur_line = 0;
812
813 // set tiff fields
814
815 // Write the tiff tags to the file
816 TIFFSetField(tiff_handle, TIFFTAG_IMAGEWIDTH, width);
817 TIFFSetField(tiff_handle, TIFFTAG_IMAGELENGTH, height);
818
819 TIFFSetField(tiff_handle, TIFFTAG_BITSPERSAMPLE, bytes_per_sample * 8);
820 TIFFSetField(tiff_handle, TIFFTAG_SAMPLESPERPIXEL, num_components);
821
822 planar_configuration = PLANARCONFIG_CONTIG;
823 TIFFSetField(tiff_handle, TIFFTAG_PLANARCONFIG, planar_configuration);
824
825 if (num_components == 1)
826 {
827 TIFFSetField(tiff_handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
828 }
829 else if (num_components == 2)
830 {
831 TIFFSetField(tiff_handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
832 // possible values are EXTRASAMPLE_UNSPECIFIED = 0;
833 // EXTRASAMPLE_ASSOCALPHA = 1; EXTRASAMPLE_UNASSALPHA = 2;
834 const ui16 extra_samples_description[1] = { EXTRASAMPLE_ASSOCALPHA };
835 TIFFSetField(tiff_handle, TIFFTAG_EXTRASAMPLES, (uint16_t)1,
836 &extra_samples_description);
837 }
838 else if (num_components == 3)
839 {
840 TIFFSetField(tiff_handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
841 }
842 else if (num_components == 4)
843 {
844 TIFFSetField(tiff_handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
845 // possible values are EXTRASAMPLE_UNSPECIFIED = 0;
846 // EXTRASAMPLE_ASSOCALPHA = 1; EXTRASAMPLE_UNASSALPHA = 2;
847 const ui16 extra_samples_description[1] = { EXTRASAMPLE_ASSOCALPHA };
848 TIFFSetField(tiff_handle, TIFFTAG_EXTRASAMPLES, (uint16_t)1,
849 &extra_samples_description);
850 }
851
852 TIFFSetField(tiff_handle, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
853 TIFFSetField(tiff_handle, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
854 //TIFFSetField(tiff_handle, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
855 TIFFSetField(tiff_handle, TIFFTAG_ROWSPERSTRIP, height);
856
857 }
858
860 void tif_out::configure(ui32 width, ui32 height, ui32 num_components,
861 ui32 *bit_depth)
862 {
863 assert(tiff_handle == NULL); //configure before opening
864
865 this->width = width;
866 this->height = height;
867 this->num_components = num_components;
868 ui32 max_bitdepth = 0;
869 for (ui32 c = 0; c < num_components; c++)
870 {
871 this->bit_depth_of_data[c] = bit_depth[c];
872 if (bit_depth[c] > max_bitdepth)
873 max_bitdepth = bit_depth[c];
874 }
875
876 bytes_per_sample = (max_bitdepth + 7) / 8; // round up
877 if (bytes_per_sample > 2)
878 {
879 // TIFF output is currently limited to files with max_bitdepth = 16,
880 // the decoded data will be truncated to 16 bits
881 bytes_per_sample = 2;
882 }
883 samples_per_line = num_components * width;
884 bytes_per_line = bytes_per_sample * samples_per_line;
885
886 }
887
889 ui32 tif_out::write(const line_buf* line, ui32 comp_num)
890 {
891 assert(tiff_handle);
892
893 if (bytes_per_sample == 1)
894 {
895 int max_val = (1 << bit_depth_of_data[comp_num]) - 1;
896 const si32* sp = line->i32;
897 ui8* dp = buffer + comp_num;
898 if (bit_depth_of_data[comp_num] == 8)
899 {
900 for (ui32 i = width; i > 0; --i, dp += num_components)
901 {
902 // clamp the decoded sample to the allowed range
903 int val = *sp++;
904 val = val >= 0 ? val : 0;
905 val = val <= max_val ? val : max_val;
906 *dp = (ui8)val;
907 }
908 }
909 else if (bit_depth_of_data[comp_num] < 8)
910 {
911 const int bits_to_shift = 8 - (int)bit_depth_of_data[comp_num];
912 const int bit_mask = (1 << bit_depth_of_data[comp_num]) - 1;
913 for (ui32 i = width; i > 0; --i, dp += num_components)
914 {
915 // clamp the decoded sample to the allowed range
916 int val = *sp++;
917 val = val >= 0 ? val : 0;
918 val = val <= max_val ? val : max_val;
919 // shift the decoded data so the data's MSB is aligned with the
920 // 8 bit MSB
921 *dp = (ui8)((val & bit_mask) << bits_to_shift);
922 }
923 }
924 else if (bit_depth_of_data[comp_num] > 8)
925 {
926 const int bits_to_shift = (int)bit_depth_of_data[comp_num] - 8;
927 const int bit_mask = (1 << bit_depth_of_data[comp_num]) - 1;
928 for (ui32 i = width; i > 0; --i, dp += num_components)
929 {
930 // clamp the decoded sample to the allowed range
931 int val = *sp++;
932 val = val >= 0 ? val : 0;
933 val = val <= max_val ? val : max_val;
934 // shift the decoded data so the data's MSB is aligned with the
935 // 8 bit MSB
936 *dp = (ui8)((val >> bits_to_shift) & bit_mask);
937 }
938 }
939
940 }
941 else if(bytes_per_sample == 2)
942 {
943 int max_val = (1 << bit_depth_of_data[comp_num]) - 1;
944 const si32* sp = line->i32;
945 ui16* dp = (ui16*)buffer + comp_num;
946
947 if (bit_depth_of_data[comp_num] == 16)
948 {
949 for (ui32 i = width; i > 0; --i, dp += num_components)
950 {
951 // clamp the decoded sample to the allowed range
952 int val = *sp++;
953 val = val >= 0 ? val : 0;
954 val = val <= max_val ? val : max_val;
955 *dp = (ui16)val;
956 }
957 }
958 else if (bit_depth_of_data[comp_num] < 16)
959 {
960 const int bits_to_shift = 16 - (int)bit_depth_of_data[comp_num];
961 const int bit_mask = (1 << bit_depth_of_data[comp_num]) - 1;
962 for (ui32 i = width; i > 0; --i, dp += num_components)
963 {
964 // clamp the decoded sample to the allowed range
965 int val = *sp++;
966 val = val >= 0 ? val : 0;
967 val = val <= max_val ? val : max_val;
968
969 // shift the decoded data so the data's MSB is aligned with the
970 // 16 bit MSB
971 *dp = (ui16)((val & bit_mask) << bits_to_shift);
972 }
973 }
974 else if (bit_depth_of_data[comp_num] > 16)
975 {
976 const int bits_to_shift = (int)bit_depth_of_data[comp_num] - 16;
977 const int bit_mask = (1 << bit_depth_of_data[comp_num]) - 1;
978 for (ui32 i = width; i > 0; --i, dp += num_components)
979 {
980 // clamp the decoded sample to the allowed range
981 int val = *sp++;
982 val = val >= 0 ? val : 0;
983 val = val <= max_val ? val : max_val;
984
985 // shift the decoded data so the data's MSB is aligned with the
986 // 16 bit MSB
987 *dp = (ui16)((val >> bits_to_shift) & bit_mask);
988 }
989 }
990
991 }
992 // write scanline when the last component is reached
993 if (comp_num == num_components-1)
994 {
995 int result = TIFFWriteScanline(tiff_handle, buffer, cur_line++);
996 if (result != 1)
997 OJPH_ERROR(0x0300000C4, "error writing to file %s", fname);
998 }
999 return 0;
1000 }
1001 #endif /* OJPH_ENABLE_TIFF_SUPPORT */
1002
1004 //
1005 //
1006 //
1007 //
1008 //
1010
1012 void yuv_in::open(const char* filename)
1013 {
1014 assert(fh == NULL);
1015 fh = fopen(filename, "rb");
1016 if (fh == 0)
1017 OJPH_ERROR(0x03000051, "Unable to open file %s", filename);
1018
1019 //need to extract info from filename
1020
1021 assert(num_com == 1 || num_com == 3);
1022 for (ui32 i = 0; i < num_com; ++i)
1023 bytes_per_sample[i] = bit_depth[i] > 8 ? 2 : 1;
1024 ui32 max_byte_width = width[0] * bytes_per_sample[0];
1025 comp_address[0] = 0;
1026 for (ui32 i = 1; i < num_com; ++i)
1027 {
1028 comp_address[i] = comp_address[i - 1];
1029 comp_address[i] += width[i-1] * height[i-1] * bytes_per_sample[i-1];
1030 max_byte_width = ojph_max(max_byte_width, width[i]*bytes_per_sample[i]);
1031 }
1032 temp_buf = malloc(max_byte_width);
1033 fname = filename;
1034 }
1035
1037 ui32 yuv_in::read(const line_buf* line, ui32 comp_num)
1038 {
1039 assert(comp_num < num_com);
1040 size_t result = fread(temp_buf, bytes_per_sample[comp_num],
1041 width[comp_num], fh);
1042 if (result != width[comp_num])
1043 {
1044 close();
1045 OJPH_ERROR(0x03000061, "not enough data in file %s", fname);
1046 }
1047
1048 if (bytes_per_sample[comp_num] == 1)
1049 {
1050 const ui8* sp = (ui8*)temp_buf;
1051 si32* dp = line->i32;
1052 for (ui32 i = width[comp_num]; i > 0; --i, ++sp)
1053 *dp++ = (si32)*sp;
1054 }
1055 else
1056 {
1057 const ui16* sp = (ui16*)temp_buf;
1058 si32* dp = line->i32;
1059 for (ui32 i = width[comp_num]; i > 0; --i, ++sp)
1060 *dp++ = (si32)*sp;
1061 }
1062
1063 return width[comp_num];
1064 }
1065
1067 void yuv_in::set_img_props(const size& s, ui32 num_components,
1068 ui32 num_downsamplings, const point *subsampling)
1069 {
1070 if (num_components != 1 && num_components !=3)
1071 OJPH_ERROR(0x03000071, "yuv_in support 1 or 3 components");
1072 this->num_com = num_components;
1073
1074 if (num_downsamplings < 1)
1075 OJPH_ERROR(0x03000072, "one or more downsampling must be provided");
1076
1077 ui32 last_downsamp_idx = 0;
1078 for (ui32 i = 0; i < num_components; ++i)
1079 {
1080 point cp_ds = subsampling[i<num_downsamplings ? i : last_downsamp_idx];
1081 last_downsamp_idx += last_downsamp_idx + 1 < num_downsamplings ? 1 : 0;
1082
1083 this->subsampling[i] = cp_ds;
1084 }
1085
1086 for (ui32 i = 0; i < num_components; ++i)
1087 {
1088 width[i] = ojph_div_ceil(s.w, this->subsampling[i].x);
1089 height[i] = ojph_div_ceil(s.h, this->subsampling[i].y);
1090 }
1091 }
1092
1094 void yuv_in::set_bit_depth(ui32 num_bit_depths, ui32* bit_depth)
1095 {
1096 if (num_bit_depths < 1)
1097 OJPH_ERROR(0x03000081, "one or more bit_depths must be provided");
1098 ui32 last_bd_idx = 0;
1099 for (ui32 i = 0; i < 3; ++i)
1100 {
1101 ui32 bd = bit_depth[i < num_bit_depths ? i : last_bd_idx];
1102 last_bd_idx += last_bd_idx + 1 < num_bit_depths ? 1 : 0;
1103
1104 this->bit_depth[i] = bd;
1105 }
1106 }
1107
1109 //
1110 //
1111 //
1112 //
1113 //
1115
1118 {
1119 close();
1120 if (buffer)
1121 {
1122 free(buffer);
1123 buffer = NULL;
1124 buffer_size = 0;
1125 }
1126 if (comp_width)
1127 {
1128 delete [] comp_width;
1129 comp_width = NULL;
1130 }
1131 }
1132
1134 void yuv_out::open(char *filename)
1135 {
1136 assert(fh == NULL); //configure before open
1137 fh = fopen(filename, "wb");
1138 if (fh == 0)
1139 OJPH_ERROR(0x03000091, "Unable to open file %s", filename);
1140 fname = filename;
1141 }
1142
1144 void yuv_out::configure(ui32 bit_depth, ui32 num_components,
1145 ui32* comp_width)
1146 {
1147 assert(fh == NULL);
1148 this->num_components = num_components;
1149 this->bit_depth = bit_depth;
1150 this->comp_width = new ui32[num_components];
1151 ui32 tw = 0;
1152 for (ui32 i = 0; i < num_components; ++i)
1153 {
1154 this->comp_width[i] = comp_width[i];
1155 tw = ojph_max(tw, this->comp_width[i]);
1156 }
1157 this->width = tw;
1158 buffer_size = tw * (bit_depth > 8 ? 2 : 1);
1159 buffer = (ui8*)malloc(buffer_size);
1160 }
1161
1163 ui32 yuv_out::write(const line_buf* line, ui32 comp_num)
1164 {
1165 assert(fh);
1166 assert(comp_num < num_components);
1167
1168 int max_val = (1<<bit_depth) - 1;
1169 ui32 w = comp_width[comp_num];
1170 if (bit_depth > 8)
1171 {
1172 const si32 *sp = line->i32;
1173 ui16 *dp = (ui16 *)buffer;
1174 for (ui32 i = w; i > 0; --i)
1175 {
1176 int val = *sp++;
1177 val = val >= 0 ? val : 0;
1178 val = val <= max_val ? val : max_val;
1179 *dp++ = (ui16)val;
1180 }
1181 if (fwrite(buffer, 2, w, fh) != w)
1182 OJPH_ERROR(0x030000A1, "unable to write to file %s", fname);
1183 }
1184 else
1185 {
1186 const si32 *sp = line->i32;
1187 ui8 *dp = (ui8 *)buffer;
1188 for (ui32 i = w; i > 0; --i)
1189 {
1190 int val = *sp++;
1191 val = val >= 0 ? val : 0;
1192 val = val <= max_val ? val : max_val;
1193 *dp++ = (ui8)val;
1194 }
1195 if (fwrite(buffer, 1, w, fh) != w)
1196 OJPH_ERROR(0x030000A2, "unable to write to file %s", fname);
1197 }
1198
1199 return w;
1200 }
1201}
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:406
const char * fname
Definition: ojph_img_io.h:405
void open(char *filename)
virtual ui32 write(const line_buf *line, ui32 comp_num)
ui32 bytes_per_line
Definition: ojph_img_io.h:410
ui32 bytes_per_sample
Definition: ojph_img_io.h:407
const line_buf * lptr[3]
Definition: ojph_img_io.h:412
conversion_fun converter
Definition: ojph_img_io.h:411
void configure(ui32 width, ui32 height, ui32 num_components, ui32 bit_depth)
ui32 samples_per_line
Definition: ojph_img_io.h:410
ui32 width[3]
Definition: ojph_img_io.h:285
virtual ui32 read(const line_buf *line, ui32 comp_num)
ui32 height[3]
Definition: ojph_img_io.h:285
void open(const char *filename)
void * temp_buf
Definition: ojph_img_io.h:284
const char * fname
Definition: ojph_img_io.h:283
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:286
point subsampling[3]
Definition: ojph_img_io.h:293
void close()
Definition: ojph_img_io.h:270
ui32 bit_depth[3]
Definition: ojph_img_io.h:291
ui32 comp_address[3]
Definition: ojph_img_io.h:287
const char * fname
Definition: ojph_img_io.h:505
void open(char *filename)
ui32 * comp_width
Definition: ojph_img_io.h:509
ui32 num_components
Definition: ojph_img_io.h:507
void configure(ui32 bit_depth, ui32 num_components, ui32 *comp_width)
virtual void close()
Definition: ojph_img_io.h:501
virtual ~yuv_out()
virtual ui32 write(const line_buf *line, ui32 comp_num)
void gen_cvrt_32b1c_to_16ub1c_le(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, int bit_depth, int count)
int ojph_fseek(FILE *stream, si64 offset, int origin)
Definition: ojph_file.h:61
void avx2_cvrt_32b1c_to_8ub1c(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, int bit_depth, int count)
static void eat_white_spaces(FILE *fh)
Definition: ojph_img_io.cpp:62
void sse41_cvrt_32b3c_to_16ub3c_be(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, int bit_depth, int count)
si64 ojph_ftell(FILE *stream)
Definition: ojph_file.h:66
void gen_cvrt_32b1c_to_8ub1c(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, int bit_depth, int count)
Definition: ojph_img_io.cpp:89
void sse41_cvrt_32b1c_to_16ub1c_be(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, int bit_depth, int count)
@ X86_CPU_EXT_LEVEL_AVX2
Definition: ojph_arch.h:83
@ X86_CPU_EXT_LEVEL_SSE41
Definition: ojph_arch.h:80
void avx2_cvrt_32b3c_to_8ub3c(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, int bit_depth, int count)
uint16_t ui16
Definition: ojph_defs.h:52
void sse41_cvrt_32b1c_to_8ub1c(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, int bit_depth, int count)
void gen_cvrt_32b3c_to_16ub3c_le(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, int bit_depth, int count)
void gen_cvrt_32b3c_to_8ub3c(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, int bit_depth, int count)
static ui16 be2le(const ui16 v)
Definition: ojph_img_io.cpp:55
int get_cpu_ext_level()
Definition: ojph_arch.cpp:182
static ui32 count_leading_zeros(ui32 val)
Definition: ojph_arch.h:109
void gen_cvrt_32b3c_to_16ub3c_be(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, int bit_depth, int count)
int32_t si32
Definition: ojph_defs.h:55
void avx2_cvrt_32b1c_to_16ub1c_be(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, int bit_depth, int count)
void sse41_cvrt_32b3c_to_8ub3c(const line_buf *ln0, const line_buf *ln1, const line_buf *ln2, void *dp, int bit_depth, int count)
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, int bit_depth, int 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