Esempio n. 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);
                 }
             }
         }
     }
 }
Esempio n. 2
0
        /// <exception cref="System.IO.IOException"/>
        private void SetInt32(Com.Drew.Metadata.Directory directory, int tagType, RandomAccessReader reader)
        {
            int i = reader.GetInt32(tagType);

            if (i != 0)
            {
                directory.SetInt(tagType, i);
            }
        }
Esempio n. 3
0
        /// <exception cref="System.IO.IOException"/>
        private void SetInt64(Com.Drew.Metadata.Directory directory, int tagType, RandomAccessReader reader)
        {
            long l = reader.GetInt64(tagType);

            if (l != 0)
            {
                directory.SetLong(tagType, l);
            }
        }
Esempio n. 4
0
        public virtual void Extract([NotNull] RandomAccessReader reader, [NotNull] Com.Drew.Metadata.Metadata metadata)
        {
            // TODO review whether the 'tagPtr' values below really do require RandomAccessReader or whether SequentialReader may be used instead
            IccDirectory directory = new IccDirectory();

            try
            {
                int profileByteCount = reader.GetInt32(IccDirectory.TagProfileByteCount);
                directory.SetInt(IccDirectory.TagProfileByteCount, profileByteCount);
                // For these tags, the int value of the tag is in fact it's offset within the buffer.
                Set4ByteString(directory, IccDirectory.TagCmmType, reader);
                SetInt32(directory, IccDirectory.TagProfileVersion, reader);
                Set4ByteString(directory, IccDirectory.TagProfileClass, reader);
                Set4ByteString(directory, IccDirectory.TagColorSpace, reader);
                Set4ByteString(directory, IccDirectory.TagProfileConnectionSpace, reader);
                SetDate(directory, IccDirectory.TagProfileDatetime, reader);
                Set4ByteString(directory, IccDirectory.TagSignature, reader);
                Set4ByteString(directory, IccDirectory.TagPlatform, reader);
                SetInt32(directory, IccDirectory.TagCmmFlags, reader);
                Set4ByteString(directory, IccDirectory.TagDeviceMake, reader);
                int temp = reader.GetInt32(IccDirectory.TagDeviceModel);
                if (temp != 0)
                {
                    if (temp <= unchecked ((int)(0x20202020)))
                    {
                        directory.SetInt(IccDirectory.TagDeviceModel, temp);
                    }
                    else
                    {
                        directory.SetString(IccDirectory.TagDeviceModel, GetStringFromInt32(temp));
                    }
                }
                SetInt32(directory, IccDirectory.TagRenderingIntent, reader);
                SetInt64(directory, IccDirectory.TagDeviceAttr, reader);
                float[] xyz = new float[] { reader.GetS15Fixed16(IccDirectory.TagXyzValues), reader.GetS15Fixed16(IccDirectory.TagXyzValues + 4), reader.GetS15Fixed16(IccDirectory.TagXyzValues + 8) };
                directory.SetObject(IccDirectory.TagXyzValues, xyz);
                // Process 'ICC tags'
                int tagCount = reader.GetInt32(IccDirectory.TagTagCount);
                directory.SetInt(IccDirectory.TagTagCount, tagCount);
                for (int i = 0; i < tagCount; i++)
                {
                    int     pos     = IccDirectory.TagTagCount + 4 + i * 12;
                    int     tagType = reader.GetInt32(pos);
                    int     tagPtr  = reader.GetInt32(pos + 4);
                    int     tagLen  = reader.GetInt32(pos + 8);
                    sbyte[] b       = reader.GetBytes(tagPtr, tagLen);
                    directory.SetByteArray(tagType, b);
                }
            }
            catch (IOException ex)
            {
                directory.AddError("Exception reading ICC profile: " + ex.Message);
            }
            metadata.AddDirectory(directory);
        }
Esempio n. 5
0
        public virtual void ExtractTiff(RandomAccessReader reader, Com.Drew.Metadata.Metadata metadata)
        {
            ExifIFD0Directory directory = metadata.GetOrCreateDirectory <ExifIFD0Directory>();

            try
            {
                ExtractTiff(reader, metadata, directory, 0);
            }
            catch (IOException e)
            {
                directory.AddError("IO problem: " + e.Message);
            }
        }
Esempio n. 6
0
        /// <exception cref="System.IO.IOException"/>
        private void SetDate(IccDirectory directory, int tagType, RandomAccessReader reader)
        {
            int y = reader.GetUInt16(tagType);
            int m = reader.GetUInt16(tagType + 2);
            int d = reader.GetUInt16(tagType + 4);
            int h = reader.GetUInt16(tagType + 6);
            int M = reader.GetUInt16(tagType + 8);
            int s = reader.GetUInt16(tagType + 10);

            //        final Date value = new Date(Date.UTC(y - 1900, m - 1, d, h, M, s));
            Sharpen.Calendar calendar = Sharpen.Calendar.GetInstance(Sharpen.Extensions.GetTimeZone("UTC"));
            calendar.Set(y, m, d, h, M, s);
            DateTime value = calendar.GetTime();

            directory.SetDate(tagType, value);
        }
