Mercurial > octave-libtiff
changeset 31154:828b7cc9aa36
Tiff write: added support for BiLevel stripped images and added unit tests
* __tiff__.cc(write_stripped_image): implemented support for writing logical
images.
* Tiff.m: added tests for writing stripped images using the write method.
author | magedrifaat <magedrifaat@gmail.com> |
---|---|
date | Thu, 04 Aug 2022 00:02:27 +0200 |
parents | c66d6c7f025e |
children | a30b144bc10b |
files | libinterp/dldfcn/__tiff__.cc scripts/io/Tiff.m |
diffstat | 2 files changed, 203 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/dldfcn/__tiff__.cc Wed Aug 03 22:06:43 2022 +0200 +++ b/libinterp/dldfcn/__tiff__.cc Thu Aug 04 00:02:27 2022 +0200 @@ -1268,12 +1268,45 @@ { rows_in_strip = get_rows_in_strip (strip, strip_count, row_per_strip, image_data); - strip_size = rows_in_strip * image_data->width * sizeof (P); - if (image_data->planar_configuration == PLANARCONFIG_CONTIG) - strip_size *= image_data->samples_per_pixel; - if (! TIFFWriteEncodedStrip (tif, strip, pixel_fvec, strip_size)) - error ("Failed to rite strip data"); - pixel_fvec += strip_size; + if (image_data->bits_per_sample == 8 + || image_data->bits_per_sample == 16 + || image_data->bits_per_sample == 32 + || image_data->bits_per_sample == 64) + { + strip_size = rows_in_strip * image_data->width * sizeof (P); + if (image_data->planar_configuration == PLANARCONFIG_CONTIG) + strip_size *= image_data->samples_per_pixel; + if (! TIFFWriteEncodedStrip (tif, strip, pixel_fvec, strip_size)) + error ("Failed to rite strip data"); + pixel_fvec += strip_size; + } + else if (image_data->bits_per_sample == 1) + { + // Create a buffer to hold the packed strip data + // Unique pointers are faster than vectors for constant size buffers + std::unique_ptr<uint8_t []> strip_ptr + = std::make_unique<uint8_t []> (TIFFStripSize (tif)); + uint8_t *strip_buf = strip_ptr.get (); + // According to the format specification, the row should be byte + // aligned so the number of bytes is rounded up to the nearest byte + uint32_t padded_width = (image_data->width + 7) / 8; + // Packing the pixel data into bits + for (uint32_t row = 0; row < rows_in_strip; row++) + { + for (uint32_t col = 0; col < image_data->width; col++) + { + uint8_t shift = 7 - col % 8; + strip_buf[row * padded_width + col / 8] + |= pixel_fvec[col] << shift; + } + pixel_fvec += image_data->width; + } + strip_size = padded_width * rows_in_strip; + if (TIFFWriteEncodedStrip (tif, strip, strip_buf, strip_size) == -1) + error ("Failed to write strip data to image"); + } + else + error ("Unsupported bit depth"); } }
--- a/scripts/io/Tiff.m Wed Aug 03 22:06:43 2022 +0200 +++ b/scripts/io/Tiff.m Thu Aug 04 00:02:27 2022 +0200 @@ -897,3 +897,167 @@ %! fail ("computeTile (img, 1, 1)", "The image is stripped not tiled"); %! endfunction %! file_wrapper (@test_fn); + +## test write method one pixel bilevel image +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 1, "ImageWidth", 1)); +%! write (img, logical ([1])); +%! img.close(); +%! verify_data (filename, logical ([1]), [1, 1]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method one strip bilevel image +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 10, "ImageWidth", 10)); +%! data = logical (repmat ([1,0,0,0,1,0,1,1,1,0], [10, 1])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [10, 10]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method multi-strip bilevel image +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 10, "ImageWidth", 10, +%! "RowsPerStrip", 3)); +%! data = logical (repmat ([1,0,0,0,1,0,1,1,1,0], [10, 1])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [10, 10]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method one pixel grayscale image +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 1, "ImageWidth", 1, +%! "BitsPerSample", 8)); +%! write (img, uint8 ([255])); +%! img.close(); +%! verify_data (filename, uint8 ([255]), [1, 1]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method one strip grayscale image +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 10, "ImageWidth", 10, +%! "BitsPerSample", 8)); +%! data = uint8 (reshape (1:100, [10, 10])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [10, 10]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method multi-strip grayscale image +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 10, "ImageWidth", 10, +%! "BitsPerSample", 8, "RowsPerStrip", 3)); +%! data = uint8 (reshape (1:100, [10, 10])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [10, 10]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method multi-strip RGB image chunky +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 10, "ImageWidth", 10, +%! "BitsPerSample", 8, "RowsPerStrip", 3, +%! "SamplesPerPixel", 3, "PlanarConfiguration", 1, +%! "PhotometricInterpretation", 2)); +%! data = uint8 (reshape (1:300, [10, 10, 3])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [10, 10, 3]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method multi-strip RGB image separate +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 10, "ImageWidth", 10, +%! "BitsPerSample", 8, "RowsPerStrip", 3, +%! "SamplesPerPixel", 3, "PlanarConfiguration", 2, +%! "PhotometricInterpretation", 2)); +%! data = uint8 (reshape (1:300, [10, 10, 3])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [10, 10, 3]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method 16-bit multi-strip image +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 10, "ImageWidth", 10, +%! "BitsPerSample", 16, "RowsPerStrip", 3, +%! "SamplesPerPixel", 3, "PlanarConfiguration", 1, +%! "PhotometricInterpretation", 2)); +%! data = uint16 (reshape (1:300, [10, 10, 3])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [10, 10, 3]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method 32-bit multi-strip image +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 10, "ImageWidth", 10, +%! "BitsPerSample", 32, "RowsPerStrip", 3, +%! "SamplesPerPixel", 3, "PlanarConfiguration", 1, +%! "PhotometricInterpretation", 2)); +%! data = uint32 (reshape (1:300, [10, 10, 3])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [10, 10, 3]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method single-precision image +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 10, "ImageWidth", 10, +%! "BitsPerSample", 32, "RowsPerStrip", 3, +%! "SamplesPerPixel", 3, "PlanarConfiguration", 1, +%! "PhotometricInterpretation", 2, "SampleFormat", 3)); +%! data = single (reshape (1:300, [10, 10, 3])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [10, 10, 3]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method single-precision image +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 10, "ImageWidth", 10, +%! "BitsPerSample", 64, "RowsPerStrip", 3, +%! "SamplesPerPixel", 3, "PlanarConfiguration", 1, +%! "PhotometricInterpretation", 2, "SampleFormat", 3)); +%! data = double (reshape (1:300, [10, 10, 3])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [10, 10, 3]); +%! endfunction +%! file_wrapper (@test_fn);