// Я решил возвращать не просто строку, но пару ключ-значение. Я думаю, это пригодится, когда я изменю дизайн // Exif-окна (вместо textbox - listview с двумя столбиками) public ExifTag ReadTag(BinaryReader reader, long tiffHeader, long dirEntryTag) { reader.BaseStream.Seek(dirEntryTag, SeekOrigin.Begin); ushort tag = EndiannessIO.ReadUInt16(reader.ReadUInt16(), LittleEndian.Value); ushort type = EndiannessIO.ReadUInt16(reader.ReadUInt16(), LittleEndian.Value); uint count = EndiannessIO.ReadUInt32(reader.ReadUInt32(), LittleEndian.Value); byte[] valueOrOffset = BitConverter.GetBytes(EndiannessIO.ReadUInt32(reader.ReadUInt32(), !LittleEndian.Value)); ExifTag currentExifTag = LoadedExifTags.Any((pair) => { return(pair.Key == tag); }) ? new ExifTag(tag, LoadedExifTags.First(item => item.Key == tag).Value, "") : new ExifTag(tag, $"Unknown Tag: {tag:X}", ""); switch (type) { case (int)IFDTypeEnum.Byte: case (int)IFDTypeEnum.Undefined: if (count == 1) { currentExifTag.TagValue = Encoding.ASCII.GetString(reader.ReadBytes(2)); break; } reader.BaseStream.Seek( (count > 4) ? EndiannessIO.ReadUInt32( BitConverter.ToUInt32(valueOrOffset, 0), false) + tiffHeader : dirEntryTag + 8, SeekOrigin.Begin ); currentExifTag.TagValue = Encoding.ASCII.GetString( reader.ReadBytes((count != 0) ? (int)count - 1 : 0) ); break; case (int)IFDTypeEnum.ASCII: reader.BaseStream.Seek( (count > 4) ? EndiannessIO.ReadUInt32( BitConverter.ToUInt32(valueOrOffset, 0), false) + tiffHeader : dirEntryTag + 8, SeekOrigin.Begin ); currentExifTag.TagValue = Encoding.ASCII.GetString( reader.ReadBytes((count != 0) ? (int)count - 1 : 0) ); break; case (int)IFDTypeEnum.Short: reader.BaseStream.Seek( (count > 2) ? EndiannessIO.ReadUInt32( BitConverter.ToUInt32(valueOrOffset, 0), false) + tiffHeader : dirEntryTag + 8, SeekOrigin.Begin ); for (int i = 0; i < count; i++) { currentExifTag.TagValue += EndiannessIO.ReadUInt16(reader.ReadUInt16(), LittleEndian.Value); } break; case (int)IFDTypeEnum.Long: reader.BaseStream.Seek( (count > 1) ? EndiannessIO.ReadUInt32( BitConverter.ToUInt32(valueOrOffset, 0), false) + tiffHeader : dirEntryTag + 8, SeekOrigin.Begin ); for (int i = 0; i < count; i++) { currentExifTag.TagValue += EndiannessIO.ReadUInt32(reader.ReadUInt32(), LittleEndian.Value).ToString(); } break; case (int)IFDTypeEnum.Rational: reader.BaseStream.Seek( EndiannessIO.ReadUInt32( BitConverter.ToUInt32(valueOrOffset, 0), false) + tiffHeader, SeekOrigin.Begin); for (int i = 0; i < count; i++) { uint numerator = EndiannessIO.ReadUInt32(reader.ReadUInt32(), LittleEndian.Value); uint denominator = EndiannessIO.ReadUInt32(reader.ReadUInt32(), LittleEndian.Value); currentExifTag.TagValue += $"{numerator / (denominator * 1.0)} [{numerator}/{denominator}] "; } break; case (int)IFDTypeEnum.SLong: reader.BaseStream.Seek( (count > 1) ? EndiannessIO.ReadUInt32( BitConverter.ToUInt32(valueOrOffset, 0), false) + tiffHeader : dirEntryTag + 8, SeekOrigin.Begin ); for (int i = 0; i < count; i++) { currentExifTag.TagValue += EndiannessIO.ReadInt32(reader.ReadInt32(), LittleEndian.Value).ToString(); } break; case (int)IFDTypeEnum.SRational: reader.BaseStream.Seek( EndiannessIO.ReadUInt32( BitConverter.ToUInt32(valueOrOffset, 0), false) + tiffHeader, SeekOrigin.Begin); for (int i = 0; i < count; i++) { int numerator = EndiannessIO.ReadInt32(reader.ReadInt32(), LittleEndian.Value); int denominator = EndiannessIO.ReadInt32(reader.ReadInt32(), LittleEndian.Value); currentExifTag.TagValue += $"{numerator / (denominator * 1.0)} [{numerator}/{denominator}] "; } break; } reader.BaseStream.Seek(tiffHeader, SeekOrigin.Begin); return(currentExifTag); }
private List <ExifTag> ReadTagsInFileStream(BinaryReader reader) // Поиск тегов в файле { List <ExifTag> foundTags = new List <ExifTag>(); LittleEndian = CheckEndiannessInStream(reader); long tiffPosition = reader.BaseStream.Position; reader.BaseStream.Seek(4, SeekOrigin.Current); uint firstIFDOffset = reader.ReadUInt32(); ushort entries = reader.ReadUInt16(); if (LittleEndian.HasValue) { if (!LittleEndian.Value) { firstIFDOffset = EndiannessIO.ReadUInt32(firstIFDOffset, LittleEndian.Value); entries = EndiannessIO.ReadUInt16(entries, LittleEndian.Value); } } else { foundTags.Add(new ExifTag(0, null, "Неверные данные TIFF (Отсутствует порядок байтов)")); return(foundTags); } if (firstIFDOffset < 0x00000008) { foundTags.Add(new ExifTag(0, null, "Неверные данные TIFF (Неправильное смещение IFD)")); return(foundTags); } long dirPosition = tiffPosition + firstIFDOffset; // вначале читаем 0 IFD, в котором лежат данные TIFF for (int i = 0; i < entries; i++) { foundTags.Add(ReadTag(reader, tiffPosition, 2 + dirPosition + i * 12)); // набросок } // Указатель на Exif IFD ExifTag exifPointerTag = foundTags.Find((tag) => tag.Tag == 0x8769); if (exifPointerTag != null) { // Я думаю, что здесь и в условии с GPS надо повторить все колдунство сверху в пределах функции long exifPointerPosition = tiffPosition + long.Parse(exifPointerTag.TagValue); reader.BaseStream.Seek(exifPointerPosition, SeekOrigin.Begin); entries = EndiannessIO.ReadUInt16(reader.ReadUInt16(), LittleEndian.Value); for (int i = 0; i < entries; i++) { foundTags.Add(ReadTag(reader, tiffPosition, 2 + exifPointerPosition + i * 12)); } } // Указатель на GPS IFD ExifTag gpsPointerTag = foundTags.Find((tag) => tag.Tag == 0x8825); if (gpsPointerTag != null) { long gpsPointerPosition = tiffPosition + long.Parse(gpsPointerTag.TagValue); reader.BaseStream.Seek(gpsPointerPosition, SeekOrigin.Begin); entries = EndiannessIO.ReadUInt16(reader.ReadUInt16(), LittleEndian.Value); for (int i = 0; i < entries; i++) { foundTags.Add(ReadTag(reader, tiffPosition, 2 + gpsPointerPosition + i * 12)); } } return(foundTags); }