Esempio n. 7
0
 /// <summary>
 /// Reads TIFF formatted Exif data a specified offset within a
 /// <see cref="Com.Drew.Lang.RandomAccessReader"/>
 /// .
 /// </summary>
 public virtual void Extract([NotNull] RandomAccessReader reader, [NotNull] Com.Drew.Metadata.Metadata metadata, int readerOffset)
 {
     try
     {
         // Read the TIFF-formatted Exif data
         new TiffReader().ProcessTiff(reader, new ExifTiffHandler(metadata, _storeThumbnailBytes), readerOffset);
     }
     catch (TiffProcessingException e)
     {
         // TODO what do to with this error state?
         Sharpen.Runtime.PrintStackTrace(e, System.Console.Error);
     }
     catch (IOException e)
     {
         // TODO what do to with this error state?
         Sharpen.Runtime.PrintStackTrace(e, System.Console.Error);
     }
 }
        /// <summary>Processes a TIFF data sequence.</summary>
        /// <param name="reader">
        /// the
        /// <see cref="Com.Drew.Lang.RandomAccessReader"/>
        /// from which the data should be read
        /// </param>
        /// <param name="handler">
        /// the
        /// <see cref="TiffHandler"/>
        /// that will coordinate processing and accept read values
        /// </param>
        /// <param name="tiffHeaderOffset">the offset within <code>reader</code> at which the TIFF header starts</param>
        /// <exception cref="TiffProcessingException">
        /// if an error occurred during the processing of TIFF data that could not be
        /// ignored or recovered from
        /// </exception>
        /// <exception cref="System.IO.IOException">an error occurred while accessing the required data</exception>
        /// <exception cref="Com.Drew.Imaging.Tiff.TiffProcessingException"/>
        public virtual void ProcessTiff(RandomAccessReader reader, TiffHandler handler, int tiffHeaderOffset)
        {
            // This must be either "MM" or "II".
            short byteOrderIdentifier = reader.GetInt16(tiffHeaderOffset);

            if (byteOrderIdentifier == unchecked ((int)(0x4d4d)))
            {
                // "MM"
                reader.SetMotorolaByteOrder(true);
            }
            else
            {
                if (byteOrderIdentifier == unchecked ((int)(0x4949)))
                {
                    // "II"
                    reader.SetMotorolaByteOrder(false);
                }
                else
                {
                    throw new TiffProcessingException("Unclear distinction between Motorola/Intel byte ordering: " + byteOrderIdentifier);
                }
            }
            // Check the next two values for correctness.
            int tiffMarker = reader.GetUInt16(2 + tiffHeaderOffset);

            handler.SetTiffMarker(tiffMarker);
            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)
            {
                handler.Warn("First IFD offset is beyond the end of the TIFF data segment -- trying default offset");
                // First directory normally starts immediately after the offset bytes, so try that
                firstIfdOffset = tiffHeaderOffset + 2 + 2 + 4;
            }
            ICollection <int> processedIfdOffsets = new HashSet <int>();

            ProcessIfd(handler, reader, processedIfdOffsets, firstIfdOffset, tiffHeaderOffset);
            handler.Completed(reader, tiffHeaderOffset);
        }
        /// <summary>
        /// Performs the Jfif data extraction, adding found values to the specified
        /// instance of
        /// <see cref="Com.Drew.Metadata.Metadata"/>
        /// .
        /// </summary>
        public virtual void Extract(RandomAccessReader reader, Com.Drew.Metadata.Metadata metadata)
        {
            JfifDirectory directory = metadata.GetOrCreateDirectory <JfifDirectory>();

            try
            {
                // For JFIF, the tag number is also the offset into the segment
                int ver = reader.GetUInt16(JfifDirectory.TagVersion);
                directory.SetInt(JfifDirectory.TagVersion, ver);
                int units = reader.GetUInt8(JfifDirectory.TagUnits);
                directory.SetInt(JfifDirectory.TagUnits, units);
                int height = reader.GetUInt16(JfifDirectory.TagResx);
                directory.SetInt(JfifDirectory.TagResx, height);
                int width = reader.GetUInt16(JfifDirectory.TagResy);
                directory.SetInt(JfifDirectory.TagResy, width);
            }
            catch (IOException me)
            {
                directory.AddError(me.Message);
            }
        }
Esempio n. 10
0
        public virtual void Extract(RandomAccessReader reader, Com.Drew.Metadata.Metadata metadata)
        {
            PsdHeaderDirectory directory = metadata.GetOrCreateDirectory <PsdHeaderDirectory>();

            try
            {
                int signature = reader.GetInt32(0);
                if (signature != unchecked ((int)(0x38425053)))
                {
                    directory.AddError("Invalid PSD file signature");
                    return;
                }
                int version = reader.GetUInt16(4);
                if (version != 1 && version != 2)
                {
                    directory.AddError("Invalid PSD file version (must be 1 or 2)");
                    return;
                }
                // 6 reserved bytes are skipped here.  They should be zero.
                int channelCount = reader.GetUInt16(12);
                directory.SetInt(PsdHeaderDirectory.TagChannelCount, channelCount);
                // even though this is probably an unsigned int, the max height in practice is 300,000
                int imageHeight = reader.GetInt32(14);
                directory.SetInt(PsdHeaderDirectory.TagImageHeight, imageHeight);
                // even though this is probably an unsigned int, the max width in practice is 300,000
                int imageWidth = reader.GetInt32(18);
                directory.SetInt(PsdHeaderDirectory.TagImageWidth, imageWidth);
                int bitsPerChannel = reader.GetUInt16(22);
                directory.SetInt(PsdHeaderDirectory.TagBitsPerChannel, bitsPerChannel);
                int colorMode = reader.GetUInt16(24);
                directory.SetInt(PsdHeaderDirectory.TagColorMode, colorMode);
            }
            catch (IOException)
            {
                directory.AddError("Unable to read PSD header");
            }
        }
Esempio n. 11
0
 public abstract bool CustomProcessTag(int arg1, ICollection <int> arg2, int arg3, RandomAccessReader arg4, int arg5, int arg6);
