Пример #1
0
 public override void Completed(RandomAccessReader reader, int tiffHeaderOffset)
 {
     if (_storeThumbnailBytes)
     {
         // after the extraction process, if we have the correct tags, we may be able to store thumbnail information
         ExifThumbnailDirectory thumbnailDirectory = _metadata.GetDirectory <ExifThumbnailDirectory>();
         if (thumbnailDirectory != null && thumbnailDirectory.ContainsTag(ExifThumbnailDirectory.TagThumbnailCompression))
         {
             int?offset = thumbnailDirectory.GetInteger(ExifThumbnailDirectory.TagThumbnailOffset);
             int?length = thumbnailDirectory.GetInteger(ExifThumbnailDirectory.TagThumbnailLength);
             if (offset != null && length != null)
             {
                 try
                 {
                     sbyte[] thumbnailData = reader.GetBytes(tiffHeaderOffset + offset.Value, length.Value);
                     thumbnailDirectory.SetThumbnailData(thumbnailData);
                 }
                 catch (IOException ex)
                 {
                     thumbnailDirectory.AddError("Invalid thumbnail data specification: " + ex.Message);
                 }
             }
         }
     }
 }
Пример #2
0
        public virtual void TestThumbnailCompression()
        {
            ExifThumbnailDirectory directory = ExifReaderTest.ProcessBytes <ExifThumbnailDirectory>("Tests/Data/manuallyAddedThumbnail.jpg.app1");

            // 6 means JPEG compression
            Sharpen.Tests.AreEqual(6, directory.GetInt(ExifThumbnailDirectory.TagThumbnailCompression));
        }
 public virtual void SetUp()
 {
     Com.Drew.Metadata.Metadata metadata = ExifReaderTest.ProcessBytes("Tests/Data/nikonMakernoteType1.jpg.app1");
     _nikonDirectory = metadata.GetFirstDirectoryOfType<NikonType1MakernoteDirectory>();
     _exifSubIFDDirectory = metadata.GetFirstDirectoryOfType<ExifSubIFDDirectory>();
     _exifIFD0Directory = metadata.GetFirstDirectoryOfType<ExifIFD0Directory>();
     _thumbDirectory = metadata.GetFirstDirectoryOfType<ExifThumbnailDirectory>();
 }
Пример #4
0
        public virtual void TestThumbnailData()
        {
            ExifThumbnailDirectory directory = ExifReaderTest.ProcessBytes <ExifThumbnailDirectory>("Tests/Data/manuallyAddedThumbnail.jpg.app1");

            sbyte[] thumbnailData = directory.GetThumbnailData();
            NUnit.Framework.Assert.IsNotNull(thumbnailData);
            Sharpen.Tests.AreEqual(2970, thumbnailData.Length);
        }
Пример #5
0
 public virtual void SetUp()
 {
     Com.Drew.Metadata.Metadata metadata = ExifReaderTest.ProcessBytes("Tests/Data/nikonMakernoteType1.jpg.app1");
     _nikonDirectory      = metadata.GetDirectory <NikonType1MakernoteDirectory>();
     _exifSubIFDDirectory = metadata.GetDirectory <ExifSubIFDDirectory>();
     _exifIFD0Directory   = metadata.GetDirectory <ExifIFD0Directory>();
     _thumbDirectory      = metadata.GetDirectory <ExifThumbnailDirectory>();
 }
