changeset 31113:a74059523d74

Tiff read: use template to remove repitition in filling matrices * __tiff__.cc (read_stripped_image): modified the function to be templated so it can be used for all matrix types generically, also writes directly to the underlying pointer of the matrix.
author magedrifaat <magedrifaat@gmail.com>
date Sat, 16 Jul 2022 01:26:40 +0200
parents e3d8443585fe
children 9dead1249449
files libinterp/dldfcn/__tiff__.cc
diffstat 1 files changed, 46 insertions(+), 99 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/dldfcn/__tiff__.cc	Fri Jul 15 21:41:13 2022 +0200
+++ b/libinterp/dldfcn/__tiff__.cc	Sat Jul 16 01:26:40 2022 +0200
@@ -30,14 +30,19 @@
     uint16_t samples_per_pixel;
     uint16_t bits_per_sample;
     uint16_t planar_configuration;
-    uint16_t pixel_size;
     uint16_t is_tiled;
   };
 
-  void
-  read_stripped_image (TIFF *tif, tiff_image_data *image_data,
-                      void ***pixel_buffer)
+  template <typename T>
+  octave_value
+  read_stripped_image (TIFF *tif, tiff_image_data *image_data)
   {
+    typedef typename T::element_type P;
+
+    T img = T (dim_vector (image_data->height, image_data->width,
+                            image_data->samples_per_pixel));
+    P *img_fvec = img.fortran_vec ();
+
     // Obtain the necessary data for handling the strips
     uint32_t strip_count = TIFFNumberOfStrips (tif);
     tdata_t buf = _TIFFmalloc (TIFFStripSize (tif));
@@ -71,27 +76,29 @@
                   {
                     uint32_t row_offset = row_size_in_bits / 8
                                           * row_subindex;
-                    // TODO(maged): support arbitrary BitsPerSample
-                    // for palette images
+                    // TODO(maged): support arbitrary BitsPerSample?
                     if (image_data->bits_per_sample >= 8
                         && image_data->bits_per_sample % 8 == 0)
                       {
                         // TODO(maged): copy entire strip at once?
-                        memcpy (pixel_buffer[row_index + row_subindex][column],
-                                buf + row_offset
-                                + column * image_data->pixel_size,
-                                image_data->pixel_size);
+                        for (uint16_t sample = 0;
+                             sample < image_data->samples_per_pixel; sample++)
+                          img_fvec[sample * image_data->width * image_data->height
+                                   + column * image_data->height
+                                   + row_index + row_subindex]
+                            = ((P *)buf)[row_subindex * image_data->width * image_data->samples_per_pixel
+                                         + column * image_data->samples_per_pixel + sample];
                       }
                     else if (image_data->bits_per_sample == 4
                               && image_data->samples_per_pixel == 1)
                       {
                         // TODO(maged): Check FillOrder for completeness
-                        uint8_t byte
+                        uint8_t nibble
                           = ((uint8_t *)buf)[row_offset + column / 2];
                         // Extract the needed nibble from the byte
-                        byte = (column % 2 == 0? byte >> 4: byte) & 0x0F;
-                        uint8_t ***u8_img = (uint8_t ***)pixel_buffer;
-                        u8_img[row_index + row_subindex][column][0] = byte;
+                        nibble = (column % 2 == 0? nibble >> 4: nibble) & 0x0F;
+                        img_fvec[(row_index + row_subindex)
+                                 + column * image_data->height] = nibble;
                       }
                     else if (image_data->bits_per_sample == 1
                               && image_data->samples_per_pixel == 1)
@@ -100,8 +107,8 @@
                           = ((uint8_t *)buf)[row_offset + column / 8];
                         // Extract the needed bit from the byte
                         uint8_t bit = (byte >> (7 - column % 8)) & 0x01;
-                        uint8_t ***u8_img = (uint8_t ***)pixel_buffer;
-                        u8_img[row_index + row_subindex][column][0] = bit;
+                        img_fvec[(row_index + row_subindex)
+                                 + column * image_data->height] = bit;
                       }
                     else
                       error ("Unsupported bit depth");
@@ -113,6 +120,19 @@
           error ("Images with multiple planes are not implemented yet");
       }
     _TIFFfree (buf);
+
+    return octave_value(img);
+  }
+
+  template <typename T>
+  octave_value
+  read_image (TIFF *tif, tiff_image_data *image_data)
+  {
+    if (image_data->is_tiled)
+      // TODO(maged): Implement tiled images
+      error ("Tiled images are not implemented yet");
+    else
+      return read_stripped_image<T> (tif, image_data);
   }
 
   // Error if status is not 1 (success status for TIFFGetField)
