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