Пример #6
0
        public virtual void TestThumbnailYResolution()
        {
            ExifThumbnailDirectory directory = ExifReaderTest.ProcessBytes <ExifThumbnailDirectory>("Tests/Data/manuallyAddedThumbnail.jpg.app1");
            Rational rational = directory.GetRational(ExifThumbnailDirectory.TagYResolution);

            NUnit.Framework.Assert.IsNotNull(rational);
            Sharpen.Tests.AreEqual(72, rational.GetNumerator());
            Sharpen.Tests.AreEqual(1, rational.GetDenominator());
        }
 public virtual void SetUp()
 {
     Com.Drew.Metadata.Metadata metadata = ExifReaderTest.ProcessBytes("Tests/Data/nikonMakernoteType2b.jpg.app1");
     _nikonDirectory      = metadata.GetFirstDirectoryOfType <NikonType2MakernoteDirectory>();
     _exifIFD0Directory   = metadata.GetFirstDirectoryOfType <ExifIFD0Directory>();
     _exifSubIFDDirectory = metadata.GetFirstDirectoryOfType <ExifSubIFDDirectory>();
     _thumbDirectory      = metadata.GetFirstDirectoryOfType <ExifThumbnailDirectory>();
     NUnit.Framework.Assert.IsNotNull(_nikonDirectory);
     NUnit.Framework.Assert.IsNotNull(_exifSubIFDDirectory);
 }
		public virtual void SetUp()
		{
			Com.Drew.Metadata.Metadata metadata = ExifReaderTest.ProcessBytes("Tests/Data/nikonMakernoteType2b.jpg.app1");
			_nikonDirectory = metadata.GetDirectory<NikonType2MakernoteDirectory>();
			_exifIFD0Directory = metadata.GetDirectory<ExifIFD0Directory>();
			_exifSubIFDDirectory = metadata.GetDirectory<ExifSubIFDDirectory>();
			_thumbDirectory = metadata.GetDirectory<ExifThumbnailDirectory>();
			NUnit.Framework.Assert.IsNotNull(_nikonDirectory);
			NUnit.Framework.Assert.IsNotNull(_exifSubIFDDirectory);
		}
		public virtual void TestGetYCbCrSubsamplingDescription()
		{
			ExifThumbnailDirectory directory = new ExifThumbnailDirectory();
			directory.SetIntArray(ExifThumbnailDirectory.TagYcbcrSubsampling, new int[] { 2, 1 });
			ExifThumbnailDescriptor descriptor = new ExifThumbnailDescriptor(directory);
			Sharpen.Tests.AreEqual("YCbCr4:2:2", descriptor.GetDescription(ExifThumbnailDirectory.TagYcbcrSubsampling));
			Sharpen.Tests.AreEqual("YCbCr4:2:2", descriptor.GetYCbCrSubsamplingDescription());
			directory.SetIntArray(ExifThumbnailDirectory.TagYcbcrSubsampling, new int[] { 2, 2 });
			Sharpen.Tests.AreEqual("YCbCr4:2:0", descriptor.GetDescription(ExifThumbnailDirectory.TagYcbcrSubsampling));
			Sharpen.Tests.AreEqual("YCbCr4:2:0", descriptor.GetYCbCrSubsamplingDescription());
		}
		public virtual void TestGetDirectoryName()
		{
			Com.Drew.Metadata.Directory subIFDDirectory = new ExifSubIFDDirectory();
			Com.Drew.Metadata.Directory ifd0Directory = new ExifIFD0Directory();
			Com.Drew.Metadata.Directory thumbDirectory = new ExifThumbnailDirectory();
			Sharpen.Tests.IsFalse(subIFDDirectory.HasErrors());
			Sharpen.Tests.IsFalse(ifd0Directory.HasErrors());
			Sharpen.Tests.IsFalse(thumbDirectory.HasErrors());
			Sharpen.Tests.AreEqual("Exif IFD0", ifd0Directory.GetName());
			Sharpen.Tests.AreEqual("Exif SubIFD", subIFDDirectory.GetName());
			Sharpen.Tests.AreEqual("Exif Thumbnail", thumbDirectory.GetName());
		}
Пример #11
0
 public virtual void TestGetDirectoryName()
 {
     Com.Drew.Metadata.Directory subIFDDirectory = new ExifSubIFDDirectory();
     Com.Drew.Metadata.Directory ifd0Directory   = new ExifIFD0Directory();
     Com.Drew.Metadata.Directory thumbDirectory  = new ExifThumbnailDirectory();
     Sharpen.Tests.IsFalse(subIFDDirectory.HasErrors());
     Sharpen.Tests.IsFalse(ifd0Directory.HasErrors());
     Sharpen.Tests.IsFalse(thumbDirectory.HasErrors());
     Sharpen.Tests.AreEqual("Exif IFD0", ifd0Directory.GetName());
     Sharpen.Tests.AreEqual("Exif SubIFD", subIFDDirectory.GetName());
     Sharpen.Tests.AreEqual("Exif Thumbnail", thumbDirectory.GetName());
 }
