changeset 31175:ed329571ec88

Tiff: added support for creating and reading sub-directories * __tiff__.cc (F__tiff_set_sub_directory__): added logic to check existance and validation of offsets. * __tiff__,cc (set_field_data): handled SubIFD tag correctly to enable creating sub-directories.
author magedrifaat <magedrifaat@gmail.com>
date Tue, 16 Aug 2022 22:57:21 +0200
parents 1f19e9a06f2d
children c07461ca34d6
files libinterp/corefcn/__tiff__.cc
diffstat 1 files changed, 85 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/__tiff__.cc	Tue Aug 16 18:01:12 2022 +0200
+++ b/libinterp/corefcn/__tiff__.cc	Tue Aug 16 22:57:21 2022 +0200
@@ -718,68 +718,46 @@
       {
       case TIFF_BYTE:
       case TIFF_UNDEFINED:
-        {
-          retval = static_cast<double> (*(reinterpret_cast<uint8_t *> (data)));
-          break;
-        }
+        retval = static_cast<double> (*(reinterpret_cast<uint8_t *> (data)));
+        break;
       case TIFF_SHORT:
-        {
-          retval = static_cast<double> (*(reinterpret_cast<uint16_t *> (data)));
-          break;
-        }
+        retval = static_cast<double> (*(reinterpret_cast<uint16_t *> (data)));
+        break;
       case TIFF_LONG:
-        {
-          retval = static_cast<double> (*(reinterpret_cast<uint32_t *> (data)));
-          break;
-        }
+        retval = static_cast<double> (*(reinterpret_cast<uint32_t *> (data)));
+        break;
       case TIFF_LONG8:
-        {
-          retval = static_cast<double> (*(reinterpret_cast<uint64_t *> (data)));
-          break;
-        }
+        retval = static_cast<double> (*(reinterpret_cast<uint64_t *> (data)));
+        break;
       case TIFF_RATIONAL:
-        {
-          retval = *(reinterpret_cast<float *> (data));
-          break;
-        }
+        retval = *(reinterpret_cast<float *> (data));
+        break;
       case TIFF_SBYTE:
-        {
-          retval = static_cast<double> (*(reinterpret_cast<int8_t *> (data)));
-          break;
-        }
+        retval = static_cast<double> (*(reinterpret_cast<int8_t *> (data)));
+        break;
       case TIFF_SSHORT:
-        {
-          retval = static_cast<double> (*(reinterpret_cast<int16_t *> (data)));
-          break;
-        }
+        retval = static_cast<double> (*(reinterpret_cast<int16_t *> (data)));
+        break;
       case TIFF_SLONG:
-        {
-          retval = static_cast<double> (*(reinterpret_cast<int32_t *> (data)));
-          break;
-        }
+        retval = static_cast<double> (*(reinterpret_cast<int32_t *> (data)));
+        break;
       case TIFF_SLONG8:
-        {
-          retval = static_cast<double> (*(reinterpret_cast<int64_t *> (data)));
-          break;
-        }
+        retval = static_cast<double> (*(reinterpret_cast<int64_t *> (data)));
+        break;
       case TIFF_FLOAT:
-        {
-          retval = *(reinterpret_cast<float *> (data));
-          break;
-        }
+        retval = *(reinterpret_cast<float *> (data));
+        break;
       case TIFF_DOUBLE:
-        {
-          retval = *(reinterpret_cast<double *> (data));
-          break;
-        }
+        retval = *(reinterpret_cast<double *> (data));
+        break;
       case TIFF_SRATIONAL:
-        {
-          retval = *(reinterpret_cast<float *> (data));
-          break;
-        }
+        retval = *(reinterpret_cast<float *> (data));
+        break;
       case TIFF_IFD:
+        retval = static_cast<double> (*(reinterpret_cast<uint32_t *> (data)));
+        break;
       case TIFF_IFD8:
-        error ("Unimplemented IFFD data type");
+        retval = static_cast<double> (*(reinterpret_cast<uint64_t *> (data)));
         break;
       default:
         error ("Unsupported tag data type");
@@ -935,10 +913,25 @@
               break;
             }
           case TIFF_IFD:
+            {
+              uint32NDArray arr (arr_dims);
+              for (uint32_t i = 0; i < count; i++)
+                {
+                  arr(i) = (reinterpret_cast<uint32_t *> (data))[i];
+                }
+              retval = octave_value (arr);
+              break;
+            }
           case TIFF_IFD8:
-            // TODO(maged): implement IFD datatype?
-            error ("Unimplemented IFD data type");
-            break;
+            {
+              uint64NDArray arr (arr_dims);
+              for (uint32_t i = 0; i < count; i++)
+                {
+                  arr(i) = (reinterpret_cast<uint64_t *> (data))[i];
+                }
+              retval = octave_value (arr);
+              break;
+            }
           default:
             error ("Unsupported tag data type");
           }
