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 
47 namespace 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
299  temp_buf = malloc(temp_buf_byte_size);
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);
509  converter(lptr[0], lptr[1], lptr[2], buffer, bit_depth, width);
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