Esempio n. 1
0
        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);
        }
Esempio n. 2
0
#pragma warning restore IDE0032 // Use auto property

            public ParserIFDEntry(EndianBinaryReader reader, MetadataSection section)
            {
                entry             = new IFDEntry(reader);
                offsetIsBigEndian = reader.Endianess == Endianess.Big;
                Section           = section;
            }
Esempio n. 3
0
        private static ICollection <MetadataEntry> ConvertIFDEntriesToMetadataEntries(EndianBinaryReader reader, List <ParserIFDEntry> entries)
        {
            List <MetadataEntry> metadataEntries = new List <MetadataEntry>(entries.Count);
            bool swapNumberByteOrder             = reader.Endianess == Endianess.Big;

            for (int i = 0; i < entries.Count; i++)
            {
                ParserIFDEntry entry = entries[i];

                byte[] propertyData;
                if (entry.OffsetFieldContainsValue)
                {
                    propertyData = entry.GetValueBytesFromOffset();
                    if (propertyData == null)
                    {
                        continue;
                    }
                }
                else
                {
                    long bytesToRead = entry.Count * TagDataTypeUtil.GetSizeInBytes(entry.Type);

                    // Skip any tags that are empty or larger than 2 GB.
                    if (bytesToRead == 0 || bytesToRead > int.MaxValue)
                    {
                        continue;
                    }

                    uint offset = entry.Offset;

                    if ((offset + bytesToRead) > reader.Length)
                    {
                        continue;
                    }

                    reader.Position = offset;

                    propertyData = reader.ReadBytes((int)bytesToRead);

                    if (swapNumberByteOrder)
                    {
                        // Paint.NET converts all multi-byte numbers to little-endian.
                        switch (entry.Type)
                        {
                        case TagDataType.Short:
                        case TagDataType.SShort:
                            propertyData = SwapShortArrayToLittleEndian(propertyData, entry.Count);
                            break;

                        case TagDataType.Long:
                        case TagDataType.SLong:
                        case TagDataType.Float:
                            propertyData = SwapLongArrayToLittleEndian(propertyData, entry.Count);
                            break;

                        case TagDataType.Rational:
                        case TagDataType.SRational:
                            propertyData = SwapRationalArrayToLittleEndian(propertyData, entry.Count);
                            break;

                        case TagDataType.Double:
                            propertyData = SwapDoubleArrayToLittleEndian(propertyData, entry.Count);
                            break;

                        case TagDataType.Byte:
                        case TagDataType.Ascii:
                        case TagDataType.Undefined:
                        case TagDataType.SByte:
                        default:
                            break;
                        }
                    }
                }

                metadataEntries.Add(new MetadataEntry(entry.Section, entry.Tag, entry.Type, propertyData));
            }

            return(metadataEntries);
        }