Mercurial > octave-libtiff
changeset 31157:dc3d2744916d
Tiff: added readEncodedStrip method and corresponding unit tests
* __tiff__.cc(F__tiff_read_encoded_strip__): added internal functino to process
arguments of readEncodedStrip method.
* __tiff__.cc(readStrip): implemented logic for reading the strip from the image.
* Tiff.m: added the method readEncodedStrip to the Tiff class and added
the necessary unit tests for the method.
author | magedrifaat <magedrifaat@gmail.com> |
---|---|
date | Fri, 05 Aug 2022 22:44:55 +0200 |
parents | 1e633a093faa |
children | f2ae7763739a |
files | libinterp/dldfcn/__tiff__.cc scripts/io/Tiff.m |
diffstat | 2 files changed, 210 insertions(+), 33 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/dldfcn/__tiff__.cc Thu Aug 04 19:29:36 2022 +0200 +++ b/libinterp/dldfcn/__tiff__.cc Fri Aug 05 22:44:55 2022 +0200 @@ -76,6 +76,89 @@ } } + uint32_t get_rows_in_strip (uint32_t strip_no, uint32_t strip_count, + uint32_t rows_per_strip, + tiff_image_data *image_data) + { + // Calculate the expected number of elements in the strip data array + // All strips have equal number of rows except strips at the bottom + // of the image can have less number of rows + uint32_t rows_in_strip = rows_per_strip; + if (image_data->planar_configuration == PLANARCONFIG_CONTIG) + { + // All strips have equal number of rows excpet strips at the bottom + // of the image can have less number of rows + if (strip_no == strip_count - 1) + rows_in_strip = image_data->height - rows_in_strip * strip_no; + } + else if (image_data->planar_configuration == PLANARCONFIG_SEPARATE) + { + // For separate planes, we should check the last strip of each channel + uint32_t strips_per_channel + = strip_count / image_data->samples_per_pixel; + for (uint32_t boundary_strip = strips_per_channel - 1; + boundary_strip <= strip_count; + boundary_strip += strips_per_channel) + if (strip_no == boundary_strip) + rows_in_strip = image_data->height + - rows_in_strip * (strip_no % strips_per_channel); + } + else + error ("Planar Configuration not supported"); + + return rows_in_strip; + } + + template <typename T> + octave_value + read_strip (TIFF *tif, uint32_t strip_no, tiff_image_data * image_data) + { + // ASSUMES stripped image and strip_no is a valid zero-based strip + // index for the tif image + + uint32_t rows_in_strip; + if (! TIFFGetFieldDefaulted (tif, TIFFTAG_ROWSPERSTRIP, &rows_in_strip)) + error ("Failed to obtain a value for RowsPerStrip"); + + if (rows_in_strip > image_data->height) + rows_in_strip = image_data->height; + + uint32_t strip_count = TIFFNumberOfStrips (tif); + rows_in_strip = get_rows_in_strip (strip_no, strip_count, + rows_in_strip, image_data); + dim_vector strip_dims; + if (image_data->planar_configuration == PLANARCONFIG_CONTIG) + strip_dims = dim_vector (image_data->samples_per_pixel, + image_data->width, rows_in_strip); + else if (image_data->planar_configuration == PLANARCONFIG_SEPARATE) + strip_dims = dim_vector (image_data->width, rows_in_strip, 1); + else + error ("Unsupported bit depth"); + + T strip_data (strip_dims); + + if (TIFFReadEncodedStrip (tif, strip_no, + strip_data.fortran_vec (), -1) == -1) + error ("Failed to read strip data"); + + Array<octave_idx_type> perm (dim_vector (3, 1)); + if (image_data->planar_configuration == PLANARCONFIG_CONTIG) + { + perm(0) = 2; + perm(1) = 1; + perm(2) = 0; + } + else if (image_data->planar_configuration == PLANARCONFIG_SEPARATE) + { + perm(0) = 1; + perm(1) = 0; + perm(2) = 2; + } + + strip_data = strip_data.permute (perm); + return octave_value (strip_data); + } + template <typename T> octave_value read_stripped_image (TIFF *tif, tiff_image_data *image_data) @@ -885,39 +968,6 @@ error ("Failed to set tag value"); } - uint32_t get_rows_in_strip (uint32_t strip_no, uint32_t strip_count, - uint32_t rows_per_strip, - tiff_image_data *image_data) - { - // Calculate the expected number of elements in the strip data array - // All strips have equal number of rows except strips at the bottom - // of the image can have less number of rows - uint32_t rows_in_strip = rows_per_strip; - if (image_data->planar_configuration == PLANARCONFIG_CONTIG) - { - // All strips have equal number of rows excpet strips at the bottom - // of the image can have less number of rows - if (strip_no == strip_count - 1) - rows_in_strip = image_data->height - rows_in_strip * strip_no; - } - else if (image_data->planar_configuration == PLANARCONFIG_SEPARATE) - { - // For separate planes, we should check the last strip of each channel - uint32_t strips_per_channel - = strip_count / image_data->samples_per_pixel; - for (uint32_t boundary_strip = strips_per_channel - 1; - boundary_strip <= strip_count; - boundary_strip += strips_per_channel) - if (strip_no == boundary_strip) - rows_in_strip = image_data->height - - rows_in_strip * (strip_no % strips_per_channel); - } - else - error ("Planar Configuration not supported"); - - return rows_in_strip; - } - template <typename T> void write_strip (TIFF *tif, uint32_t strip_no, T strip_data, @@ -1686,6 +1736,85 @@ #endif } + DEFUN_DLD (__tiff_read_encoded_strip__, args, nargout, + "Read the image in the current IFD") + { +#if defined (HAVE_TIFF) + int nargin = args.length (); + + if (nargin != 2) + error ("rong number of arguments"); + + TIFF *tif = (TIFF *)(args(0).uint64_value ()); + + // TODO(maged): nargout and ycbcr + octave_unused_parameter (nargout); + + if (TIFFIsTiled (tif)) + error ("The image is tiled not stripped"); + + // TODO(maged): what is the behavior in matlab + uint32_t strip_no; + if (args(1).is_scalar_type ()) + strip_no = args(1).uint32_scalar_value (); + else + error ("Expected scalar for strip number"); + + if (strip_no < 1 || strip_no > TIFFNumberOfStrips (tif)) + error ("Strip number out of bounds"); + + // Convert from Octave's 1-based indexing to zero-based indexing + strip_no--; + + // Obtain all necessary tags + tiff_image_data image_data (tif); + + 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"); + + octave_value_list retval; + switch (image_data.bits_per_sample) + { + case 1: + retval(0) = read_strip<boolNDArray> (tif, strip_no, &image_data); + break; + case 8: + retval(0) = read_strip<uint8NDArray> (tif, strip_no, &image_data); + break; + case 16: + retval(0) = read_strip<uint16NDArray> (tif, strip_no, &image_data); + break; + case 32: + if (sample_format == 3) + retval(0) = read_strip<FloatNDArray> (tif, strip_no, &image_data); + else + retval(0) = read_strip<uint32NDArray> (tif, strip_no, &image_data); + break; + case 64: + if (sample_format == 3) + retval(0) = read_strip<NDArray> (tif, strip_no, &image_data); + else + retval(0) = read_strip<uint64NDArray> (tif, strip_no, &image_data); + break; + default: + error ("Unsupported bit depth"); + } + + return retval; +#else + err_disabled_feature ("readEncodedStrip", "Tiff"); +#endif + } + DEFUN_DLD (__tiff_write__, args, , "Write the image data to the current IFD") {
--- a/scripts/io/Tiff.m Thu Aug 04 19:29:36 2022 +0200 +++ b/scripts/io/Tiff.m Fri Aug 05 22:44:55 2022 +0200 @@ -116,6 +116,13 @@ argout = __tiff_read__ (t.tiff_handle); endfunction + function stripData = readEncodedStrip (t, stripNumber) + if (t.closed) + error ("Image file was closed"); + endif + stripData = __tiff_read_encoded_strip__ (t.tiff_handle, stripNumber); + endfunction + function write (t, imageData) if (t.closed) error ("Image file was closed"); @@ -1168,3 +1175,44 @@ %! verify_data (filename, data, [40, 40, 3]); %! endfunction %! file_wrapper (@test_fn); + +## test readEncodedStrip RGB Chunky +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 10, "ImageWidth", 10, +%! "BitsPerSample", 16, "SamplesPerPixel", 3, +%! "PhotometricInterpretation", 2, "RowsPerStrip", 6, +%! "PlanarConfiguration", 1)); +%! data = uint16 (reshape (1:300, [10, 10, 3])); +%! write (img, data); +%! s1 = readEncodedStrip (img, 1); +%! s2 = readEncodedStrip (img, 2); +%! assert ([s1;s2], data); +%! img.close(); +%! endfunction +%! file_wrapper (@test_fn); + +## test readEncodedStrip RGB Separated +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 10, "ImageWidth", 10, +%! "BitsPerSample", 16, "SamplesPerPixel", 3, +%! "PhotometricInterpretation", 2, "RowsPerStrip", 6, +%! "PlanarConfiguration", 2)); +%! data = uint16 (reshape (1:300, [10, 10, 3])); +%! write (img, data); +%! s1 = readEncodedStrip (img, 1); +%! s2 = readEncodedStrip (img, 2); +%! s3 = readEncodedStrip (img, 3); +%! s4 = readEncodedStrip (img, 4); +%! s5 = readEncodedStrip (img, 5); +%! s6 = readEncodedStrip (img, 6); +%! s = [s1;s2]; +%! s(:, :, 2) = [s3;s4]; +%! s(:, :, 3) = [s5;s6]; +%! assert (s, data); +%! img.close(); +%! endfunction +%! file_wrapper (@test_fn);