Пример #12
0
        public virtual void TestResolution()
        {
            Com.Drew.Metadata.Metadata metadata           = ExifReaderTest.ProcessBytes("Tests/Data/withUncompressedRGBThumbnail.jpg.app1");
            ExifThumbnailDirectory     thumbnailDirectory = metadata.GetDirectory <ExifThumbnailDirectory>();

            NUnit.Framework.Assert.IsNotNull(thumbnailDirectory);
            Sharpen.Tests.AreEqual(72, thumbnailDirectory.GetInt(ExifThumbnailDirectory.TagXResolution));
            ExifIFD0Directory exifIFD0Directory = metadata.GetDirectory <ExifIFD0Directory>();

            NUnit.Framework.Assert.IsNotNull(exifIFD0Directory);
            Sharpen.Tests.AreEqual(216, exifIFD0Directory.GetInt(ExifIFD0Directory.TagXResolution));
        }
Пример #13
0
        public virtual void TestGetYCbCrSubsamplingDescription()
        {
            ExifThumbnailDirectory directory = new ExifThumbnailDirectory();

            directory.SetIntArray(ExifThumbnailDirectory.TagYcbcrSubsampling, new int[] { 2, 1 });
            ExifThumbnailDescriptor descriptor = new ExifThumbnailDescriptor(directory);

            Sharpen.Tests.AreEqual("YCbCr4:2:2", descriptor.GetDescription(ExifThumbnailDirectory.TagYcbcrSubsampling));
            Sharpen.Tests.AreEqual("YCbCr4:2:2", descriptor.GetYCbCrSubsamplingDescription());
            directory.SetIntArray(ExifThumbnailDirectory.TagYcbcrSubsampling, new int[] { 2, 2 });
            Sharpen.Tests.AreEqual("YCbCr4:2:0", descriptor.GetDescription(ExifThumbnailDirectory.TagYcbcrSubsampling));
            Sharpen.Tests.AreEqual("YCbCr4:2:0", descriptor.GetYCbCrSubsamplingDescription());
        }
Пример #14
0
        public virtual void TestDifferenceImageAndThumbnailOrientations()
        {
            // This metadata contains different orientations for the thumbnail and the main image.
            // These values used to be merged into a single directory, causing errors.
            // This unit test demonstrates correct behaviour.
            Com.Drew.Metadata.Metadata metadata           = ProcessBytes("Tests/Data/repeatedOrientationTagWithDifferentValues.jpg.app1");
            ExifIFD0Directory          ifd0Directory      = metadata.GetFirstDirectoryOfType <ExifIFD0Directory>();
            ExifThumbnailDirectory     thumbnailDirectory = metadata.GetFirstDirectoryOfType <ExifThumbnailDirectory>();

            NUnit.Framework.Assert.IsNotNull(ifd0Directory);
            NUnit.Framework.Assert.IsNotNull(thumbnailDirectory);
            Sharpen.Tests.AreEqual(1, ifd0Directory.GetInt(ExifIFD0Directory.TagOrientation));
            Sharpen.Tests.AreEqual(8, thumbnailDirectory.GetInt(ExifThumbnailDirectory.TagOrientation));
        }
Пример #15
0
        public virtual void TestGetThumbnailData()
        {
            ExifThumbnailDirectory directory = ExifReaderTest.ProcessBytes <ExifThumbnailDirectory>("Tests/Data/withExif.jpg.app1");

            sbyte[] thumbData = directory.GetThumbnailData();
            NUnit.Framework.Assert.IsNotNull(thumbData);
            try
            {
                // attempt to read the thumbnail -- it should be a legal Jpeg file
                JpegSegmentReader.ReadSegments(new SequentialByteArrayReader(thumbData), null);
            }
            catch (JpegProcessingException)
            {
                NUnit.Framework.Assert.Fail("Unable to construct JpegSegmentReader from thumbnail data");
            }
        }