Esempio n. 12
0
 /// <summary>
 /// Reads TIFF formatted Exif data from start of the specified
 /// <see cref="Com.Drew.Lang.RandomAccessReader"/>
 /// .
 /// </summary>
 public virtual void Extract([NotNull] RandomAccessReader reader, [NotNull] Com.Drew.Metadata.Metadata metadata)
 {
     Extract(reader, metadata, 0);
 }
        public virtual void Extract(RandomAccessReader reader, Com.Drew.Metadata.Metadata metadata)
        {
            PhotoshopDirectory directory = metadata.GetOrCreateDirectory <PhotoshopDirectory>();
            int pos;

            try
            {
                pos = reader.GetString(0, 13).Equals("Photoshop 3.0") ? 14 : 0;
            }
            catch (IOException)
            {
                directory.AddError("Unable to read header");
                return;
            }
            long length;

            try
            {
                length = reader.GetLength();
            }
            catch (IOException e)
            {
                directory.AddError("Unable to read Photoshop data: " + e.Message);
                return;
            }
            while (pos < length)
            {
                try
                {
                    // 4 bytes for the signature.  Should always be "8BIM".
                    //String signature = new String(data, pos, 4);
                    pos += 4;
                    // 2 bytes for the resource identifier (tag type).
                    int tagType = reader.GetUInt16(pos);
                    // segment type
                    pos += 2;
                    // A variable number of bytes holding a pascal string (two leading bytes for length).
                    int descriptionLength = reader.GetUInt16(pos);
                    pos += 2;
                    // Some basic bounds checking
                    if (descriptionLength < 0 || descriptionLength + pos > length)
                    {
                        return;
                    }
                    //String description = new String(data, pos, descriptionLength);
                    pos += descriptionLength;
                    // The number of bytes is padded with a trailing zero, if needed, to make the size even.
                    if (pos % 2 != 0)
                    {
                        pos++;
                    }
                    // 4 bytes for the size of the resource data that follows.
                    int byteCount = reader.GetInt32(pos);
                    pos += 4;
                    // The resource data.
                    sbyte[] tagBytes = reader.GetBytes(pos, byteCount);
                    pos += byteCount;
                    // The number of bytes is padded with a trailing zero, if needed, to make the size even.
                    if (pos % 2 != 0)
                    {
                        pos++;
                    }
                    directory.SetByteArray(tagType, tagBytes);
                    // TODO allow rebasing the reader with a new zero-point, rather than copying data here
                    if (tagType == PhotoshopDirectory.TagIptc)
                    {
                        new IptcReader().Extract(new SequentialByteArrayReader(tagBytes), metadata, tagBytes.Length);
                    }
                    if (tagType >= unchecked ((int)(0x0fa0)) && tagType <= unchecked ((int)(0x1387)))
                    {
                        PhotoshopDirectory._tagNameMap.Put(tagType, Sharpen.Extensions.StringFormat("Plug-in %d Data", tagType - unchecked ((int)(0x0fa0)) + 1));
                    }
                }
                catch (IOException ex)
                {
                    directory.AddError(ex.Message);
                    return;
                }
            }
        }
Esempio n. 14
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);
                    }
                }
            }
        }
Esempio n. 15
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);
            }
        }
Esempio n. 16
0
        private static void ProcessTag(Com.Drew.Metadata.Directory directory, int tagType, int tagValueOffset, int componentCount, int formatCode, RandomAccessReader reader)
        {
            switch (formatCode)
            {
            case FmtUndefined:
            {
                // Directory simply stores raw values
                // The display side uses a Descriptor class per directory to turn the raw values into 'pretty' descriptions
                // this includes exif user comments
                directory.SetByteArray(tagType, reader.GetBytes(tagValueOffset, componentCount));
                break;
            }

            case FmtString:
            {
                string @string = reader.GetNullTerminatedString(tagValueOffset, componentCount);
                directory.SetString(tagType, @string);
                break;
            }

            case FmtSrational:
            {
                if (componentCount == 1)
                {
                    directory.SetRational(tagType, new Rational(reader.GetInt32(tagValueOffset), reader.GetInt32(tagValueOffset + 4)));
                }
                else
                {
                    if (componentCount > 1)
                    {
                        Rational[] rationals = new Rational[componentCount];
                        for (int i = 0; i < componentCount; i++)
                        {
                            rationals[i] = new Rational(reader.GetInt32(tagValueOffset + (8 * i)), reader.GetInt32(tagValueOffset + 4 + (8 * i)));
                        }
                        directory.SetRationalArray(tagType, rationals);
                    }
                }
                break;
            }

            case FmtUrational:
            {
                if (componentCount == 1)
                {
                    directory.SetRational(tagType, new Rational(reader.GetUInt32(tagValueOffset), reader.GetUInt32(tagValueOffset + 4)));
                }
                else
                {
                    if (componentCount > 1)
                    {
                        Rational[] rationals = new Rational[componentCount];
                        for (int i = 0; i < componentCount; i++)
                        {
                            rationals[i] = new Rational(reader.GetUInt32(tagValueOffset + (8 * i)), reader.GetUInt32(tagValueOffset + 4 + (8 * i)));
                        }
                        directory.SetRationalArray(tagType, rationals);
                    }
                }
                break;
            }

            case FmtSingle:
            {
                if (componentCount == 1)
                {
                    directory.SetFloat(tagType, reader.GetFloat32(tagValueOffset));
                }
                else
                {
                    float[] floats = new float[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        floats[i] = reader.GetFloat32(tagValueOffset + (i * 4));
                    }
                    directory.SetFloatArray(tagType, floats);
                }
                break;
            }

            case FmtDouble:
            {
                if (componentCount == 1)
                {
                    directory.SetDouble(tagType, reader.GetDouble64(tagValueOffset));
                }
                else
                {
                    double[] doubles = new double[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        doubles[i] = reader.GetDouble64(tagValueOffset + (i * 4));
                    }
                    directory.SetDoubleArray(tagType, doubles);
                }
                break;
            }

            case FmtSbyte:
            {
                //
                // Note that all integral types are stored as int32 internally (the largest supported by TIFF)
                //
                if (componentCount == 1)
                {
                    directory.SetInt(tagType, reader.GetInt8(tagValueOffset));
                }
                else
                {
                    int[] bytes = new int[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        bytes[i] = reader.GetInt8(tagValueOffset + i);
                    }
                    directory.SetIntArray(tagType, bytes);
                }
                break;
            }

            case FmtByte:
            {
                if (componentCount == 1)
                {
                    directory.SetInt(tagType, reader.GetUInt8(tagValueOffset));
                }
                else
                {
                    int[] bytes = new int[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        bytes[i] = reader.GetUInt8(tagValueOffset + i);
                    }
                    directory.SetIntArray(tagType, bytes);
                }
                break;
            }

            case FmtUshort:
            {
                if (componentCount == 1)
                {
                    int i = reader.GetUInt16(tagValueOffset);
                    directory.SetInt(tagType, i);
                }
                else
                {
                    int[] ints = new int[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        ints[i] = reader.GetUInt16(tagValueOffset + (i * 2));
                    }
                    directory.SetIntArray(tagType, ints);
                }
                break;
            }

            case FmtSshort:
            {
                if (componentCount == 1)
                {
                    int i = reader.GetInt16(tagValueOffset);
                    directory.SetInt(tagType, i);
                }
                else
                {
                    int[] ints = new int[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        ints[i] = reader.GetInt16(tagValueOffset + (i * 2));
                    }
                    directory.SetIntArray(tagType, ints);
                }
                break;
            }

            case FmtSlong:
            case FmtUlong:
            {
                // NOTE 'long' in this case means 32 bit, not 64
                if (componentCount == 1)
                {
                    int i = reader.GetInt32(tagValueOffset);
                    directory.SetInt(tagType, i);
                }
                else
                {
                    int[] ints = new int[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        ints[i] = reader.GetInt32(tagValueOffset + (i * 4));
                    }
                    directory.SetIntArray(tagType, ints);
                }
                break;
            }

            default:
            {
                directory.AddError("Unknown format code " + formatCode + " for tag " + tagType);
                break;
            }
            }
        }
