/// <summary> /// Gets a directory regarding its type /// </summary> /// <param name="aTypeStr">the type you are looking for</param> /// <returns>the directory found</returns> /// <exception cref="ArgumentException">if aType is not a Directory like class</exception> public AbstractDirectory GetDirectory(string aTypeStr) { Type aType = Type.GetType(aTypeStr); if (!Type.GetType("com.drew.metadata.AbstractDirectory").IsAssignableFrom(aType)) { throw new ArgumentException("Class type passed to GetDirectory must be an implementation of com.drew.metadata.AbstractDirectory"); } // check if we've already issued this type of directory if (this.ContainsDirectory(aType)) { return(directoryMap[aType]); } AbstractDirectory lcDirectory = null; try { ConstructorInfo[] lcConstructor = aType.GetConstructors(); lcDirectory = (AbstractDirectory)lcConstructor[0].Invoke(null); } catch (Exception e) { throw new SystemException( "Cannot instantiate provided Directory type: " + aType, e); } // store the directory in case it'str requested later this.directoryMap.Add(aType, lcDirectory); return(lcDirectory); }
/// <summary> /// Creates a new Directory. /// </summary> /// <param name="aBundleName">bundle name for this directory</param> protected AbstractDirectory(string aBundleName) : this() { this.BundleName = aBundleName; // Load the bundle IResourceBundle bundle = ResourceBundleFactory.CreateDefaultBundle(aBundleName); AbstractDirectory.tagNameMap[this.GetType()] = AbstractDirectory.FillTagMap(this.GetType(), bundle); }
/// <summary> /// Returns the specified tag value as a date, if possible. /// </summary> /// <param name="aTagType">the specified tag type</param> /// <returns>the specified tag value as a date, if possible.</returns> public DateTime GetDate(int aTagType) { object lcObj = GetObject(aTagType); if (lcObj == null) { throw new MetadataException( "Tag " + GetTagName(aTagType) + " has not been set -- check using containsTag() first"); } else if (lcObj is DateTime) { return((DateTime)lcObj); } else if (lcObj is string) { string lcDateString = (string)lcObj; try { DateTime res = DateTime.Today; if (DateTime.TryParse(lcDateString, out res)) { return(res); } // Was not able to parse date using standard format // We try the following format DateTime resu = AbstractDirectory.ParseDate(lcDateString); if (resu == DateTime.Today) { Trace.TraceWarning("Was not able to parse date '" + lcDateString + "'"); } return(resu); } catch { } } throw new MetadataException("Obj is :" + lcObj.GetType() + " and look like:" + lcObj.ToString()); }
/// <summary> /// Creates a directory tag. /// /// Examples : /// <pre> /// <directory name="Exif"> /// <tag> /// ... /// </tag> /// <tag> /// ... /// </tag> /// </directory> /// </pre> /// </summary> /// <param name="aBuff">where to put info</param> /// <param name="aDirectory">the information to add</param> protected virtual void CreateDirectory(StringBuilder aBuff, AbstractDirectory aDirectory) { if (aDirectory != null) { Open(aBuff, "directory name=\"" + aDirectory.GetName() + "\"", true); foreach(Tag lcTag in aDirectory) { CreateTag(aBuff, lcTag); } Close(aBuff, "directory", true); } }
/// <summary> /// Creates a directory tag. /// </summary> /// <param name="aBuff">where to put info</param> /// <param name="aDirectory">the information to add</param> protected virtual void CreateDirectory(StringBuilder aBuff, AbstractDirectory aDirectory) { if (aDirectory != null) { aBuff.Append("--| ").Append(aDirectory.GetName()).Append(" |--"); aBuff.AppendLine(); foreach(Tag lcTag in aDirectory) { CreateTag(aBuff, lcTag); } } }
/// <summary> /// Constructor of the object /// </summary> /// <param name="aDirectory">a base.directory</param> public KyoceraDescriptor(AbstractDirectory aDirectory) : base(aDirectory) { }
/// <summary> /// Constructor of the object /// </summary> /// <param name="aDirectory">a base.directory</param> public CasioType1Descriptor(AbstractDirectory aDirectory) : base(aDirectory) { }
/// <summary> /// Constructor of the object /// </summary> /// <param name="directory">a directory</param> public JpegDescriptor(AbstractDirectory directory) : base(directory) { }
/// <summary> /// Constructor of the object /// </summary> /// <param name="base.directory">a base.directory</param> public ExifInteropDescriptor(AbstractDirectory aDirectory) : base(aDirectory) { }
/// <summary> /// Creates a directory tag. /// /// Examples : /// <pre> /// <directory name="Exif"> /// <tag> /// ... /// </tag> /// <tag> /// ... /// </tag> /// </directory> /// </pre> /// </summary> /// <param name="aBuff">where to put info</param> /// <param name="aDirectory">the information to add</param> protected virtual void CreateDirectory(StringBuilder aBuff, AbstractDirectory aDirectory) { if (aDirectory != null) { this.Open(aBuff, "directory", "name", aDirectory.GetName(),"class", aDirectory.GetType(), true); foreach(Tag lcTag in aDirectory){ this.CreateTag(aBuff, lcTag); } this.Close(aBuff, "directory", true); } }
/// <summary> /// Constructor of the object /// </summary> /// <param name="aDirectory">a base.directory</param> public PanasonicDescriptor(AbstractDirectory aDirectory) : base(aDirectory) { }
/// <summary> /// Will stock the thumbnail into exif directory if available. /// </summary> /// <param name="exifDirectory">where to stock the thumbnail</param> /// <param name="tiffHeaderOffset">the tiff lcHeader lcOffset value</param> private void StoreThumbnailBytes(AbstractDirectory exifDirectory, int tiffHeaderOffset) { if (!exifDirectory.ContainsTag(ExifDirectory.TAG_COMPRESSION)) { return; } if (!exifDirectory.ContainsTag(ExifDirectory.TAG_THUMBNAIL_LENGTH) || !exifDirectory.ContainsTag(ExifDirectory.TAG_THUMBNAIL_OFFSET)) { return; } try { int offset = exifDirectory.GetInt(ExifDirectory.TAG_THUMBNAIL_OFFSET); int length = exifDirectory.GetInt(ExifDirectory.TAG_THUMBNAIL_LENGTH); byte[] result = new byte[length]; for (int i = 0; i < result.Length; i++) { result[i] = base.data[tiffHeaderOffset + offset + i]; } exifDirectory.SetObject(ExifDirectory.TAG_THUMBNAIL_DATA, result); } catch (Exception e) { exifDirectory.HasError = true; Trace.TraceError("Unable to extract thumbnail: " + e.Message); } }
/// <summary> /// Processes tag /// </summary> /// <param name="directory">the directory</param> /// <param name="aTagType">the tag type</param> /// <param name="tagValueOffset">the lcOffset value</param> /// <param name="componentCount">the component count</param> /// <param name="formatCode">the format code</param> private void ProcessTag( AbstractDirectory directory, int tagType, int tagValueOffset, int componentCount, int formatCode) { // Directory simply stores raw values // The display side uses a Descriptor class per directory to turn the raw values into 'pretty' descriptions switch (formatCode) { case FMT_UNDEFINED: Debug.Write("Found a tag made of bytes"); // this includes exif user comments byte[] tagBytes = new byte[componentCount]; int byteCount = componentCount * BYTES_PER_FORMAT[formatCode]; for (int i = 0; i < byteCount; i++) { tagBytes[i] = base.data[tagValueOffset + i]; } directory.SetObject(tagType, tagBytes); break; case FMT_STRING: Debug.Write("Found a tag made of string"); string lcStr = null; if (tagType == ExifDirectory.TAG_USER_COMMENT) { lcStr = ReadCommentString( tagValueOffset, componentCount, formatCode); } else { lcStr = ReadString(tagValueOffset, componentCount); } directory.SetObject(tagType, lcStr); break; case FMT_SRATIONAL: //goto case FMT_URATIONAL; case FMT_URATIONAL: if (componentCount == 1) { Debug.Write("Found a tag made of rational"); Rational rational = new Rational(Get32Bits(tagValueOffset), Get32Bits(tagValueOffset + 4)); directory.SetObject(tagType, rational); } else { Debug.Write("Found a tag made of rationals"); Rational[] rationals = new Rational[componentCount]; for (int i = 0; i < componentCount; i++) { rationals[i] = new Rational(Get32Bits(tagValueOffset + (8 * i)), Get32Bits(tagValueOffset + 4 + (8 * i))); } directory.SetObject(tagType, rationals); } break; case FMT_SBYTE: //goto case FMT_BYTE; case FMT_BYTE: if (componentCount == 1) { Debug.Write("Found a tag made of byte"); // this may need to be a byte, but I think casting to int is fine int b = base.data[tagValueOffset]; directory.SetObject(tagType, b); } else { Debug.Write("Found a tag made of bytes but will use ints"); int[] bytes = new int[componentCount]; for (int i = 0; i < componentCount; i++) { bytes[i] = base.data[tagValueOffset + i]; } directory.SetIntArray(tagType, bytes); } break; case FMT_SINGLE: //goto case FMT_DOUBLE; case FMT_DOUBLE: if (componentCount == 1) { Debug.Write("Found a tag made of double but will use int"); int i = base.data[tagValueOffset]; directory.SetObject(tagType, i); } else { Debug.Write("Found a tag made of doubles but will use ints"); int[] ints = new int[componentCount]; for (int i = 0; i < componentCount; i++) { ints[i] = base.data[tagValueOffset + i]; } directory.SetIntArray(tagType, ints); } break; case FMT_USHORT: //goto case FMT_SSHORT; case FMT_SSHORT: if (componentCount == 1) { Debug.Write("Found a tag made of short but will use int"); int i = Get16Bits(tagValueOffset); directory.SetObject(tagType, i); } else { Debug.Write("Found a tag made of shorts but will use ints"); int[] ints = new int[componentCount]; for (int i = 0; i < componentCount; i++) { ints[i] = Get16Bits(tagValueOffset + (i * 2)); } directory.SetIntArray(tagType, ints); } break; case FMT_SLONG: //goto case FMT_ULONG; case FMT_ULONG: if (componentCount == 1) { Debug.Write("Found a tag made of long but will use int"); int i = Get32Bits(tagValueOffset); directory.SetObject(tagType, i); } else { Debug.Write("Found a tag made of longs but will use ints"); int[] ints = new int[componentCount]; for (int i = 0; i < componentCount; i++) { ints[i] = Get32Bits(tagValueOffset + (i * 4)); } directory.SetIntArray(tagType, ints); } break; default: Trace.TraceWarning("Unknown format code " + formatCode + " for tag " + tagType); break; } }
/// <summary> /// Process one of the nested Tiff IFD directories. /// 2 bytes: number of tags for each tag /// 2 bytes: tag type /// 2 bytes: format code /// 4 bytes: component count /// </summary> /// <param name="directory">the directory</param> /// <param name="dirStartOffSet">where to start</param> private void ProcessDirectory(AbstractDirectory directory, IDictionary<int, string> processedDirectoryOffsets, int dirStartOffset, int tiffHeaderOffset) { // check for directories we've already visited to avoid stack overflows when recursive/cyclic directory structures exist if (processedDirectoryOffsets.ContainsKey(dirStartOffset)) { return; } // remember that we've visited this directory so that we don't visit it again later processedDirectoryOffsets.Add(dirStartOffset, MARK_AS_PROCESSED); if (dirStartOffset >= base.data.Length || dirStartOffset < 0) { directory.HasError = true; Trace.TraceError("Ignored directory marked to start outside data segement"); return; } if (!IsDirectoryLengthValid(dirStartOffset, tiffHeaderOffset)) { directory.HasError = true; Trace.TraceError("Illegally sized directory"); return; } // First two bytes in the IFD are the tag count int dirTagCount = Get16Bits(dirStartOffset); // Handle each tag in this directory for (int tagNumber = 0; tagNumber < dirTagCount; tagNumber++) { int tagOffset = CalculateTagOffset(dirStartOffset, tagNumber); // 2 bytes for the tag type int tagType = Get16Bits(tagOffset); // 2 bytes for the format code int formatCode = Get16Bits(tagOffset + 2); if (formatCode < 1 || formatCode > MAX_FORMAT_CODE) { directory.HasError = true; Trace.TraceError("Invalid format code: " + formatCode); continue; } // 4 bytes dictate the number of components in this tag'lcStr data int componentCount = Get32Bits(tagOffset + 4); if (componentCount < 0) { directory.HasError = true; Trace.TraceError("Negative component count in EXIF"); continue; } // each component may have more than one byte... calculate the total number of bytes int byteCount = componentCount * BYTES_PER_FORMAT[formatCode]; int tagValueOffset = CalculateTagValueOffset(byteCount, tagOffset, tiffHeaderOffset); if (tagValueOffset < 0 || tagValueOffset > base.data.Length) { directory.HasError = true; Trace.TraceError("Illegal pointer offset value in EXIF"); 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 > base.data.Length) { directory.HasError = true; Trace.TraceError("Illegal number of bytes: " + byteCount); continue; } // Calculate the value as an lcOffset for cases where the tag represents directory int subdirOffset = tiffHeaderOffset + Get32Bits(tagValueOffset); switch (tagType) { case TAG_EXIF_OFFSET: ProcessDirectory(this.metadata.GetDirectory("com.drew.metadata.exif.ExifDirectory"), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); continue; case TAG_INTEROP_OFFSET: ProcessDirectory(this.metadata.GetDirectory("com.drew.metadata.exif.ExifInteropDirectory"), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); continue; case TAG_GPS_INFO_OFFSET: ProcessDirectory(this.metadata.GetDirectory("com.drew.metadata.exif.GpsDirectory"), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); continue; case TAG_MAKER_NOTE: ProcessMakerNote(tagValueOffset, processedDirectoryOffsets, tiffHeaderOffset); continue; default: ProcessTag(directory, tagType, tagValueOffset, componentCount, formatCode); break; } } // End of for // at the end of each IFD is an optional link to the next IFD int finalTagOffset = CalculateTagOffset(dirStartOffset, dirTagCount); int nextDirectoryOffset = Get32Bits(finalTagOffset); if (nextDirectoryOffset != 0) { nextDirectoryOffset += tiffHeaderOffset; if (nextDirectoryOffset >= base.data.Length) { Trace.TraceWarning("Last 4 bytes of IFD reference another IFD with an address that is out of bounds\nNote this could have been caused by jhead 1.3 cropping too much"); return; } else if (nextDirectoryOffset < dirStartOffset) { Trace.TraceWarning("Last 4 bytes of IFD reference another IFD with an address that is before the start of this directory"); return; } // the next directory is of same type as this one ProcessDirectory(directory, processedDirectoryOffsets, nextDirectoryOffset, tiffHeaderOffset); } }
/// <summary> /// Creates a directory tag. /// </summary> /// <param name="aBuff">where to put info</param> /// <param name="aDirectory">the information to add</param> protected virtual void CreateDirectory(StringBuilder aBuff, AbstractDirectory aDirectory) { if (aDirectory != null) { aBuff.Append("--| ").Append(aDirectory.GetName()).Append(" |--"); aBuff.AppendLine(); IEnumerator<Tag> lcTagsEnum = aDirectory.GetTagIterator(); while (lcTagsEnum.MoveNext()) { Tag lcTag = lcTagsEnum.Current; CreateTag(aBuff, lcTag); lcTag = null; } } }
/// <summary> /// This method serves as marsheller of objects for dataset. /// It converts from IPTC octets to relevant java object. /// </summary> /// <param name="aDirectory">the directory</param> /// <param name="aDirectoryType">the directory type</param> /// <param name="aTagType">the tag type</param> /// <param name="anOffset">the lcOffset</param> /// <param name="aTagByteCount">the tag byte count</param> private void ProcessTag( AbstractDirectory aDirectory, int aDirectoryType, int aTagType, int anOffset, int aTagByteCount) { int tagIdentifier = aTagType | (aDirectoryType << 8); switch (tagIdentifier) { case IptcDirectory.TAG_RECORD_VERSION: // short short shortValue = (short)((base.data[anOffset] << 8) | base.data[anOffset + 1]); aDirectory.SetObject(tagIdentifier, shortValue); return; case IptcDirectory.TAG_URGENCY: // byte aDirectory.SetObject(tagIdentifier, base.data[anOffset]); return; case IptcDirectory.TAG_RELEASE_DATE: case IptcDirectory.TAG_DATE_CREATED: // Date object if (aTagByteCount >= 8) { string dateStr = Utils.Decode(base.data, anOffset, aTagByteCount, false); try { int year = Convert.ToInt32(dateStr.Substring(0, 4)); int month = Convert.ToInt32(dateStr.Substring(4, 2)); //No -1 here; int day = Convert.ToInt32(dateStr.Substring(6, 2)); DateTime date = new DateTime(year, month, day); aDirectory.SetObject(tagIdentifier, date); return; } catch (Exception) { // fall through and we'll store whatever was there as a String } } break; // Added for .Net compiler //case IptcDirectory.TAG_RELEASE_TIME: //case IptcDirectory.TAG_TIME_CREATED: } // If no special handling by now, treat it as a string string str = null; if (aTagByteCount < 1) { str = ""; } else { str = Utils.Decode(base.data, anOffset, aTagByteCount, false); } if (aDirectory.ContainsTag(tagIdentifier)) { string[] oldStrings; string[] newStrings; try { oldStrings = aDirectory.GetStringArray(tagIdentifier); } catch (MetadataException) { oldStrings = null; } if (oldStrings == null) { newStrings = new String[1]; } else { newStrings = new string[oldStrings.Length + 1]; for (int i = 0; i < oldStrings.Length; i++) { newStrings[i] = oldStrings[i]; } } newStrings[newStrings.Length - 1] = str; aDirectory.SetObject(tagIdentifier, newStrings); } else { aDirectory.SetObject(tagIdentifier, str); } }
/// <summary> /// Constructor of the object /// </summary> /// <param name="aDirectory">a directory</param> public AbstractTagDescriptor(AbstractDirectory aDirectory) : base() { this.directory = aDirectory; }
/// <summary> /// Constructor of the object /// </summary> /// <param name="aDirectory">a base.directory</param> public NikonType1Descriptor(AbstractDirectory aDirectory) : base(aDirectory) { }
/// <summary> /// Constructor of the object /// </summary> /// <param name="aDirectory">a base.directory</param> public FujifilmDescriptor(AbstractDirectory aDirectory) : base(aDirectory) { }
/// <summary> /// Constructor of the object /// </summary> /// <param name="aTagType">the type of this tag</param> /// <param name="aDirectory">the directory of this tag</param> public Tag(int aTagType, AbstractDirectory aDirectory) : base() { this.tagType = aTagType; this.directory = aDirectory; }
/// <summary> /// Constructor of the object /// </summary> /// <param name="aDirectory">a base.directory</param> public GpsDescriptor(AbstractDirectory aDirectory) : base(aDirectory) { }
/// <summary> /// Creates a directory tag. /// /// Examples : /// <pre> /// <directory name="Exif"> /// <tag> /// ... /// </tag> /// <tag> /// ... /// </tag> /// </directory> /// </pre> /// </summary> /// <param name="aBuff">where to put info</param> /// <param name="aDirectory">the information to add</param> protected virtual void CreateDirectory(StringBuilder aBuff, AbstractDirectory aDirectory) { if (aDirectory != null) { Open(aBuff, "directory name=\"" + aDirectory.GetName() + "\"", true); IEnumerator<Tag> lcTagsEnum = aDirectory.GetTagIterator(); while (lcTagsEnum.MoveNext()) { Tag lcTag = lcTagsEnum.Current; CreateTag(aBuff, lcTag); lcTag = null; } Close(aBuff, "directory", true); } }
/// <summary> /// Constructor of the object /// </summary> /// <param name="aDirectory">a base.directory</param> public IptcDescriptor(AbstractDirectory aDirectory) : base(aDirectory) { }
/// <summary> /// Constructor of the object /// </summary> /// <param name="directory">a directory</param> public SonyDescriptor(AbstractDirectory directory) : base(directory) { }
/// <summary> /// Constructor of the object /// </summary> /// <param name="aDirectory">a directory</param> public CanonDescriptor(AbstractDirectory aDirectory) : base(aDirectory) { }
/// <summary> /// Constructor of the object /// </summary> /// <param name="directory">a directory</param> public KodakDescriptor(AbstractDirectory directory) : base(directory) { }
/// <summary> /// Constructor of the object /// </summary> /// <param name="directory">a directory</param> public ExifDescriptor(AbstractDirectory directory) : base(directory) { }
/// <summary> /// Constructor of the object /// </summary> /// <param name="aDirectory">a base.directory</param> public OlympusDescriptor(AbstractDirectory aDirectory) : base(aDirectory) { }
/// <summary> /// Constructor of the object /// </summary> /// <param name="base.directory">a base.directory</param> public PentaxDescriptor(AbstractDirectory aDirectory) : base(aDirectory) { }