Esempio n. 1
0
 /// <exception cref="System.IO.IOException"/>
 public override bool CustomProcessTag(int tagOffset, ICollection <int> processedIfdOffsets, int tiffHeaderOffset, IndexedReader reader, int tagId, int byteCount)
 {
     // Custom processing for the Makernote tag
     if (tagId == ExifDirectoryBase.TagMakernote && CurrentDirectory is ExifSubIfdDirectory)
     {
         return(ProcessMakernote(tagOffset, processedIfdOffsets, tiffHeaderOffset, reader));
     }
     // Custom processing for embedded IPTC data
     if (tagId == ExifDirectoryBase.TagIptcNaa && CurrentDirectory is ExifIfd0Directory)
     {
         // NOTE Adobe sets type 4 for IPTC instead of 7
         if (reader.GetSByte(tagOffset) == 0x1c)
         {
             var iptcBytes = reader.GetBytes(tagOffset, byteCount);
             Directories.Add(new IptcReader().Extract(new SequentialByteArrayReader(iptcBytes), iptcBytes.Length));
             return(true);
         }
         return(false);
     }
     return(false);
 }
Esempio n. 2
0
        private static void ProcessKodakMakernote([NotNull] KodakMakernoteDirectory directory, int tagValueOffset, [NotNull] IndexedReader reader)
        {
            // Kodak's makernote is not in IFD format. It has values at fixed offsets.
            var dataOffset = tagValueOffset + 8;

            try
            {
                directory.Set(KodakMakernoteDirectory.TagKodakModel, reader.GetString(dataOffset, 8));
                directory.Set(KodakMakernoteDirectory.TagQuality, reader.GetByte(dataOffset + 9));
                directory.Set(KodakMakernoteDirectory.TagBurstMode, reader.GetByte(dataOffset + 10));
                directory.Set(KodakMakernoteDirectory.TagImageWidth, reader.GetUInt16(dataOffset + 12));
                directory.Set(KodakMakernoteDirectory.TagImageHeight, reader.GetUInt16(dataOffset + 14));
                directory.Set(KodakMakernoteDirectory.TagYearCreated, reader.GetUInt16(dataOffset + 16));
                directory.Set(KodakMakernoteDirectory.TagMonthDayCreated, reader.GetBytes(dataOffset + 18, 2));
                directory.Set(KodakMakernoteDirectory.TagTimeCreated, reader.GetBytes(dataOffset + 20, 4));
                directory.Set(KodakMakernoteDirectory.TagBurstMode2, reader.GetUInt16(dataOffset + 24));
                directory.Set(KodakMakernoteDirectory.TagShutterMode, reader.GetByte(dataOffset + 27));
                directory.Set(KodakMakernoteDirectory.TagMeteringMode, reader.GetByte(dataOffset + 28));
                directory.Set(KodakMakernoteDirectory.TagSequenceNumber, reader.GetByte(dataOffset + 29));
                directory.Set(KodakMakernoteDirectory.TagFNumber, reader.GetUInt16(dataOffset + 30));
                directory.Set(KodakMakernoteDirectory.TagExposureTime, reader.GetUInt32(dataOffset + 32));
                directory.Set(KodakMakernoteDirectory.TagExposureCompensation, reader.GetInt16(dataOffset + 36));
                directory.Set(KodakMakernoteDirectory.TagFocusMode, reader.GetByte(dataOffset + 56));
                directory.Set(KodakMakernoteDirectory.TagWhiteBalance, reader.GetByte(dataOffset + 64));
                directory.Set(KodakMakernoteDirectory.TagFlashMode, reader.GetByte(dataOffset + 92));
                directory.Set(KodakMakernoteDirectory.TagFlashFired, reader.GetByte(dataOffset + 93));
                directory.Set(KodakMakernoteDirectory.TagIsoSetting, reader.GetUInt16(dataOffset + 94));
                directory.Set(KodakMakernoteDirectory.TagIso, reader.GetUInt16(dataOffset + 96));
                directory.Set(KodakMakernoteDirectory.TagTotalZoom, reader.GetUInt16(dataOffset + 98));
                directory.Set(KodakMakernoteDirectory.TagDateTimeStamp, reader.GetUInt16(dataOffset + 100));
                directory.Set(KodakMakernoteDirectory.TagColorMode, reader.GetUInt16(dataOffset + 102));
                directory.Set(KodakMakernoteDirectory.TagDigitalZoom, reader.GetUInt16(dataOffset + 104));
                directory.Set(KodakMakernoteDirectory.TagSharpness, reader.GetSByte(dataOffset + 107));
            }
            catch (IOException ex)
            {
                directory.AddError("Error processing Kodak makernote data: " + ex.Message);
            }
        }
