changeset 31172:3f5f1404af8a

Tiff: added directory methods (currentDirectory, nextDirectory, ...) * __tiff__.cc: implemented the internal functions for the directory methods. * Tiff.m: added the methods to the class and added a test for the methods.
author magedrifaat <magedrifaat@gmail.com>
date Sun, 14 Aug 2022 21:02:58 +0200
parents 8bf3fa6b6977
children 0abc9779f751
files libinterp/corefcn/__tiff__.cc scripts/io/Tiff.m
diffstat 2 files changed, 244 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/__tiff__.cc	Sun Aug 14 02:40:03 2022 +0200
+++ b/libinterp/corefcn/__tiff__.cc	Sun Aug 14 21:02:58 2022 +0200
@@ -1181,11 +1181,18 @@
     if (TIFFFieldPassCount (fip))
       error ("Unsupported tag");
     
+    TIFFDataType tag_datatype = TIFFFieldDataType (fip);
+
     // According to matlab, the value must be a scalar double
-    if (! tag_ov.is_scalar_type () || ! tag_ov.is_double_type ())
+    // except for strings
+    if (tag_datatype == TIFF_ASCII)
+      {
+        if (! tag_ov.is_string ())
+          error ("Expected string for ascii tag");
+      }
+    else if (! tag_ov.is_scalar_type () || ! tag_ov.is_double_type ())
       error ("Tag value must be a scalar double");
     
-    TIFFDataType tag_datatype = TIFFFieldDataType (fip);
     switch (tag_datatype)
       {
       case TIFF_BYTE:
@@ -2400,6 +2407,7 @@
     TIFF *tif = (TIFF *)(args(0).uint64_value ());
 
     // TODO(maged): check matlab behavior for missing/ wrong/ out of bounds row
+    // matlab row must be double (scalar or array),  and checks bounds
     uint32_t row = args (1).uint32_scalar_value ();
     
     tiff_image_data image_data (tif);
@@ -2409,7 +2417,6 @@
     if (row < 1 || row > image_data.height)
       error ("Row out of bounds of the image");
     
-    // TODO(maged): check if matlab require the first row in strip as well
     // Convert from 1-based indexing to zero-based
     row--;
 
@@ -2437,6 +2444,7 @@
       = 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");
     
@@ -2882,6 +2890,165 @@
 #endif
   }
 
