/// <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); }
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); } }
/// <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); }