@@ -659,7 +679,6 @@
 
     // Check: Strips vs Tiles
     //        Planar Configuration
-    //        StripByteCounts
     //        SamplesPerPixel and bits_per_smaple
     //        nargout and ycbcr
     //        ExtendedSamples? TransferFunction? GrayResponse? ColorMap?
@@ -689,103 +708,31 @@
                         &image_data.planar_configuration))
       error ("Failed to read the PlanarConfiguration tag");
     
-    image_data.pixel_size = image_data.samples_per_pixel
-                            * (image_data.bits_per_sample / 8);
     image_data.is_tiled = TIFFIsTiled(tif);
-
-    // Create memory for storing the image data
-    // TODO(maged): replace malloc with a suitable C++ structure
-    void ***image = (void ***)malloc (sizeof(void ***) * image_data.height);
-    for (uint32_t row = 0; row < image_data.height; row++)
-      {
-        image[row] = (void **)malloc (sizeof(void **) * image_data.width);
-        for (uint32_t column = 0; column < image_data.width; column++)
-          // Allocate at least one byte per pixel (For BitsPerSample < 8)
-          image[row][column] = malloc (image_data.pixel_size > 0 ?
-                                       image_data.pixel_size: 1);
-      }
-
-    if (image_data.is_tiled)
-      // TODO(maged): Implement tiled images
-      error ("Tiled images are not implemented yet");
-    else
-      {
-        read_stripped_image (tif, &image_data, image);
-      }
     
     octave_value_list retval;
-    dim_vector arr_dims (image_data.height, image_data.width,
-                         image_data.samples_per_pixel);
-    // TODO(maged): what about palette images? are they handled internally?
     switch (image_data.bits_per_sample)
       {
       case 1:
-        {
-          boolNDArray arr(arr_dims);
-          for (uint32_t row = 0; row < image_data.height; row++)
-            for (uint32_t column = 0; column < image_data.width; column++)
-              for (uint16_t sample = 0; sample < image_data.samples_per_pixel; sample++)
-                arr(row, column, sample) = ((uint8_t ***)image)[row][column][sample];
-          
-          retval(0) = arr;
-          break;
-        }
+        retval(0) = read_image<boolNDArray> (tif, &image_data);
+        break;
       case 4:
       case 8:
-        {
-          uint8NDArray arr(arr_dims);
-          for (uint32_t row = 0; row < image_data.height; row++)
-            for (uint32_t column = 0; column < image_data.width; column++)
-              for (uint16_t sample = 0; sample < image_data.samples_per_pixel; sample++)
-                arr(row, column, sample) = ((uint8_t ***)image)[row][column][sample];
-          
-          retval(0) = arr;
-          break;
-        }
+        retval(0) = read_image<uint8NDArray> (tif, &image_data);
+        break;
       case 16:
-        {
-          uint16NDArray arr(arr_dims);
-          for (uint32_t row = 0; row < image_data.height; row++)
-            for (uint32_t column = 0; column < image_data.width; column++)
-              for (uint16_t sample = 0; sample < image_data.samples_per_pixel; sample++)
-                arr(row, column, sample) = ((uint16_t ***)image)[row][column][sample];
-          
-          retval(0) = arr;
-          break;
-        }
+        retval(0) = read_image<uint16NDArray> (tif, &image_data);
+        break;
       case 32:
-        {
-          uint32NDArray arr(arr_dims);
-          for (uint32_t row = 0; row < image_data.height; row++)
-            for (uint32_t column = 0; column < image_data.width; column++)
-              for (uint16_t sample = 0; sample < image_data.samples_per_pixel; sample++)
-                arr(row, column, sample) = ((uint32_t ***)image)[row][column][sample];
-          
-          retval(0) = arr;
-          break;
-        }
+        retval(0) = read_image<uint32NDArray> (tif, &image_data);
+        break;
       case 64:
-        {
-          uint64NDArray arr(arr_dims);
-          for (uint32_t row = 0; row < image_data.height; row++)
-            for (uint32_t column = 0; column < image_data.width; column++)
-              for (uint16_t sample = 0; sample < image_data.samples_per_pixel; sample++)
-                arr(row, column, sample) = ((uint64_t ***)image)[row][column][sample];
-          
-          retval(0) = arr;
-          break;
-        }
+        retval(0) = read_image<uint64NDArray> (tif, &image_data);
+        break;
       default:
         error ("Unsupported bit depth");
       }
     
-    for (uint32_t row = 0; row < image_data.height; row++)
-      {
-        for (uint32_t column = 0; column < image_data.width; column++)
-          free (image[row][column]);
-        
-        free (image[row]);
-      }
     return retval;
 #else
     err_disabled_feature ("read", "Tiff");