/// <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)); }
/// <summary> /// Update the XMP stored in the Tiff IFD /// </summary> /// <param name="exif"> /// A <see cref="IFDTag"/> The Tiff IFD to update the entries /// </param> private void UpdateTags (IFDTag exif) { // update the XMP entry 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 ())); }
/// <summary> /// Reads the file with a specified read style. /// </summary> /// <param name="propertiesStyle"> /// A <see cref="ReadStyle" /> value specifying at what level /// of accuracy to read the media properties, or <see /// cref="ReadStyle.None" /> to ignore the properties. /// </param> private void Read (ReadStyle propertiesStyle) { Mode = AccessMode.Read; try { uint offset = ReadFirstIFDOffset (); var ifd_tag = new IFDTag (); var reader = new IFDReader (this, is_bigendian, ifd_tag.Structure, 0, offset, (uint) Length); reader.Read (); ImageTag.AddTag (ifd_tag); // Find XMP data var xmp_entry = ifd_tag.Structure.GetEntry (0, (ushort) IFDEntryTag.XMP) as ByteVectorIFDEntry; if (xmp_entry != null) { ImageTag.AddTag (new XmpTag (xmp_entry.Data.ToString ())); } if (propertiesStyle == ReadStyle.None) return; properties = ExtractProperties (); } finally { Mode = AccessMode.Closed; } }
/// <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); } } }