Esempio n. 17
0
        /// <exception cref="System.IO.IOException"/>
        private void Set4ByteString(Com.Drew.Metadata.Directory directory, int tagType, RandomAccessReader reader)
        {
            int i = reader.GetInt32(tagType);

            if (i != 0)
            {
                directory.SetString(tagType, GetStringFromInt32(i));
            }
        }
Esempio n. 18
0
        private static void ProcessKodakMakernote(KodakMakernoteDirectory directory, int tagValueOffset, RandomAccessReader reader)
        {
            // Kodak's makernote is not in IFD format. It has values at fixed offsets.
            int dataOffset = tagValueOffset + 8;

            try
            {
                directory.SetString(KodakMakernoteDirectory.TagKodakModel, reader.GetString(dataOffset, 8));
                directory.SetInt(KodakMakernoteDirectory.TagQuality, reader.GetUInt8(dataOffset + 9));
                directory.SetInt(KodakMakernoteDirectory.TagBurstMode, reader.GetUInt8(dataOffset + 10));
                directory.SetInt(KodakMakernoteDirectory.TagImageWidth, reader.GetUInt16(dataOffset + 12));
                directory.SetInt(KodakMakernoteDirectory.TagImageHeight, reader.GetUInt16(dataOffset + 14));
                directory.SetInt(KodakMakernoteDirectory.TagYearCreated, reader.GetUInt16(dataOffset + 16));
                directory.SetByteArray(KodakMakernoteDirectory.TagMonthDayCreated, reader.GetBytes(dataOffset + 18, 2));
                directory.SetByteArray(KodakMakernoteDirectory.TagTimeCreated, reader.GetBytes(dataOffset + 20, 4));
                directory.SetInt(KodakMakernoteDirectory.TagBurstMode2, reader.GetUInt16(dataOffset + 24));
                directory.SetInt(KodakMakernoteDirectory.TagShutterMode, reader.GetUInt8(dataOffset + 27));
                directory.SetInt(KodakMakernoteDirectory.TagMeteringMode, reader.GetUInt8(dataOffset + 28));
                directory.SetInt(KodakMakernoteDirectory.TagSequenceNumber, reader.GetUInt8(dataOffset + 29));
                directory.SetInt(KodakMakernoteDirectory.TagFNumber, reader.GetUInt16(dataOffset + 30));
                directory.SetLong(KodakMakernoteDirectory.TagExposureTime, reader.GetUInt32(dataOffset + 32));
                directory.SetInt(KodakMakernoteDirectory.TagExposureCompensation, reader.GetInt16(dataOffset + 36));
                directory.SetInt(KodakMakernoteDirectory.TagFocusMode, reader.GetUInt8(dataOffset + 56));
                directory.SetInt(KodakMakernoteDirectory.TagWhiteBalance, reader.GetUInt8(dataOffset + 64));
                directory.SetInt(KodakMakernoteDirectory.TagFlashMode, reader.GetUInt8(dataOffset + 92));
                directory.SetInt(KodakMakernoteDirectory.TagFlashFired, reader.GetUInt8(dataOffset + 93));
                directory.SetInt(KodakMakernoteDirectory.TagIsoSetting, reader.GetUInt16(dataOffset + 94));
                directory.SetInt(KodakMakernoteDirectory.TagIso, reader.GetUInt16(dataOffset + 96));
                directory.SetInt(KodakMakernoteDirectory.TagTotalZoom, reader.GetUInt16(dataOffset + 98));
                directory.SetInt(KodakMakernoteDirectory.TagDateTimeStamp, reader.GetUInt16(dataOffset + 100));
                directory.SetInt(KodakMakernoteDirectory.TagColorMode, reader.GetUInt16(dataOffset + 102));
                directory.SetInt(KodakMakernoteDirectory.TagDigitalZoom, reader.GetUInt16(dataOffset + 104));
                directory.SetInt(KodakMakernoteDirectory.TagSharpness, reader.GetInt8(dataOffset + 107));
            }
            catch (IOException ex)
            {
                directory.AddError("Error processing Kodak makernote data: " + ex.Message);
            }
        }