+  DEFUN (__tiff_current_directory__, args, ,
+         "Get the index of the current directory")
+  {
+#if defined (HAVE_TIFF)
+    int nargin = args.length ();
+
+    if (nargin != 1)
+      error ("Wrong number of arguments\n");
+    
+    TIFF *tif = (TIFF *)(args(0).uint64_value ());
+
+    // TODO(maged): check matlab behavior
+    uint16_t dir = TIFFCurrentDirectory (tif);
+    if (dir == (uint16_t)-1)
+      dir = 0;
+    
+    return octave_value_list (octave_value (dir + 1));
+#else
+    err_disabled_feature ("currentDirectory", "Tiff");
+#endif
+  }
+
+  DEFUN (__tiff_last_directory__, args, ,
+         "Get the whether the current directory is the last")
+  {
+#if defined (HAVE_TIFF)
+    int nargin = args.length ();
+
+    if (nargin != 1)
+      error ("Wrong number of arguments\n");
+    
+    TIFF *tif = (TIFF *)(args(0).uint64_value ());
+
+    bool is_last = TIFFLastDirectory (tif);
+    
+    return octave_value_list (octave_value (is_last));
+#else
+    err_disabled_feature ("lastDirectory", "Tiff");
+#endif
+  }
+
+  DEFUN (__tiff_next_directory__, args, ,
+         "Set the next IFD as the current IFD")
+  {
+#if defined (HAVE_TIFF)
+    int nargin = args.length ();
+
+    if (nargin != 1)
+      error ("Wrong number of arguments\n");
+    
+    TIFF *tif = (TIFF *)(args(0).uint64_value ());
+
+    // TODO(maged): check if matlab handles this case different from
+    // an erronous next IFD
+    bool is_last = TIFFLastDirectory (tif);
+    if (is_last)
+      error ("Current directory is the last directory");
+    
+    if (! TIFFReadDirectory (tif))
+      error ("Failed to read the next directory");
+    
+    return octave_value_list ();
+#else
+    err_disabled_feature ("nextDirectory", "Tiff");
+#endif
+  }
+
+  DEFUN (__tiff_set_directory__, args, ,
+         "Set the current IFD using the given index")
+  {
+#if defined (HAVE_TIFF)
+    int nargin = args.length ();
+
+    if (nargin != 2)
+      error ("Wrong number of arguments\n");
+    
+    TIFF *tif = (TIFF *)(args(0).uint64_value ());
+
+    // TODO(maged): check matlab behavior for wrong argument type
+    // and out of bounds index
+    uint16_t dir = args(1).uint16_scalar_value ();
+    if (dir < 1 || dir > TIFFNumberOfDirectories (tif))
+      error ("Directory index out of bounds");
+    
+    dir--;
+
+    if (! TIFFSetDirectory(tif, dir))
+      error ("Failed to read directory");
+
+    return octave_value_list ();
+#else
+    err_disabled_feature ("setDirectory", "Tiff");
+#endif
+  }
+
+  DEFUN (__tiff_write_directory__, args, ,
+         "Write the current IFD to file and create a new one")
+  {
+#if defined (HAVE_TIFF)
+    int nargin = args.length ();
+
+    if (nargin != 1)
+      error ("Wrong number of arguments\n");
+    
+    TIFF *tif = (TIFF *)(args(0).uint64_value ());
+    // TODO(maged): check if matlab errors for leaving a corrupt directory
+    // Check if mtalab always writes directories at the end for both w and a (And r+)
+    if (! TIFFWriteDirectory(tif))
+      error ("Failed to write directory");
+
+    return octave_value_list ();
+#else
+    err_disabled_feature ("writeDirectory", "Tiff");
+#endif
+  }
+
+  DEFUN (__tiff_rewrite_directory__, args, ,
+         "Rewrite modifications to the current IFD")
+  {
+#if defined (HAVE_TIFF)
+    int nargin = args.length ();
+
+    if (nargin != 1)
+      error ("Wrong number of arguments\n");
+    
+    TIFF *tif = (TIFF *)(args(0).uint64_value ());
+    // TODO(maged): check if matlab errors for leaving a corrupt directory
+    // check if matlab changes directory after the call or switches back
+    if (! TIFFRewriteDirectory(tif))
+      error ("Failed to rewrite directory");
+
+    return octave_value_list ();
+#else
+    err_disabled_feature ("rewriteDirectory", "Tiff");
+#endif
+  }
+
+  DEFUN (__tiff_set_sub_directory__, args, ,
+         "Set the given offset directory as the current IFD")
+  {
+#if defined (HAVE_TIFF)
+    int nargin = args.length ();
+
+    if (nargin != 2)
+      error ("Wrong number of arguments\n");
+    
+    TIFF *tif = (TIFF *)(args(0).uint64_value ());
+    
+    // TODO(maged): check if matlab requires scalar double
+    uint64_t offset = args(1).uint64_scalar_value ();
+    if (! TIFFSetSubDirectory (tif, offset))
+      error ("Failed to switch to the sub directory");
+
+    return octave_value_list ();
+#else
+    err_disabled_feature ("setSubDirectory", "Tiff");
+#endif
+  }
+
   DEFUN (__tiff_version__, , ,
              "Get the version stamp of LibTIFF")
   {
--- a/scripts/io/Tiff.m	Sun Aug 14 02:40:03 2022 +0200
+++ b/scripts/io/Tiff.m	Sun Aug 14 21:02:58 2022 +0200
@@ -330,6 +330,55 @@
       tileNumber = __tiff_compute_tile__ (t.tiff_handle, varargin{:});
     endfunction
 
+    function dirNum = currentDirectory (t)
+      if (t.closed)
+        error ("Image file was closed");
+      endif
+      dirNum = __tiff_current_directory__ (t.tiff_handle);
+    endfunction
+
+    function isLast = lastDirectory (t)
+      if (t.closed)
+        error ("Image file was closed");
+      endif
+      isLast = __tiff_last_directory__ (t.tiff_handle);
+    endfunction
+
+    function nextDirectory (t)
+      if (t.closed)
+        error ("Image file was closed");
+      endif
+      __tiff_next_directory__ (t.tiff_handle);
+    endfunction
+
+    function setDirectory (t, dirNum)
+      if (t.closed)
+        error ("Image file was closed");
+      endif
+      __tiff_set_directory__ (t.tiff_handle, dirNum);
+    endfunction
+
+    function writeDirectory (t)
+      if (t.closed)
+        error ("Image file was closed");
+      endif
+      __tiff_write_directory__ (t.tiff_handle);
+    endfunction
+
+    function rewriteDirectory (t)
+      if (t.closed)
+        error ("Image file was closed");
+      endif
+      __tiff_rewrite_directory__ (t.tiff_handle);
+    endfunction
+
+    function setSubDirectory (t, offset)
+      if (t.closed)
+        error ("Image file was closed");
+      endif
+      __tiff_set_sub_directory__ (t.tiff_handle, offset);
+    endfunction
+
     % TODO(maged): add documentation and make print_usage work
   endmethods
 
@@ -1624,3 +1673,28 @@
 %!    assert (alpha, data(1:16,1:32,4));
 %!  endfunction
 %!  file_wrapper (@test_fn);
+
+## test directory manipulation
+%!testif HAVE_TIFF
+%!  function test_fn (filename)
+%!    img = Tiff (filename, "w");
+%!    tags = struct (
+%!      "ImageLength", 10, "ImageWidth", 10, "BitsPerSample", 8
+%!    );
+%!    setTag (img, tags);
+%!    data = uint8 (reshape (1:100, [10, 10]));
+%!    write(img, data);
+%!    img.writeDirectory ();
+%!    setTag (img, tags);
+%!    write(img, data);
+%!    img.close();
+%!    img = Tiff (filename);
+%!    assert (img.currentDirectory, 1);
+%!    assert (img.lastDirectory, logical (0));
+%!    img.nextDirectory ();
+%!    assert (img.currentDirectory, 2);
+%!    assert (img.lastDirectory, logical (1));
+%!    img.setDirectory (1);
+%!    assert (img.currentDirectory, 1);
+%!  endfunction
+%!  file_wrapper (@test_fn)
\ No newline at end of file