changeset 31156:1e633a093faa

Tiff write: added support for logical tile images and corresponding unit tests * __tiff__.cc(write_tiled_image): added logic for logical images. * Tiff.m: added unit tests for write method for tiled images.
author magedrifaat <magedrifaat@gmail.com>
date Thu, 04 Aug 2022 19:29:36 +0200
parents a30b144bc10b
children dc3d2744916d
files libinterp/dldfcn/__tiff__.cc scripts/io/Tiff.m
diffstat 2 files changed, 149 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/dldfcn/__tiff__.cc	Thu Aug 04 03:12:42 2022 +0200
+++ b/libinterp/dldfcn/__tiff__.cc	Thu Aug 04 19:29:36 2022 +0200
@@ -1282,6 +1282,9 @@
           }
         else if (image_data->bits_per_sample == 1)
           {
+            if (image_data->samples_per_pixel != 1)
+              error ("Bi-Level images must have one channel only");
+            
             // 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
@@ -1316,8 +1319,6 @@
   {
     // TODO(maged): remove this? ASSUMES pixel data dimensions are already validated
 
-    typedef typename T::element_type P;
-
     uint32_t tile_width, tile_height;
     if (! TIFFGetField (tif, TIFFTAG_TILEWIDTH, &tile_width))
       error ("Failed to get the tile width");
@@ -1385,14 +1386,47 @@
     uint8_t *pixel_fvec
       = reinterpret_cast<uint8_t *> (pixel_data.fortran_vec ());
     uint32_t tile_count = TIFFNumberOfTiles (tif);
-    uint64_t tile_size = tile_width * tile_height * sizeof (P);
-    if (image_data->planar_configuration == PLANARCONFIG_CONTIG)
-      tile_size *= image_data->samples_per_pixel;
+    tsize_t tile_size = TIFFTileSize (tif);
+
     for (uint32_t tile = 0; tile <tile_count; tile++)
       {
-        if (! TIFFWriteEncodedTile (tif, tile, pixel_fvec, tile_size))
-          error ("Failed to write tile data");
-        pixel_fvec += tile_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)
+          {
+            if (! TIFFWriteEncodedTile (tif, tile, pixel_fvec, tile_size))
+              error ("Failed to write tile data");
+            pixel_fvec += tile_size;
+          }
+        else if (image_data->bits_per_sample == 1)
+          {
+            if (image_data->samples_per_pixel != 1)
+              error ("Bi-Level images must have one channel only");
+            
+            // Create a buffer to hold the packed tile data
+            // Unique pointers are faster than vectors for
+            // constant size buffers
+            std::unique_ptr<uint8_t []> tile_ptr
+              = std::make_unique<uint8_t []> (tile_size);
+            uint8_t *tile_buf = tile_ptr.get ();
+            // Packing the pixel data into bits
+            for (uint32_t row = 0; row < tile_height; row++)
+              {
+                for (uint32_t col = 0; col < tile_width; col++)
+                {
+                  uint8_t shift = 7 - col % 8;
+                  tile_buf[row * tile_width / 8 + col / 8]
+                    |= pixel_fvec[col] << shift;
+                }
+                pixel_fvec += tile_width;
+              }
+            if (TIFFWriteEncodedTile (tif, tile, tile_buf,
+                                      TIFFTileSize (tif)) == -1)
+              error ("Failed to write tile data to image");
+          }
+        else
+          error ("Unsupported bit depth");
       }
 
   }
--- a/scripts/io/Tiff.m	Thu Aug 04 03:12:42 2022 +0200
+++ b/scripts/io/Tiff.m	Thu Aug 04 19:29:36 2022 +0200
@@ -1061,3 +1061,110 @@
 %!    verify_data (filename, data, [10, 10, 3]);
 %!  endfunction
 %!  file_wrapper (@test_fn);
