private static void ProcessReconyxMakernote([NotNull] ReconyxMakernoteDirectory directory, int makernoteOffset, [NotNull] IndexedReader reader)
        {
            directory.Set(ReconyxMakernoteDirectory.TagMakernoteVersion, reader.GetUInt16(makernoteOffset));

            // revision and build are reversed from .NET ordering
            ushort major     = reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagFirmwareVersion);
            ushort minor     = reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagFirmwareVersion + 2);
            ushort revision  = reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagFirmwareVersion + 4);
            string buildYear = reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagFirmwareVersion + 6).ToString("x4");
            string buildDate = reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagFirmwareVersion + 8).ToString("x4");
            int    build     = int.Parse(buildYear + buildDate);

            directory.Set(ReconyxMakernoteDirectory.TagFirmwareVersion, new Version(major, minor, revision, build));

            directory.Set(ReconyxMakernoteDirectory.TagTriggerMode, new string((char)reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagTriggerMode), 1));
            directory.Set(ReconyxMakernoteDirectory.TagSequence,
                          new[]
            {
                reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagSequence),
                reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagSequence + 2)
            });

            uint eventNumberHigh = reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagEventNumber);
            uint eventNumberLow  = reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagEventNumber + 2);

            directory.Set(ReconyxMakernoteDirectory.TagEventNumber, (eventNumberHigh << 16) + eventNumberLow);

            ushort seconds = reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagDateTimeOriginal);
            ushort minutes = reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagDateTimeOriginal + 2);
            ushort hour    = reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagDateTimeOriginal + 4);
            ushort month   = reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagDateTimeOriginal + 6);
            ushort day     = reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagDateTimeOriginal + 8);
            ushort year    = reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagDateTimeOriginal + 10);

            directory.Set(ReconyxMakernoteDirectory.TagDateTimeOriginal, new DateTime(year, month, day, hour, minutes, seconds));

            directory.Set(ReconyxMakernoteDirectory.TagMoonPhase, reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagMoonPhase));
            directory.Set(ReconyxMakernoteDirectory.TagAmbientTemperatureFarenheit, reader.GetInt16(makernoteOffset + ReconyxMakernoteDirectory.TagAmbientTemperatureFarenheit));
            directory.Set(ReconyxMakernoteDirectory.TagAmbientTemperature, reader.GetInt16(makernoteOffset + ReconyxMakernoteDirectory.TagAmbientTemperature));
            directory.Set(ReconyxMakernoteDirectory.TagSerialNumber, reader.GetString(makernoteOffset + ReconyxMakernoteDirectory.TagSerialNumber, 28, Encoding.Unicode));
            // two unread bytes: the serial number's terminating null

            directory.Set(ReconyxMakernoteDirectory.TagContrast, reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagContrast));
            directory.Set(ReconyxMakernoteDirectory.TagBrightness, reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagBrightness));
            directory.Set(ReconyxMakernoteDirectory.TagSharpness, reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagSharpness));
            directory.Set(ReconyxMakernoteDirectory.TagSaturation, reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagSaturation));
            directory.Set(ReconyxMakernoteDirectory.TagInfraredIlluminator, reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagInfraredIlluminator));
            directory.Set(ReconyxMakernoteDirectory.TagMotionSensitivity, reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagMotionSensitivity));
            directory.Set(ReconyxMakernoteDirectory.TagBatteryVoltage, reader.GetUInt16(makernoteOffset + ReconyxMakernoteDirectory.TagBatteryVoltage) / 1000.0);
            directory.Set(ReconyxMakernoteDirectory.TagUserLabel, reader.GetNullTerminatedString(makernoteOffset + ReconyxMakernoteDirectory.TagUserLabel, 44));
        }
        private static void ProcessBinary([NotNull] Directory directory, int tagValueOffset, [NotNull] IndexedReader reader, int byteCount, bool issigned = true, int arrayLength = 1)
        {
            // expects signed/unsigned int16 (for now)
            int byteSize = issigned ? sizeof(short) : sizeof(ushort);

            // 'directory' is assumed to contain tags that correspond to the byte position unless it's a set of bytes
            for (var i = 0; i < byteCount; i++)
            {
                if (directory.HasTagName(i))
                {
                    // only process this tag if the 'next' integral tag exists. Otherwise, it's a set of bytes
                    if (i < byteCount - 1 && directory.HasTagName(i + 1))
                    {
                        if (issigned)
                        {
                            directory.Set(i, reader.GetInt16(tagValueOffset + (i * byteSize)));
                        }
                        else
                        {
                            directory.Set(i, reader.GetUInt16(tagValueOffset + (i * byteSize)));
                        }
                    }
                    else
                    {
                        // the next arrayLength bytes are a multi-byte value
                        if (issigned)
                        {
                            short[] val = new short[arrayLength];
                            for (int j = 0; j < val.Length; j++)
                            {
                                val[j] = reader.GetInt16(tagValueOffset + ((i + j) * byteSize));
                            }
                            directory.Set(i, val);
                        }
                        else
                        {
                            ushort[] val = new ushort[arrayLength];
                            for (int j = 0; j < val.Length; j++)
                            {
                                val[j] = reader.GetUInt16(tagValueOffset + ((i + j) * byteSize));
                            }
                            directory.Set(i, val);
                        }

                        i += arrayLength - 1;
                    }
                }
            }
        }
