/// <summary> /// Attempts to extract the media properties of the main /// photo. /// </summary> /// <returns> /// A <see cref="Properties" /> object with a best effort guess /// at the right values. When no guess at all can be made, /// <see langword="null" /> is returned. /// </returns> private Properties ExtractProperties() { int width = 0, height = 0; IFDTag tag = GetTag(TagTypes.TiffIFD) as IFDTag; IFDStructure structure = tag.Structure; width = (int)(structure.GetLongValue(0, 0x07) ?? 0); height = (int)(structure.GetLongValue(0, 0x06) ?? 0); var vendor = ImageTag.Make; if (vendor == "LEICA") { vendor = "Leica"; } var desc = String.Format("{0} RAW File", vendor); if (width > 0 && height > 0) { return(new Properties(TimeSpan.Zero, new Codec(width, height, desc))); } return(null); }
protected override Properties ExtractProperties() { int width = 0, height = 0; IFDTag tag = GetTag(TagTypes.TiffIFD) as IFDTag; IFDStructure structure = tag.Structure; var sub_ifds = structure.GetEntry(0, (ushort)IFDEntryTag.SubIFDs) as SubIFDArrayEntry; if (sub_ifds == null) { return(base.ExtractProperties()); } foreach (var entry in sub_ifds.Entries) { var type = entry.GetLongValue(0, (ushort)IFDEntryTag.NewSubfileType); if (type == 0) { width = (int)(entry.GetLongValue(0, (ushort)IFDEntryTag.ImageWidth) ?? 0); height = (int)(entry.GetLongValue(0, (ushort)IFDEntryTag.ImageLength) ?? 0); break; } } if (width > 0 && height > 0) { return(new Properties(TimeSpan.Zero, CreateCodec(width, height))); } return(base.ExtractProperties()); }
/// <summary> /// Construcor. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag ID of the entry this instance /// represents /// </param> /// <param name="type"> /// A <see cref="System.UInt16"/> with the type of the IFD entry. /// </param> /// <param name="count"> /// A <see cref="System.UInt32"/> with the count of the IFD entry. /// </param> /// <param name="structure"> /// A <see cref="IFDStructure"/> to be stored /// </param> public SubIFDEntry (ushort tag, ushort type, uint count, IFDStructure structure) { Tag = tag; Type = type; Count = count; Structure = structure; }
/// <summary> /// Try to parse the given IFD entry, used to discover format-specific entries. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag of the entry. /// </param> /// <param name="type"> /// A <see cref="System.UInt16"/> with the type of the entry. /// </param> /// <param name="count"> /// A <see cref="System.UInt32"/> with the data count of the entry. /// </param> /// <param name="base_offset"> /// A <see cref="System.Int64"/> with the base offset which every offsets in the /// IFD are relative to. /// </param> /// <param name="offset"> /// A <see cref="System.UInt32"/> with the offset of the entry. /// </param> /// <returns> /// A <see cref="IFDEntry"/> with the given parameters, or null if none was parsed, after /// which the normal TIFF parsing is used. /// </returns> protected override IFDEntry ParseIFDEntry(ushort tag, ushort type, uint count, long base_offset, uint offset) { if (tag == (ushort)Nikon3MakerNoteEntryTag.Preview) { // SubIFD with Preview Image // The entry itself is usually a long // 2TODO: handle JPEGInterchangeFormat and JPEGInterchangeFormatLength correctly // The preview field contains a long with an offset to an IFD // that contains the preview image. We need to be careful // though: this IFD does not contain a valid next-offset // pointer. For this reason, we only read the first IFD and // ignore the rest (which is preview image data, directly // starting after the IFD entries). type = (ushort)IFDEntryType.IFD; IFDStructure ifd_structure = new IFDStructure(); IFDReader reader = CreateSubIFDReader(file, is_bigendian, ifd_structure, base_offset, offset, max_offset); reader.Read(1); return(new SubIFDEntry(tag, type, (uint)ifd_structure.Directories.Length, ifd_structure)); } return(base.ParseIFDEntry(tag, type, count, base_offset, offset)); }
/// <summary> /// Construcor. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag ID of the entry this instance /// represents /// </param> /// <param name="type"> /// A <see cref="System.UInt16"/> with the type of the IFD entry. /// </param> /// <param name="count"> /// A <see cref="System.UInt32"/> with the count of the IFD entry. /// </param> /// <param name="structure"> /// A <see cref="IFDStructure"/> to be stored /// </param> public SubIFDEntry(ushort tag, ushort type, uint count, IFDStructure structure) { Tag = tag; Type = type; Count = count; Structure = structure; }
/// <summary> /// Attempts to extract the media properties of the main /// photo. /// </summary> /// <returns> /// A <see cref="Properties" /> object with a best effort guess /// at the right values. When no guess at all can be made, /// <see langword="null" /> is returned. /// </returns> protected override Properties ExtractProperties() { int width = 0, height = 0; IFDTag tag = GetTag(TagTypes.TiffIFD) as IFDTag; IFDStructure structure = tag.Structure; // DNG uses SubIFDs for images, the one with SubfileType = 0 is the RAW data. var sub_ifds = structure.GetEntry(0, (ushort)IFDEntryTag.SubIFDs) as SubIFDArrayEntry; if (sub_ifds == null) { return(base.ExtractProperties()); } foreach (var entry in sub_ifds.Entries) { var type = entry.GetLongValue(0, (ushort)IFDEntryTag.NewSubfileType); if (type == 0) { width = (int)(entry.GetLongValue(0, (ushort)IFDEntryTag.ImageWidth) ?? 0); height = (int)(entry.GetLongValue(0, (ushort)IFDEntryTag.ImageLength) ?? 0); break; // No need to iterate the other SubIFDs } } if (width > 0 && height > 0) { return(new Properties(TimeSpan.Zero, CreateCodec(width, height))); } // Fall back to normal detection. return(base.ExtractProperties()); }
/// <summary> /// Construcor. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag ID of the entry this instance /// represents /// </param> /// <param name="structure"> /// A <see cref="IFDStructure"/> with the IFD structure, which is stored by this /// instance /// </param> /// <param name="makernoteType"> /// A <see cref="MakernoteType"/> with the type of the makernote. /// </param> /// <param name="prefix"> /// A <see cref="ByteVector"/> containing the prefix, which should be rendered /// before the real IFD. /// </param> /// <param name="ifdOffset"> /// A <see cref="System.UInt32"/> with the offset in addition to the relative /// offsets in the IFD /// </param> /// <param name="absoluteOffset"> /// A <see cref="System.Boolean"/> indicating if the offsets of the IFD are relative /// to the <paramref name="ifdOffset"/>, or absolut to the base offset of the /// surrounding IFD. /// </param> /// <param name="is_bigendian"> /// A <see cref="System.Nullable"/> indicating if the current IFD is encoded in /// big- or little endian. It it is <see langword="null"/>, the endianess of the /// surrounding IFD is used. /// </param> public MakernoteIFDEntry(ushort tag, IFDStructure structure, MakernoteType makernoteType, ByteVector prefix, uint ifdOffset, bool absoluteOffset, bool?is_bigendian) { Tag = tag; Structure = structure; MakernoteType = makernoteType; this.prefix = prefix; this.ifd_offset = ifdOffset; this.absolute_offset = absoluteOffset; this.is_bigendian = is_bigendian; }
protected override IFDEntry ParseIFDEntry(ushort tag, ushort type, uint count, long base_offset, uint offset) { if (tag == (ushort)Nikon3MakerNoteEntryTag.Preview) { type = (ushort)IFDEntryType.IFD; IFDStructure ifd_structure = new IFDStructure(); IFDReader reader = CreateSubIFDReader(file, is_bigendian, ifd_structure, base_offset, offset, max_offset); reader.Read(1); return(new SubIFDEntry(tag, type, (uint)ifd_structure.Directories.Length, ifd_structure)); } return(base.ParseIFDEntry(tag, type, count, base_offset, offset)); }
protected virtual Properties ExtractProperties() { int width = 0, height = 0; IFDTag tag = GetTag(TagTypes.TiffIFD) as IFDTag; IFDStructure structure = tag.Structure; width = (int)(structure.GetLongValue(0, (ushort)IFDEntryTag.ImageWidth) ?? 0); height = (int)(structure.GetLongValue(0, (ushort)IFDEntryTag.ImageLength) ?? 0); if (width > 0 && height > 0) { return(new Properties(TimeSpan.Zero, CreateCodec(width, height))); } return(null); }
/// <summary> /// Creates an IFD reader to parse the file. /// </summary> /// <param name="file"> /// A <see cref="File"/> to read from. /// </param> /// <param name="is_bigendian"> /// A <see cref="System.Boolean"/>, it must be true, if the data of the IFD should be /// read as bigendian, otherwise false. /// </param> /// <param name="structure"> /// A <see cref="IFDStructure"/> that will be populated. /// </param> /// <param name="base_offset"> /// A <see cref="System.Int64"/> value describing the base were the IFD offsets /// refer to. E.g. in Jpegs the IFD are located in an Segment and the offsets /// inside the IFD refer from the beginning of this segment. So <paramref /// name="base_offset"/> must contain the beginning of the segment. /// </param> /// <param name="ifd_offset"> /// A <see cref="System.UInt32"/> value with the beginning of the IFD relative to /// <paramref name="base_offset"/>. /// </param> /// <param name="max_offset"> /// A <see cref="System.UInt32"/> value with maximal possible offset. This is to limit /// the size of the possible data; /// </param> protected virtual IFDReader CreateIFDReader(BaseTiffFile file, bool is_bigendian, IFDStructure structure, long base_offset, uint ifd_offset, uint max_offset) { return(new IFDReader(file, is_bigendian, structure, base_offset, ifd_offset, max_offset)); }
/// <summary> /// Constructor. Creates a makernote instance just containing an IFD and /// without any special prefix or offset behavior. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag ID of the entry this instance /// represents /// </param> /// <param name="structure"> /// A <see cref="IFDStructure"/> with the IFD structure, which is stored by this /// instance /// </param> /// <param name="makernote_type"> /// A <see cref="MakernoteType"/> with the type of the makernote. /// </param> public MakernoteIFDEntry(ushort tag, IFDStructure structure, MakernoteType makernote_type) : this(tag, structure, makernote_type, null, 0, true, null) { }
static string structDumper(IFDStructure st, ushort tagParentCode, StringBuilder blsExt = null, int recurse = 0) { //Encoding enc = Encoding.GetEncoding(1251); Encoding enc = Encoding.Unicode; string pref = string.Empty; if (recurse > 0) { for (int i = 0; i < recurse; ++i) { pref += "\t"; } } System.Text.StringBuilder bld = blsExt ?? new System.Text.StringBuilder(); bld.AppendFormat("{0}Directories Count = {1}\r\n", pref, st.Directories.Length); Type enumFldType = typeof(IFDEntryTag); if (tagParentCode != 0) { if (tagParentCode == (ushort)IFDEntryTag.ExifIFD) { enumFldType = typeof(ExifEntryTag); } else if (tagParentCode == (ushort)IFDEntryTag.GPSIFD) { enumFldType = typeof(GPSEntryTag); } else if (tagParentCode == (ushort)IFDEntryTag.OPIProxy) { enumFldType = typeof(IOPEntryTag); } } int cnt = 1; foreach (IFDDirectory dir in st.Directories) { bld.AppendFormat("{0}Dir {1}:\r\n", pref, cnt++); foreach (var kv in dir) { string tagName = null; try { tagName = Enum.GetName(enumFldType, kv.Key); } catch { }; if (string.IsNullOrEmpty(tagName)) { tagName = kv.Key.ToString(); } bld.AppendFormat("{0}{1}/{2}: ", pref, tagName, kv.Value.GetType().Name); if (kv.Value.GetType().GetProperty("Value") != null) { dynamic d = kv.Value; bld.Append(d.Value); } if (kv.Value is ByteVectorIFDEntry) { ByteVectorIFDEntry bv = (ByteVectorIFDEntry)kv.Value; bld.AppendFormat(" len = {0}, [{1}]", bv.Data.Data.Length, enc.GetString(bv.Data.Data)); } else if (kv.Value is UndefinedIFDEntry) { UndefinedIFDEntry ue = (UndefinedIFDEntry)kv.Value; bld.AppendFormat(" len = {0}, [{1}]", ue.Data.Data.Length, enc.GetString(ue.Data.Data)); } else if (kv.Value is SubIFDEntry) { SubIFDEntry sub = (SubIFDEntry)kv.Value; structDumper(sub.Structure, sub.Tag, bld, recurse + 1); } bld.AppendLine(); } } return(blsExt == null?bld.ToString() : string.Empty); }
/// <summary> /// Try to parse the given IFD entry, used to discover format-specific entries. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag of the entry. /// </param> /// <param name="type"> /// A <see cref="System.UInt16"/> with the type of the entry. /// </param> /// <param name="count"> /// A <see cref="System.UInt32"/> with the data count of the entry. /// </param> /// <param name="base_offset"> /// A <see cref="System.Int64"/> with the base offset which every offsets in the /// IFD are relative to. /// </param> /// <param name="offset"> /// A <see cref="System.UInt32"/> with the offset of the entry. /// </param> /// <returns> /// A <see cref="IFDEntry"/> with the given parameters, or null if none was parsed, after /// which the normal TIFF parsing is used. /// </returns> protected override IFDEntry ParseIFDEntry (ushort tag, ushort type, uint count, long base_offset, uint offset) { if (tag == (ushort) Nikon3MakerNoteEntryTag.Preview) { // SubIFD with Preview Image // The entry itself is usually a long // TODO: handle JPEGInterchangeFormat and JPEGInterchangeFormatLength correctly // The preview field contains a long with an offset to an IFD // that contains the preview image. We need to be careful // though: this IFD does not contain a valid next-offset // pointer. For this reason, we only read the first IFD and // ignore the rest (which is preview image data, directly // starting after the IFD entries). type = (ushort) IFDEntryType.IFD; IFDStructure ifd_structure = new IFDStructure (); IFDReader reader = CreateSubIFDReader (file, is_bigendian, ifd_structure, base_offset, offset, max_offset); reader.Read (1); return new SubIFDEntry (tag, type, (uint) ifd_structure.Directories.Length, ifd_structure); } return base.ParseIFDEntry (tag, type, count, base_offset, offset); }
/// <summary> /// Constructor. Reads an IFD from given file, using the given endianness. /// </summary> /// <param name="file"> /// A <see cref="File"/> to read from. /// </param> /// <param name="is_bigendian"> /// A <see cref="System.Boolean"/>, it must be true, if the data of the IFD should be /// read as bigendian, otherwise false. /// </param> /// <param name="structure"> /// A <see cref="IFDStructure"/> that will be populated. /// </param> /// <param name="base_offset"> /// A <see cref="System.Int64"/> value describing the base were the IFD offsets /// refer to. E.g. in Jpegs the IFD are located in an Segment and the offsets /// inside the IFD refer from the beginning of this segment. So <paramref /// name="base_offset"/> must contain the beginning of the segment. /// </param> /// <param name="ifd_offset"> /// A <see cref="System.UInt32"/> value with the beginning of the IFD relative to /// <paramref name="base_offset"/>. /// </param> /// <param name="max_offset"> /// A <see cref="System.UInt32"/> value with maximal possible offset. This is to limit /// the size of the possible data; /// </param> public Nikon3MakernoteReader (File file, bool is_bigendian, IFDStructure structure, long base_offset, uint ifd_offset, uint max_offset) : base (file, is_bigendian, structure, base_offset, ifd_offset, max_offset) { }
/// <summary> /// Constructor. Reads an IFD from given file, using the given endianness. /// </summary> /// <param name="file"> /// A <see cref="File"/> to read from. /// </param> /// <param name="is_bigendian"> /// A <see cref="System.Boolean"/>, it must be true, if the data of the IFD should be /// read as bigendian, otherwise false. /// </param> /// <param name="structure"> /// A <see cref="IFDStructure"/> that will be populated. /// </param> /// <param name="base_offset"> /// A <see cref="System.Int64"/> value describing the base were the IFD offsets /// refer to. E.g. in Jpegs the IFD are located in an Segment and the offsets /// inside the IFD refer from the beginning of this segment. So <paramref /// name="base_offset"/> must contain the beginning of the segment. /// </param> /// <param name="ifd_offset"> /// A <see cref="System.UInt32"/> value with the beginning of the IFD relative to /// <paramref name="base_offset"/>. /// </param> /// <param name="max_offset"> /// A <see cref="System.UInt32"/> value with maximal possible offset. This is to limit /// the size of the possible data; /// </param> public IFDReader(BaseTiffFile file, bool is_bigendian, IFDStructure structure, long base_offset, uint ifd_offset, uint max_offset) : base(file, is_bigendian, structure, base_offset, ifd_offset, max_offset) { }
/// <summary> /// Constructor. Reads an IFD from given file, using the given endianness. /// </summary> /// <param name="file"> /// A <see cref="File"/> to read from. /// </param> /// <param name="is_bigendian"> /// A <see cref="System.Boolean"/>, it must be true, if the data of the IFD should be /// read as bigendian, otherwise false. /// </param> /// <param name="structure"> /// A <see cref="IFDStructure"/> that will be populated. /// </param> /// <param name="base_offset"> /// A <see cref="System.Int64"/> value describing the base were the IFD offsets /// refer to. E.g. in Jpegs the IFD are located in an Segment and the offsets /// inside the IFD refer from the beginning of this segment. So <paramref /// name="base_offset"/> must contain the beginning of the segment. /// </param> /// <param name="ifd_offset"> /// A <see cref="System.UInt32"/> value with the beginning of the IFD relative to /// <paramref name="base_offset"/>. /// </param> /// <param name="max_offset"> /// A <see cref="System.UInt32"/> value with maximal possible offset. This is to limit /// the size of the possible data; /// </param> public Nikon3MakernoteReader(File file, bool is_bigendian, IFDStructure structure, long base_offset, uint ifd_offset, uint max_offset) : base(file, is_bigendian, structure, base_offset, ifd_offset, max_offset) { }
/// <summary> /// Construcor. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag ID of the entry this instance /// represents /// </param> /// <param name="structure"> /// A <see cref="IFDStructure"/> with the IFD structure, which is stored by this /// instance /// </param> /// <param name="makernote_type"> /// A <see cref="MakernoteType"/> with the type of the makernote. /// </param> /// <param name="prefix"> /// A <see cref="ByteVector"/> containing the prefix, which should be rendered /// before the real IFD. /// </param> /// <param name="ifd_offset"> /// A <see cref="System.UInt32"/> with the offset in addition to the relative /// offsets in the IFD /// </param> /// <param name="absolute_offset"> /// A <see cref="System.Boolean"/> indicating if the offsets of the IFD are relative /// to the <paramref name="ifd_offset"/>, or absolut to the base offset of the /// surrounding IFD. /// </param> /// <param name="is_bigendian"> /// A <see cref="System.Nullable"/> indicating if the current IFD is encoded in /// big- or little endian. It it is <see langword="null"/>, the endianess of the /// surrounding IFD is used. /// </param> public MakernoteIFDEntry (ushort tag, IFDStructure structure, MakernoteType makernote_type, ByteVector prefix, uint ifd_offset, bool absolute_offset, bool? is_bigendian) { Tag = tag; Structure = structure; MakernoteType = makernote_type; this.prefix = prefix; this.ifd_offset = ifd_offset; this.absolute_offset = absolute_offset; this.is_bigendian = is_bigendian; }
/// <summary> /// Constructor. Creates a makernote instance just containing an IFD and /// without any special prefix or offset behavior. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag ID of the entry this instance /// represents /// </param> /// <param name="structure"> /// A <see cref="IFDStructure"/> with the IFD structure, which is stored by this /// instance /// </param> /// <param name="makernote_type"> /// A <see cref="MakernoteType"/> with the type of the makernote. /// </param> public MakernoteIFDEntry (ushort tag, IFDStructure structure, MakernoteType makernote_type) : this (tag, structure, makernote_type, null, 0, true, null) {}
static void ParsePhoto(string path) { TagLib.File file = null; try { file = TagLib.File.Create(path); } catch (TagLib.UnsupportedFormatException) { Console.WriteLine("UNSUPPORTED FILE: " + path); Console.WriteLine(String.Empty); Console.WriteLine("---------------------------------------"); Console.WriteLine(String.Empty); return; } var image = file as TagLib.Image.File; if (file == null) { Console.WriteLine("NOT AN IMAGE FILE: " + path); Console.WriteLine(String.Empty); Console.WriteLine("---------------------------------------"); Console.WriteLine(String.Empty); return; } Console.WriteLine(String.Empty); Console.WriteLine(path); Console.WriteLine(String.Empty); Console.WriteLine("Tags in object : " + image.TagTypes); Console.WriteLine(String.Empty); Console.WriteLine("Comment : " + image.ImageTag.Comment); Console.Write("Keywords : "); foreach (var keyword in image.ImageTag.Keywords) { Console.Write(keyword + " "); } Console.WriteLine(String.Empty); Console.WriteLine("Title : " + image.ImageTag.Title); Console.WriteLine("Copyright : " + image.ImageTag.Copyright); Console.WriteLine(); Console.WriteLine("Rating : " + image.ImageTag.Rating); Console.WriteLine("DateTime : " + image.ImageTag.DateTime); Console.WriteLine("Orientation : " + image.ImageTag.Orientation); Console.WriteLine("Software : " + image.ImageTag.Software); Console.WriteLine("ExposureTime : " + image.ImageTag.ExposureTime); Console.WriteLine("FNumber : " + image.ImageTag.FNumber); Console.WriteLine("ISOSpeedRatings : " + image.ImageTag.ISOSpeedRatings); Console.WriteLine("FocalLength : " + image.ImageTag.FocalLength); Console.WriteLine("FocalLength35mm : " + image.ImageTag.FocalLengthIn35mmFilm); Console.WriteLine("Make : " + image.ImageTag.Make); Console.WriteLine("Model : " + image.ImageTag.Model); if (image.Properties != null) { Console.WriteLine("Width : " + image.Properties.PhotoWidth); Console.WriteLine("Height : " + image.Properties.PhotoHeight); Console.WriteLine("Type : " + image.Properties.Description); } Console.WriteLine(); Console.WriteLine("Writable? : " + image.Writeable.ToString()); Console.WriteLine("Corrupt? : " + image.PossiblyCorrupt.ToString()); if (image.PossiblyCorrupt) { foreach (string reason in image.CorruptionReasons) { Console.WriteLine(" * " + reason); } } Console.WriteLine("tag types = " + file.TagTypes); string lens = image.ImageTag.Xmp.GetLangAltNode("http://ns.adobe.com/exif/1.0/aux/", "Lens"); Console.WriteLine("Lens = " + lens); IFDTag tag = file.GetTag(TagTypes.TiffIFD) as IFDTag; IFDStructure struc = tag.Structure; Console.WriteLine(structDumper(struc, (ushort)0)); /*SubIFDEntry sub = struc.GetEntry(0, (ushort)IFDEntryTag.ExifIFD) as SubIFDEntry; * IFDStructure exif_structure = sub.Structure; * MakernoteIFDEntry makernote = exif_structure.GetEntry(0, (ushort)ExifEntryTag.MakerNote) as MakernoteIFDEntry; * makernote = struc.GetEntry(0, (ushort)ExifEntryTag.MakerNote) as MakernoteIFDEntry; * IFDStructure makernote_struct = makernote.Structure; * IFDEntry entry = makernote_struct.GetEntry(0, (ushort)CanonMakerNoteEntryTag.LensModel); * Console.WriteLine("Lens : " + (entry as StringIFDEntry).Value);*/ Console.WriteLine("---------------------------------------"); }