// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageProcessorCore { using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; /// /// Represents an EXIF profile providing access to the collection of values. /// public sealed class ExifProfile { /// /// The byte array to read the EXIF profile from. /// private readonly byte[] data; /// /// The collection of EXIF values /// private Collection values; /// /// The list of invalid EXIF tags /// private List invalidTags; /// /// The thumbnail offset position in the byte stream /// private int thumbnailOffset; /// /// The thumbnail length in the byte stream /// private int thumbnailLength; /// /// Initializes a new instance of the class. /// public ExifProfile() : this((byte[])null) { } /// /// Initializes a new instance of the class. /// /// The byte array to read the EXIF profile from. public ExifProfile(byte[] data) { this.Parts = ExifParts.All; this.data = data; this.invalidTags = new List(); } /// /// Initializes a new instance of the class /// by making a copy from another EXIF profile. /// /// The other EXIF profile, where the clone should be made from. /// is null. public ExifProfile(ExifProfile other) { Guard.NotNull(other, nameof(other)); this.Parts = other.Parts; this.thumbnailLength = other.thumbnailLength; this.thumbnailOffset = other.thumbnailOffset; this.invalidTags = new List(other.invalidTags); if (other.values != null) { this.values = new Collection(); foreach (ExifValue value in other.values) { this.values.Add(new ExifValue(value)); } } else { this.data = other.data; } } /// /// Gets or sets which parts will be written when the profile is added to an image. /// public ExifParts Parts { get; set; } /// /// Gets the tags that where found but contained an invalid value. /// public IEnumerable InvalidTags => this.invalidTags; /// /// Gets the values of this EXIF profile. /// public IEnumerable Values { get { this.InitializeValues(); return this.values; } } /// /// Returns the thumbnail in the EXIF profile when available. /// /// The pixel format. /// The packed format. uint, long, float. public Image CreateThumbnail() where TColor : struct, IPackedVector where TPacked : struct { this.InitializeValues(); if (this.thumbnailOffset == 0 || this.thumbnailLength == 0) { return null; } if (this.data.Length < (this.thumbnailOffset + this.thumbnailLength)) { return null; } using (MemoryStream memStream = new MemoryStream(this.data, this.thumbnailOffset, this.thumbnailLength)) { return new Image(memStream); } } /// /// Returns the value with the specified tag. /// /// The tag of the EXIF value. public ExifValue GetValue(ExifTag tag) { foreach (ExifValue exifValue in this.Values) { if (exifValue.Tag == tag) return exifValue; } return null; } /// /// Removes the value with the specified tag. /// /// The tag of the EXIF value. public bool RemoveValue(ExifTag tag) { this.InitializeValues(); for (int i = 0; i < this.values.Count; i++) { if (this.values[i].Tag == tag) { this.values.RemoveAt(i); return true; } } return false; } /// /// Sets the value of the specified tag. /// /// The tag of the EXIF value. /// The value. public void SetValue(ExifTag tag, object value) { foreach (ExifValue exifValue in this.Values) { if (exifValue.Tag == tag) { exifValue.Value = value; return; } } ExifValue newExifValue = ExifValue.Create(tag, value); this.values.Add(newExifValue); } /// /// Converts this instance to a byte array. /// /// The public byte[] ToByteArray() { if (this.values == null) { return this.data; } if (this.values.Count == 0) { return null; } ExifWriter writer = new ExifWriter(this.values, this.Parts); return writer.GetData(); } private void InitializeValues() { if (this.values != null) { return; } if (this.data == null) { this.values = new Collection(); return; } ExifReader reader = new ExifReader(); this.values = reader.Read(this.data); this.invalidTags = new List(reader.InvalidTags); this.thumbnailOffset = (int)reader.ThumbnailOffset; this.thumbnailLength = (int)reader.ThumbnailLength; } } }