/// <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)); } }
/// <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); } }
/// <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); } }
protected internal virtual void PushDirectory([NotNull] Type directoryClass) { _directoryStack.Push(_currentDirectory); try { _currentDirectory = (Directory)System.Activator.CreateInstance(directoryClass); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (MemberAccessException e) { throw new RuntimeException(e); } _metadata.AddDirectory(_currentDirectory); }
protected internal DirectoryTiffHandler(Com.Drew.Metadata.Metadata metadata, Type initialDirectoryClass) { _metadata = metadata; try { _currentDirectory = (Directory)System.Activator.CreateInstance(initialDirectoryClass); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (MemberAccessException e) { throw new RuntimeException(e); } _metadata.AddDirectory(_currentDirectory); }
protected internal DirectoryTiffHandler(Com.Drew.Metadata.Metadata metadata, Type initialDirectoryClass) { _metadata = metadata; try { _currentDirectory = (Directory)System.Activator.CreateInstance(initialDirectoryClass); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (MemberAccessException e) { throw new RuntimeException(e); } _metadata.AddDirectory(_currentDirectory); }
public virtual void Extract(SequentialReader reader, Com.Drew.Metadata.Metadata metadata) { Com.Drew.Metadata.Directory directory = metadata.GetOrCreateDirectory <AdobeJpegDirectory>(); try { reader.SetMotorolaByteOrder(false); if (!reader.GetString(5).Equals("Adobe")) { directory.AddError("Invalid Adobe JPEG data header."); return; } directory.SetInt(AdobeJpegDirectory.TagDctEncodeVersion, reader.GetUInt16()); directory.SetInt(AdobeJpegDirectory.TagApp14Flags0, reader.GetUInt16()); directory.SetInt(AdobeJpegDirectory.TagApp14Flags1, reader.GetUInt16()); directory.SetInt(AdobeJpegDirectory.TagColorTransform, reader.GetInt8()); } catch (IOException ex) { directory.AddError("IO exception processing data: " + ex.Message); } }
protected internal virtual void PushDirectory <T>() where T : Com.Drew.Metadata.Directory { System.Diagnostics.Debug.Assert((typeof(T) != _currentDirectory.GetType())); _directoryStack.Push(_currentDirectory); _currentDirectory = _metadata.GetOrCreateDirectory <T>(); }
public virtual void Setup() { _directory = new MockDirectory(); }
public Tag(int tagType, Com.Drew.Metadata.Directory directory) { _tagType = tagType; _directory = directory; }
private void Validate(Com.Drew.Metadata.Metadata metadata) { Com.Drew.Metadata.Directory directory = metadata.GetDirectory <ExifSubIFDDirectory>(); NUnit.Framework.Assert.IsNotNull(directory); Sharpen.Tests.AreEqual("80", directory.GetString(ExifSubIFDDirectory.TagIsoEquivalent)); }
/// <exception cref="System.IO.IOException"/> private void ProcessTag([NotNull] SequentialReader reader, [NotNull] Com.Drew.Metadata.Directory directory, int directoryType, int tagType, int tagByteCount) { int tagIdentifier = tagType | (directoryType << 8); // Some images have been seen that specify a zero byte tag, which cannot be of much use. // We elect here to completely ignore the tag. The IPTC specification doesn't mention // anything about the interpretation of this situation. // https://raw.githubusercontent.com/wiki/drewnoakes/metadata-extractor/docs/IPTC-IIMV4.2.pdf if (tagByteCount == 0) { directory.SetString(tagIdentifier, string.Empty); return; } string @string = null; switch (tagIdentifier) { case IptcDirectory.TagCodedCharacterSet: { sbyte[] bytes = reader.GetBytes(tagByteCount); string charset = Iso2022Converter.ConvertISO2022CharsetToJavaCharset(bytes); if (charset == null) { // Unable to determine the charset, so fall through and treat tag as a regular string @string = Sharpen.Runtime.GetStringForBytes(bytes); break; } directory.SetString(tagIdentifier, charset); return; } case IptcDirectory.TagEnvelopeRecordVersion: case IptcDirectory.TagApplicationRecordVersion: case IptcDirectory.TagFileVersion: case IptcDirectory.TagArmVersion: case IptcDirectory.TagProgramVersion: { // short if (tagByteCount >= 2) { int shortValue = reader.GetUInt16(); reader.Skip(tagByteCount - 2); directory.SetInt(tagIdentifier, shortValue); return; } break; } case IptcDirectory.TagUrgency: { // byte directory.SetInt(tagIdentifier, reader.GetUInt8()); reader.Skip(tagByteCount - 1); return; } case IptcDirectory.TagReleaseDate: case IptcDirectory.TagDateCreated: { // Date object if (tagByteCount >= 8) { @string = reader.GetString(tagByteCount); try { int year = System.Convert.ToInt32(Sharpen.Runtime.Substring(@string, 0, 4)); int month = System.Convert.ToInt32(Sharpen.Runtime.Substring(@string, 4, 6)) - 1; int day = System.Convert.ToInt32(Sharpen.Runtime.Substring(@string, 6, 8)); DateTime date = new Sharpen.GregorianCalendar(year, month, day).GetTime(); directory.SetDate(tagIdentifier, date); return; } catch (FormatException) { } } else { // fall through and we'll process the 'string' value below reader.Skip(tagByteCount); } goto case IptcDirectory.TagReleaseTime; } case IptcDirectory.TagReleaseTime: case IptcDirectory.TagTimeCreated: default: { break; } } // time... // fall through // If we haven't returned yet, treat it as a string // NOTE that there's a chance we've already loaded the value as a string above, but failed to parse the value if (@string == null) { string encoding = directory.GetString(IptcDirectory.TagCodedCharacterSet); if (encoding != null) { @string = reader.GetString(tagByteCount, encoding); } else { sbyte[] bytes_1 = reader.GetBytes(tagByteCount); encoding = Iso2022Converter.GuessEncoding(bytes_1); @string = encoding != null?Sharpen.Runtime.GetStringForBytes(bytes_1, encoding) : Sharpen.Runtime.GetStringForBytes(bytes_1); } } if (directory.ContainsTag(tagIdentifier)) { // this fancy string[] business avoids using an ArrayList for performance reasons string[] oldStrings = directory.GetStringArray(tagIdentifier); string[] newStrings; if (oldStrings == null) { newStrings = new string[1]; } else { newStrings = new string[oldStrings.Length + 1]; System.Array.Copy(oldStrings, 0, newStrings, 0, oldStrings.Length); } newStrings[newStrings.Length - 1] = @string; directory.SetStringArray(tagIdentifier, newStrings); } else { directory.SetString(tagIdentifier, @string); } }
/// <exception cref="System.IO.IOException"/> private void ProcessTag(SequentialReader reader, Com.Drew.Metadata.Directory directory, int directoryType, int tagType, int tagByteCount) { int tagIdentifier = tagType | (directoryType << 8); string @string = null; switch (tagIdentifier) { case IptcDirectory.TagApplicationRecordVersion: { // short int shortValue = reader.GetUInt16(); reader.Skip(tagByteCount - 2); directory.SetInt(tagIdentifier, shortValue); return; } case IptcDirectory.TagUrgency: { // byte directory.SetInt(tagIdentifier, reader.GetUInt8()); reader.Skip(tagByteCount - 1); return; } case IptcDirectory.TagReleaseDate: case IptcDirectory.TagDateCreated: { // Date object if (tagByteCount >= 8) { @string = reader.GetString(tagByteCount); try { int year = System.Convert.ToInt32(Sharpen.Runtime.Substring(@string, 0, 4)); int month = System.Convert.ToInt32(Sharpen.Runtime.Substring(@string, 4, 6)) - 1; int day = System.Convert.ToInt32(Sharpen.Runtime.Substring(@string, 6, 8)); DateTime date = new Sharpen.GregorianCalendar(year, month, day).GetTime(); directory.SetDate(tagIdentifier, date); return; } catch (FormatException) { } } else { // fall through and we'll process the 'string' value below reader.Skip(tagByteCount); } goto case IptcDirectory.TagReleaseTime; } case IptcDirectory.TagReleaseTime: case IptcDirectory.TagTimeCreated: default: { break; } } // time... // fall through // If we haven't returned yet, treat it as a string // NOTE that there's a chance we've already loaded the value as a string above, but failed to parse the value if (@string == null) { @string = reader.GetString(tagByteCount, Runtime.GetProperty("file.encoding")); } // "ISO-8859-1" if (directory.ContainsTag(tagIdentifier)) { // this fancy string[] business avoids using an ArrayList for performance reasons string[] oldStrings = directory.GetStringArray(tagIdentifier); string[] newStrings; if (oldStrings == null) { newStrings = new string[1]; } else { newStrings = new string[oldStrings.Length + 1]; System.Array.Copy(oldStrings, 0, newStrings, 0, oldStrings.Length); } newStrings[newStrings.Length - 1] = @string; directory.SetStringArray(tagIdentifier, newStrings); } else { directory.SetString(tagIdentifier, @string); } }
public virtual void Setup() { _directory = new MockDirectory(); }
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); } }
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); } } } }
/// <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); }
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; } } }
protected internal virtual void PushDirectory([NotNull] Type directoryClass) { _directoryStack.Push(_currentDirectory); try { _currentDirectory = (Directory)System.Activator.CreateInstance(directoryClass); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (MemberAccessException e) { throw new RuntimeException(e); } _metadata.AddDirectory(_currentDirectory); }
public virtual void EndingIFD() { _currentDirectory = _directoryStack.IsEmpty() ? null : _directoryStack.Pop(); }
protected internal DirectoryTiffHandler(Com.Drew.Metadata.Metadata metadata, Type initialDirectory) { _metadata = metadata; _currentDirectory = _metadata.GetOrCreateDirectory(initialDirectory); }
public Tag(int tagType, [NotNull] Com.Drew.Metadata.Directory directory) { _tagType = tagType; _directory = directory; }
public virtual void EndingIFD() { _currentDirectory = _directoryStack.IsEmpty() ? null : _directoryStack.Pop(); }