changeset 31201:e5e8cb049b4b

__tiff_imfinfo__: converted to private octave function * libinterp/corefcn/__tiff__.cc: removed internal function __tiff__imfinfo__. * scipts/image/private/__tiff_imfinfo__.m: implemented private octave function __tiff_imfinfo__. * scripts/image/module.mk: added entry for the new function.
author magedrifaat <magedrifaat@gmail.com>
date Fri, 02 Sep 2022 20:52:47 +0200
parents 4e8152ccc61a
children be6ccdcd5775
files libinterp/corefcn/__tiff__.cc scripts/image/module.mk scripts/image/private/__tiff_imfinfo__.m scripts/image/private/__tiff_imread__.m
diffstat 4 files changed, 177 insertions(+), 304 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/__tiff__.cc	Fri Sep 02 03:41:05 2022 +0200
+++ b/libinterp/corefcn/__tiff__.cc	Fri Sep 02 20:52:47 2022 +0200
@@ -3602,307 +3602,4 @@
     err_disabled_feature ("F__tiff_make_tagid__", "Tiff");
 #endif
   }
-
-  DEFUN (__tiff_imfinfo__, args, ,
-         "Handler for imfinfo that uses Tiff interface")
-  {
-#if defined (HAVE_TIFF)
-    int nargin = args.length ();
-
-    if (nargin < 1)
-      error ("imfinfo: missing filename argument");
-    
-    if (! args(0).is_string ())
-      error ("imfinfo: filename must be a string");
-    
-    std::string filename = args(0).string_value ();
-
-    const sys::file_stat fs (filename);
-    if (! fs)
-      error ("imfinfo: error reading '%s': %s", filename.c_str (),
-             fs.error ().c_str ());
-    
-    TIFF *tif = TIFFOpen (filename.c_str (), "rc");
-    if (! tif)
-      error ("imfinfo: error reading '%s': LibTIFF failed to read file",
-             filename.c_str ());
-    
-    // The destructor for this object will be called when the function returnd
-    // or in case of an error so the file will always get closed at the end
-    octave_tiff_handle tiff_handle (tif);
-
-    // A lot of the logic here is copied from __magick_finfo__ due to the
-    // great similarity between the two functions but this function is
-    // format specific so a lot of the details are different
-    uint16_t dir_count = TIFFNumberOfDirectories (tif);
-    
-    // Null terminated char* list to be used to create a string_vector
-    static const char *fields[] = {
-      "Filename",
-      "FileModDate",
-      "FileSize",
-      "Format",
-      "FormatVersion",
-      "Width",
-      "Height",
-      "BitDepth",
-      "ColorType",
-      "FormatSignature",
-      "ByteOrder",
-      "NewSubFileType",
-      "BitsPerSample",
-      "Compression",
-      "PhotometricInterpretation",
-      "StripOffsets",
-      "SamplesPerPixel",
-      "RowsPerStrip",
-      "StripByteCounts",
-      "XResolution",
-      "YResolution",
-      "ResolutionUnit",
-      "Colormap",
-      "PlanarConfiguration",
-      "TileWidth",
-      "TileLength",
-      "TileOffsets",
-      "TileByteCounts",
-      "Orientation",
-      "FillOrder",
-      "GrayResponseUnit",
-      "MaxSampleValue",
-      "MinSampleValue",
-      "Thresholding",
-      "Offset",
-      "ImageDescription",
-      nullptr
-    };
-    
-    // A map to be used as a struct array to hold a scalar_map for each
-    // directory
-    octave_map info (dim_vector (dir_count, 1), string_vector (fields));
-
-    // populate template_info with the info that is common between all
-    // directories in the file
-    octave_scalar_map template_info = (string_vector (fields));
-    template_info.setfield ("Format", octave_value ("tif"));
-    template_info.setfield ("FormatVersion", octave_value (""));
-    const sys::localtime mtime (fs.mtime ());
-    const std::string filetime = mtime.strftime ("%e-%b-%Y %H:%M:%S");
-    template_info.setfield ("Filename",    octave_value (filename));
-    template_info.setfield ("FileModDate", octave_value (filetime));
-    template_info.setfield ("FileSize",    octave_value (fs.size ()));
-
-    // Extract the image signature (first 4 bytes in file)
-    std::ifstream tif_file;
-#if defined (OCTAVE_USE_WINDOWS_API)
-    std::wstring wname = sys::u8_to_wstring (filename);
-    tif_file.open (wname.c_str (), std::ios_base::binary);
-#else
-    tif_file.open (filename.c_str (), std::ios_base::binary);
-#endif
-    uint8NDArray signature (dim_vector (1, 4));;
-    tif_file.read (reinterpret_cast<char *> (signature.fortran_vec ()), 4);
-    tif_file.close ();
-    template_info.setfield ("FormatSignature", octave_value (signature));
-
-    std::string byte_order
-      = TIFFIsBigEndian (tif)? "big-endian": "little-endian";
-    template_info.setfield ("ByteOrder", octave_value (byte_order));
-
-    // Extract directory specific information
-    for (uint16_t dir = 0; dir < dir_count; dir++)
-      {
-        octave_scalar_map dir_info (template_info);
-
-        // Switch to the directory
-        if (! TIFFSetDirectory (tif, dir))
-          error ("imfinfo: Failed to access frame %d\n", dir);
-        
-        tiff_image_data image_data (tif);
-        dir_info.setfield ("Width", octave_value (image_data.width));
-        
-        dir_info.setfield ("Height", octave_value (image_data.height));
-        
-        uint16_t bit_depth = image_data.samples_per_pixel
-                             * image_data.bits_per_sample;
-        dir_info.setfield ("BitDepth", octave_value (bit_depth));
-        
-        std::string planar = "unrecognized";
-        if (image_data.planar_configuration == 1)
-          planar = "Chunky";
-        else if (image_data.planar_configuration == 2)
-          planar = "Separate";
-        dir_info.setfield ("PlanarConfiguration", octave_value (planar));
-
-        // Extract photometric information as well as color map if exists
-        std::string color_str, photometric_str;
-        uint16_t photometric = PHOTOMETRIC_MINISBLACK;
-        octave_value cmap = octave_value (Matrix ());
-        const TIFFField *fip;
-        TIFFGetField (tif, TIFFTAG_PHOTOMETRIC, &photometric);
-        switch (photometric)
-          {
-          case PHOTOMETRIC_MINISBLACK:
-            color_str = "grayscale";
-            photometric_str = "BlasckIsZero";
-            break;
-          case PHOTOMETRIC_MINISWHITE:
-            color_str = "grayscale";
-            photometric_str = "WhiteIsZero";
-            break;
-          case PHOTOMETRIC_RGB:
-            color_str = "truecolor";
-            photometric_str = "RGB";
-            break;
-          case PHOTOMETRIC_PALETTE:
-            color_str = "indexed";
-            photometric_str = "RGB Palette";
-            fip = TIFFFieldWithTag (tif, TIFFTAG_COLORMAP);
-            cmap = get_field_data (tif, fip);
-            break;
-          case PHOTOMETRIC_SEPARATED:
-            color_str = "CMYK";
-            photometric_str = "CMYK";
-            break;
-          default:
-            color_str = "undefined";
-            photometric_str = "undefined";
-          }
-        dir_info.setfield ("ColorType", octave_value(color_str));
-        dir_info.setfield ("PhotometricInterpretation",
-                           octave_value(photometric_str));
-        dir_info.setfield ("Colormap", octave_value (cmap));
-
-        fip = TIFFFieldWithTag (tif, TIFFTAG_SUBFILETYPE);
-        dir_info.setfield ("NewSubFileType", get_field_data (tif, fip));
-
-        fip = TIFFFieldWithTag (tif, TIFFTAG_BITSPERSAMPLE);
-        dir_info.setfield ("BitsPerSample", get_field_data (tif, fip));
-
-        fip = TIFFFieldWithTag (tif, TIFFTAG_SAMPLESPERPIXEL);
-        dir_info.setfield ("SamplesPerPixel", get_field_data (tif, fip));
-
-        // Use LibTIFF's compression codec to extract compression scheme name
-        uint16_t compression;
-        TIFFGetFieldDefaulted (tif, TIFFTAG_COMPRESSION, &compression);
-        std::string comp_str = "unrecognized";
-        const TIFFCodec *codec = TIFFFindCODEC (compression);
-        if (codec)
-          comp_str = codec->name;
-        dir_info.setfield ("Compression", octave_value (comp_str));
-
-        // Set strip-specific and tile-specific fields accordingly
-        bool tiled = TIFFIsTiled (tif);
-        fip = TIFFFieldWithTag (tif, TIFFTAG_TILELENGTH);
-        dir_info.setfield ("TileLength", tiled? get_field_data (tif, fip)
-                                         : octave_value (Matrix ()));
-        fip = TIFFFieldWithTag (tif, TIFFTAG_TILEWIDTH);
-        dir_info.setfield ("TileWidth", tiled? get_field_data (tif, fip)
-                                        : octave_value (Matrix ()));
-        fip = TIFFFieldWithTag (tif, TIFFTAG_TILEOFFSETS);
-        dir_info.setfield ("TileOffsets", tiled? get_field_data (tif, fip)
-                                          : octave_value (Matrix ()));
-        fip = TIFFFieldWithTag (tif, TIFFTAG_TILEBYTECOUNTS);
-        dir_info.setfield ("TileByteCounts", tiled? get_field_data (tif, fip)
-                                             : octave_value (Matrix ()));
-        fip = TIFFFieldWithTag (tif, TIFFTAG_ROWSPERSTRIP);
-        dir_info.setfield ("RowsPerStrip", tiled? octave_value (Matrix ())
-                                           : get_field_data (tif, fip));
-        fip = TIFFFieldWithTag (tif, TIFFTAG_STRIPOFFSETS);
-        dir_info.setfield ("StripOffsets", tiled? octave_value (Matrix ())
-                                           : get_field_data (tif, fip));
-        fip = TIFFFieldWithTag (tif, TIFFTAG_STRIPBYTECOUNTS);
-        dir_info.setfield ("StripByteCounts", tiled? octave_value (Matrix ())
-                                              : get_field_data (tif, fip));
-        
-        uint16_t res;
-        if (TIFFGetField (tif, TIFFTAG_XRESOLUTION, &res))
-          dir_info.setfield ("XResolution", octave_value (res));
-        else
-          dir_info.setfield ("XResolution", octave_value (Matrix ()));
-
-        if (TIFFGetField (tif, TIFFTAG_YRESOLUTION, &res))
-          dir_info.setfield ("YResolution", octave_value (res));
-        else
-          dir_info.setfield ("YResolution", octave_value (Matrix ()));
-        
-        TIFFGetFieldDefaulted (tif, TIFFTAG_RESOLUTIONUNIT, &res);
-        std::string res_unit = "Inch";
-        if (res == 1)
-          res_unit = "None";
-        else if (res == 3)
-          res_unit = "Centimeter";
-        dir_info.setfield ("ResolutionUnit", octave_value(res_unit));
-
-        fip = TIFFFieldWithTag (tif, TIFFTAG_ORIENTATION);
-        dir_info.setfield ("Orientation", get_field_data (tif, fip));
-
-        fip = TIFFFieldWithTag (tif, TIFFTAG_FILLORDER);
-        dir_info.setfield ("FillOrder", get_field_data (tif, fip));
-        
-        // The current version of LibTIFF (4.4.0) doesn't set the deafult
-        // value for GrayResponseUnit corectly, so we can't use
-        // TIFFGetFieldDefaulted, instead we set the default value ourselves
-        double gray_response_unit = 0.01;
-        uint16_t gray_unit_val;
-        if (TIFFGetField (tif, TIFFTAG_GRAYRESPONSEUNIT, &gray_unit_val))
-          {
-            switch (gray_unit_val)
-              {
-              case GRAYRESPONSEUNIT_10S:
-                gray_response_unit = 0.1;
-                break;
-              case GRAYRESPONSEUNIT_100S:
-                gray_response_unit = 0.01;
-                break;
-              case GRAYRESPONSEUNIT_1000S:
-                gray_response_unit = 0.001;
-                break;
-              case GRAYRESPONSEUNIT_10000S:
-                gray_response_unit = 0.0001;
-                break;
-              case GRAYRESPONSEUNIT_100000S:
-                gray_response_unit = 0.00001;
-                break;
-              }
-          }
-        dir_info.setfield ("GrayResponseUnit",
-                           octave_value (gray_response_unit));
-
-        // The current version of LibTIFF (4.4.0) doesn't set the deafult
-        // value for MinSampleValue and MaxSampleValue, so we can't use
-        // TIFFGetFieldDefaulted, instead we set the default value ourselves
-        uint16_t min_sample_value = 0;
-        uint16_t max_sample_value = (1<<image_data.bits_per_sample) - 1;
-        TIFFGetField (tif, TIFFTAG_MINSAMPLEVALUE, &min_sample_value);
-        TIFFGetField (tif, TIFFTAG_MAXSAMPLEVALUE, &max_sample_value);
-        dim_vector vector_dims = dim_vector (1, image_data.samples_per_pixel);
-        NDArray min_sample_values (vector_dims, min_sample_value);
-        NDArray max_sample_values (vector_dims, max_sample_value);
-        dir_info.setfield ("MinSampleValue",
-                           octave_value (min_sample_values));
-        dir_info.setfield ("MaxSampleValue",
-                           octave_value (max_sample_values));
-
-        fip = TIFFFieldWithTag (tif, TIFFTAG_THRESHHOLDING);
-        dir_info.setfield ("Thresholding", get_field_data (tif, fip));
-
-        dir_info.setfield ("Offset",
-                           octave_value (TIFFCurrentDirOffset (tif)));
-        
-        char *desc = NULL;
-        if (TIFFGetField (tif, TIFFTAG_IMAGEDESCRIPTION, &desc))
-          dir_info.setfield ("ImageDescription", octave_value (desc));
-        else
-          dir_info.setfield ("ImageDescription", octave_value (""));
-
-        // Insert the directory information into the map
-        info.fast_elem_insert (dir, dir_info);
-      }
-
-    return ovl (info);
-#else
-    err_disabled_feature ("imfinfo", "Tiff");
-#endif
-  }
 }
