57 return (
ui16)((v<<8) | (v>>8));
67 if (c ==
' ' || c ==
'\r' || c ==
'\n' || c ==
'\t')
71 while (c !=
'\n') c = fgetc(fh);
93 fh = fopen(filename,
"rb");
95 OJPH_ERROR(0x030000001,
"Unable to open file %s", filename);
100 if (fread(t, 1, 2,
fh) != 2)
103 OJPH_ERROR(0x030000002,
"Error reading file %s", filename);
107 if (t[0] !=
'P' || (t[1] !=
'5' && t[1] !=
'6'))
110 OJPH_ERROR(0x030000003,
"unknown file type for file %s", filename);
113 size_t len = strlen(filename);
114 if (t[1] ==
'5' && strncmp(filename + len - 4,
".pgm", 4) != 0)
117 OJPH_ERROR(0x030000004,
"wrong file extension, a file with "
118 "keyword P5 must have a .pgm extension for file %s", filename);
120 if (t[1] ==
'6' && strncmp(filename + len - 4,
".ppm", 4) != 0)
123 OJPH_ERROR(0x030000005,
"wrong file extension, a file with keyword P6 "
124 "must have a .ppm extension fir file %s", filename);
135 OJPH_ERROR(0x030000006,
"error in file format for file %s", filename);
157 OJPH_ERROR(0x030000007,
"error allocating mmeory");
188 if (
planar || comp_num == 0)
190 size_t result = fread(
233 assert(
fh == NULL &&
buffer == NULL);
236 size_t len = strlen(filename);
239 if (strncmp(
".ppm", filename + len - 4, 4) == 0)
241 filename[len - 2] =
'g';
242 OJPH_WARN(0x03000001,
"file was renamed %s\n", filename);
244 if (strncmp(
".PPM", filename + len - 4, 4) == 0)
246 filename[len - 2] =
'G';
247 OJPH_WARN(0x03000002,
"file was renamed %s\n", filename);
250 fh = fopen(filename,
"wb");
253 "unable to open file %s for writing", filename);
261 size_t len = strlen(filename);
264 if (strncmp(
".pgm", filename + len - 4, 4) == 0)
266 filename[len - 2] =
'p';
267 OJPH_WARN(0x03000003,
"file was renamed %s\n", filename);
269 if (strncmp(
".PGM", filename + len - 4, 4) == 0)
271 filename[len - 2] =
'P';
272 OJPH_WARN(0x03000004,
"file was renamed %s\n", filename);
275 fh = fopen(filename,
"wb");
278 "unable to open file %s for writing", filename);
282 OJPH_ERROR(0x030000023,
"error writing to file %s", filename);
297 "ppm supports 3 colour components, while pgm supports 1");
313 assert(comp_num == 0);
323 val = val >= 0 ? val : 0;
324 val = val <= max_val ? val : max_val;
336 val = val >= 0 ? val : 0;
337 val = val <= max_val ? val : max_val;
353 for (
ui32 i =
width; i > 0; --i, dp += 3)
356 val = val >= 0 ? val : 0;
357 val = val <= max_val ? val : max_val;
366 for (
ui32 i =
width; i > 0; --i, dp += 3)
369 val = val >= 0 ? val : 0;
370 val = val <= max_val ? val : max_val;
376 size_t result = fwrite(
buffer,
392 #ifdef OJPH_ENABLE_TIFF_SUPPORT
394 void tif_in::open(
const char* filename)
397 if ((tiff_handle = TIFFOpen(filename,
"r")) == NULL)
398 OJPH_ERROR(0x0300000B1,
"Unable to open file %s", filename);
402 ui32 tiff_height = 0;
403 TIFFGetField(tiff_handle, TIFFTAG_IMAGEWIDTH, &tiff_width);
404 TIFFGetField(tiff_handle, TIFFTAG_IMAGELENGTH, &tiff_height);
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);
412 tiff_samples_per_pixel =
413 (tiff_samples_per_pixel < 1) ? 1 : tiff_samples_per_pixel;
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);
420 planar_configuration = tiff_planar_configuration;
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);
427 if (tiff_planar_configuration == PLANARCONFIG_SEPARATE)
429 bytes_per_line = tiff_samples_per_pixel * TIFFScanlineSize64(tiff_handle);
433 bytes_per_line = TIFFScanlineSize64(tiff_handle);
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);
444 if( tiff_bits_per_sample != 8 && tiff_bits_per_sample != 16 )
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);
452 if( TIFFIsTiled( tiff_handle ) )
454 OJPH_ERROR(0x0300000B4,
"\nTIFF IO is currently limited to TIF files "
455 "without tiles. \nInput file %s has been detected as tiled", filename);
458 if(PHOTOMETRIC_RGB != tiff_photometric &&
459 PHOTOMETRIC_MINISBLACK != tiff_photometric )
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);
468 if( tiff_samples_per_pixel > 4 )
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);
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;
486 if (tiff_planar_configuration == PLANARCONFIG_SEPARATE &&
487 bytes_per_sample == 1)
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);
496 if (tiff_planar_configuration == PLANARCONFIG_SEPARATE &&
497 bytes_per_sample == 2)
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);
511 void tif_in::set_bit_depth(
ui32 num_bit_depths,
ui32* bit_depth)
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)
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;
521 if (bd > 32 || bd < 1)
524 "bit_depth = %d, this must be an integer from 1-32", bd);
526 this->bit_depth[i] = bd;
531 ui32 tif_in::read(
const line_buf* line,
ui32 comp_num)
533 assert(bytes_per_line != 0 && tiff_handle != 0 && comp_num < num_comps);
534 assert((
ui32)line->size >= width);
538 if (PLANARCONFIG_SEPARATE == planar_configuration && 0 == comp_num )
540 for (
unsigned short color = 0; color < num_comps; color++)
542 if (bytes_per_sample == 1)
544 TIFFReadScanline(tiff_handle, line_buffer_for_planar_support_uint8,
547 uint8_t* line_buffer_of_interleaved_components =
548 (uint8_t*)line_buffer;
549 for (
ui32 i = 0; i < width; i++, x += num_comps)
551 line_buffer_of_interleaved_components[x] =
552 line_buffer_for_planar_support_uint8[i];
555 else if (bytes_per_sample == 2)
557 TIFFReadScanline(tiff_handle, line_buffer_for_planar_support_uint16,
560 ui16* line_buffer_of_interleaved_components = (
ui16*)line_buffer;
561 for (
ui32 i = 0; i < width; i++, x += num_comps)
563 line_buffer_of_interleaved_components[x] =
564 line_buffer_for_planar_support_uint16[i];
571 else if (planar_configuration == PLANARCONFIG_CONTIG && 0 == comp_num)
573 TIFFReadScanline(tiff_handle, line_buffer, cur_line++);
575 if (cur_line >= height)
580 if (bytes_per_sample == 1)
582 const ui8* sp = (
ui8*)line_buffer + comp_num;
583 si32* dp = line->i32;
584 if (bit_depth[comp_num] == 8)
586 for (
ui32 i = width; i > 0; --i, sp += num_comps)
589 else if (bit_depth[comp_num] < 8)
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);
597 else if (bit_depth[comp_num] > 8)
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);
605 else if(bytes_per_sample == 2)
607 if (bit_depth[comp_num] == 16)
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)
614 else if (bit_depth[comp_num] < 16)
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);
624 else if (bit_depth[comp_num] > 16)
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);
648 void tif_out::open(
char* filename)
651 ui32 max_bitdepth = 0;
652 for (
ui32 c = 0; c < num_components; c++)
654 if (bit_depth_of_data[c] > max_bitdepth)
655 max_bitdepth = bit_depth_of_data[c];
657 if (max_bitdepth > 16)
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);
663 if (num_components > 4)
665 OJPH_ERROR(0x0300000C3,
"TIFF IO is currently limited to files with "
666 "num_components=1 to 4");
669 assert(tiff_handle == NULL && buffer == NULL);
670 if ((tiff_handle = TIFFOpen(filename,
"w")) == NULL)
672 OJPH_ERROR(0x0300000C1,
"unable to open file %s for writing", filename);
675 buffer_size = width * num_components * bytes_per_sample;
676 buffer = (
ui8*)malloc(buffer_size);
683 TIFFSetField(tiff_handle, TIFFTAG_IMAGEWIDTH, width);
684 TIFFSetField(tiff_handle, TIFFTAG_IMAGELENGTH, height);
686 TIFFSetField(tiff_handle, TIFFTAG_BITSPERSAMPLE, bytes_per_sample * 8);
687 TIFFSetField(tiff_handle, TIFFTAG_SAMPLESPERPIXEL, num_components);
689 planar_configuration = PLANARCONFIG_CONTIG;
690 TIFFSetField(tiff_handle, TIFFTAG_PLANARCONFIG, planar_configuration);
692 if (num_components == 1)
694 TIFFSetField(tiff_handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
696 else if (num_components == 2)
698 TIFFSetField(tiff_handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
701 const ui16 extra_samples_description[1] = { EXTRASAMPLE_ASSOCALPHA };
702 TIFFSetField(tiff_handle, TIFFTAG_EXTRASAMPLES, (uint16_t)1,
703 &extra_samples_description);
705 else if (num_components == 3)
707 TIFFSetField(tiff_handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
709 else if (num_components == 4)
711 TIFFSetField(tiff_handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
714 const ui16 extra_samples_description[1] = { EXTRASAMPLE_ASSOCALPHA };
715 TIFFSetField(tiff_handle, TIFFTAG_EXTRASAMPLES, (uint16_t)1,
716 &extra_samples_description);
719 TIFFSetField(tiff_handle, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
720 TIFFSetField(tiff_handle, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
722 TIFFSetField(tiff_handle, TIFFTAG_ROWSPERSTRIP, height);
727 void tif_out::configure(
ui32 width,
ui32 height,
ui32 num_components,
730 assert(tiff_handle == NULL);
733 this->height = height;
734 this->num_components = num_components;
735 ui32 max_bitdepth = 0;
736 for (
ui32 c = 0; c < num_components; c++)
738 this->bit_depth_of_data[c] = bit_depth[c];
739 if (bit_depth[c] > max_bitdepth)
740 max_bitdepth = bit_depth[c];
743 bytes_per_sample = (max_bitdepth + 7) / 8;
744 if (bytes_per_sample > 2)
748 bytes_per_sample = 2;
750 samples_per_line = num_components * width;
751 bytes_per_line = bytes_per_sample * samples_per_line;
756 ui32 tif_out::write(
const line_buf* line,
ui32 comp_num)
760 if (bytes_per_sample == 1)
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)
767 for (
int i = width; i > 0; --i, dp += num_components)
771 val = val >= 0 ? val : 0;
772 val = val <= max_val ? val : max_val;
776 else if (bit_depth_of_data[comp_num] < 8)
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)
784 val = val >= 0 ? val : 0;
785 val = val <= max_val ? val : max_val;
788 *dp = (
ui8)((val & bit_mask) << bits_to_shift);
791 else if (bit_depth_of_data[comp_num] > 8)
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)
799 val = val >= 0 ? val : 0;
800 val = val <= max_val ? val : max_val;
803 *dp = (
ui8)((val >> bits_to_shift) & bit_mask);
808 else if(bytes_per_sample == 2)
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;
814 if (bit_depth_of_data[comp_num] == 16)
816 for (
int i = width; i > 0; --i, dp += num_components)
820 val = val >= 0 ? val : 0;
821 val = val <= max_val ? val : max_val;
825 else if (bit_depth_of_data[comp_num] < 16)
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)
833 val = val >= 0 ? val : 0;
834 val = val <= max_val ? val : max_val;
838 *dp = (
ui16)((val & bit_mask) << bits_to_shift);
841 else if (bit_depth_of_data[comp_num] > 16)
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)
849 val = val >= 0 ? val : 0;
850 val = val <= max_val ? val : max_val;
854 *dp = (
ui16)((val >> bits_to_shift) & bit_mask);
860 if (comp_num == num_components-1)
862 int result = TIFFWriteScanline(tiff_handle, buffer, cur_line++);
864 OJPH_ERROR(0x0300000C4,
"error writing to file %s", fname);
882 fh = fopen(filename,
"rb");
884 OJPH_ERROR(0x03000051,
"Unable to open file %s", filename);
909 if (result !=
width[comp_num])
919 for (
ui32 i =
width[comp_num]; i > 0; --i, ++sp)
926 for (
ui32 i =
width[comp_num]; i > 0; --i, ++sp)
930 return width[comp_num];
935 ui32 num_downsamplings,
const point *subsampling)
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;
941 if (num_downsamplings < 1)
942 OJPH_ERROR(0x03000072,
"one or more downsampling must be provided");
944 ui32 last_downsamp_idx = 0;
945 for (
ui32 i = 0; i < num_components; ++i)
948 last_downsamp_idx += last_downsamp_idx + 1 < num_downsamplings ? 1 : 0;
950 this->subsampling[i] = cp_ds;
953 for (
ui32 i = 0; i < num_components; ++i)
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)
969 last_bd_idx += last_bd_idx + 1 < num_bit_depths ? 1 : 0;
971 this->bit_depth[i] = bd;
1004 fh = fopen(filename,
"wb");
1006 OJPH_ERROR(0x03000091,
"Unable to open file %s", filename);
1022 tw =
ojph_max(tw, this->comp_width[i]);
1041 for (
ui32 i = w; i > 0; --i)
1044 val = val >= 0 ? val : 0;
1045 val = val <= max_val ? val : max_val;
1055 for (
ui32 i = w; i > 0; --i)
1058 val = val >= 0 ? val : 0;
1059 val = val <= max_val ? val : max_val;
void pre_alloc_data(size_t num_ele, ui32 pre_size)
T * post_alloc_data(size_t num_ele, ui32 pre_size)
void open(const char *filename)
mem_fixed_allocator * alloc_p
virtual ui32 read(const line_buf *line, ui32 comp_num)
void open(char *filename)
virtual ui32 write(const line_buf *line, ui32 comp_num)
void configure(ui32 width, ui32 height, ui32 num_components, ui32 bit_depth)
virtual ui32 read(const line_buf *line, ui32 comp_num)
void open(const char *filename)
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)
void open(char *filename)
void configure(ui32 bit_depth, ui32 num_components, ui32 *comp_width)
virtual ui32 write(const line_buf *line, ui32 comp_num)
int ojph_fseek(FILE *stream, si64 offset, int origin)
static void eat_white_spaces(FILE *fh)
si64 ojph_ftell(FILE *stream)
static ui16 be2le(const ui16 v)
static ui32 count_leading_zeros(ui32 val)
#define ojph_div_ceil(a, b)
#define OJPH_ERROR(t,...)