/// <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)); }
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)); }
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> /// 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); } } }