Esempio n. 3
0
        /// <exception cref="System.IO.IOException"/>
        private static void ProcessTag(ITiffHandler handler, int tagId, int tagValueOffset, int componentCount, TiffDataFormatCode formatCode, IndexedReader reader)
        {
            switch (formatCode)
            {
            case TiffDataFormatCode.Undefined:
            {
                // this includes exif user comments
                handler.SetByteArray(tagId, reader.GetBytes(tagValueOffset, componentCount));
                break;
            }

            case TiffDataFormatCode.String:
            {
                handler.SetString(tagId, reader.GetNullTerminatedStringValue(tagValueOffset, componentCount));
                break;
            }

            case TiffDataFormatCode.RationalS:
            {
                if (componentCount == 1)
                {
                    handler.SetRational(tagId, new Rational(reader.GetInt32(tagValueOffset), reader.GetInt32(tagValueOffset + 4)));
                }
                else if (componentCount > 1)
                {
                    var array = new Rational[componentCount];
                    for (var 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 TiffDataFormatCode.RationalU:
            {
                if (componentCount == 1)
                {
                    handler.SetRational(tagId, new Rational(reader.GetUInt32(tagValueOffset), reader.GetUInt32(tagValueOffset + 4)));
                }
                else if (componentCount > 1)
                {
                    var array = new Rational[componentCount];
                    for (var 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 TiffDataFormatCode.Single:
            {
                if (componentCount == 1)
                {
                    handler.SetFloat(tagId, reader.GetFloat32(tagValueOffset));
                }
                else
                {
                    var array = new float[componentCount];
                    for (var i = 0; i < componentCount; i++)
                    {
                        array[i] = reader.GetFloat32(tagValueOffset + i * 4);
                    }
                    handler.SetFloatArray(tagId, array);
                }
                break;
            }

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

            case TiffDataFormatCode.Int8S:
            {
                if (componentCount == 1)
                {
                    handler.SetInt8S(tagId, reader.GetSByte(tagValueOffset));
                }
                else
                {
                    var array = new sbyte[componentCount];
                    for (var i = 0; i < componentCount; i++)
                    {
                        array[i] = reader.GetSByte(tagValueOffset + i);
                    }
                    handler.SetInt8SArray(tagId, array);
                }
                break;
            }

            case TiffDataFormatCode.Int8U:
            {
                if (componentCount == 1)
                {
                    handler.SetInt8U(tagId, reader.GetByte(tagValueOffset));
                }
                else
                {
                    var array = new byte[componentCount];
                    for (var i = 0; i < componentCount; i++)
                    {
                        array[i] = reader.GetByte(tagValueOffset + i);
                    }
                    handler.SetInt8UArray(tagId, array);
                }
                break;
            }

            case TiffDataFormatCode.Int16S:
            {
                if (componentCount == 1)
                {
                    handler.SetInt16S(tagId, reader.GetInt16(tagValueOffset));
                }
                else
                {
                    var array = new short[componentCount];
                    for (var i = 0; i < componentCount; i++)
                    {
                        array[i] = reader.GetInt16(tagValueOffset + i * 2);
                    }
                    handler.SetInt16SArray(tagId, array);
                }
                break;
            }

            case TiffDataFormatCode.Int16U:
            {
                if (componentCount == 1)
                {
                    handler.SetInt16U(tagId, reader.GetUInt16(tagValueOffset));
                }
                else
                {
                    var array = new ushort[componentCount];
                    for (var i = 0; i < componentCount; i++)
                    {
                        array[i] = reader.GetUInt16(tagValueOffset + i * 2);
                    }
                    handler.SetInt16UArray(tagId, array);
                }
                break;
            }

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

            case TiffDataFormatCode.Int32U:
            {
                // NOTE 'long' in this case means 32 bit, not 64
                if (componentCount == 1)
                {
                    handler.SetInt32U(tagId, reader.GetUInt32(tagValueOffset));
                }
                else
                {
                    var array = new uint[componentCount];
                    for (var i = 0; i < componentCount; i++)
                    {
                        array[i] = reader.GetUInt32(tagValueOffset + i * 4);
                    }
                    handler.SetInt32UArray(tagId, array);
                }
                break;
            }

            default:
            {
                handler.Error($"Invalid TIFF tag format code {formatCode} for tag 0x{tagId:X4}");
                break;
            }
            }
        }
        public override bool CustomProcessTag(int tagOffset, ICollection <int> processedIfdOffsets, IndexedReader reader, int tagId, int byteCount)
        {
            // Some 0x0000 tags have a 0 byteCount. Determine whether it's bad.
            if (tagId == 0)
            {
                if (CurrentDirectory.ContainsTag(tagId))
                {
                    // Let it go through for now. Some directories handle it, some don't.
                    return(false);
                }

                // Skip over 0x0000 tags that don't have any associated bytes. No idea what it contains in this case, if anything.
                if (byteCount == 0)
                {
                    return(true);
                }
            }

            // Custom processing for the Makernote tag
            if (tagId == ExifDirectoryBase.TagMakernote && CurrentDirectory is ExifSubIfdDirectory)
            {
                return(ProcessMakernote(tagOffset, processedIfdOffsets, reader));
            }

            // Custom processing for embedded IPTC data
            if (tagId == ExifDirectoryBase.TagIptcNaa && CurrentDirectory is ExifIfd0Directory)
            {
                // NOTE Adobe sets type 4 for IPTC instead of 7
                if (reader.GetSByte(tagOffset) == 0x1c)
                {
                    var iptcBytes     = reader.GetBytes(tagOffset, byteCount);
                    var iptcDirectory = new IptcReader().Extract(new SequentialByteArrayReader(iptcBytes), iptcBytes.Length);
                    iptcDirectory.Parent = CurrentDirectory;
                    Directories.Add(iptcDirectory);
                    return(true);
                }
                return(false);
            }

            // Custom processing for embedded XMP data
            if (tagId == ExifDirectoryBase.TagApplicationNotes && CurrentDirectory is ExifIfd0Directory)
            {
                var xmpDirectory = new XmpReader().Extract(reader.GetNullTerminatedBytes(tagOffset, byteCount));
                xmpDirectory.Parent = CurrentDirectory;
                Directories.Add(xmpDirectory);
                return(true);
            }

            if (HandlePrintIM(CurrentDirectory, tagId))
            {
                var dirPrintIm = new PrintIMDirectory();
                dirPrintIm.Parent = CurrentDirectory;
                Directories.Add(dirPrintIm);
                ProcessPrintIM(dirPrintIm, tagOffset, reader, byteCount);
                return(true);
            }

            // Note: these also appear in TryEnterSubIfd because some are IFD pointers while others begin immediately
            // for the same directories
            if (CurrentDirectory is OlympusMakernoteDirectory)
            {
                switch (tagId)
                {
                case OlympusMakernoteDirectory.TagEquipment:
                    PushDirectory(new OlympusEquipmentMakernoteDirectory());
                    TiffReader.ProcessIfd(this, reader, processedIfdOffsets, tagOffset);
                    return(true);

                case OlympusMakernoteDirectory.TagCameraSettings:
                    PushDirectory(new OlympusCameraSettingsMakernoteDirectory());
                    TiffReader.ProcessIfd(this, reader, processedIfdOffsets, tagOffset);
                    return(true);

                case OlympusMakernoteDirectory.TagRawDevelopment:
                    PushDirectory(new OlympusRawDevelopmentMakernoteDirectory());
                    TiffReader.ProcessIfd(this, reader, processedIfdOffsets, tagOffset);
                    return(true);

                case OlympusMakernoteDirectory.TagRawDevelopment2:
                    PushDirectory(new OlympusRawDevelopment2MakernoteDirectory());
                    TiffReader.ProcessIfd(this, reader, processedIfdOffsets, tagOffset);
                    return(true);

                case OlympusMakernoteDirectory.TagImageProcessing:
                    PushDirectory(new OlympusImageProcessingMakernoteDirectory());
                    TiffReader.ProcessIfd(this, reader, processedIfdOffsets, tagOffset);
                    return(true);

                case OlympusMakernoteDirectory.TagFocusInfo:
                    PushDirectory(new OlympusFocusInfoMakernoteDirectory());
                    TiffReader.ProcessIfd(this, reader, processedIfdOffsets, tagOffset);
                    return(true);

                case OlympusMakernoteDirectory.TagRawInfo:
                    PushDirectory(new OlympusRawInfoMakernoteDirectory());
                    TiffReader.ProcessIfd(this, reader, processedIfdOffsets, tagOffset);
                    return(true);

                case OlympusMakernoteDirectory.TagMainInfo:
                    PushDirectory(new OlympusMakernoteDirectory());
                    TiffReader.ProcessIfd(this, reader, processedIfdOffsets, tagOffset);
                    return(true);
                }
            }

            if (CurrentDirectory is PanasonicRawIfd0Directory)
            {
                // these contain binary data with specific offsets, and can't be processed as regular ifd's.
                // The binary data is broken into 'fake' tags and there is a pattern.
                switch (tagId)
                {
                case PanasonicRawIfd0Directory.TagWbInfo:
                    var dirWbInfo = new PanasonicRawWbInfoDirectory();
                    dirWbInfo.Parent = CurrentDirectory;
                    Directories.Add(dirWbInfo);
                    ProcessBinary(dirWbInfo, tagOffset, reader, byteCount, false, 2);
                    return(true);

                case PanasonicRawIfd0Directory.TagWbInfo2:
                    var dirWbInfo2 = new PanasonicRawWbInfo2Directory();
                    dirWbInfo2.Parent = CurrentDirectory;
                    Directories.Add(dirWbInfo2);
                    ProcessBinary(dirWbInfo2, tagOffset, reader, byteCount, false, 3);
                    return(true);

                case PanasonicRawIfd0Directory.TagDistortionInfo:
                    var dirDistort = new PanasonicRawDistortionDirectory();
                    dirDistort.Parent = CurrentDirectory;
                    Directories.Add(dirDistort);
                    ProcessBinary(dirDistort, tagOffset, reader, byteCount);
                    return(true);
                }
            }

            // Panasonic RAW sometimes contains an embedded version of the data as a JPG file.
            if (tagId == PanasonicRawIfd0Directory.TagJpgFromRaw && CurrentDirectory is PanasonicRawIfd0Directory)
            {
                var jpegrawbytes = reader.GetBytes(tagOffset, byteCount);

                // Extract information from embedded image since it is metadata-rich
                var jpegmem       = new MemoryStream(jpegrawbytes);
                var jpegDirectory = Jpeg.JpegMetadataReader.ReadMetadata(jpegmem);
                foreach (var dir in jpegDirectory)
                {
                    dir.Parent = CurrentDirectory;
                    Directories.Add(dir);
                }
                return(true);
            }

            return(false);
        }