--- a/scripts/image/module.mk	Fri Sep 02 03:41:05 2022 +0200
+++ b/scripts/image/module.mk	Fri Sep 02 20:52:47 2022 +0200
@@ -6,6 +6,7 @@
   %reldir%/private/__imfinfo__.m \
   %reldir%/private/__imread__.m \
   %reldir%/private/__imwrite__.m \
+  %reldir%/private/__tiff_imfinfo__.m \
   %reldir%/private/__tiff_imread__.m \
   %reldir%/private/__tiff_imwrite__.m \
   %reldir%/private/colorspace_conversion_input_check.m \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/image/private/__tiff_imfinfo__.m	Fri Sep 02 20:52:47 2022 +0200
@@ -0,0 +1,175 @@
+function info = __tiff_imfinfo__ (filename)
+  tif = Tiff (filename);
+  dir_count = tif.numberOfDirectories ();
+
+  info = struct ();
+
+  if __have_feature__ ("MAGICK")
+    ## Obtain data from magick if available (as it handles EXIF tags)
+    info = __imfinfo__ (filename);
+  else
+    ## Otherwise just obtain common tags and ignore EXIF tags
+    [file_stat, err, msg] = stat (filename);
+    if err > 0
+      error ("imfinfo: Failed to access file: %s", msg);
+    endif
+
+    for dir_idx = 1:dir_count
+      info(dir_idx).Filename = filename;
+      info(dir_idx).FileModDate = strftime ("%e-%b-%Y %H:%M:%S",
+                                  localtime (file_stat.ctime));
+      info(dir_idx).FileSize = file_stat.size;
+      info(dir_idx).Format = "tif";
+      info(dir_idx).FormatVersion = "";
+    endfor
+  endif
+
+  for dir_idx = 1:dir_count
+    tif.setDirectory (dir_idx);
+
+    ## Read the file signature (first 4 bytes)
+    a = fopen (filename);
+    info(dir_idx).FormatSignature = reshape (fread (a, 4, "uint8"), [1, 4]);
+    fclose (a);
+
+    info(dir_idx).Width = tif.getTag (Tiff.TagID.ImageWidth);
+    info(dir_idx).Height = tif.getTag (Tiff.TagID.ImageLength);
+
+    info(dir_idx).SamplesPerPixel = tif.getTag (Tiff.TagID.SamplesPerPixel);
+    info(dir_idx).BitsPerSample = tif.getTag (Tiff.TagID.BitsPerSample);
+    info(dir_idx).BitDepth = info(dir_idx).SamplesPerPixel ...
+                             * info(dir_idx).BitsPerSample;
+    
+    planar = tif.getTag (Tiff.TagID.PlanarConfiguration);
+    if planar == Tiff.PlanarConfiguration.Chunky
+      info(dir_idx).PlanarConfiguration = "Chunky";
+    elseif planar == Tiff.PlanarConfiguration.Separate
+      info(dir_idx).PlanarConfiguration = "Separate";
+    else
+      info(dir_idx).PlanarConfiguration = "Unrecognized";
+    endif
+
+    info(dir_idx).Colormap = [];
+
+    photometrics = [Tiff.Photometric.MinIsBlack, Tiff.Photometric.MinIsWhite,...
+                    Tiff.Photometric.RGB, Tiff.Photometric.Palette,...
+                    Tiff.Photometric.Separated];
+    color_types = {"grayscale", "grayscale", "truecolor", "indexed", "cmyk"};
+    photometric_strs = {"BlackIsZero", "WhiteIsZero", "RGB",...
+                        "RGB Palette", "CMYK"};
+    
+    photometric = get_tag_defaulted (tif, Tiff.TagID.Photometric,
+                                     Tiff.Photometric.MinIsBlack);
+    idx = (photometric == photometrics);
+    if ! any (idx)
+      info(dir_idx).ColorType = "undefined";
+      info(dir_idx).PhotometricInterpretation = "undefined";
+    else
+      info(dir_idx).ColorType = color_types{idx};
+      info(dir_idx).PhotometricInterpretation = photometric_strs{idx};
+      if (photometric == Tiff.Photometric.Palette)
+        info(dir_idx).Colormap ...
+          = get_tag_defaulted (tif, Tiff.TagID.ColorMap, []);
+      endif
+    endif
+    
+    ## FIXME: implement isBigEndian
+    # if (tif.isBigEndian ())
+    #   info(dir_idx).ByteOrder = "big-endian";
+    # else
+    #   info(dir_idx).ByteOrder = "little-endian";
+    # endif
+    
+    info(dir_idx).NewSubFileType ...
+      = get_tag_defaulted (tif, Tiff.TagID.SubFileType,
+                                Tiff.SubFileType.Default);
+
+
+    info(dir_idx).Compression = "unrecognized";
+    compressions = fieldnames (Tiff.Compression);
+    compression = tif.getTag (Tiff.TagID.Compression);
+    for comp_idx = 1:numel (compressions)
+      if (compression == Tiff.Compression.(compressions{comp_idx}))
+        info(dir_idx).Compression = compressions{comp_idx};
+        break;
+      endif
+    endfor
+
+    info(dir_idx).TileLength ...
+      = get_tag_defaulted (tif, Tiff.TagID.TileLength, []);
+    info(dir_idx).TileWidth ...
+      = get_tag_defaulted (tif, Tiff.TagID.TileWidth, []);
+    
+    info(dir_idx).TileOffsets ...
+      = get_tag_defaulted (tif, Tiff.TagID.TileOffsets, []);
+    info(dir_idx).TileByteCounts ...
+      = get_tag_defaulted (tif, Tiff.TagID.TileByteCounts, []);
+    
+    info(dir_idx).RowsPerStrip ...
+      = get_tag_defaulted (tif, Tiff.TagID.RowsPerStrip, []);
+    info(dir_idx).StripOffsets ...
+      = get_tag_defaulted (tif, Tiff.TagID.StripOffsets, []);
+    info(dir_idx).StripByteCounts ...
+      = get_tag_defaulted (tif, Tiff.TagID.StripByteCounts, []);
+    
+    info(dir_idx).XResolution ...
+      = get_tag_defaulted (tif, Tiff.TagID.XResolution, []);
+    info(dir_idx).YResolution ...
+      = get_tag_defaulted (tif, Tiff.TagID.YResolution, []);
+
+    info(dir_idx).ResolutionUnit = "Inch";
+    try
+      resunit = tif.getTag (tiff.TagID.ResolutionUnit);
+      if (resunit == Tiff.ResolutionUnit.None)
+        info(dir_idx).ResolutionUnit = "None";
+      elseif (resuint == Tiff.ResolutionUnit.Centimeter)
+        info(dir_idx).ResolutionUnit = "Centimeter";
+      endif
+    end_try_catch
+
+    info(dir_idx).Orientation ...
+      = get_tag_defaulted (tif, Tiff.TagID.Orientation,
+                           Tiff.Orientation.TopLeft);
+
+    info(dir_idx).FillOrder ...
+      = get_tag_defaulted (tif, Tiff.TagID.FillOrder, 1);
+    
+    gray_unit = get_tag_defaulted (tif, Tiff.TagID.GrayResponseUnit, 2);
+    info(dir_idx).GrayResponseUnit = 1 / (10 ^ gray_unit);
+    
+    info(dir_idx).MinSampleValue ...
+      = get_tag_defaulted (tif, Tiff.TagID.MinSampleValue, 0);
+    info(dir_idx).MaxSampleValue ...
+      = get_tag_defaulted (tif, Tiff.TagID.MaxSampleValue,
+                           2^info(dir_idx).BitsPerSample - 1);
+    info(dir_idx).MinSampleValue ...
+      = repmat (info(dir_idx).MinSampleValue,
+                [1, info(dir_idx).SamplesPerPixel]);
+    info(dir_idx).MaxSampleValue ...
+      = repmat (info(dir_idx).MaxSampleValue,
+                [1, info(dir_idx).SamplesPerPixel]);
+
+    info(dir_idx).Thresholding ...
+      = get_tag_defaulted (tif, Tiff.TagID.Thresholding,
+                           Tiff.Thresholding.BiLevel);
+
+    ## FIXME: implement getDirectoryOffset method
+    # info(dir_idx).Offset = tif.getDirectoryOffset ();
+
+    info(dir_idx).ImageDescription ...
+      = get_tag_defaulted (tif, Tiff.TagID.ImageDescription, "");
+    
+    info(dir_idx).Photoshop ...
+     = get_tag_defaulted (tif, Tiff.TagID.Photoshop, []);
+    
+    info(dir_idx).XMP ...
+      = get_tag_defaulted (tif, Tiff.TagID.XMP, "");
+  endfor
+endfunction
+
+function tag_val = get_tag_defaulted (tif, tag, default_val)
+  tag_val = default_val;
+  try
+    tag_val = tif.getTag (tag);
+  end_try_catch
+endfunction
--- a/scripts/image/private/__tiff_imread__.m	Fri Sep 02 03:41:05 2022 +0200
+++ b/scripts/image/private/__tiff_imread__.m	Fri Sep 02 20:52:47 2022 +0200
@@ -144,7 +144,7 @@
   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.nchannels = img.getTag (Tiff.TagID.SamplesPerPixel);
   info.datatype = img.getTag (Tiff.TagID.SampleFormat);
   info.photometric = img.getTag (Tiff.TagID.Photometric);
 endfunction
\ No newline at end of file