public IFDEntry(EndianBinaryReader reader) { Tag = reader.ReadUInt16(); Type = (ExifValueType)reader.ReadInt16(); Count = reader.ReadUInt32(); Offset = reader.ReadUInt32(); }
/// <summary> /// Parses the EXIF data into a collection of properties. /// </summary> /// <param name="exifBytes">The EXIF bytes.</param> /// <returns> /// A collection containing the EXIF properties. /// </returns> /// <exception cref="ArgumentNullException"><paramref name="exifBytes"/> is null.</exception> internal static ExifValueCollection Parse(byte[] exifBytes) { if (exifBytes == null) { throw new ArgumentNullException(nameof(exifBytes)); } List <MetadataEntry> metadataEntries = new List <MetadataEntry>(); MemoryStream stream = null; try { stream = new MemoryStream(exifBytes); Endianess?byteOrder = TryDetectTiffByteOrder(stream); if (byteOrder.HasValue) { using (EndianBinaryReader reader = new EndianBinaryReader(stream, byteOrder.Value)) { stream = null; ushort signature = reader.ReadUInt16(); if (signature == TiffConstants.Signature) { uint ifdOffset = reader.ReadUInt32(); List <ParserIFDEntry> entries = ParseDirectories(reader, ifdOffset); metadataEntries.AddRange(ConvertIFDEntriesToMetadataEntries(reader, entries)); } } } } catch (EndOfStreamException) { } finally { stream?.Dispose(); } return(new ExifValueCollection(metadataEntries)); }
private static List <ParserIFDEntry> ParseDirectories(EndianBinaryReader reader, uint firstIFDOffset) { List <ParserIFDEntry> items = new List <ParserIFDEntry>(); bool foundExif = false; bool foundGps = false; bool foundInterop = false; Queue <MetadataOffset> ifdOffsets = new Queue <MetadataOffset>(); ifdOffsets.Enqueue(new MetadataOffset(MetadataSection.Image, firstIFDOffset)); while (ifdOffsets.Count > 0) { MetadataOffset metadataOffset = ifdOffsets.Dequeue(); MetadataSection section = metadataOffset.Section; uint offset = metadataOffset.Offset; if (offset >= reader.Length) { continue; } reader.Position = offset; ushort count = reader.ReadUInt16(); if (count == 0) { continue; } items.Capacity += count; for (int i = 0; i < count; i++) { ParserIFDEntry entry = new ParserIFDEntry(reader, section); switch (entry.Tag) { case TiffConstants.Tags.ExifIFD: if (!foundExif) { foundExif = true; ifdOffsets.Enqueue(new MetadataOffset(MetadataSection.Exif, entry.Offset)); } break; case TiffConstants.Tags.GpsIFD: if (!foundGps) { foundGps = true; ifdOffsets.Enqueue(new MetadataOffset(MetadataSection.Gps, entry.Offset)); } break; case TiffConstants.Tags.InteropIFD: if (!foundInterop) { foundInterop = true; ifdOffsets.Enqueue(new MetadataOffset(MetadataSection.Interop, entry.Offset)); } break; case TiffConstants.Tags.StripOffsets: case TiffConstants.Tags.RowsPerStrip: case TiffConstants.Tags.StripByteCounts: case TiffConstants.Tags.SubIFDs: case TiffConstants.Tags.ThumbnailOffset: case TiffConstants.Tags.ThumbnailLength: // Skip the thumbnail and/or preview images. // The StripOffsets and StripByteCounts tags are used to store a preview image in some formats. // The SubIFDs tag is used to store thumbnails in TIFF and for storing other data in some camera formats. // // Note that some cameras will also store a thumbnail as part of their private data in the EXIF MakerNote tag. // The EXIF MakerNote tag is treated as an opaque blob, so those thumbnails will be preserved. break; default: items.Add(entry); break; } System.Diagnostics.Debug.WriteLine(entry.ToString()); } } return(items); }