+
+## test write method tiled BiLevel image
+%!testif HAVE_TIFF
+%!  function test_fn (filename)
+%!    img = Tiff (filename, "w");
+%!    setTag(img, struct ("ImageLength", 40, "ImageWidth", 40,
+%!                        "TileWidth", 16, "TileLength", 16));
+%!    data = logical (repmat ([1,0,0,0,1,0,1,1,1,0], [40, 4]));
+%!    write (img, data);
+%!    img.close();
+%!    verify_data (filename, data, [40, 40]);
+%!  endfunction
+%!  file_wrapper (@test_fn);
+
+## test write method tiled grayscale image
+%!testif HAVE_TIFF
+%!  function test_fn (filename)
+%!    img = Tiff (filename, "w");
+%!    setTag(img, struct ("ImageLength", 40, "ImageWidth", 40,
+%!                        "TileWidth", 16, "TileLength", 16,
+%!                        "BitsPerSample", 16));
+%!    data = uint16 (reshape (1:1600, [40, 40]));
+%!    write (img, data);
+%!    img.close();
+%!    verify_data (filename, data, [40, 40]);
+%!  endfunction
+%!  file_wrapper (@test_fn);
+
+## test write method tiled RGB image chunky
+%!testif HAVE_TIFF
+%!  function test_fn (filename)
+%!    img = Tiff (filename, "w");
+%!    setTag(img, struct ("ImageLength", 40, "ImageWidth", 40,
+%!                        "TileWidth", 16, "TileLength", 16,
+%!                        "BitsPerSample", 16, "SamplesPerPixel", 3,
+%!                        "PhotometricInterpretation", 2,
+%!                        "PlanarConfiguration", 1));
+%!    data = uint16 (reshape (1:4800, [40, 40, 3]));
+%!    write (img, data);
+%!    img.close();
+%!    verify_data (filename, data, [40, 40, 3]);
+%!  endfunction
+%!  file_wrapper (@test_fn);
+
+## test write method tiled RGB image separate
+%!testif HAVE_TIFF
+%!  function test_fn (filename)
+%!    img = Tiff (filename, "w");
+%!    setTag(img, struct ("ImageLength", 40, "ImageWidth", 40,
+%!                        "TileWidth", 16, "TileLength", 16,
+%!                        "BitsPerSample", 16, "SamplesPerPixel", 3,
+%!                        "PhotometricInterpretation", 2,
+%!                        "PlanarConfiguration", 2));
+%!    data = uint16 (reshape (1:4800, [40, 40, 3]));
+%!    write (img, data);
+%!    img.close();
+%!    verify_data (filename, data, [40, 40, 3]);
+%!  endfunction
+%!  file_wrapper (@test_fn);
+
+## test write method 32-bit tiled image
+%!testif HAVE_TIFF
+%!  function test_fn (filename)
+%!    img = Tiff (filename, "w");
+%!    setTag(img, struct ("ImageLength", 40, "ImageWidth", 40,
+%!                        "TileWidth", 16, "TileLength", 16,
+%!                        "BitsPerSample", 32, "SamplesPerPixel", 3,
+%!                        "PhotometricInterpretation", 2,
+%!                        "PlanarConfiguration", 1));
+%!    data = uint32 (reshape (1:4800, [40, 40, 3]));
+%!    write (img, data);
+%!    img.close();
+%!    verify_data (filename, data, [40, 40, 3]);
+%!  endfunction
+%!  file_wrapper (@test_fn);
+
+## test write method single-precision tiled image
+%!testif HAVE_TIFF
+%!  function test_fn (filename)
+%!    img = Tiff (filename, "w");
+%!    setTag(img, struct ("ImageLength", 40, "ImageWidth", 40,
+%!                        "TileWidth", 16, "TileLength", 16,
+%!                        "BitsPerSample", 32, "SamplesPerPixel", 3,
+%!                        "PhotometricInterpretation", 2,
+%!                        "PlanarConfiguration", 1, "SampleFormat", 3));
+%!    data = single (reshape (1:4800, [40, 40, 3]));
+%!    write (img, data);
+%!    img.close();
+%!    verify_data (filename, data, [40, 40, 3]);
+%!  endfunction
+%!  file_wrapper (@test_fn);
+
+## test write method double-precision tiled image
+%!testif HAVE_TIFF
+%!  function test_fn (filename)
+%!    img = Tiff (filename, "w");
+%!    setTag(img, struct ("ImageLength", 40, "ImageWidth", 40,
+%!                        "TileWidth", 16, "TileLength", 16,
+%!                        "BitsPerSample", 64, "SamplesPerPixel", 3,
+%!                        "PhotometricInterpretation", 2,
+%!                        "PlanarConfiguration", 1, "SampleFormat", 3));
+%!    data = double (reshape (1:4800, [40, 40, 3]));
+%!    write (img, data);
+%!    img.close();
+%!    verify_data (filename, data, [40, 40, 3]);
+%!  endfunction
+%!  file_wrapper (@test_fn);