changeset 31144:8ba9f2326ee9

Tiff writeEncodedStrip: added support for BiLevel images * __tiff__.cc(write_strip): implemented the case for BiLevel images.
author magedrifaat <magedrifaat@gmail.com>
date Sun, 31 Jul 2022 01:26:02 +0200
parents a68f2dadafee
children 2e11f9cb30b8
files libinterp/dldfcn/__tiff__.cc
diffstat 1 files changed, 46 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/dldfcn/__tiff__.cc	Sun Jul 31 00:13:04 2022 +0200
+++ b/libinterp/dldfcn/__tiff__.cc	Sun Jul 31 01:26:02 2022 +0200
@@ -948,12 +948,52 @@
 
     // LibTIFF uses zero-based indexing as opposed to Octave's 1-based
     strip_no--;
-    // Can't rely in LibTIFF's TIFFStripSize because boundary strips
-    // can be smaller in size
-    tsize_t strip_size = strip_data.numel () * image_data->bits_per_sample / 8;
-    if (TIFFWriteEncodedStrip (tif, strip_no,
-                               strip_data.fortran_vec (), strip_size) == -1)
-      error ("Failed to write strip data to image");
+    void *data_vec = strip_data.fortran_vec ();
+    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)
+      {
+        // Can't rely on LibTIFF's TIFFStripSize because boundary strips
+        // can be smaller in size
+        tsize_t strip_size = strip_data.numel ()
+                             * image_data->bits_per_sample / 8;
+        if (TIFFWriteEncodedStrip (tif, strip_no, data_vec, strip_size) == -1)
+          error ("Failed to write strip data to image");
+        
+      }
+    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
+          = std::make_unique<uint8_t []> (TIFFStripSize (tif));
+        uint8_t *strip_buf = strip_ptr.get ();
+        uint8_t *data_u8 = reinterpret_cast<uint8_t *> (data_vec);
+        // 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] |= data_u8[col] << shift;
+            }
+            data_u8 += image_data->width;
+          }
+        tsize_t strip_size = padded_width * rows_in_strip;
+        if (TIFFWriteEncodedStrip (tif, strip_no, strip_buf, strip_size) == -1)
+          error ("Failed to write strip data to image");
+      }
+    else
+      {
+        error ("Unsupported bit depth");
+      }
   }
 
 #endif
@@ -1244,7 +1284,6 @@
         else
           error ("Expected logical matrix for BiLevel image");
         break;
-      case 4:
       case 8:
         if (args(2).is_uint8_type ())
           write_strip<uint8NDArray> (tif, strip_no,