예제 #3
0
        /// <summary>Processes a TIFF data sequence.</summary>
        /// <param name="reader">the <see cref="IndexedReader"/> from which the data should be read</param>
        /// <param name="handler">the <see cref="ITiffHandler"/> that will coordinate processing and accept read values</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="TiffProcessingException"/>
        public static void ProcessTiff(IndexedReader reader, ITiffHandler handler)
        {
            // Read byte order.
            var byteOrder = reader.GetInt16(0);

            reader = byteOrder switch
            {
                0x4d4d => reader.WithByteOrder(isMotorolaByteOrder: true),
                0x4949 => reader.WithByteOrder(isMotorolaByteOrder: false),
                _ => throw new TiffProcessingException("Unclear distinction between Motorola/Intel byte ordering: " + reader.GetInt16(0)),
            };

            // Check the next two values for correctness.
            int tiffMarker = reader.GetUInt16(2);

            handler.SetTiffMarker(tiffMarker);

            var firstIfdOffset = reader.GetInt32(4);

            // David Ekholm sent a digital camera image that has this problem
            // TODO calling Length should be avoided as it causes IndexedCapturingReader to read to the end of the stream
            if (firstIfdOffset >= reader.Length - 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 = 2 + 2 + 4;
            }

            var processedIfdOffsets = new HashSet <int>();

            ProcessIfd(handler, reader, processedIfdOffsets, firstIfdOffset);
        }
예제 #4
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);
            }
        }
예제 #5
0
        /// <summary>Processes a TIFF data sequence.</summary>
        /// <param name="reader">the <see cref="IndexedReader"/> from which the data should be read</param>
        /// <param name="handler">the <see cref="ITiffHandler"/> that will coordinate processing and accept read values</param>
        /// <param name="tiffHeaderOffset">the offset within <c>reader</c> 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="TiffProcessingException"/>
        public static void ProcessTiff([NotNull] IndexedReader reader, [NotNull] ITiffHandler handler, int tiffHeaderOffset = 0)
        {
            // Read byte order.
            switch (reader.GetInt16(tiffHeaderOffset))
            {
            case 0x4d4d:     // MM
                reader.IsMotorolaByteOrder = true;
                break;

            case 0x4949:     // II
                reader.IsMotorolaByteOrder = false;
                break;

            default:
                throw new TiffProcessingException("Unclear distinction between Motorola/Intel byte ordering: " + reader.GetInt16(tiffHeaderOffset));
            }

            // Check the next two values for correctness.
            int tiffMarker = reader.GetUInt16(2 + tiffHeaderOffset);

            handler.SetTiffMarker(tiffMarker);

            var firstIfdOffset = reader.GetInt32(4 + tiffHeaderOffset) + tiffHeaderOffset;

            // David Ekholm sent a digital camera image that has this problem
            // TODO calling Length should be avoided as it causes IndexedCapturingReader to read to the end of the stream
            if (firstIfdOffset >= reader.Length - 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;
            }

            var processedIfdOffsets = new HashSet <int>();

            ProcessIfd(handler, reader, processedIfdOffsets, firstIfdOffset, tiffHeaderOffset);

            handler.Completed(reader, tiffHeaderOffset);
        }
예제 #6
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;
            }
            }
        }