Mercurial > octave-libtiff
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