changeset 31197:1604c8812b67

Tiff: added numberOfDirectories method.
author magedrifaat <magedrifaat@gmail.com>
date Thu, 01 Sep 2022 01:56:20 +0200
parents 1da6d747bf78
children 93eb0d6e7f62
files libinterp/corefcn/__tiff__.cc scripts/image/PKG_ADD scripts/image/private/__tiff_imread__.m scripts/io/Tiff.m
diffstat 4 files changed, 178 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/__tiff__.cc	Thu Sep 01 00:10:37 2022 +0200
+++ b/libinterp/corefcn/__tiff__.cc	Thu Sep 01 01:56:20 2022 +0200
@@ -129,12 +129,6 @@
   }
 
   bool
-  is_numeric_scalar (octave_value ov)
-  {
-    return ov.isnumeric () && ov.isreal () && ov.is_scalar_type ();
-  }
-
-  bool
   is_colormap (octave_value ov)
   {
     return ov.isnumeric () && ov.isreal () && ov.isfloat ()
@@ -3188,6 +3182,30 @@
 #endif
   }
 
+  DEFUN (__tiff_number_of_directories__, args, ,
+             "Get the number of tiles in the image")
+  {
+#if defined (HAVE_TIFF)
+    int nargin = args.length ();
+
+    if (nargin == 0)
+      error ("No handle provided\n");
+    
+    octave_tiff_handle *tiff_handle
+      = octave_tiff_handle::get_tiff_handle (args(0));
+    check_closed (tiff_handle);
+
+    set_internal_handlers ();
+
+    TIFF *tif = tiff_handle->get_file ();
+    
+    double dir_count = static_cast<double> (TIFFNumberOfDirectories (tif));
+    return ovl (dir_count);
+#else
+    err_disabled_feature ("numberOfDirectories", "Tiff");
+#endif
+  }
+
   DEFUN (__tiff_compute_strip__, args, ,
              "Get the strip index containing the given row")
   {
--- a/scripts/image/PKG_ADD	Thu Sep 01 00:10:37 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-if __have_feature__ ("TIFF")
-    format = imformats("tif");
-    format.read = @__tiff_imread__;
-    format.write = @__tiff_imwrite__;
-    format.info = @__tiff_imfinfo__;
-    imformats("update", "tif", format);
-endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/image/private/__tiff_imread__.m	Thu Sep 01 01:56:20 2022 +0200
@@ -0,0 +1,150 @@
+function [A, cmap, alpha] = __tiff_imread__ (filename, varargin)
+  img = Tiff (filename);
+  dir_count = img.numberOfDirectories ();
+  
+  ## A lot of the input sanitising logic here is copied from
+  ## scripts/image/__imread__.m and adapted to the needs of the Tiff
+  ## interface
+
+  pages = [1];
+  offset = 1;
+  if (nargin > 1 && ! ischar (varargin{1}))
+    if (! is_valid_index_option (varargin {1}))
+      error ("imread: IDX must be a numeric vector");
+    endif
+    pages = varargin{1};
+    offset = 2;
+  endif
+
+  if (rem (numel (varargin) - offset + 1, 2) != 0)
+    error ("imread: PARAM/VALUE arguments must occur in pairs");
+  endif
+
+  ## Check for Index/Frames argument
+  idx = strcmpi ("index", varargin) | strcmpi ("frames", varargin);
+  if (any (idx))
+    if (sum (idx) > 1)
+      error ("imread: Index or Frames may only be specified once");
+    endif
+    val = varargin{circshift (idx, 1)};
+    if (! is_valid_index_option (val) && ! strcmpi (val, "all"))
+      error ("imread: %s must be a vector or the string 'all'", varargin{idx});
+    endif
+    if (strcmpi (val, "all"))
+      pages = 1:dir_count;
+    else
+      pages = val;
+    endif
+  endif
+  
+  if (any ((pages < 1) | (pages > dir_count)))
+    error ("imread: index/frames specified are outside the number of images");
+  endif
+
+  img.setDirectory (pages(1));
+  info = get_image_info (img);
+
+  ## Verify that all images have the same dimensions, number of channels,
+  ## bit-depth, and data type
+  for page_idx = 2:numel (pages)
+    img.setDirectory (pages(page_idx));
+    dir_info = get_image_info (img);
+    if (info.width != dir_info.width || info.height != dir_info.height)
+      error ("imread: all frames must have the same size but frame %d is different",
+             pages(page_idx));
+    endif
+    if (info.bitdepth != dir_info.bitdepth)
+      error ("imread: all frames must have the same bit depth but frame %d is different",
+             pages(page_idx));
+    endif
+    if (info.nchannels != dir_info.nchannels)
+      error ("imread: all frames must have the same number of channels but frame %d is different",
+             pages(page_idx));
+    endif
+    if (info.datatype != dir_info.datatype)
+      error ("imread: all frames must have the same data type but frame %d is different",
+             pages(page_idx));
+    endif
+    if (info.photometric != dir_info.photometric)
+      error ("imread: all frames must have the same photometric interpretation but frame %d is different",
+             pages(page_idx));
+    endif
+  endfor
+
+  region = {1:info.height, 1:info.width};
+  for idx = offset:2:(numel (varargin) - offset + 1)
+    switch (tolower (varargin{idx}))
+
+      case {"frames", "index"}
+        ## Do nothing.  This option was already processed before the loop.
+
+      case "pixelregion"
+        region = varargin{idx+1};
+        if (! iscell (region) || numel (region) != 2)
+          error ("imread: %s must be a 2-element cell array",
+                 varargin{idx});
+        endif
+        for reg_idx = 1:2
+          if (numel (region{reg_idx}) == 3)
+            ## do nothing
+          elseif (numel (region{reg_idx}) == 2)
+            region{reg_idx}(3) = region{reg_idx}(2);
+            region{reg_idx}(2) = 1;
+          else
+            error ("imread: range for %s must be a 2 or 3 element vector",
+                   varargin{idx});
+          endif
+          region{reg_idx} = floor (region{reg_idx}(1)): ...
+                            floor (region{reg_idx}(2)): ...
+                            floor (region{reg_idx}(3));
+        endfor
+        if (region{1}(end) > info.height)
+          error ("imread: end ROWS for PixelRegions option is larger than image height");
+        elseif (region{2}(end) > info.width)
+          error ("imread: end COLS for PixelRegions option is larger than image width");
+        endif
+
+      case "info"
+        ## We ignore this option.  This parameter exists in Matlab to
+        ## speed up the reading of multipage TIFF by passing a structure
+        ## that contains information about the start on the file of each
+        ## page.  We can't control it through GraphicsMagic but at least
+        ## we allow to load multiple pages with one command.
+
+      otherwise
+        error ("imread: invalid PARAMETER '%s'", varargin{idx});
+
+    endswitch
+  endfor
+
+  A = [];
+  cmap = [];
+  alpha = [];
+  for page_idx = 1:numel(pages)
+    img.setDirectory (pages(page_idx));
+    ## FIXME: This an ineffecient way to read pixel regions because it
+    ## always reads the entire image first. A better way is to figure
+    ## out which strips/tiles are needed for the region and read only those.
+    data = img.read ();
+    data = data (region{1}, region{2}, :);
+    A = cat (4, A, data);
+    if (info.photometric == Tiff.Photometric.Palette)
+      cmap = cat (3, cmap, img.getTag (Tiff.TagID.ColorMap));
+    endif
+  endfor
+
+  img.close ();
+endfunction
+
+function bool = is_valid_index_option (arg)
+  bool = isvector (arg) && isnumeric (arg) && isreal (arg);
+endfunction
+
+function info = get_image_info (img)
+  info.height = img.getTag (Tiff.TagID.ImageLength);
+  info.width = img.getTag (Tiff.TagID.ImageWidth);
+  info.bitdepth = img.getTag (Tiff.TagID.BitsPerSample);
+  info.nchannels = img.getTag (Tiff.TagID.BitsPerSample);
+  info.datatype = img.getTag (Tiff.TagID.SampleFormat);
+  info.photometric = img.getTag (Tiff.TagID.Photometric);
+endfunction
\ No newline at end of file
--- a/scripts/io/Tiff.m	Thu Sep 01 00:10:37 2022 +0200
+++ b/scripts/io/Tiff.m	Thu Sep 01 01:56:20 2022 +0200
@@ -211,6 +211,10 @@
       numTiles = __tiff_number_of_tiles__ (t.tiff_handle);
     endfunction
 
+    function numDirs = numberOfDirectories (t)
+      numDirs = __tiff_number_of_directories__ (t.tiff_handle);
+    endfunction
+
     function stripNumber = computeStrip (t, varargin)
       stripNumber = __tiff_compute_strip__ (t.tiff_handle, varargin{:});
     endfunction