Пример #16
0
        public virtual void TestWriteThumbnail()
        {
            ExifThumbnailDirectory directory = ExifReaderTest.ProcessBytes <ExifThumbnailDirectory>("Tests/Data/manuallyAddedThumbnail.jpg.app1");

            Sharpen.Tests.IsTrue(directory.HasThumbnailData());
            FilePath thumbnailFile = FilePath.CreateTempFile("thumbnail", ".jpg");

            try
            {
                directory.WriteThumbnail(thumbnailFile.GetAbsolutePath());
                FilePath file = new FilePath(thumbnailFile.GetAbsolutePath());
                Sharpen.Tests.AreEqual(2970, file.Length());
                Sharpen.Tests.IsTrue(file.Exists());
            }
            finally
            {
                if (!thumbnailFile.Delete())
                {
                    NUnit.Framework.Assert.Fail("Unable to delete temp thumbnail file.");
                }
            }
        }
Пример #17
0
        private static void ExtractTiff(RandomAccessReader reader, Com.Drew.Metadata.Metadata metadata, Com.Drew.Metadata.Directory firstDirectory, int tiffHeaderOffset)
        {
            // this should be either "MM" or "II"
            string byteOrderIdentifier = reader.GetString(tiffHeaderOffset, 2);

            if ("MM".Equals(byteOrderIdentifier))
            {
                reader.SetMotorolaByteOrder(true);
            }
            else
            {
                if ("II".Equals(byteOrderIdentifier))
                {
                    reader.SetMotorolaByteOrder(false);
                }
                else
                {
                    firstDirectory.AddError("Unclear distinction between Motorola/Intel byte ordering: " + byteOrderIdentifier);
                    return;
                }
            }
            // Check the next two values for correctness.
            int tiffMarker           = reader.GetUInt16(2 + tiffHeaderOffset);
            int standardTiffMarker   = unchecked ((int)(0x002A));
            int olympusRawTiffMarker = unchecked ((int)(0x4F52));
            // for ORF files
            int panasonicRawTiffMarker = unchecked ((int)(0x0055));

            // for RW2 files
            if (tiffMarker != standardTiffMarker && tiffMarker != olympusRawTiffMarker && tiffMarker != panasonicRawTiffMarker)
            {
                firstDirectory.AddError("Unexpected TIFF marker after byte order identifier: 0x" + Sharpen.Extensions.ToHexString(tiffMarker));
                return;
            }
            int firstIfdOffset = reader.GetInt32(4 + tiffHeaderOffset) + tiffHeaderOffset;

            // David Ekholm sent a digital camera image that has this problem
            // TODO getLength should be avoided as it causes RandomAccessStreamReader to read to the end of the stream
            if (firstIfdOffset >= reader.GetLength() - 1)
            {
                firstDirectory.AddError("First Exif directory offset is beyond end of Exif data segment");
                // First directory normally starts 14 bytes in -- try it here and catch another error in the worst case
                firstIfdOffset = 14;
            }
            ICollection <int> processedIfdOffsets = new HashSet <int>();

            ProcessIFD(firstDirectory, processedIfdOffsets, firstIfdOffset, tiffHeaderOffset, metadata, reader);
            // after the extraction process, if we have the correct tags, we may be able to store thumbnail information
            ExifThumbnailDirectory thumbnailDirectory = metadata.GetDirectory <ExifThumbnailDirectory>();

            if (thumbnailDirectory != null && thumbnailDirectory.ContainsTag(ExifThumbnailDirectory.TagThumbnailCompression))
            {
                int?offset = thumbnailDirectory.GetInteger(ExifThumbnailDirectory.TagThumbnailOffset);
                int?length = thumbnailDirectory.GetInteger(ExifThumbnailDirectory.TagThumbnailLength);
                if (offset != null && length != null)
                {
                    try
                    {
                        sbyte[] thumbnailData = reader.GetBytes(tiffHeaderOffset + offset.Value, length.Value);
                        thumbnailDirectory.SetThumbnailData(thumbnailData);
                    }
                    catch (IOException ex)
                    {
                        firstDirectory.AddError("Invalid thumbnail data specification: " + ex.Message);
                    }
                }
            }
        }