Esempio n. 19
0
        /// <exception cref="System.IO.IOException"/>
        private bool ProcessMakernote(int makernoteOffset, ICollection <int> processedIfdOffsets, int tiffHeaderOffset, RandomAccessReader reader, int byteCount)
        {
            // Determine the camera model and makernote format.
            Com.Drew.Metadata.Directory ifd0Directory = _metadata.GetDirectory <ExifIFD0Directory>();
            if (ifd0Directory == null)
            {
                return(false);
            }
            string cameraMake       = ifd0Directory.GetString(ExifIFD0Directory.TagMake);
            string firstTwoChars    = reader.GetString(makernoteOffset, 2);
            string firstThreeChars  = reader.GetString(makernoteOffset, 3);
            string firstFourChars   = reader.GetString(makernoteOffset, 4);
            string firstFiveChars   = reader.GetString(makernoteOffset, 5);
            string firstSixChars    = reader.GetString(makernoteOffset, 6);
            string firstSevenChars  = reader.GetString(makernoteOffset, 7);
            string firstEightChars  = reader.GetString(makernoteOffset, 8);
            string firstTwelveChars = reader.GetString(makernoteOffset, 12);
            bool   byteOrderBefore  = reader.IsMotorolaByteOrder();

            if ("OLYMP".Equals(firstFiveChars) || "EPSON".Equals(firstFiveChars) || "AGFA".Equals(firstFourChars))
            {
                // Olympus Makernote
                // Epson and Agfa use Olympus makernote standard: http://www.ozhiker.com/electronics/pjmt/jpeg_info/
                PushDirectory <OlympusMakernoteDirectory>();
                TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset + 8, tiffHeaderOffset);
            }
            else
            {
                if (cameraMake != null && cameraMake.ToUpper().StartsWith("MINOLTA"))
                {
                    // Cases seen with the model starting with MINOLTA in capitals seem to have a valid Olympus makernote
                    // area that commences immediately.
                    PushDirectory <OlympusMakernoteDirectory>();
                    TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset, tiffHeaderOffset);
                }
                else
                {
                    if (cameraMake != null && Sharpen.Extensions.Trim(cameraMake).ToUpper().StartsWith("NIKON"))
                    {
                        if ("Nikon".Equals(firstFiveChars))
                        {
                            switch (reader.GetUInt8(makernoteOffset + 6))
                            {
                            case 1:
                            {
                                /* There are two scenarios here:
                                 * Type 1:                  **
                                 * :0000: 4E 69 6B 6F 6E 00 01 00-05 00 02 00 02 00 06 00 Nikon...........
                                 * :0010: 00 00 EC 02 00 00 03 00-03 00 01 00 00 00 06 00 ................
                                 * Type 3:                  **
                                 * :0000: 4E 69 6B 6F 6E 00 02 00-00 00 4D 4D 00 2A 00 00 Nikon....MM.*...
                                 * :0010: 00 08 00 1E 00 01 00 07-00 00 00 04 30 32 30 30 ............0200
                                 */
                                PushDirectory <NikonType1MakernoteDirectory>();
                                TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset + 8, tiffHeaderOffset);
                                break;
                            }

                            case 2:
                            {
                                PushDirectory <NikonType2MakernoteDirectory>();
                                TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset + 18, makernoteOffset + 10);
                                break;
                            }

                            default:
                            {
                                ifd0Directory.AddError("Unsupported Nikon makernote data ignored.");
                                break;
                            }
                            }
                        }
                        else
                        {
                            // The IFD begins with the first Makernote byte (no ASCII name).  This occurs with CoolPix 775, E990 and D1 models.
                            PushDirectory <NikonType2MakernoteDirectory>();
                            TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset, tiffHeaderOffset);
                        }
                    }
                    else
                    {
                        if ("SONY CAM".Equals(firstEightChars) || "SONY DSC".Equals(firstEightChars))
                        {
                            PushDirectory <SonyType1MakernoteDirectory>();
                            TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset + 12, tiffHeaderOffset);
                        }
                        else
                        {
                            if ("SEMC MS\u0000\u0000\u0000\u0000\u0000".Equals(firstTwelveChars))
                            {
                                // force MM for this directory
                                reader.SetMotorolaByteOrder(true);
                                // skip 12 byte header + 2 for "MM" + 6
                                PushDirectory <SonyType6MakernoteDirectory>();
                                TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset + 20, tiffHeaderOffset);
                            }
                            else
                            {
                                if ("SIGMA\u0000\u0000\u0000".Equals(firstEightChars) || "FOVEON\u0000\u0000".Equals(firstEightChars))
                                {
                                    PushDirectory <SigmaMakernoteDirectory>();
                                    TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset + 10, tiffHeaderOffset);
                                }
                                else
                                {
                                    if ("KDK".Equals(firstThreeChars))
                                    {
                                        reader.SetMotorolaByteOrder(firstSevenChars.Equals("KDK INFO"));
                                        ProcessKodakMakernote(_metadata.GetOrCreateDirectory <KodakMakernoteDirectory>(), makernoteOffset, reader);
                                    }
                                    else
                                    {
                                        if (Sharpen.Runtime.EqualsIgnoreCase("Canon", cameraMake))
                                        {
                                            PushDirectory <CanonMakernoteDirectory>();
                                            TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset, tiffHeaderOffset);
                                        }
                                        else
                                        {
                                            if (cameraMake != null && cameraMake.ToUpper().StartsWith("CASIO"))
                                            {
                                                if ("QVC\u0000\u0000\u0000".Equals(firstSixChars))
                                                {
                                                    PushDirectory <CasioType2MakernoteDirectory>();
                                                    TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset + 6, tiffHeaderOffset);
                                                }
                                                else
                                                {
                                                    PushDirectory <CasioType1MakernoteDirectory>();
                                                    TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset, tiffHeaderOffset);
                                                }
                                            }
                                            else
                                            {
                                                if ("FUJIFILM".Equals(firstEightChars) || Sharpen.Runtime.EqualsIgnoreCase("Fujifilm", cameraMake))
                                                {
                                                    // Note that this also applies to certain Leica cameras, such as the Digilux-4.3
                                                    reader.SetMotorolaByteOrder(false);
                                                    // the 4 bytes after "FUJIFILM" in the makernote point to the start of the makernote
                                                    // IFD, though the offset is relative to the start of the makernote, not the TIFF
                                                    // header (like everywhere else)
                                                    int ifdStart = makernoteOffset + reader.GetInt32(makernoteOffset + 8);
                                                    PushDirectory <FujifilmMakernoteDirectory>();
                                                    TiffReader.ProcessIfd(this, reader, processedIfdOffsets, ifdStart, makernoteOffset);
                                                }
                                                else
                                                {
                                                    if ("KYOCERA".Equals(firstSevenChars))
                                                    {
                                                        // http://www.ozhiker.com/electronics/pjmt/jpeg_info/kyocera_mn.html
                                                        PushDirectory <KyoceraMakernoteDirectory>();
                                                        TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset + 22, tiffHeaderOffset);
                                                    }
                                                    else
                                                    {
                                                        if ("LEICA".Equals(firstFiveChars))
                                                        {
                                                            reader.SetMotorolaByteOrder(false);
                                                            if ("Leica Camera AG".Equals(cameraMake))
                                                            {
                                                                PushDirectory <LeicaMakernoteDirectory>();
                                                                TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset + 8, tiffHeaderOffset);
                                                            }
                                                            else
                                                            {
                                                                if ("LEICA".Equals(cameraMake))
                                                                {
                                                                    // Some Leica cameras use Panasonic makernote tags
                                                                    PushDirectory <PanasonicMakernoteDirectory>();
                                                                    TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset + 8, tiffHeaderOffset);
                                                                }
                                                                else
                                                                {
                                                                    return(false);
                                                                }
                                                            }
                                                        }
                                                        else
                                                        {
                                                            if ("Panasonic\u0000\u0000\u0000".Equals(reader.GetString(makernoteOffset, 12)))
                                                            {
                                                                // NON-Standard TIFF IFD Data using Panasonic Tags. There is no Next-IFD pointer after the IFD
                                                                // Offsets are relative to the start of the TIFF header at the beginning of the EXIF segment
                                                                // more information here: http://www.ozhiker.com/electronics/pjmt/jpeg_info/panasonic_mn.html
                                                                PushDirectory <PanasonicMakernoteDirectory>();
                                                                TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset + 12, tiffHeaderOffset);
                                                            }
                                                            else
                                                            {
                                                                if ("AOC\u0000".Equals(firstFourChars))
                                                                {
                                                                    // NON-Standard TIFF IFD Data using Casio Type 2 Tags
                                                                    // IFD has no Next-IFD pointer at end of IFD, and
                                                                    // Offsets are relative to the start of the current IFD tag, not the TIFF header
                                                                    // Observed for:
                                                                    // - Pentax ist D
                                                                    PushDirectory <CasioType2MakernoteDirectory>();
                                                                    TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset + 6, makernoteOffset);
                                                                }
                                                                else
                                                                {
                                                                    if (cameraMake != null && (cameraMake.ToUpper().StartsWith("PENTAX") || cameraMake.ToUpper().StartsWith("ASAHI")))
                                                                    {
                                                                        // NON-Standard TIFF IFD Data using Pentax Tags
                                                                        // IFD has no Next-IFD pointer at end of IFD, and
                                                                        // Offsets are relative to the start of the current IFD tag, not the TIFF header
                                                                        // Observed for:
                                                                        // - PENTAX Optio 330
                                                                        // - PENTAX Optio 430
                                                                        PushDirectory <PentaxMakernoteDirectory>();
                                                                        TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset, makernoteOffset);
                                                                    }
                                                                    else
                                                                    {
                                                                        //        } else if ("KC".equals(firstTwoChars) || "MINOL".equals(firstFiveChars) || "MLY".equals(firstThreeChars) || "+M+M+M+M".equals(firstEightChars)) {
                                                                        //            // This Konica data is not understood.  Header identified in accordance with information at this site:
                                                                        //            // http://www.ozhiker.com/electronics/pjmt/jpeg_info/minolta_mn.html
                                                                        //            // TODO add support for minolta/konica cameras
                                                                        //            exifDirectory.addError("Unsupported Konica/Minolta data ignored.");
                                                                        if ("SANYO\x0\x1\x0".Equals(firstEightChars))
                                                                        {
                                                                            PushDirectory <SanyoMakernoteDirectory>();
                                                                            TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset + 8, makernoteOffset);
                                                                        }
                                                                        else
                                                                        {
                                                                            if (cameraMake != null && cameraMake.ToLower().StartsWith("ricoh"))
                                                                            {
                                                                                if (firstTwoChars.Equals("Rv") || firstThreeChars.Equals("Rev"))
                                                                                {
                                                                                    // This is a textual format, where the makernote bytes look like:
                                                                                    //   Rv0103;Rg1C;Bg18;Ll0;Ld0;Aj0000;Bn0473800;Fp2E00:пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ
                                                                                    //   Rv0103;Rg1C;Bg18;Ll0;Ld0;Aj0000;Bn0473800;Fp2D05:пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ
                                                                                    //   Rv0207;Sf6C84;Rg76;Bg60;Gg42;Ll0;Ld0;Aj0004;Bn0B02900;Fp10B8;Md6700;Ln116900086D27;Sv263:0000000000000000000000пїЅпїЅ
                                                                                    // This format is currently unsupported
                                                                                    return(false);
                                                                                }
                                                                                else
                                                                                {
                                                                                    if (Sharpen.Runtime.EqualsIgnoreCase(firstFiveChars, "Ricoh"))
                                                                                    {
                                                                                        // Always in Motorola byte order
                                                                                        reader.SetMotorolaByteOrder(true);
                                                                                        PushDirectory <RicohMakernoteDirectory>();
                                                                                        TiffReader.ProcessIfd(this, reader, processedIfdOffsets, makernoteOffset + 8, makernoteOffset);
                                                                                    }
                                                                                }
                                                                            }
                                                                            else
                                                                            {
                                                                                // The makernote is not comprehended by this library.
                                                                                // If you are reading this and believe a particular camera's image should be processed, get in touch.
                                                                                return(false);
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            reader.SetMotorolaByteOrder(byteOrderBefore);
            return(true);
        }
Esempio n. 20
0
 /// <exception cref="System.IO.IOException"/>
 public override bool CustomProcessTag(int tagOffset, [NotNull] ICollection <int?> processedIfdOffsets, int tiffHeaderOffset, [NotNull] RandomAccessReader reader, int tagId, int byteCount)
 {
     // Custom processing for the Makernote tag
     if (tagId == ExifSubIFDDirectory.TagMakernote && _currentDirectory is ExifSubIFDDirectory)
     {
         return(ProcessMakernote(tagOffset, processedIfdOffsets, tiffHeaderOffset, reader));
     }
     // Custom processing for embedded IPTC data
     if (tagId == ExifSubIFDDirectory.TagIptcNaa && _currentDirectory is ExifIFD0Directory)
     {
         // NOTE Adobe sets type 4 for IPTC instead of 7
         if (reader.GetInt8(tagOffset) == unchecked ((int)(0x1c)))
         {
             sbyte[] iptcBytes = reader.GetBytes(tagOffset, byteCount);
             new IptcReader().Extract(new SequentialByteArrayReader(iptcBytes), _metadata, iptcBytes.Length);
             return(true);
         }
         return(false);
     }
     return(false);
 }
Esempio n. 21
0
 /// <exception cref="System.IO.IOException"/>
 public override bool CustomProcessTag(int makernoteOffset, ICollection <int> processedIfdOffsets, int tiffHeaderOffset, RandomAccessReader reader, int tagId, int byteCount)
 {
     // In Exif, we only want custom processing for the Makernote tag
     if (tagId == ExifSubIFDDirectory.TagMakernote && _currentDirectory is ExifSubIFDDirectory)
     {
         return(ProcessMakernote(makernoteOffset, processedIfdOffsets, tiffHeaderOffset, reader, byteCount));
     }
     return(false);
 }
Esempio n. 22
0
 public abstract void Completed(RandomAccessReader arg1, int arg2);
Esempio n. 23
0
 /// <summary>Processes a TIFF IFD.</summary>
 /// <remarks>
 /// Processes a TIFF IFD.
 /// <p/>
 /// IFD Header:
 /// <ul>
 /// <li><b>2 bytes</b> number of tags</li>
 /// </ul>
 /// Tag structure:
 /// <ul>
 /// <li><b>2 bytes</b> tag type</li>
 /// <li><b>2 bytes</b> format code (values 1 to 12, inclusive)</li>
 /// <li><b>4 bytes</b> component count</li>
 /// <li><b>4 bytes</b> inline value, or offset pointer if too large to fit in four bytes</li>
 /// </ul>
 /// </remarks>
 /// <param name="handler">
 /// the
 /// <see cref="TiffHandler"/>
 /// that will coordinate processing and accept read values
 /// </param>
 /// <param name="reader">
 /// the
 /// <see cref="Com.Drew.Lang.RandomAccessReader"/>
 /// from which the data should be read
 /// </param>
 /// <param name="processedIfdOffsets">the set of visited IFD offsets, to avoid revisiting the same IFD in an endless loop</param>
 /// <param name="ifdOffset">the offset within <code>reader</code> at which the IFD data starts</param>
 /// <param name="tiffHeaderOffset">the offset within <code>reader</code> at which the TIFF header starts</param>
 /// <exception cref="System.IO.IOException">an error occurred while accessing the required data</exception>
 public static void ProcessIfd(TiffHandler handler, RandomAccessReader reader, ICollection <int> processedIfdOffsets, int ifdOffset, int tiffHeaderOffset)
 {
     try
     {
         // 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)
         {
             handler.Error("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())
         {
             handler.Error("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 id
             int tagId = reader.GetUInt16(tagOffset);
             // 2 bytes for the format code
             int            formatCode = reader.GetUInt16(tagOffset + 2);
             TiffDataFormat format     = TiffDataFormat.FromTiffFormatCode(formatCode);
             if (format == null)
             {
                 // 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.
                 handler.Error("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)
             {
                 handler.Error("Negative TIFF tag component count");
                 continue;
             }
             int byteCount = componentCount * format.GetComponentSizeBytes();
             int tagValueOffset;
             if (byteCount > 4)
             {
                 // If it's bigger than 4 bytes, the dir entry contains an offset.
                 int offsetVal = reader.GetInt32(tagOffset + 8);
                 if (offsetVal + byteCount > reader.GetLength())
                 {
                     // Bogus pointer offset and / or byteCount value
                     handler.Error("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())
             {
                 handler.Error("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())
             {
                 handler.Error("Illegal number of bytes for TIFF tag data: " + byteCount);
                 continue;
             }
             //
             // Special handling for tags that point to other IFDs
             //
             if (byteCount == 4 && handler.IsTagIfdPointer(tagId))
             {
                 int subDirOffset = tiffHeaderOffset + reader.GetInt32(tagValueOffset);
                 ProcessIfd(handler, reader, processedIfdOffsets, subDirOffset, tiffHeaderOffset);
             }
             else
             {
                 if (!handler.CustomProcessTag(tagValueOffset, processedIfdOffsets, tiffHeaderOffset, reader, tagId, byteCount))
                 {
                     ProcessTag(handler, tagId, tagValueOffset, componentCount, formatCode, reader);
                 }
             }
         }
         // at the end of each IFD is an optional link to the next IFD
         int finalTagOffset = CalculateTagOffset(ifdOffset, dirTagCount);
         int nextIfdOffset  = reader.GetInt32(finalTagOffset);
         if (nextIfdOffset != 0)
         {
             nextIfdOffset += tiffHeaderOffset;
             if (nextIfdOffset >= 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 (nextIfdOffset < ifdOffset)
                 {
                     // TODO is this a valid restriction?
                     // Last 4 bytes of IFD reference another IFD with an address that is before the start of this directory
                     return;
                 }
             }
             if (handler.HasFollowerIfd())
             {
                 ProcessIfd(handler, reader, processedIfdOffsets, nextIfdOffset, tiffHeaderOffset);
             }
         }
     }
     finally
     {
         handler.EndingIFD();
     }
 }
Esempio n. 24
0
        /// <exception cref="System.IO.IOException"/>
        private static void ProcessTag(TiffHandler handler, int tagId, int tagValueOffset, int componentCount, int formatCode, RandomAccessReader reader)
        {
            switch (formatCode)
            {
            case TiffDataFormat.CodeUndefined:
            {
                // this includes exif user comments
                handler.SetByteArray(tagId, reader.GetBytes(tagValueOffset, componentCount));
                break;
            }

            case TiffDataFormat.CodeString:
            {
                handler.SetString(tagId, reader.GetNullTerminatedString(tagValueOffset, componentCount));
                break;
            }

            case TiffDataFormat.CodeRationalS:
            {
                if (componentCount == 1)
                {
                    handler.SetRational(tagId, new Rational(reader.GetInt32(tagValueOffset), reader.GetInt32(tagValueOffset + 4)));
                }
                else
                {
                    if (componentCount > 1)
                    {
                        Rational[] array = new Rational[componentCount];
                        for (int i = 0; i < componentCount; i++)
                        {
                            array[i] = new Rational(reader.GetInt32(tagValueOffset + (8 * i)), reader.GetInt32(tagValueOffset + 4 + (8 * i)));
                        }
                        handler.SetRationalArray(tagId, array);
                    }
                }
                break;
            }

            case TiffDataFormat.CodeRationalU:
            {
                if (componentCount == 1)
                {
                    handler.SetRational(tagId, new Rational(reader.GetUInt32(tagValueOffset), reader.GetUInt32(tagValueOffset + 4)));
                }
                else
                {
                    if (componentCount > 1)
                    {
                        Rational[] array = new Rational[componentCount];
                        for (int i = 0; i < componentCount; i++)
                        {
                            array[i] = new Rational(reader.GetUInt32(tagValueOffset + (8 * i)), reader.GetUInt32(tagValueOffset + 4 + (8 * i)));
                        }
                        handler.SetRationalArray(tagId, array);
                    }
                }
                break;
            }

            case TiffDataFormat.CodeSingle:
            {
                if (componentCount == 1)
                {
                    handler.SetFloat(tagId, reader.GetFloat32(tagValueOffset));
                }
                else
                {
                    float[] array = new float[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        array[i] = reader.GetFloat32(tagValueOffset + (i * 4));
                    }
                    handler.SetFloatArray(tagId, array);
                }
                break;
            }

            case TiffDataFormat.CodeDouble:
            {
                if (componentCount == 1)
                {
                    handler.SetDouble(tagId, reader.GetDouble64(tagValueOffset));
                }
                else
                {
                    double[] array = new double[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        array[i] = reader.GetDouble64(tagValueOffset + (i * 4));
                    }
                    handler.SetDoubleArray(tagId, array);
                }
                break;
            }

            case TiffDataFormat.CodeInt8S:
            {
                if (componentCount == 1)
                {
                    handler.SetInt8s(tagId, reader.GetInt8(tagValueOffset));
                }
                else
                {
                    sbyte[] array = new sbyte[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        array[i] = reader.GetInt8(tagValueOffset + i);
                    }
                    handler.SetInt8sArray(tagId, array);
                }
                break;
            }

            case TiffDataFormat.CodeInt8U:
            {
                if (componentCount == 1)
                {
                    handler.SetInt8u(tagId, reader.GetUInt8(tagValueOffset));
                }
                else
                {
                    short[] array = new short[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        array[i] = reader.GetUInt8(tagValueOffset + i);
                    }
                    handler.SetInt8uArray(tagId, array);
                }
                break;
            }

            case TiffDataFormat.CodeInt16S:
            {
                if (componentCount == 1)
                {
                    handler.SetInt16s(tagId, (int)reader.GetInt16(tagValueOffset));
                }
                else
                {
                    short[] array = new short[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        array[i] = reader.GetInt16(tagValueOffset + (i * 2));
                    }
                    handler.SetInt16sArray(tagId, array);
                }
                break;
            }

            case TiffDataFormat.CodeInt16U:
            {
                if (componentCount == 1)
                {
                    handler.SetInt16u(tagId, reader.GetUInt16(tagValueOffset));
                }
                else
                {
                    int[] array = new int[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        array[i] = reader.GetUInt16(tagValueOffset + (i * 2));
                    }
                    handler.SetInt16uArray(tagId, array);
                }
                break;
            }

            case TiffDataFormat.CodeInt32S:
            {
                // NOTE 'long' in this case means 32 bit, not 64
                if (componentCount == 1)
                {
                    handler.SetInt32s(tagId, reader.GetInt32(tagValueOffset));
                }
                else
                {
                    int[] array = new int[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        array[i] = reader.GetInt32(tagValueOffset + (i * 4));
                    }
                    handler.SetInt32sArray(tagId, array);
                }
                break;
            }

            case TiffDataFormat.CodeInt32U:
            {
                // NOTE 'long' in this case means 32 bit, not 64
                if (componentCount == 1)
                {
                    handler.SetInt32u(tagId, reader.GetUInt32(tagValueOffset));
                }
                else
                {
                    long[] array = new long[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        array[i] = reader.GetUInt32(tagValueOffset + (i * 4));
                    }
                    handler.SetInt32uArray(tagId, array);
                }
                break;
            }

            default:
            {
                handler.Error(Sharpen.Extensions.StringFormat("Unknown format code %d for tag %d", formatCode, tagId));
                break;
            }
            }
        }