private bool ProcessApp1Data(byte[] data, out DateTime dateTaken) { dateTaken = DateTime.MinValue; if (CheckTiffHeader(data, out bool isLittleEndian, out int ifdOffset) == false || ifdOffset <= 0) { return(false); } int workOffset = ifdOffset; bool isSubstituteFound = false; DateTime substituteDateTaken = DateTime.MinValue; while (workOffset > 0) { workOffset += 6; // 6 is exif header size // exif spec says all offsets start from tiff header, but current buffer starts from exif header int directoryCount; if (isLittleEndian) { directoryCount = BitConverter.ToInt16(data, workOffset); } else { directoryCount = BitConverterBE.ToInt16(data, workOffset); } workOffset += 2; bool subIFDFound = false; for (int i = 0; i < directoryCount; i++) { var ifd = ImageFileDirectory.Read(isLittleEndian, data, workOffset); if (ifd.Tag == SUBIFD) { if (isLittleEndian) { workOffset = BitConverter.ToInt32(ifd.Value.Array, ifd.Value.Offset); } else { workOffset = BitConverterBE.ToInt32(ifd.Value.Array, ifd.Value.Offset); } subIFDFound = true; break; } if (ifd.Tag == 306) { if (ifd.Type != 2 || ifd.Value.Count != 20) { continue; } isSubstituteFound = TryParseDateTime(ifd.Value.Array, ifd.Value.Offset, ifd.Value.Count, out substituteDateTaken); } else if (ifd.Tag == 0x9003 || ifd.Tag == 0x9004) { if (ifd.Type != 2 || ifd.Value.Count != 20) { return(false); } if (TryParseDateTime(ifd.Value.Array, ifd.Value.Offset, ifd.Value.Count, out dateTaken)) { return(true); } } workOffset += 12; } if (subIFDFound) { continue; } if (isLittleEndian) { workOffset = BitConverter.ToInt32(data, workOffset); } else { workOffset = BitConverterBE.ToInt32(data, workOffset); } } if (isSubstituteFound) { dateTaken = substituteDateTaken; return(true); } return(false); }
internal static ImageFileDirectory Read(bool isLittleEndian, byte[] data, int offset) { var ifd = new ImageFileDirectory(); if (isLittleEndian) { ifd.Tag = BitConverter.ToUInt16(data, offset); } else { ifd.Tag = BitConverterBE.ToUInt16(data, offset); } if (isLittleEndian) { ifd.Type = BitConverter.ToUInt16(data, offset + 2); } else { ifd.Type = BitConverterBE.ToUInt16(data, offset + 2); } uint components; uint dataOffset; if (isLittleEndian) { components = BitConverter.ToUInt32(data, offset + 4); } else { components = BitConverterBE.ToUInt32(data, offset + 4); } if (isLittleEndian) { dataOffset = BitConverter.ToUInt32(data, offset + 8) + 6; } else { dataOffset = BitConverterBE.ToUInt32(data, offset + 8) + 6; } uint componentSize = 1; if (ifd.Type == 3 || ifd.Type == 8) { componentSize = 2; } else if (ifd.Type == 4 || ifd.Type == 9 || ifd.Type == 11) { componentSize = 4; } else if (ifd.Type == 5 || ifd.Type == 10 || ifd.Type == 12) { componentSize = 8; } uint totalByteLength = componentSize * components; if (totalByteLength <= 4) { ifd.Value = new ArraySegment <byte>(data, offset + 8, (int)totalByteLength); } else { ifd.Value = new ArraySegment <byte>(data, (int)dataOffset, (int)totalByteLength); } return(ifd); }