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