# HG changeset patch # User magedrifaat # Date 1660763749 -7200 # Node ID 14edd6b09efe4acf4f9f409bc20e00348f7c6804 # Parent c7c79973007f3adc2a299e5abda38d3aea2851cf Tiff: added support for reading and writing signed images * __tiff__.cc (F__tiff_read__, F__tiff_write__, F__read_encoded_strip__, F__tiff_read_encoded_tile__): added support for reading and writing images with sample format of 2 as signed integer images. diff -r c7c79973007f -r 14edd6b09efe libinterp/corefcn/__tiff__.cc --- a/libinterp/corefcn/__tiff__.cc Wed Aug 17 18:51:16 2022 +0200 +++ b/libinterp/corefcn/__tiff__.cc Wed Aug 17 21:15:49 2022 +0200 @@ -375,6 +375,77 @@ } octave_value + read_unsigned_strip_or_tile (TIFF *tif, uint32_t strip_tile_no, + tiff_image_data *image_data) + { + switch (image_data->bits_per_sample) + { + case 1: + return read_strip_or_tile (tif, strip_tile_no, + image_data); + break; + case 8: + return read_strip_or_tile (tif, strip_tile_no, + image_data); + break; + case 16: + return read_strip_or_tile (tif, strip_tile_no, + image_data); + break; + case 32: + return read_strip_or_tile (tif, strip_tile_no, + image_data); + case 64: + return read_strip_or_tile (tif, strip_tile_no, + image_data); + default: + error ("Unsupported bit depth"); + } + } + + octave_value + read_signed_strip_or_tile (TIFF *tif, uint32_t strip_tile_no, + tiff_image_data *image_data) + { + switch (image_data->bits_per_sample) + { + case 8: + return read_strip_or_tile (tif, strip_tile_no, + image_data); + break; + case 16: + return read_strip_or_tile (tif, strip_tile_no, + image_data); + break; + case 32: + return read_strip_or_tile (tif, strip_tile_no, + image_data); + case 64: + return read_strip_or_tile (tif, strip_tile_no, + image_data); + default: + error ("Unsupported bit depth for signed images"); + } + } + + octave_value + read_float_strip_or_tile (TIFF *tif, uint32_t strip_tile_no, + tiff_image_data *image_data) + { + switch (image_data->bits_per_sample) + { + case 32: + return read_strip_or_tile (tif, strip_tile_no, + image_data); + case 64: + return read_strip_or_tile (tif, strip_tile_no, + image_data); + default: + error ("Unsupported bit depth for floating-point images"); + } + } + + octave_value handle_read_strip_or_tile (TIFF *tif, uint32_t strip_tile_no) { // Obtain all necessary tags @@ -384,47 +455,20 @@ if (! TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_format)) error ("Failed to obtain a value for sample format"); - if (sample_format == 3) - { - if (image_data.bits_per_sample != 32 - && image_data.bits_per_sample != 64) - error ("Floating point images are only supported for bit depths of 32 and 64"); - } - else if (sample_format != 1 && sample_format != 4) - error ("Unsupported sample format"); - - switch (image_data.bits_per_sample) + switch (sample_format) { case 1: - return read_strip_or_tile (tif, strip_tile_no, - &image_data); - break; - case 8: - return read_strip_or_tile (tif, strip_tile_no, - &image_data); - break; - case 16: - return read_strip_or_tile (tif, strip_tile_no, - &image_data); + case 4: + return read_unsigned_strip_or_tile (tif, strip_tile_no, &image_data); break; - case 32: - if (sample_format == 3) - return read_strip_or_tile (tif, strip_tile_no, - &image_data); - else - return read_strip_or_tile (tif, strip_tile_no, - &image_data); + case 2: + return read_signed_strip_or_tile (tif, strip_tile_no, &image_data); break; - case 64: - if (sample_format == 3) - return read_strip_or_tile (tif, strip_tile_no, - &image_data); - else - return read_strip_or_tile (tif, strip_tile_no, - &image_data); + case 3: + return read_float_strip_or_tile (tif, strip_tile_no, &image_data); break; default: - error ("Unsupported bit depth"); + error ("Unsupported sample format"); } } @@ -755,6 +799,67 @@ return read_stripped_image (tif, image_data); } + octave_value + read_unsigned_image (TIFF *tif, tiff_image_data *image_data) + { + switch (image_data->bits_per_sample) + { + case 1: + return read_image (tif, image_data); + break; + case 4: + case 8: + return read_image (tif, image_data); + break; + case 16: + return read_image (tif, image_data); + break; + case 32: + return read_image (tif, image_data); + case 64: + return read_image (tif, image_data); + break; + default: + error ("Unsupported bit depth"); + } + } + + octave_value + read_signed_image (TIFF *tif, tiff_image_data *image_data) + { + switch (image_data->bits_per_sample) + { + case 8: + return read_image (tif, image_data); + break; + case 16: + return read_image (tif, image_data); + break; + case 32: + return read_image (tif, image_data); + case 64: + return read_image (tif, image_data); + break; + default: + error ("Unsupported bit depth for signed images"); + } + } + + octave_value + read_float_image (TIFF *tif, tiff_image_data *image_data) + { + switch (image_data->bits_per_sample) + { + case 32: + return read_image (tif, image_data); + case 64: + return read_image (tif, image_data); + break; + default: + error ("Unsupported bit depth for floating-point images"); + } + } + // Convert tag value to double octave_value interpret_scalar_tag_data (void *data, TIFFDataType tag_datatype) @@ -1044,7 +1149,8 @@ break; case TIFFTAG_TILEBYTECOUNTS: case TIFFTAG_TILEOFFSETS: - tag_data_ov = get_array_field_data (tif, fip, TIFFNumberOfTiles (tif)); + tag_data_ov + = get_array_field_data (tif, fip, TIFFNumberOfTiles (tif)); break; case TIFFTAG_YCBCRCOEFFICIENTS: tag_data_ov = get_array_field_data (tif, fip, 3); @@ -1145,7 +1251,8 @@ .uint16_array_value () .reshape (col_dims); - tag_data_ov = octave_value (uint16NDArray::cat (1, 3, array_list)); + tag_data_ov + = octave_value (uint16NDArray::cat (1, 3, array_list)); } break; } @@ -1173,7 +1280,8 @@ { uint16_t count; uint64_t *offsets; - validate_tiff_get_field (TIFFGetField (tif, tag_id, &count, &offsets)); + validate_tiff_get_field (TIFFGetField (tif, tag_id, + &count, &offsets)); tag_data_ov = interpret_tag_data (offsets, count, TIFFFieldDataType (fip)); break; @@ -1182,7 +1290,8 @@ { uint16_t count; uint16_t *types; - validate_tiff_get_field (TIFFGetField (tif, tag_id, &count, &types)); + validate_tiff_get_field (TIFFGetField (tif, tag_id, + &count, &types)); tag_data_ov = interpret_tag_data (types, count, TIFFFieldDataType (fip)); break; @@ -1747,31 +1856,10 @@ } void - handle_write_strip_or_tile (TIFF *tif, uint32_t strip_tile_no, - octave_value data_ov, - tiff_image_data *image_data) + write_unsigned_strip_or_tile (TIFF *tif, uint32_t strip_tile_no, + octave_value data_ov, + tiff_image_data *image_data) { - - // SampleFormat tag is not a required field and has a default value of 1 - // So we need to use TIFFGetFieldDefaulted in case it is not present in - // the file - uint16_t sample_format; - if (! TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_format)) - error ("Failed to obtain a value for sample format"); - - // TODO(maged): add support for signed integer images - if (sample_format == 3) - { - if (image_data->bits_per_sample != 32 - && image_data->bits_per_sample != 64) - error ("Floating point images are only supported for bit depths of 32 and 64"); - } - - // The standard specifies that a SampleFormat of 4 should be treated - // the same as 1 (unsigned integer) - else if (sample_format != 1 && sample_format != 4) - error ("Unsupported sample format"); - switch (image_data->bits_per_sample) { case 1: @@ -1801,41 +1889,128 @@ error ("Only uint16 data is allowed for uint images with bit depth of 16"); break; case 32: - if (sample_format == 3) - if (data_ov.is_single_type () || data_ov.is_double_type ()) - write_strip_or_tile (tif, strip_tile_no, - data_ov.float_array_value (), - image_data); - else - error ("Only single and double data are allowed for floating-point images"); + if (data_ov.is_uint32_type ()) + write_strip_or_tile (tif, strip_tile_no, + data_ov.uint32_array_value (), + image_data); else - if (data_ov.is_uint32_type ()) - write_strip_or_tile (tif, strip_tile_no, - data_ov.uint32_array_value (), - image_data); - else - error ("Only uint32 data is allowed for uint images with bit depth of 32"); + error ("Only uint32 data is allowed for uint images with bit depth of 32"); break; - case 64: - if (sample_format == 3) - if (data_ov.is_single_type () || data_ov.is_double_type ()) - write_strip_or_tile (tif, strip_tile_no, - data_ov.array_value (), - image_data); - else - error ("Only single and double data are allowed for floating-point images"); - else - if (data_ov.is_uint64_type ()) - write_strip_or_tile (tif, strip_tile_no, - data_ov.uint64_array_value (), - image_data); - else - error ("Only uint64 data is allowed for uint images with bit depth of 64"); + case 64: + if (data_ov.is_uint64_type ()) + write_strip_or_tile (tif, strip_tile_no, + data_ov.uint64_array_value (), + image_data); + else + error ("Only uint64 data is allowed for uint images with bit depth of 64"); break; default: error ("Unsupported bit depth"); } } + + void + write_signed_strip_or_tile (TIFF *tif, uint32_t strip_tile_no, + octave_value data_ov, + tiff_image_data *image_data) + { + switch (image_data->bits_per_sample) + { + case 8: + if (data_ov.is_int8_type ()) + write_strip_or_tile (tif, strip_tile_no, + data_ov.int8_array_value (), + image_data); + else + error ("Only int8 data is allowed for int images with bit depth of 8"); + break; + case 16: + if (data_ov.is_int16_type ()) + write_strip_or_tile (tif, strip_tile_no, + data_ov.int16_array_value (), + image_data); + else + error ("Only int16 data is allowed for int images with bit depth of 16"); + break; + case 32: + if (data_ov.is_int32_type ()) + write_strip_or_tile (tif, strip_tile_no, + data_ov.int32_array_value (), + image_data); + else + error ("Only int32 data is allowed for int images with bit depth of 32"); + break; + case 64: + if (data_ov.is_int64_type ()) + write_strip_or_tile (tif, strip_tile_no, + data_ov.int64_array_value (), + image_data); + else + error ("Only int64 data is allowed for int images with bit depth of 64"); + break; + default: + error ("Unsupported bit depth for signed images"); + } + } + + void + write_float_strip_or_tile (TIFF *tif, uint32_t strip_tile_no, + octave_value data_ov, + tiff_image_data *image_data) + { + switch (image_data->bits_per_sample) + { + case 32: + if (data_ov.is_single_type () || data_ov.is_double_type ()) + write_strip_or_tile (tif, strip_tile_no, + data_ov.float_array_value (), + image_data); + else + error ("Only single and double data are allowed for floating-point images"); + break; + case 64: + if (data_ov.is_single_type () || data_ov.is_double_type ()) + write_strip_or_tile (tif, strip_tile_no, + data_ov.array_value (), + image_data); + else + error ("Only single and double data are allowed for floating-point images"); + break; + default: + error ("Unsupported bit depth for floating-point images"); + } + } + + void + handle_write_strip_or_tile (TIFF *tif, uint32_t strip_tile_no, + octave_value data_ov, + tiff_image_data *image_data) + { + + // SampleFormat tag is not a required field and has a default value of 1 + // So we need to use TIFFGetFieldDefaulted in case it is not present in + // the file + uint16_t sample_format; + if (! TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_format)) + error ("Failed to obtain a value for sample format"); + + switch (sample_format) + { + case 1: + case 4: + write_unsigned_strip_or_tile (tif, strip_tile_no, data_ov, + image_data); + break; + case 2: + write_signed_strip_or_tile (tif, strip_tile_no, data_ov, image_data); + break; + case 3: + write_float_strip_or_tile (tif, strip_tile_no, data_ov, image_data); + break; + default: + error ("Unsupported sample format"); + } + } template void @@ -2079,6 +2254,117 @@ } + void + write_unsigned_image (TIFF *tif, octave_value image_ov, + tiff_image_data *image_data) + { + switch (image_data->bits_per_sample) + { + case 1: + // We need to check for both scalar and matrix types to handle single + // pixel image + if (image_ov.is_bool_scalar () || image_ov.is_bool_matrix ()) + write_image (tif, image_ov.bool_array_value (), + image_data); + else + error ("Expected logical matrix for BiLevel image"); + break; + case 8: + if (image_ov.is_uint8_type ()) + write_image (tif, image_ov.uint8_array_value (), + image_data); + else + error ("Only uint8 data is allowed for uint images with bit depth of 8"); + break; + case 16: + if (image_ov.is_uint16_type ()) + write_image (tif, image_ov.uint16_array_value (), + image_data); + else + error ("Only uint16 data is allowed for uint images with bit depth of 16"); + break; + case 32: + if (image_ov.is_uint32_type ()) + write_image (tif, image_ov.uint32_array_value (), + image_data); + else + error ("Only uint32 data is allowed for uint images with bit depth of 32"); + break; + case 64: + if (image_ov.is_uint64_type ()) + write_image (tif, image_ov.uint64_array_value (), + image_data); + else + error ("Only uint64 data is allowed for uint images with bit depth of 64"); + break; + default: + error ("Unsupported bit depth"); + } + } + + void + write_signed_image (TIFF *tif, octave_value image_ov, + tiff_image_data *image_data) + { + switch (image_data->bits_per_sample) + { + case 8: + if (image_ov.is_int8_type ()) + write_image (tif, image_ov.int8_array_value (), + image_data); + else + error ("Only int8 data is allowed for int images with bit depth of 8"); + break; + case 16: + if (image_ov.is_int16_type ()) + write_image (tif, image_ov.int16_array_value (), + image_data); + else + error ("Only int16 data is allowed for int images with bit depth of 16"); + break; + case 32: + if (image_ov.is_int32_type ()) + write_image (tif, image_ov.int32_array_value (), + image_data); + else + error ("Only int32 data is allowed for int images with bit depth of 32"); + break; + case 64: + if (image_ov.is_int64_type ()) + write_image (tif, image_ov.int64_array_value (), + image_data); + else + error ("Only int64 data is allowed for int images with bit depth of 64"); + break; + default: + error ("Unsupported bit depth for signed images"); + } + } + + void + write_float_image (TIFF *tif, octave_value image_ov, + tiff_image_data *image_data) + { + switch (image_data->bits_per_sample) + { + case 32: + if (image_ov.is_single_type () || image_ov.is_double_type ()) + write_image (tif, image_ov.float_array_value (), + image_data); + else + error ("Only single or double data are allowed for float images"); + break; + case 64: + if (image_ov.is_single_type () || image_ov.is_double_type ()) + write_image (tif, image_ov.array_value (), + image_data); + else + error ("Only single or double data are allowed for float images"); + break; + default: + error ("Unsupported bit depth for floating-point images"); + } + } #endif @@ -2100,7 +2386,9 @@ if (nargin == 2) mode = args(1).string_value (); - const std::vector supported_modes {"r", "w", "w8", "a", "r+"}; + const std::vector supported_modes { + "r", "w", "w8", "a", "r+" + }; if (std::find (supported_modes.cbegin (), supported_modes.cend (), mode) == supported_modes.cend ()) @@ -2298,41 +2586,21 @@ if (! TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_format)) error ("Failed to obtain a value for sample format"); - if (sample_format == 3) - { - if (image_data.bits_per_sample != 32 && image_data.bits_per_sample != 64) - error ("Floating point images are only supported for bit depths of 32 and 64"); - } - else if (sample_format != 1 && sample_format != 4) - error ("Unsupported sample format"); - octave_value_list retval; - switch (image_data.bits_per_sample) + switch (sample_format) { case 1: - retval(0) = read_image (tif, &image_data); - break; case 4: - case 8: - retval(0) = read_image (tif, &image_data); - break; - case 16: - retval(0) = read_image (tif, &image_data); + retval (0) = read_unsigned_image (tif, &image_data); break; - case 32: - if (sample_format == 3) - retval(0) = read_image (tif, &image_data); - else - retval(0) = read_image (tif, &image_data); + case 2: + retval (0) = read_signed_image (tif, &image_data); break; - case 64: - if (sample_format == 3) - retval(0) = read_image (tif, &image_data); - else - retval(0) = read_image (tif, &image_data); + case 3: + retval (0) = read_float_image (tif, &image_data); break; default: - error ("Unsupported bit depth"); + error ("Unsupported sample format"); } return retval; @@ -2722,70 +2990,21 @@ uint16_t sample_format; if (! TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_format)) error ("Failed to obtain a value for sample format"); - - if (sample_format == 3) - { - if (image_data.bits_per_sample != 32 - && image_data.bits_per_sample != 64) - error ("Floating point images are only supported for bit depths of 32 and 64"); - } - else if (sample_format != 1 && sample_format != 4) - error ("Unsupported sample format"); - switch (image_data.bits_per_sample) + switch (sample_format) { case 1: - // We need to check for both scalar and matrix types to handle single - // pixel image - if (args (1).is_bool_scalar () || args (1).is_bool_matrix ()) - write_image (tif, args (1).bool_array_value (), - &image_data); - else - error ("Expected logical matrix for BiLevel image"); - break; - case 8: - if (args (1).is_uint8_type ()) - write_image (tif, args (1).uint8_array_value (), - &image_data); - else - error ("Only uint8 data is allowed for uint images with bit depth of 8"); - break; - case 16: - if (args (1).is_uint16_type ()) - write_image (tif, args (1).uint16_array_value (), - &image_data); - else - error ("Only uint16 data is allowed for uint images with bit depth of 16"); + case 4: + write_unsigned_image (tif, args(1), &image_data); break; - case 32: - if (sample_format == 3) - if (args (1).is_single_type () || args (1).is_double_type ()) - write_image (tif, args (1).float_array_value (), - &image_data); - else - error ("Only single and double data are allowed for floating-point images"); - else - if (args (1).is_uint32_type ()) - write_image (tif, args (1).uint32_array_value (), - &image_data); - else - error ("Only uint32 data is allowed for uint images with bit depth of 32"); + case 2: + write_signed_image (tif, args(1), &image_data); break; - case 64: - if (sample_format == 3) - if (args (1).is_single_type () || args (1).is_double_type ()) - write_image (tif, args (1).array_value (), &image_data); - else - error ("Only single and double data are allowed for floating-point images"); - else - if (args (1).is_uint64_type ()) - write_image (tif, args (1).uint64_array_value (), - &image_data); - else - error ("Only uint64 data is allowed for uint images with bit depth of 64"); + case 3: + write_float_image (tif, args(1), &image_data); break; default: - error ("Unsupported bit depth"); + error ("Unsupported sample format"); } return octave_value_list (); @@ -3285,7 +3504,7 @@ if (! args(0).is_bool_scalar ()) error ("Expected logical value as argument"); - // Set the error and warning handlers according to the bool parameter + // Set the error and warning handlers according to the bool parameter if (args(0).bool_value ()) { TIFFSetErrorHandler (tiff_default_error_handler); diff -r c7c79973007f -r 14edd6b09efe scripts/io/Tiff.m --- a/scripts/io/Tiff.m Wed Aug 17 18:51:16 2022 +0200 +++ b/scripts/io/Tiff.m Wed Aug 17 21:15:49 2022 +0200 @@ -733,7 +733,7 @@ %! "BitsPerSample", 16, "SampleFormat", 3)); %! data = double (reshape (1:400, [20, 20])); %! fail ("writeEncodedStrip (img, 1, data)", -%! "Floating point images are only supported for bit depths of 32 and 64"); +%! "Unsupported bit depth for floating-point images"); %! img.close (); %! endfunction %! file_wrapper (@test_fn);