예제 #1
0
        /// <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);
        }
예제 #2
0
        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());
        }
예제 #3
0
		/// <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;
		}
예제 #4
0
        /// <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));
        }
예제 #5
0
 /// <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;
 }
예제 #6
0
        /// <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());
        }
예제 #7
0
 /// <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;
 }
예제 #8
0
 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));
 }
예제 #9
0
        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);
        }
예제 #10
0
 /// <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));
 }
예제 #11
0
 /// <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)
 {
 }
예제 #12
0
        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)
		{
		}
예제 #15
0
 /// <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)
 {
 }
예제 #16
0
 /// <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)
 {
 }
예제 #17
0
		/// <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;
		}
예제 #18
0
		/// <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) {}
예제 #19
0
    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("---------------------------------------");
    }