@@ -1439,9 +1432,12 @@
         }
       case TIFFTAG_SUBIFD:
         {
-          // TODO(maged): Matlab doesnt error on setting this tag
-          // but returns 0 for getTag
-          error ("Unsupported tag");
+          uint16_t subifd_count = tag_ov.uint16_scalar_value ();
+          std::unique_ptr<uint64_t []> subifd_offsets
+            = std::make_unique<uint64_t []> (subifd_count);
+          uint64_t *offfsets_ptr = subifd_offsets.get ();
+          if (! TIFFSetField (tif, tag_id, subifd_count, offfsets_ptr))
+            error ("Failed to set tag");
           break;
         }
       case TIFFTAG_EXTRASAMPLES:
@@ -2426,9 +2422,9 @@
 
     // Matlab (R2022a) requires row to be double
     if (! args(1).is_double_type ())
-      error ("row must be double");
+      error ("row should be of type double");
     
-    uint32_t row = args (1).uint32_scalar_value ();
+    uint32_t row = args(1).uint32_scalar_value ();
     
     tiff_image_data image_data (tif);
     if (image_data.is_tiled)
@@ -2466,11 +2462,6 @@
     uint8NDArray strip_data (strip_dims);
     uint32_t *strip_ptr
       = reinterpret_cast <uint32_t *> (strip_data.fortran_vec ());
-    
-    // TODO(maged): check if matlab does anything with orientation tag
-    // matlab uses the orientation tag to correct the data
-    // if (! TIFFReadRGBAStrip (tif, row, strip_ptr))
-    //   error ("Failed to read strip");
 
     TIFFRGBAImage img_config;
     char emsg[1024];
@@ -2527,10 +2518,13 @@
     
     TIFF *tif = (TIFF *)(args(0).uint64_value ());
 
-    // TODO(maged): check matlab behavior for missing/ wrong/ out of bounds vals
-    // matlab checks bounds and requires double vals (scalar or array)
-    uint32_t row = args (1).uint32_scalar_value ();
-    uint32_t col = args (2).uint32_scalar_value ();
+    if (! args(1).is_double_type ())
+      error ("row should be of type double");
+    if (! args(2).is_double_type ())
+      error ("col should be of type double");
+    
+    uint32_t row = args(1).uint32_scalar_value ();
+    uint32_t col = args(2).uint32_scalar_value ();
     
     tiff_image_data image_data (tif);
     if (! image_data.is_tiled)
@@ -2575,11 +2569,6 @@
     uint8NDArray tile_data (tile_dims);
     uint32_t *tile_ptr
       = reinterpret_cast <uint32_t *> (tile_data.fortran_vec ());
-    
-    // TODO(maged): check if matlab does anything with orientation tag
-    // matlab uses orientation tag to correct the data
-    // if (! TIFFReadRGBATile (tif, col, row, tile_ptr))
-    //   error ("Failed to read tile");
 
     TIFFRGBAImage img_config;
     char emsg[1024];
@@ -2960,13 +2949,10 @@
     
     TIFF *tif = (TIFF *)(args(0).uint64_value ());
 
-    // TODO(maged): check matlab behavior
-    // matlab returns double and handles the special case as 0!
     uint16_t dir = TIFFCurrentDirectory (tif);
-    if (dir == (uint16_t)-1)
-      dir = 0;
+    dir++;
     
-    return octave_value_list (octave_value (dir + 1));
+    return octave_value_list (octave_value (static_cast<double> (dir)));
 #else
     err_disabled_feature ("currentDirectory", "Tiff");
 #endif
@@ -3051,8 +3037,7 @@
       error ("Wrong number of arguments\n");
     
     TIFF *tif = (TIFF *)(args(0).uint64_value ());
-    // TODO(maged): Check if mtalab always writes directories at the end for both w and a (And r+)
-    // it does
+    
     if (! TIFFWriteDirectory(tif))
       error ("Failed to write directory");
 
@@ -3096,7 +3081,29 @@
     // TODO(maged): check if matlab requires scalar double
     // matlab expects double, uint32, or uint64
     // and checks the subIFD tag first
+    if (! args(1).is_double_type () && ! args(1).is_uint32_type ()
+        && ! args(1).is_uint64_type ())
+      error ("Expected offset of type double, uint32 or uint64");
+    
+    uint16_t count;
+    uint64_t *offsets;
+    if (! TIFFGetField (tif, TIFFTAG_SUBIFD, &count, &offsets))
+      error ("The current directory doesn't have sub directories");
+    
     uint64_t offset = args(1).uint64_scalar_value ();
+
+    // TODO(maged): check if matlab validates the offset
+    int found = 0;
+    for (uint16_t i = 0; i < count; i++)
+      if (offset == offsets[i])
+        {
+          found = 1;
+          break;
+        }
+    
+    if (! found)
+      error ("No Sub directory with the given offset");
+    
     if (! TIFFSetSubDirectory (tif, offset))
       error ("Failed to switch to the sub directory");