/// <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()); }
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()); }
private ByteVector RenderExifSegment() { IFDTag exif = ImageTag.Exif; if (exif == null) { return(null); } uint first_ifd_offset = 8; var renderer = new IFDRenderer(true, exif.Structure, first_ifd_offset); ByteVector exif_data = renderer.Render(); uint segment_size = (uint)(first_ifd_offset + exif_data.Count + 2 + 6); if (segment_size > ushort.MaxValue) { throw new Exception("Exif Segment is too big to render"); } ByteVector data = new ByteVector(new byte[] { 0xFF, (byte)Marker.APP1 }); data.Add(ByteVector.FromUShort((ushort)segment_size)); data.Add("Exif\0\0"); data.Add(ByteVector.FromString("MM", StringType.Latin1)); data.Add(ByteVector.FromUShort(42)); data.Add(ByteVector.FromUInt(first_ifd_offset)); data.Add(exif_data); return(data); }
public void CheckMakerNote(File file) { IFDTag tag = file.GetTag(TagTypes.TiffIFD) as IFDTag; Assert.IsNotNull(tag, "tag"); var makernote_ifd = tag.ExifIFD.GetEntry(0, (ushort)ExifEntryTag.MakerNote) as MakernoteIFDEntry; Assert.IsNotNull(makernote_ifd, "makernote ifd"); Assert.AreEqual(MakernoteType.Nikon3, makernote_ifd.MakernoteType); var structure = makernote_ifd.Structure; Assert.IsNotNull(structure, "structure"); { var entry = structure.GetEntry(0, 0x01) as UndefinedIFDEntry; Assert.IsNotNull(entry); ByteVector read_bytes = entry.Data; ByteVector expected_bytes = new ByteVector(new byte [] { 48, 50, 49, 48 }); Assert.AreEqual(expected_bytes.Count, read_bytes.Count); for (int i = 0; i < expected_bytes.Count; i++) { Assert.AreEqual(expected_bytes[i], read_bytes[i]); } } { var entry = structure.GetEntry(0, 0x05) as StringIFDEntry; Assert.IsNotNull(entry, "entry 0x05"); Assert.AreEqual("AUTO ", entry.Value); } { var entry = structure.GetEntry(0, 0x09) as StringIFDEntry; Assert.IsNotNull(entry, "entry 0x09"); Assert.AreEqual(" ", entry.Value); } { var entry = structure.GetEntry(0, 0x0B) as SShortArrayIFDEntry; Assert.IsNotNull(entry, "entry 0x0B"); var values = entry.Values; Assert.IsNotNull(values, "values of entry 0x0B"); Assert.AreEqual(2, values.Length); Assert.AreEqual(0, values[0]); Assert.AreEqual(0, values[1]); } { var entry = structure.GetEntry(0, 0x84) as RationalArrayIFDEntry; Assert.IsNotNull(entry, "entry 0x84"); var values = entry.Values; Assert.IsNotNull(values, "values of entry 0x84"); Assert.AreEqual(4, values.Length); Assert.AreEqual(180.0d / 10.0d, (double)values[0]); Assert.AreEqual(2000.0d / 10.0d, (double)values[1]); Assert.AreEqual(35.0d / 10.0d, (double)values[2]); Assert.AreEqual(56.0d / 10.0d, (double)values[3]); } }
public void CheckMakerNote(File file) { IFDTag tag = file.GetTag(TagTypes.TiffIFD) as IFDTag; Assert.IsNotNull(tag, "tag"); var makernote_ifd = tag.ExifIFD.GetEntry(0, (ushort)ExifEntryTag.MakerNote) as MakernoteIFDEntry; Assert.IsNotNull(makernote_ifd, "makernote ifd"); Assert.AreEqual(MakernoteType.Sony, makernote_ifd.MakernoteType); var structure = makernote_ifd.Structure; Assert.IsNotNull(structure, "structure"); //Tag info from http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Sony.html //0x0102: image quality { var entry = structure.GetEntry(0, 0x0102) as LongIFDEntry; Assert.IsNotNull(entry, "entry 0x0102"); Assert.AreEqual(2, entry.Value); } //0x0115: white balance { var entry = structure.GetEntry(0, 0x0115) as LongIFDEntry; Assert.IsNotNull(entry, "entry 0x0115"); Assert.AreEqual(0, entry.Value); } //0xb026: image stabilizer { var entry = structure.GetEntry(0, 0xb026) as LongIFDEntry; Assert.IsNotNull(entry, "entry 0xb026"); Assert.AreEqual(0, entry.Value); } }
public string GetTagString(IFDTag tag) { if (Tags.ContainsKey(tag)) { return(Tags[tag].ValueString); } return(""); }
private void UpdateTags(IFDTag exif) { exif.Structure.RemoveTag(0, (ushort)IFDEntryTag.XMP); XmpTag xmp = ImageTag.Xmp; if (xmp != null) { exif.Structure.AddEntry(0, new ByteVectorIFDEntry((ushort)IFDEntryTag.XMP, xmp.Render())); } }
public void CheckMakerNote(File file) { IFDTag tag = file.GetTag(TagTypes.TiffIFD) as IFDTag; Assert.IsNotNull(tag, "tag"); var makernote_ifd = tag.ExifIFD.GetEntry(0, (ushort)ExifEntryTag.MakerNote) as MakernoteIFDEntry; Assert.IsNotNull(makernote_ifd, "makernote ifd"); Assert.AreEqual(MakernoteType.Olympus2, makernote_ifd.MakernoteType); var structure = makernote_ifd.Structure; Assert.IsNotNull(structure, "structure"); /*{ * var entry = structure.GetEntry (0, 0x01) as UndefinedIFDEntry; * Assert.IsNotNull (entry); * ByteVector read_bytes = entry.Data; * ByteVector expected_bytes = new ByteVector (new byte [] {48, 50, 49, 48}); * * Assert.AreEqual (expected_bytes.Count, read_bytes.Count); * for (int i = 0; i < expected_bytes.Count; i++) * Assert.AreEqual (expected_bytes[i], read_bytes[i]); * } * { * var entry = structure.GetEntry (0, 0x04) as StringIFDEntry; * Assert.IsNotNull (entry, "entry 0x04"); * Assert.AreEqual ("FINE ", entry.Value); * } * { * var entry = structure.GetEntry (0, 0x08) as StringIFDEntry; * Assert.IsNotNull (entry, "entry 0x08"); * Assert.AreEqual ("NORMAL ", entry.Value); * } * { * var entry = structure.GetEntry (0, 0x92) as SShortIFDEntry; * Assert.IsNotNull (entry, "entry 0x92"); * Assert.AreEqual (0, entry.Value); * } * { * var entry = structure.GetEntry (0, 0x9A) as RationalArrayIFDEntry; * Assert.IsNotNull (entry, "entry 0x9A"); * var values = entry.Values; * * Assert.IsNotNull (values, "values of entry 0x9A"); * Assert.AreEqual (2, values.Length); * Assert.AreEqual (78.0d/10.0d, (double) values[0]); * Assert.AreEqual (78.0d/10.0d, (double) values[1]); * }*/ }
private Properties ExtractProperties() { int width = 0, height = 0; IFDTag tag = GetTag(TagTypes.TiffIFD) as IFDTag; width = (int)(tag.ExifIFD.GetLongValue(0, (ushort)ExifEntryTag.PixelXDimension) ?? 0); height = (int)(tag.ExifIFD.GetLongValue(0, (ushort)ExifEntryTag.PixelYDimension) ?? 0); if (width > 0 && height > 0) { return(new Properties(TimeSpan.Zero, new Codec(width, height, "Canon RAW File"))); } return(null); }
/// <summary> /// Gets a tag of a specified type from the current instance, /// optionally creating a new tag if possible. /// </summary> /// <param name="type"> /// A <see cref="TagLib.TagTypes" /> value indicating the /// type of tag to read. /// </param> /// <param name="create"> /// A <see cref="bool" /> value specifying whether or not to /// try and create the tag if one is not found. /// </param> /// <returns> /// A <see cref="Tag" /> object containing the tag that was /// found in or added to the current instance. If no /// matching tag was found and none was created, <see /// langword="null" /> is returned. /// </returns> public override TagLib.Tag GetTag(TagLib.TagTypes type, bool create) { foreach (Tag tag in ImageTag.AllTags) { if ((tag.TagTypes & type) == type) { return(tag); } } if (!create || (type & ImageTag.AllowedTypes) == 0) { return(null); } ImageTag new_tag = null; switch (type) { case TagTypes.JpegComment: new_tag = new JpegCommentTag(); break; case TagTypes.GifComment: new_tag = new GifCommentTag(); break; case TagTypes.Png: new_tag = new PngTag(); break; case TagTypes.TiffIFD: new_tag = new IFDTag(); break; case TagTypes.XMP: new_tag = new XmpTag(); break; } if (new_tag != null) { ImageTag.AddTag(new_tag); return(new_tag); } throw new NotImplementedException(String.Format("Adding tag of type {0} not supported!", type)); }
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); }
private void WriteFile() { IFDTag exif = ImageTag.Exif; if (exif == null) { throw new Exception("Tiff file without tags"); } UpdateTags(exif); uint first_ifd_offset = 8; ByteVector data = RenderHeader(first_ifd_offset); var renderer = new IFDRenderer(IsBigEndian, exif.Structure, first_ifd_offset); data.Add(renderer.Render()); Insert(data, 0, Length); }
private void ReadAPP1Segment(ushort length) { long position = Tell; ByteVector data = null; int exif_header_length = 14; if ((ImageTag.TagTypes & TagLib.TagTypes.TiffIFD) == 0x00 && length >= exif_header_length) { data = ReadBlock(exif_header_length); if (data.Count == exif_header_length && data.Mid(0, 6).ToString().Equals(EXIF_IDENTIFIER)) { bool is_bigendian = data.Mid(6, 2).ToString().Equals("MM"); ushort magic = data.Mid(8, 2).ToUShort(is_bigendian); if (magic != 42) { throw new Exception(String.Format("Invalid TIFF magic: {0}", magic)); } uint ifd_offset = data.Mid(10, 4).ToUInt(is_bigendian); var exif = new IFDTag(); var reader = new IFDReader(this, is_bigendian, exif.Structure, position + 6, ifd_offset, (uint)(length - 6)); reader.Read(); ImageTag.AddTag(exif); AddMetadataBlock(position - 4, length + 4); return; } } int xmp_header_length = XmpTag.XAP_NS.Length + 1; if ((ImageTag.TagTypes & TagLib.TagTypes.XMP) == 0x00 && length >= xmp_header_length) { if (data == null) { data = ReadBlock(xmp_header_length); } else { data.Add(ReadBlock(xmp_header_length - exif_header_length)); } if (data.ToString().Equals(XmpTag.XAP_NS + "\0")) { ByteVector xmp_data = ReadBlock(length - xmp_header_length); ImageTag.AddTag(new XmpTag(xmp_data.ToString(), this)); AddMetadataBlock(position - 4, length + 4); } } }
/// <summary> /// Creates a <see cref="ByteVector"/> for the Exif segment of this file /// </summary> /// <returns> /// A <see cref="ByteVector"/> with the whole Exif segment, if exif tags /// exists, otherwise null. /// </returns> ByteVector RenderExifSegment() { // Check, if IFD0 is contained IFDTag exif = ImageTag.Exif; if (exif == null) { return(null); } // first IFD starts at 8 uint first_ifd_offset = 8; // Render IFD0 // FIXME: store endianess and use it here var renderer = new IFDRenderer(true, exif.Structure, first_ifd_offset); ByteVector exif_data = renderer.Render(); uint segment_size = (uint)(first_ifd_offset + exif_data.Count + 2 + 6); // do not render data segments, which cannot fit into the possible segment size if (segment_size > ushort.MaxValue) { throw new Exception("Exif Segment is too big to render"); } // Create whole segment var data = new ByteVector(new byte[] { 0xFF, (byte)Marker.APP1 }) { ByteVector.FromUShort((ushort)segment_size), "Exif\0\0", ByteVector.FromString("MM", StringType.Latin1), ByteVector.FromUShort(42), ByteVector.FromUInt(first_ifd_offset), // Add ifd data itself exif_data }; return(data); }
public void CheckMakerNote(File file) { IFDTag tag = file.GetTag(TagTypes.TiffIFD) as IFDTag; Assert.IsNotNull(tag, "tag"); var makernote_ifd = tag.ExifIFD.GetEntry(0, (ushort)ExifEntryTag.MakerNote) as MakernoteIFDEntry; Assert.IsNotNull(makernote_ifd, "makernote ifd"); Assert.AreEqual(MakernoteType.Olympus1, makernote_ifd.MakernoteType); var structure = makernote_ifd.Structure; Assert.IsNotNull(structure, "structure"); { var entry = structure.GetEntry(0, 0x0200) as LongArrayIFDEntry; Assert.IsNotNull(entry, "entry 0x0200"); uint[] values = entry.Values; Assert.IsNotNull(values, "values of entry 0x0200"); Assert.AreEqual(3, values.Length); Assert.AreEqual(0, values[0]); Assert.AreEqual(0, values[1]); Assert.AreEqual(0, values[2]); } { var entry = structure.GetEntry(0, 0x0204) as RationalIFDEntry; Assert.IsNotNull(entry, "entry 0x0204"); Assert.AreEqual(100.0d / 100.0d, (double)entry.Value); } { var entry = structure.GetEntry(0, 0x0207) as StringIFDEntry; Assert.IsNotNull(entry, "entry 0x0207"); Assert.AreEqual("D4303", entry.Value); } }
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("---------------------------------------"); }
/// <summary> /// Reads an APP1 segment to find EXIF or XMP metadata. /// </summary> /// <param name="length"> /// The length of the segment that will be read. /// </param> private void ReadAPP1Segment(ushort length) { long position = Tell; ByteVector data = null; // for an Exif segment, the data block consists of 14 bytes of: // * 6 bytes Exif identifier string // * 2 bytes bigendian indication MM (or II) // * 2 bytes Tiff magic number (42) // * 4 bytes offset of the first IFD in this segment // // the last two points are alreay encoded according to // big- or littleendian int exif_header_length = 14; // could be an Exif segment if ((ImageTag.TagTypes & TagLib.TagTypes.TiffIFD) == 0x00 && length >= exif_header_length) { data = ReadBlock(exif_header_length); if (data.Count == exif_header_length && data.Mid(0, 6).ToString().Equals(EXIF_IDENTIFIER)) { bool is_bigendian = data.Mid(6, 2).ToString().Equals("MM"); ushort magic = data.Mid(8, 2).ToUShort(is_bigendian); if (magic != 42) { throw new Exception(String.Format("Invalid TIFF magic: {0}", magic)); } uint ifd_offset = data.Mid(10, 4).ToUInt(is_bigendian); var exif = new IFDTag(); var reader = new IFDReader(this, is_bigendian, exif.Structure, position + 6, ifd_offset, (uint)(length - 6)); reader.Read(); ImageTag.AddTag(exif); AddMetadataBlock(position - 4, length + 4); return; } } int xmp_header_length = XmpTag.XAP_NS.Length + 1; // could be an Xmp segment if ((ImageTag.TagTypes & TagLib.TagTypes.XMP) == 0x00 && length >= xmp_header_length) { // if already data is read for determining the Exif segment, // just read the remaining bytes. // NOTE: that (exif_header_length < xmp_header_length) holds if (data == null) { data = ReadBlock(xmp_header_length); } else { data.Add(ReadBlock(xmp_header_length - exif_header_length)); } if (data.ToString().Equals(XmpTag.XAP_NS + "\0")) { ByteVector xmp_data = ReadBlock(length - xmp_header_length); ImageTag.AddTag(new XmpTag(xmp_data.ToString(), this)); AddMetadataBlock(position - 4, length + 4); } } }
/// <summary> /// Gets a tag of a specified type from the current instance, /// optionally creating a new tag if possible. /// </summary> /// <param name="type"> /// A <see cref="TagLib.TagTypes" /> value indicating the /// type of tag to read. /// </param> /// <param name="create"> /// A <see cref="bool" /> value specifying whether or not to /// try and create the tag if one is not found. /// </param> /// <returns> /// A <see cref="Tag" /> object containing the tag that was /// found in or added to the current instance. If no /// matching tag was found and none was created, <see /// langword="null" /> is returned. /// </returns> public override TagLib.Tag GetTag(TagLib.TagTypes type, bool create) { TagLib.Tag tag = base.GetTag (type, false); if (tag != null) { return tag; } if (!create || (type & ImageTag.AllowedTypes) == 0) return null; if (type != TagTypes.TiffIFD) return base.GetTag (type, create); ImageTag new_tag = new IFDTag (this); ImageTag.AddTag (new_tag); return new_tag; }