Пример #18
0
        public virtual void TestThumbnailLength()
        {
            ExifThumbnailDirectory directory = ExifReaderTest.ProcessBytes <ExifThumbnailDirectory>("Tests/Data/manuallyAddedThumbnail.jpg.app1");

            Sharpen.Tests.AreEqual(2970, directory.GetInt(ExifThumbnailDirectory.TagThumbnailLength));
        }
Пример #19
0
        private static void ProcessIFD(Com.Drew.Metadata.Directory directory, ICollection <int> processedIfdOffsets, int ifdOffset, int tiffHeaderOffset, Com.Drew.Metadata.Metadata metadata, RandomAccessReader reader)
        {
            // check for directories we've already visited to avoid stack overflows when recursive/cyclic directory structures exist
            if (processedIfdOffsets.Contains(Sharpen.Extensions.ValueOf(ifdOffset)))
            {
                return;
            }
            // remember that we've visited this directory so that we don't visit it again later
            processedIfdOffsets.Add(ifdOffset);
            if (ifdOffset >= reader.GetLength() || ifdOffset < 0)
            {
                directory.AddError("Ignored IFD marked to start outside data segment");
                return;
            }
            // First two bytes in the IFD are the number of tags in this directory
            int dirTagCount = reader.GetUInt16(ifdOffset);
            int dirLength   = (2 + (12 * dirTagCount) + 4);

            if (dirLength + ifdOffset > reader.GetLength())
            {
                directory.AddError("Illegally sized IFD");
                return;
            }
            // Handle each tag in this directory
            for (int tagNumber = 0; tagNumber < dirTagCount; tagNumber++)
            {
                int tagOffset = CalculateTagOffset(ifdOffset, tagNumber);
                // 2 bytes for the tag type
                int tagType = reader.GetUInt16(tagOffset);
                // 2 bytes for the format code
                int formatCode = reader.GetUInt16(tagOffset + 2);
                if (formatCode < 1 || formatCode > MaxFormatCode)
                {
                    // This error suggests that we are processing at an incorrect index and will generate
                    // rubbish until we go out of bounds (which may be a while).  Exit now.
                    directory.AddError("Invalid TIFF tag format code: " + formatCode);
                    return;
                }
                // 4 bytes dictate the number of components in this tag's data
                int componentCount = reader.GetInt32(tagOffset + 4);
                if (componentCount < 0)
                {
                    directory.AddError("Negative TIFF tag component count");
                    continue;
                }
                // each component may have more than one byte... calculate the total number of bytes
                int byteCount = componentCount * BytesPerFormat[formatCode];
                int tagValueOffset;
                if (byteCount > 4)
                {
                    // If it's bigger than 4 bytes, the dir entry contains an offset.
                    // dirEntryOffset must be passed, as some makernote implementations (e.g. Fujifilm) incorrectly use an
                    // offset relative to the start of the makernote itself, not the TIFF segment.
                    int offsetVal = reader.GetInt32(tagOffset + 8);
                    if (offsetVal + byteCount > reader.GetLength())
                    {
                        // Bogus pointer offset and / or byteCount value
                        directory.AddError("Illegal TIFF tag pointer offset");
                        continue;
                    }
                    tagValueOffset = tiffHeaderOffset + offsetVal;
                }
                else
                {
                    // 4 bytes or less and value is in the dir entry itself
                    tagValueOffset = tagOffset + 8;
                }
                if (tagValueOffset < 0 || tagValueOffset > reader.GetLength())
                {
                    directory.AddError("Illegal TIFF tag pointer offset");
                    continue;
                }
                // Check that this tag isn't going to allocate outside the bounds of the data array.
                // This addresses an uncommon OutOfMemoryError.
                if (byteCount < 0 || tagValueOffset + byteCount > reader.GetLength())
                {
                    directory.AddError("Illegal number of bytes for TIFF tag data: " + byteCount);
                    continue;
                }
                //
                // Special handling for certain known tags that point to or contain other chunks of data to be processed
                //
                if (tagType == ExifIFD0Directory.TagExifSubIfdOffset && directory is ExifIFD0Directory)
                {
                    if (byteCount != 4)
                    {
                        directory.AddError("Exif SubIFD Offset tag should have a component count of four (bytes) for the offset.");
                    }
                    else
                    {
                        int subDirOffset = tiffHeaderOffset + reader.GetInt32(tagValueOffset);
                        ProcessIFD(metadata.GetOrCreateDirectory <ExifSubIFDDirectory>(), processedIfdOffsets, subDirOffset, tiffHeaderOffset, metadata, reader);
                    }
                }
                else
                {
                    if (tagType == ExifSubIFDDirectory.TagInteropOffset && directory is ExifSubIFDDirectory)
                    {
                        if (byteCount != 4)
                        {
                            directory.AddError("Exif Interop Offset tag should have a component count of four (bytes) for the offset.");
                        }
                        else
                        {
                            int subDirOffset = tiffHeaderOffset + reader.GetInt32(tagValueOffset);
                            ProcessIFD(metadata.GetOrCreateDirectory <ExifInteropDirectory>(), processedIfdOffsets, subDirOffset, tiffHeaderOffset, metadata, reader);
                        }
                    }
                    else
                    {
                        if (tagType == ExifIFD0Directory.TagGpsInfoOffset && directory is ExifIFD0Directory)
                        {
                            if (byteCount != 4)
                            {
                                directory.AddError("Exif GPS Info Offset tag should have a component count of four (bytes) for the offset.");
                            }
                            else
                            {
                                int subDirOffset = tiffHeaderOffset + reader.GetInt32(tagValueOffset);
                                ProcessIFD(metadata.GetOrCreateDirectory <GpsDirectory>(), processedIfdOffsets, subDirOffset, tiffHeaderOffset, metadata, reader);
                            }
                        }
                        else
                        {
                            if (tagType == ExifSubIFDDirectory.TagMakernote && directory is ExifSubIFDDirectory)
                            {
                                // The makernote tag contains the encoded makernote data directly.
                                // Pass the offset to this tag's value. Manufacturer/Model-specific logic will be used to
                                // determine the correct offset for further processing.
                                ProcessMakernote(tagValueOffset, processedIfdOffsets, tiffHeaderOffset, metadata, reader);
                            }
                            else
                            {
                                ProcessTag(directory, tagType, tagValueOffset, componentCount, formatCode, reader);
                            }
                        }
                    }
                }
            }
            // at the end of each IFD is an optional link to the next IFD
            int finalTagOffset      = CalculateTagOffset(ifdOffset, dirTagCount);
            int nextDirectoryOffset = reader.GetInt32(finalTagOffset);

            if (nextDirectoryOffset != 0)
            {
                nextDirectoryOffset += tiffHeaderOffset;
                if (nextDirectoryOffset >= reader.GetLength())
                {
                    // Last 4 bytes of IFD reference another IFD with an address that is out of bounds
                    // Note this could have been caused by jhead 1.3 cropping too much
                    return;
                }
                else
                {
                    if (nextDirectoryOffset < ifdOffset)
                    {
                        // Last 4 bytes of IFD reference another IFD with an address that is before the start of this directory
                        return;
                    }
                }
                // TODO in Exif, the only known 'follower' IFD is the thumbnail one, however this may not be the case
                ExifThumbnailDirectory nextDirectory = metadata.GetOrCreateDirectory <ExifThumbnailDirectory>();
                ProcessIFD(nextDirectory, processedIfdOffsets, nextDirectoryOffset, tiffHeaderOffset, metadata, reader);
            }
        }