Revert "Temp8 tinymce"

This commit is contained in:
Warren Buckley
2018-11-22 14:05:51 +00:00
committed by GitHub
parent 2a0748fc1e
commit 54a2aa00a7
6677 changed files with 646351 additions and 410535 deletions

View File

@@ -1,88 +1,88 @@
using System;
using System.Text;
using System.Xml;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Web;
using Newtonsoft.Json;
using Umbraco.Core.Media;
namespace Umbraco.Web.Media.EmbedProviders
{
//TODO: Make all Http calls async
public abstract class AbstractOEmbedProvider : IEmbedProvider
{
private static HttpClient _httpClient;
public virtual bool SupportsDimensions
{
get { return true; }
}
[ProviderSetting]
public string APIEndpoint { get; set; }
[ProviderSetting]
public Dictionary<string, string> RequestParams { get; set; }
public abstract string GetMarkup(string url, int maxWidth, int maxHeight);
public virtual string BuildFullUrl(string url, int maxWidth, int maxHeight)
{
if (Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute) == false)
throw new ArgumentException("Not a valid Url");
var fullUrl = new StringBuilder();
fullUrl.Append(APIEndpoint);
fullUrl.Append("?url=" + HttpUtility.UrlEncode(url));
foreach (var p in RequestParams)
fullUrl.Append(string.Format("&{0}={1}", p.Key, p.Value));
if (maxWidth > 0)
fullUrl.Append("&maxwidth=" + maxWidth);
if (maxHeight > 0)
fullUrl.Append("&maxheight=" + maxHeight);
return fullUrl.ToString();
}
public virtual string DownloadResponse(string url)
{
if (_httpClient == null)
_httpClient = new HttpClient();
using (var request = new HttpRequestMessage(HttpMethod.Get, url))
{
var response = _httpClient.SendAsync(request).Result;
return response.Content.ReadAsStringAsync().Result;
}
}
public virtual T GetJsonResponse<T>(string url) where T : class
{
var response = DownloadResponse(url);
return JsonConvert.DeserializeObject<T>(response);
}
public virtual XmlDocument GetXmlResponse(string url)
{
var response = DownloadResponse(url);
var doc = new XmlDocument();
doc.LoadXml(response);
return doc;
}
public virtual string GetXmlProperty(XmlDocument doc, string property)
{
var selectSingleNode = doc.SelectSingleNode(property);
return selectSingleNode != null ? selectSingleNode.InnerText : string.Empty;
}
}
}
using System;
using System.Text;
using System.Xml;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Web;
using Newtonsoft.Json;
using Umbraco.Core.Media;
namespace Umbraco.Web.Media.EmbedProviders
{
//TODO: Make all Http calls async
public abstract class AbstractOEmbedProvider : IEmbedProvider
{
private static HttpClient _httpClient;
public virtual bool SupportsDimensions
{
get { return true; }
}
[ProviderSetting]
public string APIEndpoint { get; set; }
[ProviderSetting]
public Dictionary<string, string> RequestParams { get; set; }
public abstract string GetMarkup(string url, int maxWidth, int maxHeight);
public virtual string BuildFullUrl(string url, int maxWidth, int maxHeight)
{
if (Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute) == false)
throw new ArgumentException("Not a valid Url");
var fullUrl = new StringBuilder();
fullUrl.Append(APIEndpoint);
fullUrl.Append("?url=" + HttpUtility.UrlEncode(url));
foreach (var p in RequestParams)
fullUrl.Append(string.Format("&{0}={1}", p.Key, p.Value));
if (maxWidth > 0)
fullUrl.Append("&maxwidth=" + maxWidth);
if (maxHeight > 0)
fullUrl.Append("&maxheight=" + maxHeight);
return fullUrl.ToString();
}
public virtual string DownloadResponse(string url)
{
if (_httpClient == null)
_httpClient = new HttpClient();
using (var request = new HttpRequestMessage(HttpMethod.Get, url))
{
var response = _httpClient.SendAsync(request).Result;
return response.Content.ReadAsStringAsync().Result;
}
}
public virtual T GetJsonResponse<T>(string url) where T : class
{
var response = DownloadResponse(url);
return JsonConvert.DeserializeObject<T>(response);
}
public virtual XmlDocument GetXmlResponse(string url)
{
var response = DownloadResponse(url);
var doc = new XmlDocument();
doc.LoadXml(response);
return doc;
}
public virtual string GetXmlProperty(XmlDocument doc, string property)
{
var selectSingleNode = doc.SelectSingleNode(property);
return selectSingleNode != null ? selectSingleNode.InnerText : string.Empty;
}
}
}

View File

@@ -1,14 +1,14 @@
using Umbraco.Core.Media;
namespace Umbraco.Web.Media.EmbedProviders
{
public abstract class AbstractProvider : IEmbedProvider
{
public virtual bool SupportsDimensions
{
get { return true; }
}
public abstract string GetMarkup(string url, int maxWidth, int maxHeight);
}
}
using Umbraco.Core.Media;
namespace Umbraco.Web.Media.EmbedProviders
{
public abstract class AbstractProvider : IEmbedProvider
{
public virtual bool SupportsDimensions
{
get { return true; }
}
public abstract string GetMarkup(string url, int maxWidth, int maxHeight);
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.ComponentModel;
using System.Web;
namespace Umbraco.Web.Media.EmbedProviders
{
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This is no longer used and will be removed from the codebase in the future, for Flickr, use the Umbraco.Web.Media.EmbedProviders.OEmbedPhoto provider")]
public class Flickr : AbstractOEmbedProvider
{
public override string GetMarkup(string url, int maxWidth, int maxHeight)
{
var flickrUrl = BuildFullUrl(url, maxWidth, maxHeight);
var doc = GetXmlResponse(flickrUrl);
string imageUrl = doc.SelectSingleNode("/oembed/url").InnerText;
string imageWidth = doc.SelectSingleNode("/oembed/width").InnerText;
string imageHeight = doc.SelectSingleNode("/oembed/height").InnerText;
string imageTitle = doc.SelectSingleNode("/oembed/title").InnerText;
return string.Format("<img src=\"{0}\" width\"{1}\" height=\"{2}\" alt=\"{3}\" />",
imageUrl, imageWidth, imageHeight, HttpUtility.HtmlEncode(imageTitle));
}
}
}

View File

@@ -19,4 +19,4 @@ namespace Umbraco.Web.Media.EmbedProviders
imageUrl, imageWidth, imageHeight, HttpUtility.HtmlEncode(imageTitle));
}
}
}
}

View File

@@ -1,6 +1,6 @@
namespace Umbraco.Web.Media.EmbedProviders
{
public class OEmbedRich : OEmbedVideo
{
}
}
namespace Umbraco.Web.Media.EmbedProviders
{
public class OEmbedRich : OEmbedVideo
{
}
}

View File

@@ -1,15 +1,15 @@
using System.Xml;
namespace Umbraco.Web.Media.EmbedProviders
{
public class OEmbedVideo : AbstractOEmbedProvider
{
public override string GetMarkup(string url, int maxWidth, int maxHeight)
{
string requestUrl = BuildFullUrl(url, maxWidth, maxHeight);
XmlDocument doc = GetXmlResponse(requestUrl);
return GetXmlProperty(doc, "/oembed/html");
}
}
}
using System.Xml;
namespace Umbraco.Web.Media.EmbedProviders
{
public class OEmbedVideo : AbstractOEmbedProvider
{
public override string GetMarkup(string url, int maxWidth, int maxHeight)
{
string requestUrl = BuildFullUrl(url, maxWidth, maxHeight);
XmlDocument doc = GetXmlResponse(requestUrl);
return GetXmlProperty(doc, "/oembed/html");
}
}
}

View File

@@ -1,14 +1,14 @@
using System.Linq;
using System.Xml;
using Umbraco.Core.Media;
namespace Umbraco.Web.Media.EmbedProviders.Settings
{
public class Dictionary : IEmbedSettingProvider
{
public object GetSetting(XmlNode settingNode)
{
return settingNode.ChildNodes.Cast<XmlNode>().ToDictionary(item => item.Attributes != null ? item.Attributes["name"].Value : null, item => item.InnerText);
}
}
}
using System.Linq;
using System.Xml;
using Umbraco.Core.Media;
namespace Umbraco.Web.Media.EmbedProviders.Settings
{
public class Dictionary : IEmbedSettingProvider
{
public object GetSetting(XmlNode settingNode)
{
return settingNode.ChildNodes.Cast<XmlNode>().ToDictionary(item => item.Attributes != null ? item.Attributes["name"].Value : null, item => item.InnerText);
}
}
}

View File

@@ -1,13 +1,13 @@
using System.Xml;
using Umbraco.Core.Media;
namespace Umbraco.Web.Media.EmbedProviders.Settings
{
public class String : IEmbedSettingProvider
{
public object GetSetting(XmlNode settingNode)
{
return settingNode.InnerText;
}
}
}
using System.Xml;
using Umbraco.Core.Media;
namespace Umbraco.Web.Media.EmbedProviders.Settings
{
public class String : IEmbedSettingProvider
{
public object GetSetting(XmlNode settingNode)
{
return settingNode.InnerText;
}
}
}

View File

@@ -1,23 +1,23 @@
using HtmlAgilityPack;
namespace Umbraco.Web.Media.EmbedProviders
{
public class Twitgoo : AbstractProvider
{
public override bool SupportsDimensions
{
get { return false; }
}
public override string GetMarkup(string url, int maxWidth, int maxHeight)
{
var web = new HtmlWeb();
var doc = web.Load(url);
var img = doc.DocumentNode.SelectSingleNode("//img [@id = 'fullsize']").Attributes["src"];
return string.Format("<img src=\"{0}\"/>",
img.Value);
}
}
}
using HtmlAgilityPack;
namespace Umbraco.Web.Media.EmbedProviders
{
public class Twitgoo : AbstractProvider
{
public override bool SupportsDimensions
{
get { return false; }
}
public override string GetMarkup(string url, int maxWidth, int maxHeight)
{
var web = new HtmlWeb();
var doc = web.Load(url);
var img = doc.DocumentNode.SelectSingleNode("//img [@id = 'fullsize']").Attributes["src"];
return string.Format("<img src=\"{0}\"/>",
img.Value);
}
}
}

View File

@@ -1,405 +0,0 @@
using System;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// An endian-aware converter for converting between base data types
/// and an array of bytes.
/// </summary>
internal class BitConverterEx
{
#region Public Enums
/// <summary>
/// Represents the byte order.
/// </summary>
public enum ByteOrder
{
LittleEndian = 1,
BigEndian = 2,
}
#endregion
#region Member Variables
private ByteOrder mFrom, mTo;
#endregion
#region Constructors
public BitConverterEx(ByteOrder from, ByteOrder to)
{
mFrom = from;
mTo = to;
}
#endregion
#region Properties
/// <summary>
/// Indicates the byte order in which data is stored in this platform.
/// </summary>
public static ByteOrder SystemByteOrder
{
get
{
return (BitConverter.IsLittleEndian ? ByteOrder.LittleEndian : ByteOrder.BigEndian);
}
}
#endregion
#region Predefined Values
/// <summary>
/// Returns a bit converter that converts between little-endian and system byte-order.
/// </summary>
public static BitConverterEx LittleEndian
{
get
{
return new BitConverterEx(ByteOrder.LittleEndian, BitConverterEx.SystemByteOrder);
}
}
/// <summary>
/// Returns a bit converter that converts between big-endian and system byte-order.
/// </summary>
public static BitConverterEx BigEndian
{
get
{
return new BitConverterEx(ByteOrder.BigEndian, BitConverterEx.SystemByteOrder);
}
}
/// <summary>
/// Returns a bit converter that does not do any byte-order conversion.
/// </summary>
public static BitConverterEx SystemEndian
{
get
{
return new BitConverterEx(BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder);
}
}
#endregion
#region Static Methods
/// <summary>
/// Converts the given array of bytes to a Unicode character.
/// </summary>
public static char ToChar(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 2, from, to);
return BitConverter.ToChar(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 16-bit unsigned integer.
/// </summary>
public static ushort ToUInt16(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 2, from, to);
return BitConverter.ToUInt16(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 32-bit unsigned integer.
/// </summary>
public static uint ToUInt32(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 4, from, to);
return BitConverter.ToUInt32(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 64-bit unsigned integer.
/// </summary>
public static ulong ToUInt64(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 8, from, to);
return BitConverter.ToUInt64(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 16-bit signed integer.
/// </summary>
public static short ToInt16(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 2, from, to);
return BitConverter.ToInt16(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 32-bit signed integer.
/// </summary>
public static int ToInt32(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 4, from, to);
return BitConverter.ToInt32(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 64-bit signed integer.
/// </summary>
public static long ToInt64(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 8, from, to);
return BitConverter.ToInt64(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a single precision floating number.
/// </summary>
public static float ToSingle(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 4, from, to);
return BitConverter.ToSingle(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a double precision floating number.
/// </summary>
public static double ToDouble(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 8, from, to);
return BitConverter.ToDouble(data, 0);
}
/// <summary>
/// Converts the given 16-bit unsigned integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(ushort value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given 32-bit unsigned integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(uint value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given 64-bit unsigned integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(ulong value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given 16-bit signed integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(short value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given 32-bit signed integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(int value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given 64-bit signed integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(long value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given single precision floating-point number to an array of bytes.
/// </summary>
public static byte[] GetBytes(float value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given double precision floating-point number to an array of bytes.
/// </summary>
public static byte[] GetBytes(double value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
#endregion
#region Instance Methods
/// <summary>
/// Converts the given array of bytes to a 16-bit unsigned integer.
/// </summary>
public char ToChar(byte[] value, long startIndex)
{
return BitConverterEx.ToChar(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a 16-bit unsigned integer.
/// </summary>
public ushort ToUInt16(byte[] value, long startIndex)
{
return BitConverterEx.ToUInt16(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a 32-bit unsigned integer.
/// </summary>
public uint ToUInt32(byte[] value, long startIndex)
{
return BitConverterEx.ToUInt32(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a 64-bit unsigned integer.
/// </summary>
public ulong ToUInt64(byte[] value, long startIndex)
{
return BitConverterEx.ToUInt64(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a 16-bit signed integer.
/// </summary>
public short ToInt16(byte[] value, long startIndex)
{
return BitConverterEx.ToInt16(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a 32-bit signed integer.
/// </summary>
public int ToInt32(byte[] value, long startIndex)
{
return BitConverterEx.ToInt32(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a 64-bit signed integer.
/// </summary>
public long ToInt64(byte[] value, long startIndex)
{
return BitConverterEx.ToInt64(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a single precision floating number.
/// </summary>
public float ToSingle(byte[] value, long startIndex)
{
return BitConverterEx.ToSingle(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a double precision floating number.
/// </summary>
public double ToDouble(byte[] value, long startIndex)
{
return BitConverterEx.ToDouble(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given 16-bit unsigned integer to an array of bytes.
/// </summary>
public byte[] GetBytes(ushort value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
/// <summary>
/// Converts the given 32-bit unsigned integer to an array of bytes.
/// </summary>
public byte[] GetBytes(uint value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
/// <summary>
/// Converts the given 64-bit unsigned integer to an array of bytes.
/// </summary>
public byte[] GetBytes(ulong value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
/// <summary>
/// Converts the given 16-bit signed integer to an array of bytes.
/// </summary>
public byte[] GetBytes(short value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
/// <summary>
/// Converts the given 32-bit signed integer to an array of bytes.
/// </summary>
public byte[] GetBytes(int value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
/// <summary>
/// Converts the given 64-bit signed integer to an array of bytes.
/// </summary>
public byte[] GetBytes(long value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
/// <summary>
/// Converts the given single precision floating-point number to an array of bytes.
/// </summary>
public byte[] GetBytes(float value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
/// <summary>
/// Converts the given double precision floating-point number to an array of bytes.
/// </summary>
public byte[] GetBytes(double value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
#endregion
#region Private Helpers
/// <summary>
/// Reverse the array of bytes as needed.
/// </summary>
private static byte[] CheckData(byte[] value, long startIndex, long length, ByteOrder from, ByteOrder to)
{
byte[] data = new byte[length];
Array.Copy(value, startIndex, data, 0, length);
if (from != to)
Array.Reverse(data);
return data;
}
/// <summary>
/// Reverse the array of bytes as needed.
/// </summary>
private static byte[] CheckData(byte[] value, ByteOrder from, ByteOrder to)
{
return CheckData(value, 0, value.Length, from, to);
}
#endregion
}
}

View File

@@ -1,357 +0,0 @@
using System;
using System.Text;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Converts between exif data types and array of bytes.
/// </summary>
internal class ExifBitConverter : BitConverterEx
{
#region Constructors
public ExifBitConverter(ByteOrder from, ByteOrder to)
: base(from, to)
{
;
}
#endregion
#region Static Methods
/// <summary>
/// Returns an ASCII string converted from the given byte array.
/// </summary>
public static string ToAscii(byte[] data, bool endatfirstnull, Encoding encoding)
{
int len = data.Length;
if (endatfirstnull)
{
len = Array.IndexOf(data, (byte)0);
if (len == -1) len = data.Length;
}
return encoding.GetString(data, 0, len);
}
/// <summary>
/// Returns an ASCII string converted from the given byte array.
/// </summary>
public static string ToAscii(byte[] data, Encoding encoding)
{
return ToAscii(data, true, encoding);
}
/// <summary>
/// Returns a string converted from the given byte array.
/// from the numeric value of each byte.
/// </summary>
public static string ToString(byte[] data)
{
StringBuilder sb = new StringBuilder();
foreach (byte b in data)
sb.Append(b);
return sb.ToString();
}
/// <summary>
/// Returns a DateTime object converted from the given byte array.
/// </summary>
public static DateTime ToDateTime(byte[] data, bool hastime)
{
string str = ToAscii(data, Encoding.ASCII);
string[] parts = str.Split(new char[] { ':', ' ' });
try
{
if (hastime && parts.Length == 6)
{
// yyyy:MM:dd HH:mm:ss
// This is the expected format though some cameras
// can use single digits. See Issue 21.
return new DateTime(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]), int.Parse(parts[4]), int.Parse(parts[5]));
}
else if (!hastime && parts.Length == 3)
{
// yyyy:MM:dd
return new DateTime(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]));
}
else
{
return DateTime.MinValue;
}
}
catch (ArgumentOutOfRangeException)
{
return DateTime.MinValue;
}
catch (ArgumentException)
{
return DateTime.MinValue;
}
}
/// <summary>
/// Returns a DateTime object converted from the given byte array.
/// </summary>
public static DateTime ToDateTime(byte[] data)
{
return ToDateTime(data, true);
}
/// <summary>
/// Returns an unsigned rational number converted from the first
/// eight bytes of the given byte array. The first four bytes are
/// assumed to be the numerator and the next four bytes are the
/// denumerator.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static MathEx.UFraction32 ToURational(byte[] data, ByteOrder frombyteorder)
{
byte[] num = new byte[4];
byte[] den = new byte[4];
Array.Copy(data, 0, num, 0, 4);
Array.Copy(data, 4, den, 0, 4);
return new MathEx.UFraction32(ToUInt32(num, 0, frombyteorder, BitConverterEx.SystemByteOrder), ToUInt32(den, 0, frombyteorder, BitConverterEx.SystemByteOrder));
}
/// <summary>
/// Returns a signed rational number converted from the first
/// eight bytes of the given byte array. The first four bytes are
/// assumed to be the numerator and the next four bytes are the
/// denumerator.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static MathEx.Fraction32 ToSRational(byte[] data, ByteOrder frombyteorder)
{
byte[] num = new byte[4];
byte[] den = new byte[4];
Array.Copy(data, 0, num, 0, 4);
Array.Copy(data, 4, den, 0, 4);
return new MathEx.Fraction32(ToInt32(num, 0, frombyteorder, BitConverterEx.SystemByteOrder), ToInt32(den, 0, frombyteorder, BitConverterEx.SystemByteOrder));
}
/// <summary>
/// Returns an array of 16-bit unsigned integers converted from
/// the given byte array.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static ushort[] ToUShortArray(byte[] data, int count, ByteOrder frombyteorder)
{
ushort[] numbers = new ushort[count];
for (uint i = 0; i < count; i++)
{
byte[] num = new byte[2];
Array.Copy(data, i * 2, num, 0, 2);
numbers[i] = ToUInt16(num, 0, frombyteorder, BitConverterEx.SystemByteOrder);
}
return numbers;
}
/// <summary>
/// Returns an array of 32-bit unsigned integers converted from
/// the given byte array.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static uint[] ToUIntArray(byte[] data, int count, ByteOrder frombyteorder)
{
uint[] numbers = new uint[count];
for (uint i = 0; i < count; i++)
{
byte[] num = new byte[4];
Array.Copy(data, i * 4, num, 0, 4);
numbers[i] = ToUInt32(num, 0, frombyteorder, BitConverterEx.SystemByteOrder);
}
return numbers;
}
/// <summary>
/// Returns an array of 32-bit signed integers converted from
/// the given byte array.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static int[] ToSIntArray(byte[] data, int count, ByteOrder byteorder)
{
int[] numbers = new int[count];
for (uint i = 0; i < count; i++)
{
byte[] num = new byte[4];
Array.Copy(data, i * 4, num, 0, 4);
numbers[i] = ToInt32(num, 0, byteorder, BitConverterEx.SystemByteOrder);
}
return numbers;
}
/// <summary>
/// Returns an array of unsigned rational numbers converted from
/// the given byte array.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static MathEx.UFraction32[] ToURationalArray(byte[] data, int count, ByteOrder frombyteorder)
{
MathEx.UFraction32[] numbers = new MathEx.UFraction32[count];
for (uint i = 0; i < count; i++)
{
byte[] num = new byte[4];
byte[] den = new byte[4];
Array.Copy(data, i * 8, num, 0, 4);
Array.Copy(data, i * 8 + 4, den, 0, 4);
numbers[i].Set(ToUInt32(num, 0, frombyteorder, BitConverterEx.SystemByteOrder), ToUInt32(den, 0, frombyteorder, BitConverterEx.SystemByteOrder));
}
return numbers;
}
/// <summary>
/// Returns an array of signed rational numbers converted from
/// the given byte array.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static MathEx.Fraction32[] ToSRationalArray(byte[] data, int count, ByteOrder frombyteorder)
{
MathEx.Fraction32[] numbers = new MathEx.Fraction32[count];
for (uint i = 0; i < count; i++)
{
byte[] num = new byte[4];
byte[] den = new byte[4];
Array.Copy(data, i * 8, num, 0, 4);
Array.Copy(data, i * 8 + 4, den, 0, 4);
numbers[i].Set(ToInt32(num, 0, frombyteorder, BitConverterEx.SystemByteOrder), ToInt32(den, 0, frombyteorder, BitConverterEx.SystemByteOrder));
}
return numbers;
}
/// <summary>
/// Converts the given ascii string to an array of bytes optionally adding a null terminator.
/// </summary>
public static byte[] GetBytes(string value, bool addnull, Encoding encoding)
{
if (addnull) value += '\0';
return encoding.GetBytes(value);
}
/// <summary>
/// Converts the given ascii string to an array of bytes without adding a null terminator.
/// </summary>
public static byte[] GetBytes(string value, Encoding encoding)
{
return GetBytes(value, false, encoding);
}
/// <summary>
/// Converts the given datetime to an array of bytes with a null terminator.
/// </summary>
public static byte[] GetBytes(DateTime value, bool hastime)
{
string str = "";
if (hastime)
str = value.ToString("yyyy:MM:dd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
else
str = value.ToString("yyyy:MM:dd", System.Globalization.CultureInfo.InvariantCulture);
return GetBytes(str, true, Encoding.ASCII);
}
/// <summary>
/// Converts the given unsigned rational number to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(MathEx.UFraction32 value, ByteOrder tobyteorder)
{
byte[] num = GetBytes(value.Numerator, BitConverterEx.SystemByteOrder, tobyteorder);
byte[] den = GetBytes(value.Denominator, BitConverterEx.SystemByteOrder, tobyteorder);
byte[] data = new byte[8];
Array.Copy(num, 0, data, 0, 4);
Array.Copy(den, 0, data, 4, 4);
return data;
}
/// <summary>
/// Converts the given signed rational number to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(MathEx.Fraction32 value, ByteOrder tobyteorder)
{
byte[] num = GetBytes(value.Numerator, BitConverterEx.SystemByteOrder, tobyteorder);
byte[] den = GetBytes(value.Denominator, BitConverterEx.SystemByteOrder, tobyteorder);
byte[] data = new byte[8];
Array.Copy(num, 0, data, 0, 4);
Array.Copy(den, 0, data, 4, 4);
return data;
}
/// <summary>
/// Converts the given array of 16-bit unsigned integers to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(ushort[] value, ByteOrder tobyteorder)
{
byte[] data = new byte[2 * value.Length];
for (int i = 0; i < value.Length; i++)
{
byte[] num = GetBytes(value[i], BitConverterEx.SystemByteOrder, tobyteorder);
Array.Copy(num, 0, data, i * 2, 2);
}
return data;
}
/// <summary>
/// Converts the given array of 32-bit unsigned integers to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(uint[] value, ByteOrder tobyteorder)
{
byte[] data = new byte[4 * value.Length];
for (int i = 0; i < value.Length; i++)
{
byte[] num = GetBytes(value[i], BitConverterEx.SystemByteOrder, tobyteorder);
Array.Copy(num, 0, data, i * 4, 4);
}
return data;
}
/// <summary>
/// Converts the given array of 32-bit signed integers to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(int[] value, ByteOrder tobyteorder)
{
byte[] data = new byte[4 * value.Length];
for (int i = 0; i < value.Length; i++)
{
byte[] num = GetBytes(value[i], BitConverterEx.SystemByteOrder, tobyteorder);
Array.Copy(num, 0, data, i * 4, 4);
}
return data;
}
/// <summary>
/// Converts the given array of unsigned rationals to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(MathEx.UFraction32[] value, ByteOrder tobyteorder)
{
byte[] data = new byte[8 * value.Length];
for (int i = 0; i < value.Length; i++)
{
byte[] num = GetBytes(value[i].Numerator, BitConverterEx.SystemByteOrder, tobyteorder);
byte[] den = GetBytes(value[i].Denominator, BitConverterEx.SystemByteOrder, tobyteorder);
Array.Copy(num, 0, data, i * 8, 4);
Array.Copy(den, 0, data, i * 8 + 4, 4);
}
return data;
}
/// <summary>
/// Converts the given array of signed rationals to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(MathEx.Fraction32[] value, ByteOrder tobyteorder)
{
byte[] data = new byte[8 * value.Length];
for (int i = 0; i < value.Length; i++)
{
byte[] num = GetBytes(value[i].Numerator, BitConverterEx.SystemByteOrder, tobyteorder);
byte[] den = GetBytes(value[i].Denominator, BitConverterEx.SystemByteOrder, tobyteorder);
Array.Copy(num, 0, data, i * 8, 4);
Array.Copy(den, 0, data, i * 8 + 4, 4);
}
return data;
}
#endregion
}
}

View File

@@ -1,292 +0,0 @@
using System;
namespace Umbraco.Web.Media.Exif
{
internal enum Compression : ushort
{
Uncompressed = 1,
CCITT1D = 2,
Group3Fax = 3,
Group4Fax = 4,
LZW = 5,
JPEG = 6,
PackBits = 32773,
}
internal enum PhotometricInterpretation : ushort
{
WhiteIsZero = 0,
BlackIsZero = 1,
RGB = 2,
RGBPalette = 3,
TransparencyMask = 4,
CMYK = 5,
YCbCr = 6,
CIELab = 8,
}
internal enum Orientation : ushort
{
Normal = 1,
MirroredVertically = 2,
Rotated180 = 3,
MirroredHorizontally = 4,
RotatedLeftAndMirroredVertically = 5,
RotatedRight = 6,
RotatedLeft = 7,
RotatedRightAndMirroredVertically = 8,
}
internal enum PlanarConfiguration : ushort
{
ChunkyFormat = 1,
PlanarFormat = 2,
}
internal enum YCbCrPositioning : ushort
{
Centered = 1,
CoSited = 2,
}
internal enum ResolutionUnit : ushort
{
Inches = 2,
Centimeters = 3,
}
internal enum ColorSpace : ushort
{
sRGB = 1,
Uncalibrated = 0xfff,
}
internal enum ExposureProgram : ushort
{
NotDefined = 0,
Manual = 1,
Normal = 2,
AperturePriority = 3,
ShutterPriority = 4,
/// <summary>
/// Biased toward depth of field.
/// </summary>
Creative = 5,
/// <summary>
/// Biased toward fast shutter speed.
/// </summary>
Action = 6,
/// <summary>
/// For closeup photos with the background out of focus.
/// </summary>
Portrait = 7,
/// <summary>
/// For landscape photos with the background in focus.
/// </summary>
Landscape = 8,
}
internal enum MeteringMode : ushort
{
Unknown = 0,
Average = 1,
CenterWeightedAverage = 2,
Spot = 3,
MultiSpot = 4,
Pattern = 5,
Partial = 6,
Other = 255,
}
internal enum LightSource : ushort
{
Unknown = 0,
Daylight = 1,
Fluorescent = 2,
Tungsten = 3,
Flash = 4,
FineWeather = 9,
CloudyWeather = 10,
Shade = 11,
/// <summary>
/// D 5700 7100K
/// </summary>
DaylightFluorescent = 12,
/// <summary>
/// N 4600 5400K
/// </summary>
DayWhiteFluorescent = 13,
/// <summary>
/// W 3900 4500K
/// </summary>
CoolWhiteFluorescent = 14,
/// <summary>
/// WW 3200 3700K
/// </summary>
WhiteFluorescent = 15,
StandardLightA = 17,
StandardLightB = 18,
StandardLightC = 19,
D55 = 20,
D65 = 21,
D75 = 22,
D50 = 23,
ISOStudioTungsten = 24,
OtherLightSource = 255,
}
[Flags]
internal enum Flash : ushort
{
FlashDidNotFire = 0,
StrobeReturnLightNotDetected = 4,
StrobeReturnLightDetected = 2,
FlashFired = 1,
CompulsoryFlashMode = 8,
AutoMode = 16,
NoFlashFunction = 32,
RedEyeReductionMode = 64,
}
internal enum SensingMethod : ushort
{
NotDefined = 1,
OneChipColorAreaSensor = 2,
TwoChipColorAreaSensor = 3,
ThreeChipColorAreaSensor = 4,
ColorSequentialAreaSensor = 5,
TriLinearSensor = 7,
ColorSequentialLinearSensor = 8,
}
internal enum FileSource : byte // UNDEFINED
{
DSC = 3,
}
internal enum SceneType : byte // UNDEFINED
{
DirectlyPhotographedImage = 1,
}
internal enum CustomRendered : ushort
{
NormalProcess = 0,
CustomProcess = 1,
}
internal enum ExposureMode : ushort
{
Auto = 0,
Manual = 1,
AutoBracket = 2,
}
internal enum WhiteBalance : ushort
{
Auto = 0,
Manual = 1,
}
internal enum SceneCaptureType : ushort
{
Standard = 0,
Landscape = 1,
Portrait = 2,
NightScene = 3,
}
internal enum GainControl : ushort
{
None = 0,
LowGainUp = 1,
HighGainUp = 2,
LowGainDown = 3,
HighGainDown = 4,
}
internal enum Contrast : ushort
{
Normal = 0,
Soft = 1,
Hard = 2,
}
internal enum Saturation : ushort
{
Normal = 0,
Low = 1,
High = 2,
}
internal enum Sharpness : ushort
{
Normal = 0,
Soft = 1,
Hard = 2,
}
internal enum SubjectDistanceRange : ushort
{
Unknown = 0,
Macro = 1,
CloseView = 2,
DistantView = 3,
}
internal enum GPSLatitudeRef : byte // ASCII
{
North = 78, // 'N'
South = 83, // 'S'
}
internal enum GPSLongitudeRef : byte // ASCII
{
West = 87, // 'W'
East = 69, // 'E'
}
internal enum GPSAltitudeRef : byte
{
AboveSeaLevel = 0,
BelowSeaLevel = 1,
}
internal enum GPSStatus : byte // ASCII
{
MeasurementInProgress = 65, // 'A'
MeasurementInteroperability = 86, // 'V'
}
internal enum GPSMeasureMode : byte // ASCII
{
TwoDimensional = 50, // '2'
ThreeDimensional = 51, // '3'
}
internal enum GPSSpeedRef : byte // ASCII
{
KilometersPerHour = 75, // 'K'
MilesPerHour = 77, // 'M'
Knots = 78, // 'N'
}
internal enum GPSDirectionRef : byte // ASCII
{
TrueDirection = 84, // 'T'
MagneticDirection = 77, // 'M'
}
internal enum GPSDistanceRef : byte // ASCII
{
Kilometers = 75, // 'K'
Miles = 77, // 'M'
Knots = 78, // 'N'
}
internal enum GPSDifferential : ushort
{
MeasurementWithoutDifferentialCorrection = 0,
DifferentialCorrectionApplied = 1,
}
}

View File

@@ -1,42 +0,0 @@
using System;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// The exception that is thrown when the format of the JPEG/Exif file
/// could not be understood.
/// </summary>
internal class NotValidExifFileException : Exception
{
public NotValidExifFileException()
: base("Not a valid JPEG/Exif file.")
{
;
}
public NotValidExifFileException(string message)
: base(message)
{
;
}
}
/// <summary>
/// The exception that is thrown when an invalid enum type is given to an
/// ExifEnumProperty.
/// </summary>
internal class UnknownEnumTypeException : Exception
{
public UnknownEnumTypeException()
: base("Unknown enum type.")
{
;
}
public UnknownEnumTypeException(string message)
: base(message)
{
;
}
}
}

View File

@@ -1,373 +0,0 @@
using System;
using System.Text;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents an enumerated value.
/// </summary>
internal class ExifEnumProperty<T> : ExifProperty
{
protected T mValue;
protected bool mIsBitField;
protected override object _Value { get { return Value; } set { Value = (T)value; } }
public new T Value { get { return mValue; } set { mValue = value; } }
public bool IsBitField { get { return mIsBitField; } }
static public implicit operator T(ExifEnumProperty<T> obj) { return (T)obj.mValue; }
public override string ToString() { return mValue.ToString(); }
public ExifEnumProperty(ExifTag tag, T value, bool isbitfield)
: base(tag)
{
mValue = value;
mIsBitField = isbitfield;
}
public ExifEnumProperty(ExifTag tag, T value)
: this(tag, value, false)
{
;
}
public override ExifInterOperability Interoperability
{
get
{
ushort tagid = ExifTagFactory.GetTagID(mTag);
Type type = typeof(T);
Type basetype = Enum.GetUnderlyingType(type);
if (type == typeof(FileSource) || type == typeof(SceneType))
{
// UNDEFINED
return new ExifInterOperability(tagid, 7, 1, new byte[] { (byte)((object)mValue) });
}
else if (type == typeof(GPSLatitudeRef) || type == typeof(GPSLongitudeRef) ||
type == typeof(GPSStatus) || type == typeof(GPSMeasureMode) ||
type == typeof(GPSSpeedRef) || type == typeof(GPSDirectionRef) ||
type == typeof(GPSDistanceRef))
{
// ASCII
return new ExifInterOperability(tagid, 2, 2, new byte[] { (byte)((object)mValue), 0 });
}
else if (basetype == typeof(byte))
{
// BYTE
return new ExifInterOperability(tagid, 1, 1, new byte[] { (byte)((object)mValue) });
}
else if (basetype == typeof(ushort))
{
// SHORT
return new ExifInterOperability(tagid, 3, 1, ExifBitConverter.GetBytes((ushort)((object)mValue), BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder));
}
else
throw new UnknownEnumTypeException();
}
}
}
/// <summary>
/// Represents an ASCII string. (EXIF Specification: UNDEFINED) Used for the UserComment field.
/// </summary>
internal class ExifEncodedString : ExifProperty
{
protected string mValue;
private Encoding mEncoding;
protected override object _Value { get { return Value; } set { Value = (string)value; } }
public new string Value { get { return mValue; } set { mValue = value; } }
public Encoding Encoding { get { return mEncoding; } set { mEncoding = value; } }
static public implicit operator string(ExifEncodedString obj) { return obj.mValue; }
public override string ToString() { return mValue; }
public ExifEncodedString(ExifTag tag, string value, Encoding encoding)
: base(tag)
{
mValue = value;
mEncoding = encoding;
}
public override ExifInterOperability Interoperability
{
get
{
string enc = "";
if (mEncoding == null)
enc = "\0\0\0\0\0\0\0\0";
else if (mEncoding.EncodingName == "US-ASCII")
enc = "ASCII\0\0\0";
else if (mEncoding.EncodingName == "Japanese (JIS 0208-1990 and 0212-1990)")
enc = "JIS\0\0\0\0\0";
else if (mEncoding.EncodingName == "Unicode")
enc = "Unicode\0";
else
enc = "\0\0\0\0\0\0\0\0";
byte[] benc = Encoding.ASCII.GetBytes(enc);
byte[] bstr = (mEncoding == null ? Encoding.ASCII.GetBytes(mValue) : mEncoding.GetBytes(mValue));
byte[] data = new byte[benc.Length + bstr.Length];
Array.Copy(benc, 0, data, 0, benc.Length);
Array.Copy(bstr, 0, data, benc.Length, bstr.Length);
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 7, (uint)data.Length, data);
}
}
}
/// <summary>
/// Represents an ASCII string formatted as DateTime. (EXIF Specification: ASCII) Used for the date time fields.
/// </summary>
internal class ExifDateTime : ExifProperty
{
protected DateTime mValue;
protected override object _Value { get { return Value; } set { Value = (DateTime)value; } }
public new DateTime Value { get { return mValue; } set { mValue = value; } }
static public implicit operator DateTime(ExifDateTime obj) { return obj.mValue; }
public override string ToString() { return mValue.ToString("yyyy.MM.dd HH:mm:ss"); }
public ExifDateTime(ExifTag tag, DateTime value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 2, (uint)20, ExifBitConverter.GetBytes(mValue, true));
}
}
}
/// <summary>
/// Represents the exif version as a 4 byte ASCII string. (EXIF Specification: UNDEFINED)
/// Used for the ExifVersion, FlashpixVersion, InteroperabilityVersion and GPSVersionID fields.
/// </summary>
internal class ExifVersion : ExifProperty
{
protected string mValue;
protected override object _Value { get { return Value; } set { Value = (string)value; } }
public new string Value { get { return mValue; } set { mValue = value.Substring(0, 4); } }
public ExifVersion(ExifTag tag, string value)
: base(tag)
{
if (value.Length > 4)
mValue = value.Substring(0, 4);
else if (value.Length < 4)
mValue = value + new string(' ', 4 - value.Length);
else
mValue = value;
}
public override string ToString()
{
return mValue;
}
public override ExifInterOperability Interoperability
{
get
{
if (mTag == ExifTag.ExifVersion || mTag == ExifTag.FlashpixVersion || mTag == ExifTag.InteroperabilityVersion)
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 7, 4, Encoding.ASCII.GetBytes(mValue));
else
{
byte[] data = new byte[4];
for (int i = 0; i < 4; i++)
data[i] = byte.Parse(mValue[0].ToString());
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 7, 4, data);
}
}
}
}
/// <summary>
/// Represents the location and area of the subject (EXIF Specification: 2xSHORT)
/// The coordinate values, width, and height are expressed in relation to the
/// upper left as origin, prior to rotation processing as per the Rotation tag.
/// </summary>
internal class ExifPointSubjectArea : ExifUShortArray
{
protected new ushort[] Value { get { return mValue; } set { mValue = value; } }
public ushort X { get { return mValue[0]; } set { mValue[0] = value; } }
public ushort Y { get { return mValue[1]; } set { mValue[1] = value; } }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("({0:d}, {1:d})", mValue[0], mValue[1]);
return sb.ToString();
}
public ExifPointSubjectArea(ExifTag tag, ushort[] value)
: base(tag, value)
{
;
}
public ExifPointSubjectArea(ExifTag tag, ushort x, ushort y)
: base(tag, new ushort[] { x, y })
{
;
}
}
/// <summary>
/// Represents the location and area of the subject (EXIF Specification: 3xSHORT)
/// The coordinate values, width, and height are expressed in relation to the
/// upper left as origin, prior to rotation processing as per the Rotation tag.
/// </summary>
internal class ExifCircularSubjectArea : ExifPointSubjectArea
{
public ushort Diamater { get { return mValue[2]; } set { mValue[2] = value; } }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("({0:d}, {1:d}) {2:d}", mValue[0], mValue[1], mValue[2]);
return sb.ToString();
}
public ExifCircularSubjectArea(ExifTag tag, ushort[] value)
: base(tag, value)
{
;
}
public ExifCircularSubjectArea(ExifTag tag, ushort x, ushort y, ushort d)
: base(tag, new ushort[] { x, y, d })
{
;
}
}
/// <summary>
/// Represents the location and area of the subject (EXIF Specification: 4xSHORT)
/// The coordinate values, width, and height are expressed in relation to the
/// upper left as origin, prior to rotation processing as per the Rotation tag.
/// </summary>
internal class ExifRectangularSubjectArea : ExifPointSubjectArea
{
public ushort Width { get { return mValue[2]; } set { mValue[2] = value; } }
public ushort Height { get { return mValue[3]; } set { mValue[3] = value; } }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("({0:d}, {1:d}) ({2:d} x {3:d})", mValue[0], mValue[1], mValue[2], mValue[3]);
return sb.ToString();
}
public ExifRectangularSubjectArea(ExifTag tag, ushort[] value)
: base(tag, value)
{
;
}
public ExifRectangularSubjectArea(ExifTag tag, ushort x, ushort y, ushort w, ushort h)
: base(tag, new ushort[] { x, y, w, h })
{
;
}
}
/// <summary>
/// Represents GPS latitudes and longitudes (EXIF Specification: 3xRATIONAL)
/// </summary>
internal class GPSLatitudeLongitude : ExifURationalArray
{
protected new MathEx.UFraction32[] Value { get { return mValue; } set { mValue = value; } }
public MathEx.UFraction32 Degrees { get { return mValue[0]; } set { mValue[0] = value; } }
public MathEx.UFraction32 Minutes { get { return mValue[1]; } set { mValue[1] = value; } }
public MathEx.UFraction32 Seconds { get { return mValue[2]; } set { mValue[2] = value; } }
public static explicit operator float(GPSLatitudeLongitude obj) { return obj.ToFloat(); }
public float ToFloat()
{
return (float)Degrees + ((float)Minutes) / 60.0f + ((float)Seconds) / 3600.0f;
}
public override string ToString()
{
return string.Format("{0:F2}°{1:F2}'{2:F2}\"", (float)Degrees, (float)Minutes, (float)Seconds);
}
public GPSLatitudeLongitude(ExifTag tag, MathEx.UFraction32[] value)
: base(tag, value)
{
;
}
public GPSLatitudeLongitude(ExifTag tag, float d, float m, float s)
: base(tag, new MathEx.UFraction32[] { new MathEx.UFraction32(d), new MathEx.UFraction32(m), new MathEx.UFraction32(s) })
{
;
}
}
/// <summary>
/// Represents a GPS time stamp as UTC (EXIF Specification: 3xRATIONAL)
/// </summary>
internal class GPSTimeStamp : ExifURationalArray
{
protected new MathEx.UFraction32[] Value { get { return mValue; } set { mValue = value; } }
public MathEx.UFraction32 Hour { get { return mValue[0]; } set { mValue[0] = value; } }
public MathEx.UFraction32 Minute { get { return mValue[1]; } set { mValue[1] = value; } }
public MathEx.UFraction32 Second { get { return mValue[2]; } set { mValue[2] = value; } }
public override string ToString()
{
return string.Format("{0:F2}:{1:F2}:{2:F2}\"", (float)Hour, (float)Minute, (float)Second);
}
public GPSTimeStamp(ExifTag tag, MathEx.UFraction32[] value)
: base(tag, value)
{
;
}
public GPSTimeStamp(ExifTag tag, float h, float m, float s)
: base(tag, new MathEx.UFraction32[] { new MathEx.UFraction32(h), new MathEx.UFraction32(m), new MathEx.UFraction32(s) })
{
;
}
}
/// <summary>
/// Represents an ASCII string. (EXIF Specification: BYTE)
/// Used by Windows XP.
/// </summary>
internal class WindowsByteString : ExifProperty
{
protected string mValue;
protected override object _Value { get { return Value; } set { Value = (string)value; } }
public new string Value { get { return mValue; } set { mValue = value; } }
static public implicit operator string(WindowsByteString obj) { return obj.mValue; }
public override string ToString() { return mValue; }
public WindowsByteString(ExifTag tag, string value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
byte[] data = Encoding.Unicode.GetBytes(mValue);
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, (uint)data.Length, data);
}
}
}
}

View File

@@ -1,125 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Provides a custom type descriptor for an ExifFile instance.
/// </summary>
internal sealed class ExifFileTypeDescriptionProvider : TypeDescriptionProvider
{
public ExifFileTypeDescriptionProvider()
: this(TypeDescriptor.GetProvider(typeof(ImageFile)))
{
}
public ExifFileTypeDescriptionProvider(TypeDescriptionProvider parent)
: base(parent)
{
}
/// <summary>
/// Gets a custom type descriptor for the given type and object.
/// </summary>
/// <param name="objectType">The type of object for which to retrieve the type descriptor.</param>
/// <param name="instance">An instance of the type. Can be null if no instance was passed to the <see cref="T:System.ComponentModel.TypeDescriptor"/>.</param>
/// <returns>
/// An <see cref="T:System.ComponentModel.ICustomTypeDescriptor"/> that can provide metadata for the type.
/// </returns>
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
return new ExifFileTypeDescriptor(base.GetTypeDescriptor(objectType, instance), instance);
}
}
/// <summary>
/// Expands ExifProperty objects contained in an ExifFile as separate properties.
/// </summary>
internal sealed class ExifFileTypeDescriptor : CustomTypeDescriptor
{
ImageFile owner;
public ExifFileTypeDescriptor(ICustomTypeDescriptor parent, object instance)
: base(parent)
{
owner = (ImageFile)instance;
}
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
return GetProperties();
}
/// <summary>
/// Returns a collection of property descriptors for the object represented by this type descriptor.
/// </summary>
/// <returns>
/// A <see cref="T:System.ComponentModel.PropertyDescriptorCollection"/> containing the property descriptions for the object represented by this type descriptor. The default is <see cref="F:System.ComponentModel.PropertyDescriptorCollection.Empty"/>.
/// </returns>
public override PropertyDescriptorCollection GetProperties()
{
// Enumerate the original set of properties and create our new set with it
List<PropertyDescriptor> properties = new List<PropertyDescriptor>();
foreach (ExifProperty prop in owner.Properties)
{
ExifPropertyDescriptor pd = new ExifPropertyDescriptor(prop);
properties.Add(pd);
}
// Finally return the list
return new PropertyDescriptorCollection(properties.ToArray(), true);
}
}
internal sealed class ExifPropertyDescriptor : PropertyDescriptor
{
object originalValue;
ExifProperty linkedProperty;
public ExifPropertyDescriptor(ExifProperty property)
: base(property.Name, new Attribute[] { new BrowsableAttribute(true) })
{
linkedProperty = property;
originalValue = property.Value;
}
public override bool CanResetValue(object component)
{
return true;
}
public override Type ComponentType
{
get { return typeof(JPEGFile); }
}
public override object GetValue(object component)
{
return linkedProperty.Value;
}
public override bool IsReadOnly
{
get { return false; }
}
public override Type PropertyType
{
get { return linkedProperty.Value.GetType(); }
}
public override void ResetValue(object component)
{
linkedProperty.Value = originalValue;
}
public override void SetValue(object component, object value)
{
linkedProperty.Value = value;
}
public override bool ShouldSerializeValue(object component)
{
return false;
}
}
}

View File

@@ -1,60 +0,0 @@
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents interoperability data for an exif tag in the platform byte order.
/// </summary>
internal struct ExifInterOperability
{
private ushort mTagID;
private ushort mTypeID;
private uint mCount;
private byte[] mData;
/// <summary>
/// Gets the tag ID defined in the Exif standard.
/// </summary>
public ushort TagID { get { return mTagID; } }
/// <summary>
/// Gets the type code defined in the Exif standard.
/// <list type="bullet">
/// <item>1 = BYTE (byte)</item>
/// <item>2 = ASCII (byte array)</item>
/// <item>3 = SHORT (ushort)</item>
/// <item>4 = LONG (uint)</item>
/// <item>5 = RATIONAL (2 x uint: numerator, denominator)</item>
/// <item>6 = BYTE (sbyte)</item>
/// <item>7 = UNDEFINED (byte array)</item>
/// <item>8 = SSHORT (short)</item>
/// <item>9 = SLONG (int)</item>
/// <item>10 = SRATIONAL (2 x int: numerator, denominator)</item>
/// <item>11 = FLOAT (float)</item>
/// <item>12 = DOUBLE (double)</item>
/// </list>
/// </summary>
public ushort TypeID { get { return mTypeID; } }
/// <summary>
/// Gets the byte count or number of components.
/// </summary>
public uint Count { get { return mCount; } }
/// <summary>
/// Gets the field value as an array of bytes.
/// </summary>
public byte[] Data { get { return mData; } }
/// <summary>
/// Returns the string representation of this instance.
/// </summary>
/// <returns></returns>
public override string ToString()
{
return string.Format("Tag: {0}, Type: {1}, Count: {2}, Data Length: {3}", mTagID, mTypeID, mCount, mData.Length);
}
public ExifInterOperability(ushort tagid, ushort typeid, uint count, byte[] data)
{
mTagID = tagid;
mTypeID = typeid;
mCount = count;
mData = data;
}
}
}

View File

@@ -1,578 +0,0 @@
using System;
using System.Text;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents the abstract base class for an Exif property.
/// </summary>
internal abstract class ExifProperty
{
protected ExifTag mTag;
protected IFD mIFD;
protected string mName;
/// <summary>
/// Gets the Exif tag associated with this property.
/// </summary>
public ExifTag Tag { get { return mTag; } }
/// <summary>
/// Gets the IFD section contaning this property.
/// </summary>
public IFD IFD { get { return mIFD; } }
/// <summary>
/// Gets or sets the name of this property.
/// </summary>
public string Name
{
get
{
if (string.IsNullOrEmpty(mName))
return ExifTagFactory.GetTagName(mTag);
else
return mName;
}
set
{
mName = value;
}
}
protected abstract object _Value { get; set; }
/// <summary>
/// Gets or sets the value of this property.
/// </summary>
public object Value { get { return _Value; } set { _Value = value; } }
/// <summary>
/// Gets interoperability data for this property.
/// </summary>
public abstract ExifInterOperability Interoperability { get; }
public ExifProperty(ExifTag tag)
{
mTag = tag;
mIFD = ExifTagFactory.GetTagIFD(tag);
}
}
/// <summary>
/// Represents an 8-bit unsigned integer. (EXIF Specification: BYTE)
/// </summary>
internal class ExifByte : ExifProperty
{
protected byte mValue;
protected override object _Value { get { return Value; } set { Value = Convert.ToByte(value); } }
public new byte Value { get { return mValue; } set { mValue = value; } }
static public implicit operator byte(ExifByte obj) { return obj.mValue; }
public override string ToString() { return mValue.ToString(); }
public ExifByte(ExifTag tag, byte value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, 1, new byte[] { mValue });
}
}
}
/// <summary>
/// Represents an array of 8-bit unsigned integers. (EXIF Specification: BYTE with count > 1)
/// </summary>
internal class ExifByteArray : ExifProperty
{
protected byte[] mValue;
protected override object _Value { get { return Value; } set { Value = (byte[])value; } }
public new byte[] Value { get { return mValue; } set { mValue = value; } }
static public implicit operator byte[](ExifByteArray obj) { return obj.mValue; }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('[');
foreach (byte b in mValue)
{
sb.Append(b);
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
public ExifByteArray(ExifTag tag, byte[] value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, (uint)mValue.Length, mValue);
}
}
}
/// <summary>
/// Represents an ASCII string. (EXIF Specification: ASCII)
/// </summary>
internal class ExifAscii : ExifProperty
{
protected string mValue;
protected override object _Value { get { return Value; } set { Value = (string)value; } }
public new string Value { get { return mValue; } set { mValue = value; } }
public Encoding Encoding { get; private set; }
static public implicit operator string(ExifAscii obj) { return obj.mValue; }
public override string ToString() { return mValue; }
public ExifAscii(ExifTag tag, string value, Encoding encoding)
: base(tag)
{
mValue = value;
Encoding = encoding;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 2, (uint)mValue.Length + 1, ExifBitConverter.GetBytes(mValue, true, Encoding));
}
}
}
/// <summary>
/// Represents a 16-bit unsigned integer. (EXIF Specification: SHORT)
/// </summary>
internal class ExifUShort : ExifProperty
{
protected ushort mValue;
protected override object _Value { get { return Value; } set { Value = Convert.ToUInt16(value); } }
public new ushort Value { get { return mValue; } set { mValue = value; } }
static public implicit operator ushort(ExifUShort obj) { return obj.mValue; }
public override string ToString() { return mValue.ToString(); }
public ExifUShort(ExifTag tag, ushort value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 3, 1, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents an array of 16-bit unsigned integers.
/// (EXIF Specification: SHORT with count > 1)
/// </summary>
internal class ExifUShortArray : ExifProperty
{
protected ushort[] mValue;
protected override object _Value { get { return Value; } set { Value = (ushort[])value; } }
public new ushort[] Value { get { return mValue; } set { mValue = value; } }
static public implicit operator ushort[](ExifUShortArray obj) { return obj.mValue; }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('[');
foreach (ushort b in mValue)
{
sb.Append(b);
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
public ExifUShortArray(ExifTag tag, ushort[] value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 3, (uint)mValue.Length, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents a 32-bit unsigned integer. (EXIF Specification: LONG)
/// </summary>
internal class ExifUInt : ExifProperty
{
protected uint mValue;
protected override object _Value { get { return Value; } set { Value = Convert.ToUInt32(value); } }
public new uint Value { get { return mValue; } set { mValue = value; } }
static public implicit operator uint(ExifUInt obj) { return obj.mValue; }
public override string ToString() { return mValue.ToString(); }
public ExifUInt(ExifTag tag, uint value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 4, 1, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents an array of 16-bit unsigned integers.
/// (EXIF Specification: LONG with count > 1)
/// </summary>
internal class ExifUIntArray : ExifProperty
{
protected uint[] mValue;
protected override object _Value { get { return Value; } set { Value = (uint[])value; } }
public new uint[] Value { get { return mValue; } set { mValue = value; } }
static public implicit operator uint[](ExifUIntArray obj) { return obj.mValue; }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('[');
foreach (uint b in mValue)
{
sb.Append(b);
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
public ExifUIntArray(ExifTag tag, uint[] value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 3, (uint)mValue.Length, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents a rational number defined with a 32-bit unsigned numerator
/// and denominator. (EXIF Specification: RATIONAL)
/// </summary>
internal class ExifURational : ExifProperty
{
protected MathEx.UFraction32 mValue;
protected override object _Value { get { return Value; } set { Value = (MathEx.UFraction32)value; } }
public new MathEx.UFraction32 Value { get { return mValue; } set { mValue = value; } }
public override string ToString() { return mValue.ToString(); }
public float ToFloat() { return (float)mValue; }
static public explicit operator float(ExifURational obj) { return (float)obj.mValue; }
public uint[] ToArray()
{
return new uint[] { mValue.Numerator, mValue.Denominator };
}
public ExifURational(ExifTag tag, uint numerator, uint denominator)
: base(tag)
{
mValue = new MathEx.UFraction32(numerator, denominator);
}
public ExifURational(ExifTag tag, MathEx.UFraction32 value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 5, 1, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents an array of unsigned rational numbers.
/// (EXIF Specification: RATIONAL with count > 1)
/// </summary>
internal class ExifURationalArray : ExifProperty
{
protected MathEx.UFraction32[] mValue;
protected override object _Value { get { return Value; } set { Value = (MathEx.UFraction32[])value; } }
public new MathEx.UFraction32[] Value { get { return mValue; } set { mValue = value; } }
static public explicit operator float[](ExifURationalArray obj)
{
float[] result = new float[obj.mValue.Length];
for (int i = 0; i < obj.mValue.Length; i++)
result[i] = (float)obj.mValue[i];
return result;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('[');
foreach (MathEx.UFraction32 b in mValue)
{
sb.Append(b.ToString());
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
public ExifURationalArray(ExifTag tag, MathEx.UFraction32[] value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 5, (uint)mValue.Length, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents a byte array that can take any value. (EXIF Specification: UNDEFINED)
/// </summary>
internal class ExifUndefined : ExifProperty
{
protected byte[] mValue;
protected override object _Value { get { return Value; } set { Value = (byte[])value; } }
public new byte[] Value { get { return mValue; } set { mValue = value; } }
static public implicit operator byte[](ExifUndefined obj) { return obj.mValue; }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('[');
foreach (byte b in mValue)
{
sb.Append(b);
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
public ExifUndefined(ExifTag tag, byte[] value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 7, (uint)mValue.Length, mValue);
}
}
}
/// <summary>
/// Represents a 32-bit signed integer. (EXIF Specification: SLONG)
/// </summary>
internal class ExifSInt : ExifProperty
{
protected int mValue;
protected override object _Value { get { return Value; } set { Value = Convert.ToInt32(value); } }
public new int Value { get { return mValue; } set { mValue = value; } }
public override string ToString() { return mValue.ToString(); }
static public implicit operator int(ExifSInt obj) { return obj.mValue; }
public ExifSInt(ExifTag tag, int value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 9, 1, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents an array of 32-bit signed integers.
/// (EXIF Specification: SLONG with count > 1)
/// </summary>
internal class ExifSIntArray : ExifProperty
{
protected int[] mValue;
protected override object _Value { get { return Value; } set { Value = (int[])value; } }
public new int[] Value { get { return mValue; } set { mValue = value; } }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('[');
foreach (int b in mValue)
{
sb.Append(b);
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
static public implicit operator int[](ExifSIntArray obj) { return obj.mValue; }
public ExifSIntArray(ExifTag tag, int[] value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 9, (uint)mValue.Length, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents a rational number defined with a 32-bit signed numerator
/// and denominator. (EXIF Specification: SRATIONAL)
/// </summary>
internal class ExifSRational : ExifProperty
{
protected MathEx.Fraction32 mValue;
protected override object _Value { get { return Value; } set { Value = (MathEx.Fraction32)value; } }
public new MathEx.Fraction32 Value { get { return mValue; } set { mValue = value; } }
public override string ToString() { return mValue.ToString(); }
public float ToFloat() { return (float)mValue; }
static public explicit operator float(ExifSRational obj) { return (float)obj.mValue; }
public int[] ToArray()
{
return new int[] { mValue.Numerator, mValue.Denominator };
}
public ExifSRational(ExifTag tag, int numerator, int denominator)
: base(tag)
{
mValue = new MathEx.Fraction32(numerator, denominator);
}
public ExifSRational(ExifTag tag, MathEx.Fraction32 value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 10, 1, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents an array of signed rational numbers.
/// (EXIF Specification: SRATIONAL with count > 1)
/// </summary>
internal class ExifSRationalArray : ExifProperty
{
protected MathEx.Fraction32[] mValue;
protected override object _Value { get { return Value; } set { Value = (MathEx.Fraction32[])value; } }
public new MathEx.Fraction32[] Value { get { return mValue; } set { mValue = value; } }
static public explicit operator float[](ExifSRationalArray obj)
{
float[] result = new float[obj.mValue.Length];
for (int i = 0; i < obj.mValue.Length; i++)
result[i] = (float)obj.mValue[i];
return result;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('[');
foreach (MathEx.Fraction32 b in mValue)
{
sb.Append(b.ToString());
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
public ExifSRationalArray(ExifTag tag, MathEx.Fraction32[] value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 10, (uint)mValue.Length, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
}
}
}
}

View File

@@ -1,380 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents a collection of <see cref="ExifProperty"/> objects.
/// </summary>
internal class ExifPropertyCollection : IDictionary<ExifTag, ExifProperty>
{
#region Member Variables
private ImageFile parent;
private Dictionary<ExifTag, ExifProperty> items;
#endregion
#region Constructor
internal ExifPropertyCollection (ImageFile parentFile)
{
parent = parentFile;
items = new Dictionary<ExifTag, ExifProperty> ();
}
#endregion
#region Properties
/// <summary>
/// Gets the number of elements contained in the collection.
/// </summary>
public int Count {
get { return items.Count; }
}
/// <summary>
/// Gets a collection containing the keys in this collection.
/// </summary>
public ICollection<ExifTag> Keys {
get { return items.Keys; }
}
/// <summary>
/// Gets a collection containing the values in this collection.
/// </summary>
public ICollection<ExifProperty> Values {
get { return items.Values; }
}
/// <summary>
/// Gets or sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
public ExifProperty this[ExifTag key] {
get { return items[key]; }
set {
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, value);
}
}
#endregion
#region ExifProperty Collection Setters
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, byte value)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifByte (key, value));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, string value)
{
if (items.ContainsKey (key))
items.Remove (key);
if (key == ExifTag.WindowsTitle || key == ExifTag.WindowsComment || key == ExifTag.WindowsAuthor || key == ExifTag.WindowsKeywords || key == ExifTag.WindowsSubject) {
items.Add (key, new WindowsByteString (key, value));
} else {
items.Add (key, new ExifAscii (key, value, parent.Encoding));
}
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, ushort value)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifUShort (key, value));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, int value)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifSInt (key, value));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, uint value)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifUInt (key, value));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, float value)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifURational (key, new MathEx.UFraction32 (value)));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, double value)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifURational (key, new MathEx.UFraction32 (value)));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, object value)
{
Type type = value.GetType ();
if (type.IsEnum) {
Type etype = typeof(ExifEnumProperty<>).MakeGenericType (new Type[] { type });
object prop = Activator.CreateInstance (etype, new object[] { key, value });
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, (ExifProperty)prop);
} else
throw new ArgumentException ("No exif property exists for this tag.", "value");
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
/// <param name="encoding">String encoding.</param>
public void Set (ExifTag key, string value, Encoding encoding)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifEncodedString (key, value, encoding));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, DateTime value)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifDateTime (key, value));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="d">Angular degrees (or clock hours for a timestamp).</param>
/// <param name="m">Angular minutes (or clock minutes for a timestamp).</param>
/// <param name="s">Angular seconds (or clock seconds for a timestamp).</param>
public void Set (ExifTag key, float d, float m, float s)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifURationalArray (key, new MathEx.UFraction32[] { new MathEx.UFraction32 (d), new MathEx.UFraction32 (m), new MathEx.UFraction32 (s) }));
}
#endregion
#region Instance Methods
/// <summary>
/// Adds the specified item to the collection.
/// </summary>
/// <param name="item">The <see cref="ExifProperty"/> to add to the collection.</param>
public void Add (ExifProperty item)
{
ExifProperty oldItem = null;
if (items.TryGetValue (item.Tag, out oldItem))
items[item.Tag] = item;
else
items.Add (item.Tag, item);
}
/// <summary>
/// Removes all items from the collection.
/// </summary>
public void Clear ()
{
items.Clear ();
}
/// <summary>
/// Determines whether the collection contains an element with the specified key.
/// </summary>
/// <param name="key">The key to locate in the collection.</param>
/// <returns>
/// true if the collection contains an element with the key; otherwise, false.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="key"/> is null.</exception>
public bool ContainsKey (ExifTag key)
{
return items.ContainsKey (key);
}
/// <summary>
/// Removes the element with the specified key from the collection.
/// </summary>
/// <param name="key">The key of the element to remove.</param>
/// <returns>
/// true if the element is successfully removed; otherwise, false. This method also returns false if <paramref name="key"/> was not found in the original collection.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="key"/> is null.</exception>
public bool Remove (ExifTag key)
{
return items.Remove (key);
}
/// <summary>
/// Removes all items with the given IFD from the collection.
/// </summary>
/// <param name="ifd">The IFD section to remove.</param>
public void Remove (IFD ifd)
{
List<ExifTag> toRemove = new List<ExifTag> ();
foreach (KeyValuePair<ExifTag, ExifProperty> item in items) {
if (item.Value.IFD == ifd)
toRemove.Add (item.Key);
}
foreach (ExifTag tag in toRemove)
items.Remove (tag);
}
/// <summary>
/// Gets the value associated with the specified key.
/// </summary>
/// <param name="key">The key whose value to get.</param>
/// <param name="value">When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the <paramref name="value"/> parameter. This parameter is passed uninitialized.</param>
/// <returns>
/// true if the collection contains an element with the specified key; otherwise, false.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="key"/> is null.</exception>
public bool TryGetValue (ExifTag key, out ExifProperty value)
{
return items.TryGetValue (key, out value);
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
/// </returns>
public IEnumerator<ExifProperty> GetEnumerator ()
{
return Values.GetEnumerator ();
}
#endregion
#region Hidden Interface
/// <summary>
/// Adds an element with the provided key and value to the <see cref="T:System.Collections.Generic.IDictionary`2"/>.
/// </summary>
/// <param name="key">The object to use as the key of the element to add.</param>
/// <param name="value">The object to use as the value of the element to add.</param>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="key"/> is null.</exception>
/// <exception cref="T:System.ArgumentException">An element with the same key already exists in the <see cref="T:System.Collections.Generic.IDictionary`2"/>.</exception>
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IDictionary`2"/> is read-only.</exception>
void IDictionary<ExifTag, ExifProperty>.Add (ExifTag key, ExifProperty value)
{
Add (value);
}
/// <summary>
/// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary>
/// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
void ICollection<KeyValuePair<ExifTag, ExifProperty>>.Add (KeyValuePair<ExifTag, ExifProperty> item)
{
Add (item.Value);
}
bool ICollection<KeyValuePair<ExifTag, ExifProperty>>.Contains (KeyValuePair<ExifTag, ExifProperty> item)
{
throw new NotSupportedException ();
}
/// <summary>
/// Copies the elements of the <see cref="T:System.Collections.Generic.ICollection`1"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
/// </summary>
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.Generic.ICollection`1"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param>
/// <param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="array"/> is null.</exception>
/// <exception cref="T:System.ArgumentOutOfRangeException">
/// <paramref name="arrayIndex"/> is less than 0.</exception>
/// <exception cref="T:System.ArgumentException">
/// <paramref name="array"/> is multidimensional.-or-<paramref name="arrayIndex"/> is equal to or greater than the length of <paramref name="array"/>.-or-The number of elements in the source <see cref="T:System.Collections.Generic.ICollection`1"/> is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.-or-Type <paramref name="T"/> cannot be cast automatically to the type of the destination <paramref name="array"/>.</exception>
void ICollection<KeyValuePair<ExifTag, ExifProperty>>.CopyTo (KeyValuePair<ExifTag, ExifProperty>[] array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException ("array");
if (arrayIndex < 0)
throw new ArgumentOutOfRangeException ("arrayIndex");
if (array.Rank > 1)
throw new ArgumentException ("Destination array is multidimensional.", "array");
if (arrayIndex >= array.Length)
throw new ArgumentException ("arrayIndex is equal to or greater than the length of destination array", "array");
if (arrayIndex + items.Count > array.Length)
throw new ArgumentException ("There is not enough space in destination array.", "array");
int i = 0;
foreach (KeyValuePair<ExifTag, ExifProperty> item in items) {
if (i >= arrayIndex) {
array[i] = item;
}
i++;
}
}
/// <summary>
/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
/// </summary>
/// <returns>true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false.</returns>
bool ICollection<KeyValuePair<ExifTag, ExifProperty>>.IsReadOnly {
get { return false; }
}
/// <summary>
/// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary>
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
/// <returns>
/// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </returns>
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
bool ICollection<KeyValuePair<ExifTag, ExifProperty>>.Remove (KeyValuePair<ExifTag, ExifProperty> item)
{
throw new NotSupportedException ();
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
/// </returns>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
{
return GetEnumerator ();
}
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
/// </returns>
IEnumerator<KeyValuePair<ExifTag, ExifProperty>> IEnumerable<KeyValuePair<ExifTag, ExifProperty>>.GetEnumerator ()
{
return items.GetEnumerator ();
}
#endregion
}
}

View File

@@ -1,253 +0,0 @@
using System;
using System.Text;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Creates exif properties from interoperability parameters.
/// </summary>
internal static class ExifPropertyFactory
{
#region Static Methods
/// <summary>
/// Creates an ExifProperty from the given interoperability parameters.
/// </summary>
/// <param name="tag">The tag id of the exif property.</param>
/// <param name="type">The type id of the exif property.</param>
/// <param name="count">Byte or component count.</param>
/// <param name="value">Field data as an array of bytes.</param>
/// <param name="byteOrder">Byte order of value.</param>
/// <param name="ifd">IFD section containing this propery.</param>
/// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param>
/// <returns>an ExifProperty initialized from the interoperability parameters.</returns>
public static ExifProperty Get(ushort tag, ushort type, uint count, byte[] value, BitConverterEx.ByteOrder byteOrder, IFD ifd, Encoding encoding)
{
BitConverterEx conv = new BitConverterEx(byteOrder, BitConverterEx.SystemByteOrder);
// Find the exif tag corresponding to given tag id
ExifTag etag = ExifTagFactory.GetExifTag(ifd, tag);
if (ifd == IFD.Zeroth)
{
if (tag == 0x103) // Compression
return new ExifEnumProperty<Compression>(ExifTag.Compression, (Compression)conv.ToUInt16(value, 0));
else if (tag == 0x106) // PhotometricInterpretation
return new ExifEnumProperty<PhotometricInterpretation>(ExifTag.PhotometricInterpretation, (PhotometricInterpretation)conv.ToUInt16(value, 0));
else if (tag == 0x112) // Orientation
return new ExifEnumProperty<Orientation>(ExifTag.Orientation, (Orientation)conv.ToUInt16(value, 0));
else if (tag == 0x11c) // PlanarConfiguration
return new ExifEnumProperty<PlanarConfiguration>(ExifTag.PlanarConfiguration, (PlanarConfiguration)conv.ToUInt16(value, 0));
else if (tag == 0x213) // YCbCrPositioning
return new ExifEnumProperty<YCbCrPositioning>(ExifTag.YCbCrPositioning, (YCbCrPositioning)conv.ToUInt16(value, 0));
else if (tag == 0x128) // ResolutionUnit
return new ExifEnumProperty<ResolutionUnit>(ExifTag.ResolutionUnit, (ResolutionUnit)conv.ToUInt16(value, 0));
else if (tag == 0x132) // DateTime
return new ExifDateTime(ExifTag.DateTime, ExifBitConverter.ToDateTime(value));
else if (tag == 0x9c9b || tag == 0x9c9c || // Windows tags
tag == 0x9c9d || tag == 0x9c9e || tag == 0x9c9f)
return new WindowsByteString(etag, Encoding.Unicode.GetString(value).TrimEnd('\0'));
}
else if (ifd == IFD.EXIF)
{
if (tag == 0x9000) // ExifVersion
return new ExifVersion(ExifTag.ExifVersion, ExifBitConverter.ToAscii(value, Encoding.ASCII));
else if (tag == 0xa000) // FlashpixVersion
return new ExifVersion(ExifTag.FlashpixVersion, ExifBitConverter.ToAscii(value, Encoding.ASCII));
else if (tag == 0xa001) // ColorSpace
return new ExifEnumProperty<ColorSpace>(ExifTag.ColorSpace, (ColorSpace)conv.ToUInt16(value, 0));
else if (tag == 0x9286) // UserComment
{
// Default to ASCII
Encoding enc = Encoding.ASCII;
bool hasenc;
if (value.Length < 8)
hasenc = false;
else
{
hasenc = true;
string encstr = enc.GetString(value, 0, 8);
if (string.Compare(encstr, "ASCII\0\0\0", StringComparison.OrdinalIgnoreCase) == 0)
enc = Encoding.ASCII;
else if (string.Compare(encstr, "JIS\0\0\0\0\0", StringComparison.OrdinalIgnoreCase) == 0)
enc = Encoding.GetEncoding("Japanese (JIS 0208-1990 and 0212-1990)");
else if (string.Compare(encstr, "Unicode\0", StringComparison.OrdinalIgnoreCase) == 0)
enc = Encoding.Unicode;
else
hasenc = false;
}
string val = (hasenc ? enc.GetString(value, 8, value.Length - 8) : enc.GetString(value)).Trim('\0');
return new ExifEncodedString(ExifTag.UserComment, val, enc);
}
else if (tag == 0x9003) // DateTimeOriginal
return new ExifDateTime(ExifTag.DateTimeOriginal, ExifBitConverter.ToDateTime(value));
else if (tag == 0x9004) // DateTimeDigitized
return new ExifDateTime(ExifTag.DateTimeDigitized, ExifBitConverter.ToDateTime(value));
else if (tag == 0x8822) // ExposureProgram
return new ExifEnumProperty<ExposureProgram>(ExifTag.ExposureProgram, (ExposureProgram)conv.ToUInt16(value, 0));
else if (tag == 0x9207) // MeteringMode
return new ExifEnumProperty<MeteringMode>(ExifTag.MeteringMode, (MeteringMode)conv.ToUInt16(value, 0));
else if (tag == 0x9208) // LightSource
return new ExifEnumProperty<LightSource>(ExifTag.LightSource, (LightSource)conv.ToUInt16(value, 0));
else if (tag == 0x9209) // Flash
return new ExifEnumProperty<Flash>(ExifTag.Flash, (Flash)conv.ToUInt16(value, 0), true);
else if (tag == 0x9214) // SubjectArea
{
if (count == 3)
return new ExifCircularSubjectArea(ExifTag.SubjectArea, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder));
else if (count == 4)
return new ExifRectangularSubjectArea(ExifTag.SubjectArea, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder));
else // count == 2
return new ExifPointSubjectArea(ExifTag.SubjectArea, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder));
}
else if (tag == 0xa210) // FocalPlaneResolutionUnit
return new ExifEnumProperty<ResolutionUnit>(ExifTag.FocalPlaneResolutionUnit, (ResolutionUnit)conv.ToUInt16(value, 0), true);
else if (tag == 0xa214) // SubjectLocation
return new ExifPointSubjectArea(ExifTag.SubjectLocation, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder));
else if (tag == 0xa217) // SensingMethod
return new ExifEnumProperty<SensingMethod>(ExifTag.SensingMethod, (SensingMethod)conv.ToUInt16(value, 0), true);
else if (tag == 0xa300) // FileSource
return new ExifEnumProperty<FileSource>(ExifTag.FileSource, (FileSource)conv.ToUInt16(value, 0), true);
else if (tag == 0xa301) // SceneType
return new ExifEnumProperty<SceneType>(ExifTag.SceneType, (SceneType)conv.ToUInt16(value, 0), true);
else if (tag == 0xa401) // CustomRendered
return new ExifEnumProperty<CustomRendered>(ExifTag.CustomRendered, (CustomRendered)conv.ToUInt16(value, 0), true);
else if (tag == 0xa402) // ExposureMode
return new ExifEnumProperty<ExposureMode>(ExifTag.ExposureMode, (ExposureMode)conv.ToUInt16(value, 0), true);
else if (tag == 0xa403) // WhiteBalance
return new ExifEnumProperty<WhiteBalance>(ExifTag.WhiteBalance, (WhiteBalance)conv.ToUInt16(value, 0), true);
else if (tag == 0xa406) // SceneCaptureType
return new ExifEnumProperty<SceneCaptureType>(ExifTag.SceneCaptureType, (SceneCaptureType)conv.ToUInt16(value, 0), true);
else if (tag == 0xa407) // GainControl
return new ExifEnumProperty<GainControl>(ExifTag.GainControl, (GainControl)conv.ToUInt16(value, 0), true);
else if (tag == 0xa408) // Contrast
return new ExifEnumProperty<Contrast>(ExifTag.Contrast, (Contrast)conv.ToUInt16(value, 0), true);
else if (tag == 0xa409) // Saturation
return new ExifEnumProperty<Saturation>(ExifTag.Saturation, (Saturation)conv.ToUInt16(value, 0), true);
else if (tag == 0xa40a) // Sharpness
return new ExifEnumProperty<Sharpness>(ExifTag.Sharpness, (Sharpness)conv.ToUInt16(value, 0), true);
else if (tag == 0xa40c) // SubjectDistanceRange
return new ExifEnumProperty<SubjectDistanceRange>(ExifTag.SubjectDistanceRange, (SubjectDistanceRange)conv.ToUInt16(value, 0), true);
}
else if (ifd == IFD.GPS)
{
if (tag == 0) // GPSVersionID
return new ExifVersion(ExifTag.GPSVersionID, ExifBitConverter.ToString(value));
else if (tag == 1) // GPSLatitudeRef
return new ExifEnumProperty<GPSLatitudeRef>(ExifTag.GPSLatitudeRef, (GPSLatitudeRef)value[0]);
else if (tag == 2) // GPSLatitude
return new GPSLatitudeLongitude(ExifTag.GPSLatitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
else if (tag == 3) // GPSLongitudeRef
return new ExifEnumProperty<GPSLongitudeRef>(ExifTag.GPSLongitudeRef, (GPSLongitudeRef)value[0]);
else if (tag == 4) // GPSLongitude
return new GPSLatitudeLongitude(ExifTag.GPSLongitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
else if (tag == 5) // GPSAltitudeRef
return new ExifEnumProperty<GPSAltitudeRef>(ExifTag.GPSAltitudeRef, (GPSAltitudeRef)value[0]);
else if (tag == 7) // GPSTimeStamp
return new GPSTimeStamp(ExifTag.GPSTimeStamp, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
else if (tag == 9) // GPSStatus
return new ExifEnumProperty<GPSStatus>(ExifTag.GPSStatus, (GPSStatus)value[0]);
else if (tag == 10) // GPSMeasureMode
return new ExifEnumProperty<GPSMeasureMode>(ExifTag.GPSMeasureMode, (GPSMeasureMode)value[0]);
else if (tag == 12) // GPSSpeedRef
return new ExifEnumProperty<GPSSpeedRef>(ExifTag.GPSSpeedRef, (GPSSpeedRef)value[0]);
else if (tag == 14) // GPSTrackRef
return new ExifEnumProperty<GPSDirectionRef>(ExifTag.GPSTrackRef, (GPSDirectionRef)value[0]);
else if (tag == 16) // GPSImgDirectionRef
return new ExifEnumProperty<GPSDirectionRef>(ExifTag.GPSImgDirectionRef, (GPSDirectionRef)value[0]);
else if (tag == 19) // GPSDestLatitudeRef
return new ExifEnumProperty<GPSLatitudeRef>(ExifTag.GPSDestLatitudeRef, (GPSLatitudeRef)value[0]);
else if (tag == 20) // GPSDestLatitude
return new GPSLatitudeLongitude(ExifTag.GPSDestLatitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
else if (tag == 21) // GPSDestLongitudeRef
return new ExifEnumProperty<GPSLongitudeRef>(ExifTag.GPSDestLongitudeRef, (GPSLongitudeRef)value[0]);
else if (tag == 22) // GPSDestLongitude
return new GPSLatitudeLongitude(ExifTag.GPSDestLongitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
else if (tag == 23) // GPSDestBearingRef
return new ExifEnumProperty<GPSDirectionRef>(ExifTag.GPSDestBearingRef, (GPSDirectionRef)value[0]);
else if (tag == 25) // GPSDestDistanceRef
return new ExifEnumProperty<GPSDistanceRef>(ExifTag.GPSDestDistanceRef, (GPSDistanceRef)value[0]);
else if (tag == 29) // GPSDate
return new ExifDateTime(ExifTag.GPSDateStamp, ExifBitConverter.ToDateTime(value, false));
else if (tag == 30) // GPSDifferential
return new ExifEnumProperty<GPSDifferential>(ExifTag.GPSDifferential, (GPSDifferential)conv.ToUInt16(value, 0));
}
else if (ifd == IFD.Interop)
{
if (tag == 1) // InteroperabilityIndex
return new ExifAscii(ExifTag.InteroperabilityIndex, ExifBitConverter.ToAscii(value, Encoding.ASCII), Encoding.ASCII);
else if (tag == 2) // InteroperabilityVersion
return new ExifVersion(ExifTag.InteroperabilityVersion, ExifBitConverter.ToAscii(value, Encoding.ASCII));
}
else if (ifd == IFD.First)
{
if (tag == 0x103) // Compression
return new ExifEnumProperty<Compression>(ExifTag.ThumbnailCompression, (Compression)conv.ToUInt16(value, 0));
else if (tag == 0x106) // PhotometricInterpretation
return new ExifEnumProperty<PhotometricInterpretation>(ExifTag.ThumbnailPhotometricInterpretation, (PhotometricInterpretation)conv.ToUInt16(value, 0));
else if (tag == 0x112) // Orientation
return new ExifEnumProperty<Orientation>(ExifTag.ThumbnailOrientation, (Orientation)conv.ToUInt16(value, 0));
else if (tag == 0x11c) // PlanarConfiguration
return new ExifEnumProperty<PlanarConfiguration>(ExifTag.ThumbnailPlanarConfiguration, (PlanarConfiguration)conv.ToUInt16(value, 0));
else if (tag == 0x213) // YCbCrPositioning
return new ExifEnumProperty<YCbCrPositioning>(ExifTag.ThumbnailYCbCrPositioning, (YCbCrPositioning)conv.ToUInt16(value, 0));
else if (tag == 0x128) // ResolutionUnit
return new ExifEnumProperty<ResolutionUnit>(ExifTag.ThumbnailResolutionUnit, (ResolutionUnit)conv.ToUInt16(value, 0));
else if (tag == 0x132) // DateTime
return new ExifDateTime(ExifTag.ThumbnailDateTime, ExifBitConverter.ToDateTime(value));
}
if (type == 1) // 1 = BYTE An 8-bit unsigned integer.
{
if (count == 1)
return new ExifByte(etag, value[0]);
else
return new ExifByteArray(etag, value);
}
else if (type == 2) // 2 = ASCII An 8-bit byte containing one 7-bit ASCII code.
{
return new ExifAscii(etag, ExifBitConverter.ToAscii(value, encoding), encoding);
}
else if (type == 3) // 3 = SHORT A 16-bit (2-byte) unsigned integer.
{
if (count == 1)
return new ExifUShort(etag, conv.ToUInt16(value, 0));
else
return new ExifUShortArray(etag, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder));
}
else if (type == 4) // 4 = LONG A 32-bit (4-byte) unsigned integer.
{
if (count == 1)
return new ExifUInt(etag, conv.ToUInt32(value, 0));
else
return new ExifUIntArray(etag, ExifBitConverter.ToUIntArray(value, (int)count, byteOrder));
}
else if (type == 5) // 5 = RATIONAL Two LONGs. The first LONG is the numerator and the second LONG expresses the denominator.
{
if (count == 1)
return new ExifURational(etag, ExifBitConverter.ToURational(value, byteOrder));
else
return new ExifURationalArray(etag, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
}
else if (type == 7) // 7 = UNDEFINED An 8-bit byte that can take any value depending on the field definition.
return new ExifUndefined(etag, value);
else if (type == 9) // 9 = SLONG A 32-bit (4-byte) signed integer (2's complement notation).
{
if (count == 1)
return new ExifSInt(etag, conv.ToInt32(value, 0));
else
return new ExifSIntArray(etag, ExifBitConverter.ToSIntArray(value, (int)count, byteOrder));
}
else if (type == 10) // 10 = SRATIONAL Two SLONGs. The first SLONG is the numerator and the second SLONG is the denominator.
{
if (count == 1)
return new ExifSRational(etag, ExifBitConverter.ToSRational(value, byteOrder));
else
return new ExifSRationalArray(etag, ExifBitConverter.ToSRationalArray(value, (int)count, byteOrder));
}
else
throw new ArgumentException("Unknown property type.");
}
#endregion
}
}

View File

@@ -1,290 +0,0 @@

namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents the tags associated with exif fields.
/// </summary>
internal enum ExifTag : int
{
// ****************************
// Zeroth IFD
// ****************************
NewSubfileType = IFD.Zeroth + 254,
SubfileType = IFD.Zeroth + 255,
ImageWidth = IFD.Zeroth + 256,
ImageLength = IFD.Zeroth + 257,
BitsPerSample = IFD.Zeroth + 258,
Compression = IFD.Zeroth + 259,
PhotometricInterpretation = IFD.Zeroth + 262,
Threshholding = IFD.Zeroth + 263,
CellWidth = IFD.Zeroth + 264,
CellLength = IFD.Zeroth + 265,
FillOrder = IFD.Zeroth + 266,
DocumentName = IFD.Zeroth + 269,
ImageDescription = IFD.Zeroth + 270,
Make = IFD.Zeroth + 271,
Model = IFD.Zeroth + 272,
StripOffsets = IFD.Zeroth + 273,
Orientation = IFD.Zeroth + 274,
SamplesPerPixel = IFD.Zeroth + 277,
RowsPerStrip = IFD.Zeroth + 278,
StripByteCounts = IFD.Zeroth + 279,
MinSampleValue = IFD.Zeroth + 280,
MaxSampleValue = IFD.Zeroth + 281,
XResolution = IFD.Zeroth + 282,
YResolution = IFD.Zeroth + 283,
PlanarConfiguration = IFD.Zeroth + 284,
PageName = IFD.Zeroth + 285,
XPosition = IFD.Zeroth + 286,
YPosition = IFD.Zeroth + 287,
FreeOffsets = IFD.Zeroth + 288,
FreeByteCounts = IFD.Zeroth + 289,
GrayResponseUnit = IFD.Zeroth + 290,
GrayResponseCurve = IFD.Zeroth + 291,
T4Options = IFD.Zeroth + 292,
T6Options = IFD.Zeroth + 293,
ResolutionUnit = IFD.Zeroth + 296,
PageNumber = IFD.Zeroth + 297,
TransferFunction = IFD.Zeroth + 301,
Software = IFD.Zeroth + 305,
DateTime = IFD.Zeroth + 306,
Artist = IFD.Zeroth + 315,
HostComputer = IFD.Zeroth + 316,
Predictor = IFD.Zeroth + 317,
WhitePoint = IFD.Zeroth + 318,
PrimaryChromaticities = IFD.Zeroth + 319,
ColorMap = IFD.Zeroth + 320,
HalftoneHints = IFD.Zeroth + 321,
TileWidth = IFD.Zeroth + 322,
TileLength = IFD.Zeroth + 323,
TileOffsets = IFD.Zeroth + 324,
TileByteCounts = IFD.Zeroth + 325,
InkSet = IFD.Zeroth + 332,
InkNames = IFD.Zeroth + 333,
NumberOfInks = IFD.Zeroth + 334,
DotRange = IFD.Zeroth + 336,
TargetPrinter = IFD.Zeroth + 337,
ExtraSamples = IFD.Zeroth + 338,
SampleFormat = IFD.Zeroth + 339,
SMinSampleValue = IFD.Zeroth + 340,
SMaxSampleValue = IFD.Zeroth + 341,
TransferRange = IFD.Zeroth + 342,
JPEGProc = IFD.Zeroth + 512,
JPEGInterchangeFormat = IFD.Zeroth + 513,
JPEGInterchangeFormatLength = IFD.Zeroth + 514,
JPEGRestartInterval = IFD.Zeroth + 515,
JPEGLosslessPredictors = IFD.Zeroth + 517,
JPEGPointTransforms = IFD.Zeroth + 518,
JPEGQTables = IFD.Zeroth + 519,
JPEGDCTables = IFD.Zeroth + 520,
JPEGACTables = IFD.Zeroth + 521,
YCbCrCoefficients = IFD.Zeroth + 529,
YCbCrSubSampling = IFD.Zeroth + 530,
YCbCrPositioning = IFD.Zeroth + 531,
ReferenceBlackWhite = IFD.Zeroth + 532,
Copyright = IFD.Zeroth + 33432,
// Pointers to other IFDs
EXIFIFDPointer = IFD.Zeroth + 34665,
GPSIFDPointer = IFD.Zeroth + 34853,
// Windows Tags
WindowsTitle = IFD.Zeroth + 0x9c9b,
WindowsComment = IFD.Zeroth + 0x9c9c,
WindowsAuthor = IFD.Zeroth + 0x9c9d,
WindowsKeywords = IFD.Zeroth + 0x9c9e,
WindowsSubject = IFD.Zeroth + 0x9c9f,
// Rating
Rating = IFD.Zeroth + 0x4746,
RatingPercent = IFD.Zeroth + 0x4749,
// Microsoft specifing padding and offset tags
ZerothIFDPadding = IFD.Zeroth + 0xea1c,
// ****************************
// EXIF Tags
// ****************************
ExifVersion = IFD.EXIF + 36864,
FlashpixVersion = IFD.EXIF + 40960,
ColorSpace = IFD.EXIF + 40961,
ComponentsConfiguration = IFD.EXIF + 37121,
CompressedBitsPerPixel = IFD.EXIF + 37122,
PixelXDimension = IFD.EXIF + 40962,
PixelYDimension = IFD.EXIF + 40963,
MakerNote = IFD.EXIF + 37500,
UserComment = IFD.EXIF + 37510,
RelatedSoundFile = IFD.EXIF + 40964,
DateTimeOriginal = IFD.EXIF + 36867,
DateTimeDigitized = IFD.EXIF + 36868,
SubSecTime = IFD.EXIF + 37520,
SubSecTimeOriginal = IFD.EXIF + 37521,
SubSecTimeDigitized = IFD.EXIF + 37522,
ExposureTime = IFD.EXIF + 33434,
FNumber = IFD.EXIF + 33437,
ExposureProgram = IFD.EXIF + 34850,
SpectralSensitivity = IFD.EXIF + 34852,
ISOSpeedRatings = IFD.EXIF + 34855,
OECF = IFD.EXIF + 34856,
ShutterSpeedValue = IFD.EXIF + 37377,
ApertureValue = IFD.EXIF + 37378,
BrightnessValue = IFD.EXIF + 37379,
ExposureBiasValue = IFD.EXIF + 37380,
MaxApertureValue = IFD.EXIF + 37381,
SubjectDistance = IFD.EXIF + 37382,
MeteringMode = IFD.EXIF + 37383,
LightSource = IFD.EXIF + 37384,
Flash = IFD.EXIF + 37385,
FocalLength = IFD.EXIF + 37386,
SubjectArea = IFD.EXIF + 37396,
FlashEnergy = IFD.EXIF + 41483,
SpatialFrequencyResponse = IFD.EXIF + 41484,
FocalPlaneXResolution = IFD.EXIF + 41486,
FocalPlaneYResolution = IFD.EXIF + 41487,
FocalPlaneResolutionUnit = IFD.EXIF + 41488,
SubjectLocation = IFD.EXIF + 41492,
ExposureIndex = IFD.EXIF + 41493,
SensingMethod = IFD.EXIF + 41495,
FileSource = IFD.EXIF + 41728,
SceneType = IFD.EXIF + 41729,
CFAPattern = IFD.EXIF + 41730,
CustomRendered = IFD.EXIF + 41985,
ExposureMode = IFD.EXIF + 41986,
WhiteBalance = IFD.EXIF + 41987,
DigitalZoomRatio = IFD.EXIF + 41988,
FocalLengthIn35mmFilm = IFD.EXIF + 41989,
SceneCaptureType = IFD.EXIF + 41990,
GainControl = IFD.EXIF + 41991,
Contrast = IFD.EXIF + 41992,
Saturation = IFD.EXIF + 41993,
Sharpness = IFD.EXIF + 41994,
DeviceSettingDescription = IFD.EXIF + 41995,
SubjectDistanceRange = IFD.EXIF + 41996,
ImageUniqueID = IFD.EXIF + 42016,
InteroperabilityIFDPointer = IFD.EXIF + 40965,
// Microsoft specifing padding and offset tags
ExifIFDPadding = IFD.EXIF + 0xea1c,
OffsetSchema = IFD.EXIF + 0xea1d,
// ****************************
// GPS Tags
// ****************************
GPSVersionID = IFD.GPS + 0,
GPSLatitudeRef = IFD.GPS + 1,
GPSLatitude = IFD.GPS + 2,
GPSLongitudeRef = IFD.GPS + 3,
GPSLongitude = IFD.GPS + 4,
GPSAltitudeRef = IFD.GPS + 5,
GPSAltitude = IFD.GPS + 6,
GPSTimeStamp = IFD.GPS + 7,
GPSSatellites = IFD.GPS + 8,
GPSStatus = IFD.GPS + 9,
GPSMeasureMode = IFD.GPS + 10,
GPSDOP = IFD.GPS + 11,
GPSSpeedRef = IFD.GPS + 12,
GPSSpeed = IFD.GPS + 13,
GPSTrackRef = IFD.GPS + 14,
GPSTrack = IFD.GPS + 15,
GPSImgDirectionRef = IFD.GPS + 16,
GPSImgDirection = IFD.GPS + 17,
GPSMapDatum = IFD.GPS + 18,
GPSDestLatitudeRef = IFD.GPS + 19,
GPSDestLatitude = IFD.GPS + 20,
GPSDestLongitudeRef = IFD.GPS + 21,
GPSDestLongitude = IFD.GPS + 22,
GPSDestBearingRef = IFD.GPS + 23,
GPSDestBearing = IFD.GPS + 24,
GPSDestDistanceRef = IFD.GPS + 25,
GPSDestDistance = IFD.GPS + 26,
GPSProcessingMethod = IFD.GPS + 27,
GPSAreaInformation = IFD.GPS + 28,
GPSDateStamp = IFD.GPS + 29,
GPSDifferential = IFD.GPS + 30,
// ****************************
// InterOp Tags
// ****************************
InteroperabilityIndex = IFD.Interop + 1,
InteroperabilityVersion = IFD.Interop + 2,
RelatedImageWidth = IFD.Interop + 0x1001,
RelatedImageHeight = IFD.Interop + 0x1002,
// ****************************
// First IFD TIFF Tags
// ****************************
ThumbnailImageWidth = IFD.First + 256,
ThumbnailImageLength = IFD.First + 257,
ThumbnailBitsPerSample = IFD.First + 258,
ThumbnailCompression = IFD.First + 259,
ThumbnailPhotometricInterpretation = IFD.First + 262,
ThumbnailOrientation = IFD.First + 274,
ThumbnailSamplesPerPixel = IFD.First + 277,
ThumbnailPlanarConfiguration = IFD.First + 284,
ThumbnailYCbCrSubSampling = IFD.First + 530,
ThumbnailYCbCrPositioning = IFD.First + 531,
ThumbnailXResolution = IFD.First + 282,
ThumbnailYResolution = IFD.First + 283,
ThumbnailResolutionUnit = IFD.First + 296,
ThumbnailStripOffsets = IFD.First + 273,
ThumbnailRowsPerStrip = IFD.First + 278,
ThumbnailStripByteCounts = IFD.First + 279,
ThumbnailJPEGInterchangeFormat = IFD.First + 513,
ThumbnailJPEGInterchangeFormatLength = IFD.First + 514,
ThumbnailTransferFunction = IFD.First + 301,
ThumbnailWhitePoint = IFD.First + 318,
ThumbnailPrimaryChromaticities = IFD.First + 319,
ThumbnailYCbCrCoefficients = IFD.First + 529,
ThumbnailReferenceBlackWhite = IFD.First + 532,
ThumbnailDateTime = IFD.First + 306,
ThumbnailImageDescription = IFD.First + 270,
ThumbnailMake = IFD.First + 271,
ThumbnailModel = IFD.First + 272,
ThumbnailSoftware = IFD.First + 305,
ThumbnailArtist = IFD.First + 315,
ThumbnailCopyright = IFD.First + 33432,
// ****************************
// JFIF Tags
// ****************************
/// <summary>
/// Represents the JFIF version.
/// </summary>
JFIFVersion = IFD.JFIF + 1,
/// <summary>
/// Represents units for X and Y densities.
/// </summary>
JFIFUnits = IFD.JFIF + 101,
/// <summary>
/// Horizontal pixel density.
/// </summary>
XDensity = IFD.JFIF + 102,
/// <summary>
/// Vertical pixel density
/// </summary>
YDensity = IFD.JFIF + 103,
/// <summary>
/// Thumbnail horizontal pixel count.
/// </summary>
JFIFXThumbnail = IFD.JFIF + 201,
/// <summary>
/// Thumbnail vertical pixel count.
/// </summary>
JFIFYThumbnail = IFD.JFIF + 202,
/// <summary>
/// JFIF JPEG thumbnail.
/// </summary>
JFIFThumbnail = IFD.JFIF + 203,
/// <summary>
/// Code which identifies the JFIF extension.
/// </summary>
JFXXExtensionCode = IFD.JFXX + 1,
/// <summary>
/// Thumbnail horizontal pixel count.
/// </summary>
JFXXXThumbnail = IFD.JFXX + 101,
/// <summary>
/// Thumbnail vertical pixel count.
/// </summary>
JFXXYThumbnail = IFD.JFXX + 102,
/// <summary>
/// The 256-Color RGB palette.
/// </summary>
JFXXPalette = IFD.JFXX + 201,
/// <summary>
/// JFIF thumbnail. The thumbnail will be either a JPEG,
/// a 256 color palette bitmap, or a 24-bit RGB bitmap.
/// </summary>
JFXXThumbnail = IFD.JFXX + 202,
}
}

View File

@@ -1,68 +0,0 @@
using System;
namespace Umbraco.Web.Media.Exif
{
internal static class ExifTagFactory
{
#region Static Methods
/// <summary>
/// Returns the ExifTag corresponding to the given tag id.
/// </summary>
public static ExifTag GetExifTag(IFD ifd, ushort tagid)
{
return (ExifTag)(ifd + tagid);
}
/// <summary>
/// Returns the tag id corresponding to the given ExifTag.
/// </summary>
public static ushort GetTagID(ExifTag exiftag)
{
IFD ifd = GetTagIFD(exiftag);
return (ushort)((int)exiftag - (int)ifd);
}
/// <summary>
/// Returns the IFD section containing the given tag.
/// </summary>
public static IFD GetTagIFD(ExifTag tag)
{
return (IFD)(((int)tag / 100000) * 100000);
}
/// <summary>
/// Returns the string representation for the given exif tag.
/// </summary>
public static string GetTagName(ExifTag tag)
{
string name = Enum.GetName(typeof(ExifTag), tag);
if (name == null)
return "Unknown";
else
return name;
}
/// <summary>
/// Returns the string representation for the given tag id.
/// </summary>
public static string GetTagName(IFD ifd, ushort tagid)
{
return GetTagName(GetExifTag(ifd, tagid));
}
/// <summary>
/// Returns the string representation for the given exif tag including
/// IFD section and tag id.
/// </summary>
public static string GetTagLongName(ExifTag tag)
{
string ifdname = Enum.GetName(typeof(IFD), GetTagIFD(tag));
string name = Enum.GetName(typeof(ExifTag), tag);
if (name == null)
name = "Unknown";
string tagidname = GetTagID(tag).ToString();
return ifdname + ": " + name + " (" + tagidname + ")";
}
#endregion
}
}

View File

@@ -1,18 +0,0 @@
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents the IFD section containing tags.
/// </summary>
internal enum IFD : int
{
Unknown = 0,
Zeroth = 100000,
EXIF = 200000,
GPS = 300000,
Interop = 400000,
First = 500000,
MakerNote = 600000,
JFIF = 700000,
JFXX = 800000,
}
}

View File

@@ -1,144 +0,0 @@
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Text;
using Umbraco.Web.Media.TypeDetector;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents the base class for image files.
/// </summary>
[TypeDescriptionProvider(typeof(ExifFileTypeDescriptionProvider))]
internal abstract class ImageFile
{
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="ImageFile"/> class.
/// </summary>
protected ImageFile ()
{
Format = ImageFileFormat.Unknown;
Properties = new ExifPropertyCollection (this);
Encoding = Encoding.Default;
}
#endregion
#region Properties
/// <summary>
/// Returns the format of the <see cref="ImageFile"/>.
/// </summary>
public ImageFileFormat Format { get; protected set; }
/// <summary>
/// Gets the collection of Exif properties contained in the <see cref="ImageFile"/>.
/// </summary>
public ExifPropertyCollection Properties { get; private set; }
/// <summary>
/// Gets or sets the embedded thumbnail image.
/// </summary>
public ImageFile Thumbnail { get; set; }
/// <summary>
/// Gets or sets the Exif property with the given key.
/// </summary>
/// <param name="key">The Exif tag associated with the Exif property.</param>
public ExifProperty this[ExifTag key] {
get { return Properties[key]; }
set { Properties[key] = value; }
}
/// <summary>
/// Gets the encoding used for text metadata when the source encoding is unknown.
/// </summary>
public Encoding Encoding { get; protected set; }
#endregion
#region Instance Methods
/// <summary>
/// Converts the <see cref="ImageFile"/> to a <see cref="System.Drawing.Image"/>.
/// </summary>
/// <returns>Returns a <see cref="System.Drawing.Image"/> containing image data.</returns>
public abstract Image ToImage ();
/// <summary>
/// Saves the <see cref="ImageFile"/> to the specified file.
/// </summary>
/// <param name="filename">A string that contains the name of the file.</param>
public virtual void Save (string filename)
{
using (FileStream stream = new FileStream (filename, FileMode.Create, FileAccess.Write, FileShare.None)) {
Save (stream);
}
}
/// <summary>
/// Saves the <see cref="ImageFile"/> to the specified stream.
/// </summary>
/// <param name="stream">A <see cref="Sytem.IO.Stream"/> to save image data to.</param>
public abstract void Save (Stream stream);
#endregion
#region Static Methods
/// <summary>
/// Creates an <see cref="ImageFile"/> from the specified file.
/// </summary>
/// <param name="filename">A string that contains the name of the file.</param>
/// <returns>The <see cref="ImageFile"/> created from the file.</returns>
public static ImageFile FromFile (string filename)
{
return FromFile(filename, Encoding.Default);
}
/// <summary>
/// Creates an <see cref="ImageFile"/> from the specified file.
/// </summary>
/// <param name="filename">A string that contains the name of the file.</param>
/// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param>
/// <returns>The <see cref="ImageFile"/> created from the file.</returns>
public static ImageFile FromFile(string filename, Encoding encoding)
{
using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return FromStream(stream, encoding);
}
}
/// <summary>
/// Creates an <see cref="ImageFile"/> from the specified data stream.
/// </summary>
/// <param name="stream">A <see cref="Sytem.IO.Stream"/> that contains image data.</param>
/// <returns>The <see cref="ImageFile"/> created from the file.</returns>
public static ImageFile FromStream(Stream stream)
{
return FromStream(stream, Encoding.Default);
}
/// <summary>
/// Creates an <see cref="ImageFile"/> from the specified data stream.
/// </summary>
/// <param name="stream">A <see cref="Sytem.IO.Stream"/> that contains image data.</param>
/// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param>
/// <returns>The <see cref="ImageFile"/> created from the file.</returns>
public static ImageFile FromStream(Stream stream, Encoding encoding)
{
// JPEG
if (JpegDetector.IsOfType(stream))
{
return new JPEGFile(stream, encoding);
}
// TIFF
if (TIFFDetector.IsOfType(stream))
{
return new TIFFFile(stream, encoding);
}
// SVG
if (SvgDetector.IsOfType(stream))
{
return new SvgFile(stream);
}
throw new NotValidImageFileException();
}
#endregion
}
}

View File

@@ -1,97 +0,0 @@
using System;
using System.Collections.Generic;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents an image file directory.
/// </summary>
internal class ImageFileDirectory
{
/// <summary>
/// The fields contained in this IFD.
/// </summary>
public List<ImageFileDirectoryEntry> Fields { get; private set; }
/// <summary>
/// Offset to the next IFD.
/// </summary>
public uint NextIFDOffset { get; private set; }
/// <summary>
/// Compressed image data.
/// </summary>
public List<TIFFStrip> Strips { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="ImageFileDirectory"/> class.
/// </summary>
public ImageFileDirectory()
{
Fields = new List<ImageFileDirectoryEntry>();
Strips = new List<TIFFStrip>();
}
/// <summary>
/// Returns a <see cref="ImageFileDirectory"/> initialized from the given byte data.
/// </summary>
/// <param name="data">The data.</param>
/// <param name="offset">The offset into <paramref name="data"/>.</param>
/// <param name="byteOrder">The byte order of <paramref name="data"/>.</param>
/// <returns>A <see cref="ImageFileDirectory"/> initialized from the given byte data.</returns>
public static ImageFileDirectory FromBytes(byte[] data, uint offset, BitConverterEx.ByteOrder byteOrder)
{
ImageFileDirectory ifd = new ImageFileDirectory();
BitConverterEx conv = new BitConverterEx(byteOrder, BitConverterEx.SystemByteOrder);
List<uint> stripOffsets = new List<uint>();
List<uint> stripLengths = new List<uint>();
// Count
ushort fieldcount = conv.ToUInt16(data, offset);
// Read fields
for (uint i = 0; i < fieldcount; i++)
{
uint fieldoffset = offset + 2 + 12 * i;
ImageFileDirectoryEntry field = ImageFileDirectoryEntry.FromBytes(data, fieldoffset, byteOrder);
ifd.Fields.Add(field);
// Read strip offsets
if (field.Tag == 273)
{
int baselen = field.Data.Length / (int)field.Count;
for (uint j = 0; j < field.Count; j++)
{
byte[] val = new byte[baselen];
Array.Copy(field.Data, j * baselen, val, 0, baselen);
uint stripOffset = (field.Type == 3 ? (uint)BitConverter.ToUInt16(val, 0) : BitConverter.ToUInt32(val, 0));
stripOffsets.Add(stripOffset);
}
}
// Read strip lengths
if (field.Tag == 279)
{
int baselen = field.Data.Length / (int)field.Count;
for (uint j = 0; j < field.Count; j++)
{
byte[] val = new byte[baselen];
Array.Copy(field.Data, j * baselen, val, 0, baselen);
uint stripLength = (field.Type == 3 ? (uint)BitConverter.ToUInt16(val, 0) : BitConverter.ToUInt32(val, 0));
stripLengths.Add(stripLength);
}
}
}
// Save strips
if (stripOffsets.Count != stripLengths.Count)
throw new NotValidTIFFileException();
for (int i = 0; i < stripOffsets.Count; i++)
ifd.Strips.Add(new TIFFStrip(data, stripOffsets[i], stripLengths[i]));
// Offset to next ifd
ifd.NextIFDOffset = conv.ToUInt32(data, offset + 2 + 12 * fieldcount);
return ifd;
}
}
}

View File

@@ -1,117 +0,0 @@
using System;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents an entry in the image file directory.
/// </summary>
internal struct ImageFileDirectoryEntry
{
/// <summary>
/// The tag that identifies the field.
/// </summary>
public ushort Tag;
/// <summary>
/// Field type identifier.
/// </summary>
public ushort Type;
/// <summary>
/// Count of Type.
/// </summary>
public uint Count;
/// <summary>
/// Field data.
/// </summary>
public byte[] Data;
/// <summary>
/// Initializes a new instance of the <see cref="ImageFileDirectoryEntry"/> struct.
/// </summary>
/// <param name="tag">The tag that identifies the field.</param>
/// <param name="type">Field type identifier.</param>
/// <param name="count">Count of Type.</param>
/// <param name="data">Field data.</param>
public ImageFileDirectoryEntry(ushort tag, ushort type, uint count, byte[] data)
{
Tag = tag;
Type = type;
Count = count;
Data = data;
}
/// <summary>
/// Returns a <see cref="ImageFileDirectoryEntry"/> initialized from the given byte data.
/// </summary>
/// <param name="data">The data.</param>
/// <param name="offset">The offset into <paramref name="data"/>.</param>
/// <param name="byteOrder">The byte order of <paramref name="data"/>.</param>
/// <returns>A <see cref="ImageFileDirectoryEntry"/> initialized from the given byte data.</returns>
public static ImageFileDirectoryEntry FromBytes(byte[] data, uint offset, BitConverterEx.ByteOrder byteOrder)
{
// Tag ID
ushort tag = BitConverterEx.ToUInt16(data, offset, byteOrder, BitConverterEx.SystemByteOrder);
// Tag Type
ushort type = BitConverterEx.ToUInt16(data, offset + 2, byteOrder, BitConverterEx.SystemByteOrder);
// Count of Type
uint count = BitConverterEx.ToUInt32(data, offset + 4, byteOrder, BitConverterEx.SystemByteOrder);
// Field value or offset to field data
byte[] value = new byte[4];
Array.Copy(data, offset + 8, value, 0, 4);
// Calculate the bytes we need to read
uint baselength = GetBaseLength(type);
uint totallength = count * baselength;
// If field value does not fit in 4 bytes
// the value field is an offset to the actual
// field value
if (totallength > 4)
{
uint dataoffset = BitConverterEx.ToUInt32(value, 0, byteOrder, BitConverterEx.SystemByteOrder);
value = new byte[totallength];
Array.Copy(data, dataoffset, value, 0, totallength);
}
// Reverse array order if byte orders are different
if (byteOrder != BitConverterEx.SystemByteOrder)
{
for (uint i = 0; i < count; i++)
{
byte[] val = new byte[baselength];
Array.Copy(value, i * baselength, val, 0, baselength);
Array.Reverse(val);
Array.Copy(val, 0, value, i * baselength, baselength);
}
}
return new ImageFileDirectoryEntry(tag, type, count, value);
}
/// <summary>
/// Gets the base byte length for the given type.
/// </summary>
/// <param name="type">Type identifier.</param>
private static uint GetBaseLength(ushort type)
{
if (type == 1 || type == 6) // BYTE and SBYTE
return 1;
else if (type == 2 || type == 7) // ASCII and UNDEFINED
return 1;
else if (type == 3 || type == 8) // SHORT and SSHORT
return 2;
else if (type == 4 || type == 9) // LONG and SLONG
return 4;
else if (type == 5 || type == 10) // RATIONAL (2xLONG) and SRATIONAL (2xSLONG)
return 8;
else if (type == 11) // FLOAT
return 4;
else if (type == 12) // DOUBLE
return 8;
throw new ArgumentException("Unknown type identifier.", "type");
}
}
}

View File

@@ -1,25 +0,0 @@
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents the format of the <see cref="ImageFile"/>.
/// </summary>
internal enum ImageFileFormat
{
/// <summary>
/// The file is not recognized.
/// </summary>
Unknown,
/// <summary>
/// The file is a JPEG/Exif or JPEG/JFIF file.
/// </summary>
JPEG,
/// <summary>
/// The file is a TIFF File.
/// </summary>
TIFF,
/// <summary>
/// The file is a SVG File.
/// </summary>
SVG,
}
}

View File

@@ -1,40 +0,0 @@
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents the units for the X and Y densities
/// for a JFIF file.
/// </summary>
internal enum JFIFDensityUnit : byte
{
/// <summary>
/// No units, XDensity and YDensity specify the pixel aspect ratio.
/// </summary>
None = 0,
/// <summary>
/// XDensity and YDensity are dots per inch.
/// </summary>
DotsPerInch = 1,
/// <summary>
/// XDensity and YDensity are dots per cm.
/// </summary>
DotsPerCm = 2,
}
/// <summary>
/// Represents the JFIF extension.
/// </summary>
internal enum JFIFExtension : byte
{
/// <summary>
/// Thumbnail coded using JPEG.
/// </summary>
ThumbnailJPEG = 0x10,
/// <summary>
/// Thumbnail stored using a 256-Color RGB palette.
/// </summary>
ThumbnailPaletteRGB = 0x11,
/// <summary>
/// Thumbnail stored using 3 bytes/pixel (24-bit) RGB values.
/// </summary>
Thumbnail24BitRGB = 0x13,
}
}

View File

@@ -1,67 +0,0 @@
using System;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents the JFIF version as a 16 bit unsigned integer. (EXIF Specification: SHORT)
/// </summary>
internal class JFIFVersion : ExifUShort
{
/// <summary>
/// Gets the major version.
/// </summary>
public byte Major { get { return (byte)(mValue >> 8); } }
/// <summary>
/// Gets the minor version.
/// </summary>
public byte Minor { get { return (byte)(mValue - (mValue >> 8) * 256); } }
public JFIFVersion(ExifTag tag, ushort value)
: base(tag, value)
{
;
}
public override string ToString()
{
return string.Format("{0}.{1:00}", Major, Minor);
}
}
/// <summary>
/// Represents a JFIF thumbnail. (EXIF Specification: BYTE)
/// </summary>
internal class JFIFThumbnailProperty : ExifProperty
{
protected JFIFThumbnail mValue;
protected override object _Value { get { return Value; } set { Value = (JFIFThumbnail)value; } }
public new JFIFThumbnail Value { get { return mValue; } set { mValue = value; } }
public override string ToString() { return mValue.Format.ToString(); }
public JFIFThumbnailProperty(ExifTag tag, JFIFThumbnail value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
if (mValue.Format == JFIFThumbnail.ImageFormat.BMP24Bit)
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, (uint)mValue.PixelData.Length, mValue.PixelData);
else if (mValue.Format == JFIFThumbnail.ImageFormat.BMPPalette)
{
byte[] data = new byte[mValue.Palette.Length + mValue.PixelData.Length];
Array.Copy(mValue.Palette, data, mValue.Palette.Length);
Array.Copy(mValue.PixelData, 0, data, mValue.Palette.Length, mValue.PixelData.Length);
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, (uint)data.Length, data);
}
else if (mValue.Format == JFIFThumbnail.ImageFormat.JPEG)
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, (uint)mValue.PixelData.Length, mValue.PixelData);
else
throw new InvalidOperationException("Unknown thumbnail type.");
}
}
}
}

View File

@@ -1,55 +0,0 @@
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents a JFIF thumbnail.
/// </summary>
internal class JFIFThumbnail
{
#region Properties
/// <summary>
/// Gets the 256 color RGB palette.
/// </summary>
public byte[] Palette { get; private set; }
/// <summary>
/// Gets raw image data.
/// </summary>
public byte[] PixelData { get; private set; }
/// <summary>
/// Gets the image format.
/// </summary>
public ImageFormat Format { get; private set; }
#endregion
#region Public Enums
public enum ImageFormat
{
JPEG,
BMPPalette,
BMP24Bit,
}
#endregion
#region Constructors
protected JFIFThumbnail()
{
Palette = new byte[0];
PixelData = new byte[0];
}
public JFIFThumbnail(ImageFormat format, byte[] data)
: this()
{
Format = format;
PixelData = data;
}
public JFIFThumbnail(byte[] palette, byte[] data)
: this()
{
Format = ImageFormat.BMPPalette;
Palette = palette;
PixelData = data;
}
#endregion
}
}

View File

@@ -1,99 +0,0 @@
using System;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// The exception that is thrown when the format of the image file
/// could not be understood.
/// </summary>
internal class NotValidImageFileException : Exception
{
public NotValidImageFileException()
: base("Not a valid image file.")
{
;
}
public NotValidImageFileException(string message)
: base(message)
{
;
}
}
/// <summary>
/// The exception that is thrown when the format of the JPEG file
/// could not be understood.
/// </summary>
internal class NotValidJPEGFileException : Exception
{
public NotValidJPEGFileException()
: base("Not a valid JPEG file.")
{
;
}
public NotValidJPEGFileException(string message)
: base(message)
{
;
}
}
/// <summary>
/// The exception that is thrown when the format of the TIFF file
/// could not be understood.
/// </summary>
internal class NotValidTIFFileException : Exception
{
public NotValidTIFFileException()
: base("Not a valid TIFF file.")
{
;
}
public NotValidTIFFileException(string message)
: base(message)
{
;
}
}
/// <summary>
/// The exception that is thrown when the format of the TIFF header
/// could not be understood.
/// </summary>
internal class NotValidTIFFHeader : Exception
{
public NotValidTIFFHeader()
: base("Not a valid TIFF header.")
{
;
}
public NotValidTIFFHeader(string message)
: base(message)
{
;
}
}
/// <summary>
/// The exception that is thrown when the length of a section exceeds 64 kB.
/// </summary>
internal class SectionExceeds64KBException : Exception
{
public SectionExceeds64KBException()
: base("Section length exceeds 64 kB.")
{
;
}
public SectionExceeds64KBException(string message)
: base(message)
{
;
}
}
}

View File

@@ -1,918 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents the binary view of a JPEG compressed file.
/// </summary>
internal class JPEGFile : ImageFile
{
#region Member Variables
private JPEGSection jfifApp0;
private JPEGSection jfxxApp0;
private JPEGSection exifApp1;
private uint makerNoteOffset;
private long exifIFDFieldOffset, gpsIFDFieldOffset, interopIFDFieldOffset, firstIFDFieldOffset;
private long thumbOffsetLocation, thumbSizeLocation;
private uint thumbOffsetValue, thumbSizeValue;
private bool makerNoteProcessed;
#endregion
#region Properties
/// <summary>
/// Gets or sets the byte-order of the Exif properties.
/// </summary>
public BitConverterEx.ByteOrder ByteOrder { get; set; }
/// <summary>
/// Gets or sets the sections contained in the <see cref="ImageFile"/>.
/// </summary>
public List<JPEGSection> Sections { get; private set; }
/// <summary>
/// Gets or sets non-standard trailing data following the End of Image (EOI) marker.
/// </summary>
public byte[] TrailingData { get; private set; }
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="ExifFile"/> class.
/// </summary>
/// <param name="stream">A <see cref="Sytem.IO.Stream"/> that contains image data.</param>
/// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param>
protected internal JPEGFile(Stream stream, Encoding encoding)
{
Format = ImageFileFormat.JPEG;
Sections = new List<JPEGSection>();
TrailingData = new byte[0];
Encoding = encoding;
stream.Seek(0, SeekOrigin.Begin);
// Read the Start of Image (SOI) marker. SOI marker is represented
// with two bytes: 0xFF, 0xD8.
byte[] markerbytes = new byte[2];
if (stream.Read(markerbytes, 0, 2) != 2 || markerbytes[0] != 0xFF || markerbytes[1] != 0xD8)
throw new NotValidJPEGFileException();
stream.Seek(0, SeekOrigin.Begin);
// Search and read sections until we reach the end of file.
while (stream.Position != stream.Length)
{
// Read the next section marker. Section markers are two bytes
// with values 0xFF, 0x?? where ?? must not be 0x00 or 0xFF.
if (stream.Read(markerbytes, 0, 2) != 2 || markerbytes[0] != 0xFF || markerbytes[1] == 0x00 || markerbytes[1] == 0xFF)
throw new NotValidJPEGFileException();
JPEGMarker marker = (JPEGMarker)markerbytes[1];
byte[] header = new byte[0];
// SOI, EOI and RST markers do not contain any header
if (marker != JPEGMarker.SOI && marker != JPEGMarker.EOI && !(marker >= JPEGMarker.RST0 && marker <= JPEGMarker.RST7))
{
// Length of the header including the length bytes.
// This value is a 16-bit unsigned integer
// in big endian byte-order.
byte[] lengthbytes = new byte[2];
if (stream.Read(lengthbytes, 0, 2) != 2)
throw new NotValidJPEGFileException();
long length = (long)BitConverterEx.BigEndian.ToUInt16(lengthbytes, 0);
// Read section header.
header = new byte[length - 2];
int bytestoread = header.Length;
while (bytestoread > 0)
{
int count = Math.Min(bytestoread, 4 * 1024);
int bytesread = stream.Read(header, header.Length - bytestoread, count);
if (bytesread == 0)
throw new NotValidJPEGFileException();
bytestoread -= bytesread;
}
}
// Start of Scan (SOS) sections and RST sections are immediately
// followed by entropy coded data. For that, we need to read until
// the next section marker once we reach a SOS or RST.
byte[] entropydata = new byte[0];
if (marker == JPEGMarker.SOS || (marker >= JPEGMarker.RST0 && marker <= JPEGMarker.RST7))
{
long position = stream.Position;
// Search for the next section marker
while (true)
{
// Search for an 0xFF indicating start of a marker
int nextbyte = 0;
do
{
nextbyte = stream.ReadByte();
if (nextbyte == -1)
throw new NotValidJPEGFileException();
} while ((byte)nextbyte != 0xFF);
// Skip filler bytes (0xFF)
do
{
nextbyte = stream.ReadByte();
if (nextbyte == -1)
throw new NotValidJPEGFileException();
} while ((byte)nextbyte == 0xFF);
// Looks like a section marker. The next byte must not be 0x00.
if ((byte)nextbyte != 0x00)
{
// We reached a section marker. Calculate the
// length of the entropy coded data.
stream.Seek(-2, SeekOrigin.Current);
long edlength = stream.Position - position;
stream.Seek(-edlength, SeekOrigin.Current);
// Read entropy coded data
entropydata = new byte[edlength];
int bytestoread = entropydata.Length;
while (bytestoread > 0)
{
int count = Math.Min(bytestoread, 4 * 1024);
int bytesread = stream.Read(entropydata, entropydata.Length - bytestoread, count);
if (bytesread == 0)
throw new NotValidJPEGFileException();
bytestoread -= bytesread;
}
break;
}
}
}
// Store section.
JPEGSection section = new JPEGSection(marker, header, entropydata);
Sections.Add(section);
// Some propriety formats store data past the EOI marker
if (marker == JPEGMarker.EOI)
{
int bytestoread = (int)(stream.Length - stream.Position);
TrailingData = new byte[bytestoread];
while (bytestoread > 0)
{
int count = (int)Math.Min(bytestoread, 4 * 1024);
int bytesread = stream.Read(TrailingData, TrailingData.Length - bytestoread, count);
if (bytesread == 0)
throw new NotValidJPEGFileException();
bytestoread -= bytesread;
}
}
}
// Read metadata sections
ReadJFIFAPP0();
ReadJFXXAPP0();
ReadExifAPP1();
// Process the maker note
makerNoteProcessed = false;
}
#endregion
#region Instance Methods
/// <summary>
/// Saves the JPEG/Exif image to the given stream.
/// </summary>
/// <param name="filename">The path to the JPEG/Exif file.</param>
/// <param name="preserveMakerNote">Determines whether the maker note offset of
/// the original file will be preserved.</param>
public void Save(Stream stream, bool preserveMakerNote)
{
WriteJFIFApp0();
WriteJFXXApp0();
WriteExifApp1(preserveMakerNote);
// Write sections
foreach (JPEGSection section in Sections)
{
// Section header (including length bytes and section marker)
// must not exceed 64 kB.
if (section.Header.Length + 2 + 2 > 64 * 1024)
throw new SectionExceeds64KBException();
// APP sections must have a header.
// Otherwise skip the entire section.
if (section.Marker >= JPEGMarker.APP0 && section.Marker <= JPEGMarker.APP15 && section.Header.Length == 0)
continue;
// Write section marker
stream.Write(new byte[] { 0xFF, (byte)section.Marker }, 0, 2);
// SOI, EOI and RST markers do not contain any header
if (section.Marker != JPEGMarker.SOI && section.Marker != JPEGMarker.EOI && !(section.Marker >= JPEGMarker.RST0 && section.Marker <= JPEGMarker.RST7))
{
// Header length including the length field itself
stream.Write(BitConverterEx.BigEndian.GetBytes((ushort)(section.Header.Length + 2)), 0, 2);
// Write section header
if (section.Header.Length != 0)
stream.Write(section.Header, 0, section.Header.Length);
}
// Write entropy coded data
if (section.EntropyData.Length != 0)
stream.Write(section.EntropyData, 0, section.EntropyData.Length);
}
// Write trailing data, if any
if (TrailingData.Length != 0)
stream.Write(TrailingData, 0, TrailingData.Length);
}
/// <summary>
/// Saves the JPEG/Exif image with the given filename.
/// </summary>
/// <param name="filename">The path to the JPEG/Exif file.</param>
/// <param name="preserveMakerNote">Determines whether the maker note offset of
/// the original file will be preserved.</param>
public void Save(string filename, bool preserveMakerNote)
{
using (FileStream stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None))
{
Save(stream, preserveMakerNote);
}
}
/// <summary>
/// Saves the JPEG/Exif image with the given filename.
/// </summary>
/// <param name="filename">The path to the JPEG/Exif file.</param>
public override void Save(string filename)
{
Save(filename, true);
}
/// <summary>
/// Saves the JPEG/Exif image to the given stream.
/// </summary>
/// <param name="filename">The path to the JPEG/Exif file.</param>
public override void Save(Stream stream)
{
Save(stream, true);
}
/// <summary>
/// Returns a System.Drawing.Image created with image data.
/// </summary>
public override Image ToImage()
{
MemoryStream stream = new MemoryStream();
Save(stream);
return Image.FromStream(stream);
}
#endregion
#region Private Helper Methods
/// <summary>
/// Reads the APP0 section containing JFIF metadata.
/// </summary>
private void ReadJFIFAPP0()
{
// Find the APP0 section containing JFIF metadata
jfifApp0 = Sections.Find(a => (a.Marker == JPEGMarker.APP0) &&
a.Header.Length >= 5 &&
(Encoding.ASCII.GetString(a.Header, 0, 5) == "JFIF\0"));
// If there is no APP0 section, return.
if (jfifApp0 == null)
return;
byte[] header = jfifApp0.Header;
BitConverterEx jfifConv = BitConverterEx.BigEndian;
// Version
ushort version = jfifConv.ToUInt16(header, 5);
Properties.Add(new JFIFVersion(ExifTag.JFIFVersion, version));
// Units
byte unit = header[7];
Properties.Add(new ExifEnumProperty<JFIFDensityUnit>(ExifTag.JFIFUnits, (JFIFDensityUnit)unit));
// X and Y densities
ushort xdensity = jfifConv.ToUInt16(header, 8);
Properties.Add(new ExifUShort(ExifTag.XDensity, xdensity));
ushort ydensity = jfifConv.ToUInt16(header, 10);
Properties.Add(new ExifUShort(ExifTag.YDensity, ydensity));
// Thumbnails pixel count
byte xthumbnail = header[12];
Properties.Add(new ExifByte(ExifTag.JFIFXThumbnail, xthumbnail));
byte ythumbnail = header[13];
Properties.Add(new ExifByte(ExifTag.JFIFYThumbnail, ythumbnail));
// Read JFIF thumbnail
int n = xthumbnail * ythumbnail;
byte[] jfifThumbnail = new byte[n];
Array.Copy(header, 14, jfifThumbnail, 0, n);
Properties.Add(new JFIFThumbnailProperty(ExifTag.JFIFThumbnail, new JFIFThumbnail(JFIFThumbnail.ImageFormat.JPEG, jfifThumbnail)));
}
/// <summary>
/// Replaces the contents of the APP0 section with the JFIF properties.
/// </summary>
private bool WriteJFIFApp0()
{
// Which IFD sections do we have?
List<ExifProperty> ifdjfef = new List<ExifProperty>();
foreach (ExifProperty prop in Properties)
{
if (prop.IFD == IFD.JFIF)
ifdjfef.Add(prop);
}
if (ifdjfef.Count == 0)
{
// Nothing to write
return false;
}
// Create a memory stream to write the APP0 section to
MemoryStream ms = new MemoryStream();
// JFIF identifer
ms.Write(Encoding.ASCII.GetBytes("JFIF\0"), 0, 5);
// Write tags
foreach (ExifProperty prop in ifdjfef)
{
ExifInterOperability interop = prop.Interoperability;
byte[] data = interop.Data;
if (BitConverterEx.SystemByteOrder != BitConverterEx.ByteOrder.BigEndian && interop.TypeID == 3)
Array.Reverse(data);
ms.Write(data, 0, data.Length);
}
ms.Close();
// Return APP0 header
jfifApp0.Header = ms.ToArray();
return true;
}
/// <summary>
/// Reads the APP0 section containing JFIF extension metadata.
/// </summary>
private void ReadJFXXAPP0()
{
// Find the APP0 section containing JFIF metadata
jfxxApp0 = Sections.Find(a => (a.Marker == JPEGMarker.APP0) &&
a.Header.Length >= 5 &&
(Encoding.ASCII.GetString(a.Header, 0, 5) == "JFXX\0"));
// If there is no APP0 section, return.
if (jfxxApp0 == null)
return;
byte[] header = jfxxApp0.Header;
// Version
JFIFExtension version = (JFIFExtension)header[5];
Properties.Add(new ExifEnumProperty<JFIFExtension>(ExifTag.JFXXExtensionCode, version));
// Read thumbnail
if (version == JFIFExtension.ThumbnailJPEG)
{
byte[] data = new byte[header.Length - 6];
Array.Copy(header, 6, data, 0, data.Length);
Properties.Add(new JFIFThumbnailProperty(ExifTag.JFXXThumbnail, new JFIFThumbnail(JFIFThumbnail.ImageFormat.JPEG, data)));
}
else if (version == JFIFExtension.Thumbnail24BitRGB)
{
// Thumbnails pixel count
byte xthumbnail = header[6];
Properties.Add(new ExifByte(ExifTag.JFXXXThumbnail, xthumbnail));
byte ythumbnail = header[7];
Properties.Add(new ExifByte(ExifTag.JFXXYThumbnail, ythumbnail));
byte[] data = new byte[3 * xthumbnail * ythumbnail];
Array.Copy(header, 8, data, 0, data.Length);
Properties.Add(new JFIFThumbnailProperty(ExifTag.JFXXThumbnail, new JFIFThumbnail(JFIFThumbnail.ImageFormat.BMP24Bit, data)));
}
else if (version == JFIFExtension.ThumbnailPaletteRGB)
{
// Thumbnails pixel count
byte xthumbnail = header[6];
Properties.Add(new ExifByte(ExifTag.JFXXXThumbnail, xthumbnail));
byte ythumbnail = header[7];
Properties.Add(new ExifByte(ExifTag.JFXXYThumbnail, ythumbnail));
byte[] palette = new byte[768];
Array.Copy(header, 8, palette, 0, palette.Length);
byte[] data = new byte[xthumbnail * ythumbnail];
Array.Copy(header, 8 + 768, data, 0, data.Length);
Properties.Add(new JFIFThumbnailProperty(ExifTag.JFXXThumbnail, new JFIFThumbnail(palette, data)));
}
}
/// <summary>
/// Replaces the contents of the APP0 section with the JFIF extension properties.
/// </summary>
private bool WriteJFXXApp0()
{
// Which IFD sections do we have?
List<ExifProperty> ifdjfef = new List<ExifProperty>();
foreach (ExifProperty prop in Properties)
{
if (prop.IFD == IFD.JFXX)
ifdjfef.Add(prop);
}
if (ifdjfef.Count == 0)
{
// Nothing to write
return false;
}
// Create a memory stream to write the APP0 section to
MemoryStream ms = new MemoryStream();
// JFIF identifer
ms.Write(Encoding.ASCII.GetBytes("JFXX\0"), 0, 5);
// Write tags
foreach (ExifProperty prop in ifdjfef)
{
ExifInterOperability interop = prop.Interoperability;
byte[] data = interop.Data;
if (BitConverterEx.SystemByteOrder != BitConverterEx.ByteOrder.BigEndian && interop.TypeID == 3)
Array.Reverse(data);
ms.Write(data, 0, data.Length);
}
ms.Close();
// Return APP0 header
jfxxApp0.Header = ms.ToArray();
return true;
}
/// <summary>
/// Reads the APP1 section containing Exif metadata.
/// </summary>
private void ReadExifAPP1()
{
// Find the APP1 section containing Exif metadata
exifApp1 = Sections.Find(a => (a.Marker == JPEGMarker.APP1) &&
a.Header.Length >= 6 &&
(Encoding.ASCII.GetString(a.Header, 0, 6) == "Exif\0\0"));
// If there is no APP1 section, add a new one after the last APP0 section (if any).
if (exifApp1 == null)
{
int insertionIndex = Sections.FindLastIndex(a => a.Marker == JPEGMarker.APP0);
if (insertionIndex == -1) insertionIndex = 0;
insertionIndex++;
exifApp1 = new JPEGSection(JPEGMarker.APP1);
Sections.Insert(insertionIndex, exifApp1);
if (BitConverterEx.SystemByteOrder == BitConverterEx.ByteOrder.LittleEndian)
ByteOrder = BitConverterEx.ByteOrder.LittleEndian;
else
ByteOrder = BitConverterEx.ByteOrder.BigEndian;
return;
}
byte[] header = exifApp1.Header;
SortedList<int, IFD> ifdqueue = new SortedList<int, IFD>();
makerNoteOffset = 0;
// TIFF header
int tiffoffset = 6;
if (header[tiffoffset] == 0x49 && header[tiffoffset + 1] == 0x49)
ByteOrder = BitConverterEx.ByteOrder.LittleEndian;
else if (header[tiffoffset] == 0x4D && header[tiffoffset + 1] == 0x4D)
ByteOrder = BitConverterEx.ByteOrder.BigEndian;
else
throw new NotValidExifFileException();
// TIFF header may have a different byte order
BitConverterEx.ByteOrder tiffByteOrder = ByteOrder;
if (BitConverterEx.LittleEndian.ToUInt16(header, tiffoffset + 2) == 42)
tiffByteOrder = BitConverterEx.ByteOrder.LittleEndian;
else if (BitConverterEx.BigEndian.ToUInt16(header, tiffoffset + 2) == 42)
tiffByteOrder = BitConverterEx.ByteOrder.BigEndian;
else
throw new NotValidExifFileException();
// Offset to 0th IFD
int ifd0offset = (int)BitConverterEx.ToUInt32(header, tiffoffset + 4, tiffByteOrder, BitConverterEx.SystemByteOrder);
ifdqueue.Add(ifd0offset, IFD.Zeroth);
BitConverterEx conv = new BitConverterEx(ByteOrder, BitConverterEx.SystemByteOrder);
int thumboffset = -1;
int thumblength = 0;
int thumbtype = -1;
// Read IFDs
while (ifdqueue.Count != 0)
{
int ifdoffset = tiffoffset + ifdqueue.Keys[0];
IFD currentifd = ifdqueue.Values[0];
ifdqueue.RemoveAt(0);
// Field count
ushort fieldcount = conv.ToUInt16(header, ifdoffset);
for (short i = 0; i < fieldcount; i++)
{
// Read field info
int fieldoffset = ifdoffset + 2 + 12 * i;
ushort tag = conv.ToUInt16(header, fieldoffset);
ushort type = conv.ToUInt16(header, fieldoffset + 2);
uint count = conv.ToUInt32(header, fieldoffset + 4);
byte[] value = new byte[4];
Array.Copy(header, fieldoffset + 8, value, 0, 4);
// Fields containing offsets to other IFDs
if (currentifd == IFD.Zeroth && tag == 0x8769)
{
int exififdpointer = (int)conv.ToUInt32(value, 0);
ifdqueue.Add(exififdpointer, IFD.EXIF);
}
else if (currentifd == IFD.Zeroth && tag == 0x8825)
{
int gpsifdpointer = (int)conv.ToUInt32(value, 0);
ifdqueue.Add(gpsifdpointer, IFD.GPS);
}
else if (currentifd == IFD.EXIF && tag == 0xa005)
{
int interopifdpointer = (int)conv.ToUInt32(value, 0);
ifdqueue.Add(interopifdpointer, IFD.Interop);
}
// Save the offset to maker note data
if (currentifd == IFD.EXIF && tag == 37500)
makerNoteOffset = conv.ToUInt32(value, 0);
// Calculate the bytes we need to read
uint baselength = 0;
if (type == 1 || type == 2 || type == 7)
baselength = 1;
else if (type == 3)
baselength = 2;
else if (type == 4 || type == 9)
baselength = 4;
else if (type == 5 || type == 10)
baselength = 8;
uint totallength = count * baselength;
// If field value does not fit in 4 bytes
// the value field is an offset to the actual
// field value
int fieldposition = 0;
if (totallength > 4)
{
fieldposition = tiffoffset + (int)conv.ToUInt32(value, 0);
value = new byte[totallength];
Array.Copy(header, fieldposition, value, 0, totallength);
}
// Compressed thumbnail data
if (currentifd == IFD.First && tag == 0x201)
{
thumbtype = 0;
thumboffset = (int)conv.ToUInt32(value, 0);
}
else if (currentifd == IFD.First && tag == 0x202)
thumblength = (int)conv.ToUInt32(value, 0);
// Uncompressed thumbnail data
if (currentifd == IFD.First && tag == 0x111)
{
thumbtype = 1;
// Offset to first strip
if (type == 3)
thumboffset = (int)conv.ToUInt16(value, 0);
else
thumboffset = (int)conv.ToUInt32(value, 0);
}
else if (currentifd == IFD.First && tag == 0x117)
{
thumblength = 0;
for (int j = 0; j < count; j++)
{
if (type == 3)
thumblength += (int)conv.ToUInt16(value, 0);
else
thumblength += (int)conv.ToUInt32(value, 0);
}
}
// Create the exif property from the interop data
ExifProperty prop = ExifPropertyFactory.Get(tag, type, count, value, ByteOrder, currentifd, Encoding);
Properties.Add(prop);
}
// 1st IFD pointer
int firstifdpointer = (int)conv.ToUInt32(header, ifdoffset + 2 + 12 * fieldcount);
if (firstifdpointer != 0)
ifdqueue.Add(firstifdpointer, IFD.First);
// Read thumbnail
if (thumboffset != -1 && thumblength != 0 && Thumbnail == null)
{
if (thumbtype == 0)
{
using (MemoryStream ts = new MemoryStream(header, tiffoffset + thumboffset, thumblength))
{
Thumbnail = ImageFile.FromStream(ts);
}
}
}
}
}
/// <summary>
/// Replaces the contents of the APP1 section with the Exif properties.
/// </summary>
private bool WriteExifApp1(bool preserveMakerNote)
{
// Zero out IFD field offsets. We will fill those as we write the IFD sections
exifIFDFieldOffset = 0;
gpsIFDFieldOffset = 0;
interopIFDFieldOffset = 0;
firstIFDFieldOffset = 0;
// We also do not know the location of the embedded thumbnail yet
thumbOffsetLocation = 0;
thumbOffsetValue = 0;
thumbSizeLocation = 0;
thumbSizeValue = 0;
// Write thumbnail tags if they are missing, remove otherwise
if (Thumbnail == null)
{
Properties.Remove(ExifTag.ThumbnailJPEGInterchangeFormat);
Properties.Remove(ExifTag.ThumbnailJPEGInterchangeFormatLength);
}
else
{
if (!Properties.ContainsKey(ExifTag.ThumbnailJPEGInterchangeFormat))
Properties.Add(new ExifUInt(ExifTag.ThumbnailJPEGInterchangeFormat, 0));
if (!Properties.ContainsKey(ExifTag.ThumbnailJPEGInterchangeFormatLength))
Properties.Add(new ExifUInt(ExifTag.ThumbnailJPEGInterchangeFormatLength, 0));
}
// Which IFD sections do we have?
Dictionary<ExifTag, ExifProperty> ifdzeroth = new Dictionary<ExifTag, ExifProperty>();
Dictionary<ExifTag, ExifProperty> ifdexif = new Dictionary<ExifTag, ExifProperty>();
Dictionary<ExifTag, ExifProperty> ifdgps = new Dictionary<ExifTag, ExifProperty>();
Dictionary<ExifTag, ExifProperty> ifdinterop = new Dictionary<ExifTag, ExifProperty>();
Dictionary<ExifTag, ExifProperty> ifdfirst = new Dictionary<ExifTag, ExifProperty>();
foreach (ExifProperty prop in Properties)
{
switch (prop.IFD)
{
case IFD.Zeroth:
ifdzeroth.Add(prop.Tag, prop);
break;
case IFD.EXIF:
ifdexif.Add(prop.Tag, prop);
break;
case IFD.GPS:
ifdgps.Add(prop.Tag, prop);
break;
case IFD.Interop:
ifdinterop.Add(prop.Tag, prop);
break;
case IFD.First:
ifdfirst.Add(prop.Tag, prop);
break;
}
}
// Add IFD pointers if they are missing
// We will write the pointer values later on
if (ifdexif.Count != 0 && !ifdzeroth.ContainsKey(ExifTag.EXIFIFDPointer))
ifdzeroth.Add(ExifTag.EXIFIFDPointer, new ExifUInt(ExifTag.EXIFIFDPointer, 0));
if (ifdgps.Count != 0 && !ifdzeroth.ContainsKey(ExifTag.GPSIFDPointer))
ifdzeroth.Add(ExifTag.GPSIFDPointer, new ExifUInt(ExifTag.GPSIFDPointer, 0));
if (ifdinterop.Count != 0 && !ifdexif.ContainsKey(ExifTag.InteroperabilityIFDPointer))
ifdexif.Add(ExifTag.InteroperabilityIFDPointer, new ExifUInt(ExifTag.InteroperabilityIFDPointer, 0));
// Remove IFD pointers if IFD sections are missing
if (ifdexif.Count == 0 && ifdzeroth.ContainsKey(ExifTag.EXIFIFDPointer))
ifdzeroth.Remove(ExifTag.EXIFIFDPointer);
if (ifdgps.Count == 0 && ifdzeroth.ContainsKey(ExifTag.GPSIFDPointer))
ifdzeroth.Remove(ExifTag.GPSIFDPointer);
if (ifdinterop.Count == 0 && ifdexif.ContainsKey(ExifTag.InteroperabilityIFDPointer))
ifdexif.Remove(ExifTag.InteroperabilityIFDPointer);
if (ifdzeroth.Count == 0 && ifdgps.Count == 0 && ifdinterop.Count == 0 && ifdfirst.Count == 0 && Thumbnail == null)
{
// Nothing to write
return false;
}
// We will need these bitconverter to write byte-ordered data
BitConverterEx bceExif = new BitConverterEx(BitConverterEx.SystemByteOrder, ByteOrder);
// Create a memory stream to write the APP1 section to
MemoryStream ms = new MemoryStream();
// Exif identifer
ms.Write(Encoding.ASCII.GetBytes("Exif\0\0"), 0, 6);
// TIFF header
// Byte order
long tiffoffset = ms.Position;
ms.Write((ByteOrder == BitConverterEx.ByteOrder.LittleEndian ? new byte[] { 0x49, 0x49 } : new byte[] { 0x4D, 0x4D }), 0, 2);
// TIFF ID
ms.Write(bceExif.GetBytes((ushort)42), 0, 2);
// Offset to 0th IFD
ms.Write(bceExif.GetBytes((uint)8), 0, 4);
// Write IFDs
WriteIFD(ms, ifdzeroth, IFD.Zeroth, tiffoffset, preserveMakerNote);
uint exififdrelativeoffset = (uint)(ms.Position - tiffoffset);
WriteIFD(ms, ifdexif, IFD.EXIF, tiffoffset, preserveMakerNote);
uint gpsifdrelativeoffset = (uint)(ms.Position - tiffoffset);
WriteIFD(ms, ifdgps, IFD.GPS, tiffoffset, preserveMakerNote);
uint interopifdrelativeoffset = (uint)(ms.Position - tiffoffset);
WriteIFD(ms, ifdinterop, IFD.Interop, tiffoffset, preserveMakerNote);
uint firstifdrelativeoffset = (uint)(ms.Position - tiffoffset);
WriteIFD(ms, ifdfirst, IFD.First, tiffoffset, preserveMakerNote);
// Now that we now the location of IFDs we can go back and write IFD offsets
if (exifIFDFieldOffset != 0)
{
ms.Seek(exifIFDFieldOffset, SeekOrigin.Begin);
ms.Write(bceExif.GetBytes(exififdrelativeoffset), 0, 4);
}
if (gpsIFDFieldOffset != 0)
{
ms.Seek(gpsIFDFieldOffset, SeekOrigin.Begin);
ms.Write(bceExif.GetBytes(gpsifdrelativeoffset), 0, 4);
}
if (interopIFDFieldOffset != 0)
{
ms.Seek(interopIFDFieldOffset, SeekOrigin.Begin);
ms.Write(bceExif.GetBytes(interopifdrelativeoffset), 0, 4);
}
if (firstIFDFieldOffset != 0)
{
ms.Seek(firstIFDFieldOffset, SeekOrigin.Begin);
ms.Write(bceExif.GetBytes(firstifdrelativeoffset), 0, 4);
}
// We can write thumbnail location now
if (thumbOffsetLocation != 0)
{
ms.Seek(thumbOffsetLocation, SeekOrigin.Begin);
ms.Write(bceExif.GetBytes(thumbOffsetValue), 0, 4);
}
if (thumbSizeLocation != 0)
{
ms.Seek(thumbSizeLocation, SeekOrigin.Begin);
ms.Write(bceExif.GetBytes(thumbSizeValue), 0, 4);
}
ms.Close();
// Return APP1 header
exifApp1.Header = ms.ToArray();
return true;
}
private void WriteIFD(MemoryStream stream, Dictionary<ExifTag, ExifProperty> ifd, IFD ifdtype, long tiffoffset, bool preserveMakerNote)
{
BitConverterEx conv = new BitConverterEx(BitConverterEx.SystemByteOrder, ByteOrder);
// Create a queue of fields to write
Queue<ExifProperty> fieldqueue = new Queue<ExifProperty>();
foreach (ExifProperty prop in ifd.Values)
if (prop.Tag != ExifTag.MakerNote)
fieldqueue.Enqueue(prop);
// Push the maker note data to the end
if (ifd.ContainsKey(ExifTag.MakerNote))
fieldqueue.Enqueue(ifd[ExifTag.MakerNote]);
// Offset to start of field data from start of TIFF header
uint dataoffset = (uint)(2 + ifd.Count * 12 + 4 + stream.Position - tiffoffset);
uint currentdataoffset = dataoffset;
long absolutedataoffset = stream.Position + (2 + ifd.Count * 12 + 4);
bool makernotewritten = false;
// Field count
stream.Write(conv.GetBytes((ushort)ifd.Count), 0, 2);
// Fields
while (fieldqueue.Count != 0)
{
ExifProperty field = fieldqueue.Dequeue();
ExifInterOperability interop = field.Interoperability;
uint fillerbytecount = 0;
// Try to preserve the makernote data offset
if (!makernotewritten &&
!makerNoteProcessed &&
makerNoteOffset != 0 &&
ifdtype == IFD.EXIF &&
field.Tag != ExifTag.MakerNote &&
interop.Data.Length > 4 &&
currentdataoffset + interop.Data.Length > makerNoteOffset &&
ifd.ContainsKey(ExifTag.MakerNote))
{
// Delay writing this field until we write makernote data
fieldqueue.Enqueue(field);
continue;
}
else if (field.Tag == ExifTag.MakerNote)
{
makernotewritten = true;
// We may need to write filler bytes to preserve maker note offset
if (preserveMakerNote && !makerNoteProcessed && (makerNoteOffset > currentdataoffset))
fillerbytecount = makerNoteOffset - currentdataoffset;
else
fillerbytecount = 0;
}
// Tag
stream.Write(conv.GetBytes(interop.TagID), 0, 2);
// Type
stream.Write(conv.GetBytes(interop.TypeID), 0, 2);
// Count
stream.Write(conv.GetBytes(interop.Count), 0, 4);
// Field data
byte[] data = interop.Data;
if (ByteOrder != BitConverterEx.SystemByteOrder &&
(interop.TypeID == 3 || interop.TypeID == 4 || interop.TypeID == 9 ||
interop.TypeID == 5 || interop.TypeID == 10))
{
int vlen = 4;
if (interop.TypeID == 3) vlen = 2;
int n = data.Length / vlen;
for (int i = 0; i < n; i++)
Array.Reverse(data, i * vlen, vlen);
}
// Fields containing offsets to other IFDs
// Just store their offets, we will write the values later on when we know the lengths of IFDs
if (ifdtype == IFD.Zeroth && interop.TagID == 0x8769)
exifIFDFieldOffset = stream.Position;
else if (ifdtype == IFD.Zeroth && interop.TagID == 0x8825)
gpsIFDFieldOffset = stream.Position;
else if (ifdtype == IFD.EXIF && interop.TagID == 0xa005)
interopIFDFieldOffset = stream.Position;
else if (ifdtype == IFD.First && interop.TagID == 0x201)
thumbOffsetLocation = stream.Position;
else if (ifdtype == IFD.First && interop.TagID == 0x202)
thumbSizeLocation = stream.Position;
// Write 4 byte field value or field data
if (data.Length <= 4)
{
stream.Write(data, 0, data.Length);
for (int i = data.Length; i < 4; i++)
stream.WriteByte(0);
}
else
{
// Pointer to data area relative to TIFF header
stream.Write(conv.GetBytes(currentdataoffset + fillerbytecount), 0, 4);
// Actual data
long currentoffset = stream.Position;
stream.Seek(absolutedataoffset, SeekOrigin.Begin);
// Write filler bytes
for (int i = 0; i < fillerbytecount; i++)
stream.WriteByte(0xFF);
stream.Write(data, 0, data.Length);
stream.Seek(currentoffset, SeekOrigin.Begin);
// Increment pointers
currentdataoffset += fillerbytecount + (uint)data.Length;
absolutedataoffset += fillerbytecount + data.Length;
}
}
// Offset to 1st IFD
// We will write zeros for now. This will be filled after we write all IFDs
if (ifdtype == IFD.Zeroth)
firstIFDFieldOffset = stream.Position;
stream.Write(new byte[] { 0, 0, 0, 0 }, 0, 4);
// Seek to end of IFD
stream.Seek(absolutedataoffset, SeekOrigin.Begin);
// Write thumbnail data
if (ifdtype == IFD.First)
{
if (Thumbnail != null)
{
MemoryStream ts = new MemoryStream();
Thumbnail.Save(ts);
ts.Close();
byte[] thumb = ts.ToArray();
thumbOffsetValue = (uint)(stream.Position - tiffoffset);
thumbSizeValue = (uint)thumb.Length;
stream.Write(thumb, 0, thumb.Length);
ts.Dispose();
}
else
{
thumbOffsetValue = 0;
thumbSizeValue = 0;
}
}
}
#endregion
}
}

View File

@@ -1,85 +0,0 @@
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents a JPEG marker byte.
/// </summary>
internal enum JPEGMarker : byte
{
// Start Of Frame markers, non-differential, Huffman coding
SOF0 = 0xc0,
SOF1 = 0xc1,
SOF2 = 0xc2,
SOF3 = 0xc3,
// Start Of Frame markers, differential, Huffman coding
SOF5 = 0xc5,
SOF6 = 0xc6,
SOF7 = 0xc7,
// Start Of Frame markers, non-differential, arithmetic coding
JPG = 0xc8,
SOF9 = 0xc9,
SOF10 = 0xca,
SOF11 = 0xcb,
// Start Of Frame markers, differential, arithmetic coding
SOF13 = 0xcd,
SOF14 = 0xce,
SOF15 = 0xcf,
// Huffman table specification
DHT = 0xc4,
// Arithmetic coding conditioning specification
DAC = 0xcc,
// Restart interval termination
RST0 = 0xd0,
RST1 = 0xd1,
RST2 = 0xd2,
RST3 = 0xd3,
RST4 = 0xd4,
RST5 = 0xd5,
RST6 = 0xd6,
RST7 = 0xd7,
// Other markers
SOI = 0xd8,
EOI = 0xd9,
SOS = 0xda,
DQT = 0xdb,
DNL = 0xdc,
DRI = 0xdd,
DHP = 0xde,
EXP = 0xdf,
// application segments
APP0 = 0xe0,
APP1 = 0xe1,
APP2 = 0xe2,
APP3 = 0xe3,
APP4 = 0xe4,
APP5 = 0xe5,
APP6 = 0xe6,
APP7 = 0xe7,
APP8 = 0xe8,
APP9 = 0xe9,
APP10 = 0xea,
APP11 = 0xeb,
APP12 = 0xec,
APP13 = 0xed,
APP14 = 0xee,
APP15 = 0xef,
// JPEG extensions
JPG0 = 0xf0,
JPG1 = 0xf1,
JPG2 = 0xf2,
JPG3 = 0xf3,
JPG4 = 0xf4,
JPG5 = 0xf5,
JPG6 = 0xf6,
JPG7 = 0xf7,
JPG8 = 0xf8,
JPG9 = 0xf9,
JPG10 = 0xfa,
JPG11 = 0xfb,
JP1G2 = 0xfc,
JPG13 = 0xfd,
// Comment
COM = 0xfe,
// Temporary
TEM = 0x01,
}
}

View File

@@ -1,63 +0,0 @@
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents the memory view of a JPEG section.
/// A JPEG section is the data between markers of the JPEG file.
/// </summary>
internal class JPEGSection
{
#region Properties
/// <summary>
/// The marker byte representing the section.
/// </summary>
public JPEGMarker Marker { get; private set; }
/// <summary>
/// Section header as a byte array. This is different from the header
/// definition in JPEG specification in that it does not include the
/// two byte section length.
/// </summary>
public byte[] Header { get; set; }
/// <summary>
/// For the SOS and RST markers, this contains the entropy coded data.
/// </summary>
public byte[] EntropyData { get; set; }
#endregion
#region Constructors
/// <summary>
/// Constructs a JPEGSection represented by the marker byte and containing
/// the given data.
/// </summary>
/// <param name="marker">The marker byte representing the section.</param>
/// <param name="data">Section data.</param>
/// <param name="entropydata">Entropy coded data.</param>
public JPEGSection(JPEGMarker marker, byte[] data, byte[] entropydata)
{
Marker = marker;
Header = data;
EntropyData = entropydata;
}
/// <summary>
/// Constructs a JPEGSection represented by the marker byte.
/// </summary>
/// <param name="marker">The marker byte representing the section.</param>
public JPEGSection(JPEGMarker marker)
: this(marker, new byte[0], new byte[0])
{
;
}
#endregion
#region Instance Methods
/// <summary>
/// Returns a string representation of the current section.
/// </summary>
/// <returns>A System.String that represents the current section.</returns>
public override string ToString()
{
return string.Format("{0} => Header: {1} bytes, Entropy Data: {2} bytes", Marker, Header.Length, EntropyData.Length);
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,37 +0,0 @@
using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace Umbraco.Web.Media.Exif
{
internal class SvgFile : ImageFile
{
public SvgFile(Stream fileStream)
{
fileStream.Position = 0;
var document = XDocument.Load(fileStream); //if it throws an exception the ugly try catch in MediaFileSystem will catch it
var width = document.Root?.Attributes().Where(x => x.Name == "width").Select(x => x.Value).FirstOrDefault();
var height = document.Root?.Attributes().Where(x => x.Name == "height").Select(x => x.Value).FirstOrDefault();
Properties.Add(new ExifSInt(ExifTag.PixelYDimension,
height == null ? Core.Constants.Conventions.Media.DefaultSize : int.Parse(height)));
Properties.Add(new ExifSInt(ExifTag.PixelXDimension,
width == null ? Core.Constants.Conventions.Media.DefaultSize : int.Parse(width)));
Format = ImageFileFormat.SVG;
}
public override void Save(Stream stream)
{
}
public override Image ToImage()
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,177 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents the binary view of a TIFF file.
/// </summary>
internal class TIFFFile : ImageFile
{
#region Properties
/// <summary>
/// Gets the TIFF header.
/// </summary>
public TIFFHeader TIFFHeader { get; private set; }
/// <summary>
/// Gets the image file directories.
/// </summary>
public List<ImageFileDirectory> IFDs { get; private set; }
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="JPEGFile"/> class from the
/// specified data stream.
/// </summary>
/// <param name="stream">A <see cref="Sytem.IO.Stream"/> that contains image data.</param>
/// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param>
protected internal TIFFFile(Stream stream, System.Text.Encoding encoding)
{
Format = ImageFileFormat.TIFF;
IFDs = new List<ImageFileDirectory>();
Encoding = encoding;
// Read the entire stream
byte[] data = Utility.GetStreamBytes(stream);
// Read the TIFF header
TIFFHeader = TIFFHeader.FromBytes(data, 0);
uint nextIFDOffset = TIFFHeader.IFDOffset;
if (nextIFDOffset == 0)
throw new NotValidTIFFileException("The first IFD offset is zero.");
// Read IFDs in order
while (nextIFDOffset != 0)
{
ImageFileDirectory ifd = ImageFileDirectory.FromBytes(data, nextIFDOffset, TIFFHeader.ByteOrder);
nextIFDOffset = ifd.NextIFDOffset;
IFDs.Add(ifd);
}
// Process IFDs
// TODO: Add support for multiple frames
foreach (ImageFileDirectoryEntry field in IFDs[0].Fields)
{
Properties.Add(ExifPropertyFactory.Get(field.Tag, field.Type, field.Count, field.Data, BitConverterEx.SystemByteOrder, IFD.Zeroth, Encoding));
}
}
#endregion
#region Instance Methods
/// <summary>
/// Saves the <see cref="ImageFile"/> to the given stream.
/// </summary>
/// <param name="stream">The data stream used to save the image.</param>
public override void Save(Stream stream)
{
BitConverterEx conv = BitConverterEx.SystemEndian;
// Write TIFF header
uint ifdoffset = 8;
// Byte order
stream.Write((BitConverterEx.SystemByteOrder == BitConverterEx.ByteOrder.LittleEndian ? new byte[] { 0x49, 0x49 } : new byte[] { 0x4D, 0x4D }), 0, 2);
// TIFF ID
stream.Write(conv.GetBytes((ushort)42), 0, 2);
// Offset to 0th IFD, will be corrected below
stream.Write(conv.GetBytes(ifdoffset), 0, 4);
// Write IFD sections
for (int i = 0; i < IFDs.Count; i++)
{
ImageFileDirectory ifd = IFDs[i];
// Save the location of IFD offset
long ifdLocation = stream.Position - 4;
// Write strips first
byte[] stripOffsets = new byte[4 * ifd.Strips.Count];
byte[] stripLengths = new byte[4 * ifd.Strips.Count];
uint stripOffset = ifdoffset;
for (int j = 0; j < ifd.Strips.Count; j++)
{
byte[] stripData = ifd.Strips[j].Data;
byte[] oBytes = BitConverter.GetBytes(stripOffset);
byte[] lBytes = BitConverter.GetBytes((uint)stripData.Length);
Array.Copy(oBytes, 0, stripOffsets, 4 * j, 4);
Array.Copy(lBytes, 0, stripLengths, 4 * j, 4);
stream.Write(stripData, 0, stripData.Length);
stripOffset += (uint)stripData.Length;
}
// Remove old strip tags
for (int j = ifd.Fields.Count - 1; j > 0; j--)
{
ushort tag = ifd.Fields[j].Tag;
if (tag == 273 || tag == 279)
ifd.Fields.RemoveAt(j);
}
// Write new strip tags
ifd.Fields.Add(new ImageFileDirectoryEntry(273, 4, (uint)ifd.Strips.Count, stripOffsets));
ifd.Fields.Add(new ImageFileDirectoryEntry(279, 4, (uint)ifd.Strips.Count, stripLengths));
// Write fields after strips
ifdoffset = stripOffset;
// Correct IFD offset
long currentLocation = stream.Position;
stream.Seek(ifdLocation, SeekOrigin.Begin);
stream.Write(conv.GetBytes(ifdoffset), 0, 4);
stream.Seek(currentLocation, SeekOrigin.Begin);
// Offset to field data
uint dataOffset = ifdoffset + 2 + (uint)ifd.Fields.Count * 12 + 4;
// Field count
stream.Write(conv.GetBytes((ushort)ifd.Fields.Count), 0, 2);
// Fields
foreach (ImageFileDirectoryEntry field in ifd.Fields)
{
// Tag
stream.Write(conv.GetBytes(field.Tag), 0, 2);
// Type
stream.Write(conv.GetBytes(field.Type), 0, 2);
// Count
stream.Write(conv.GetBytes(field.Count), 0, 4);
// Field data
byte[] data = field.Data;
if (data.Length <= 4)
{
stream.Write(data, 0, data.Length);
for (int j = data.Length; j < 4; j++)
stream.WriteByte(0);
}
else
{
stream.Write(conv.GetBytes(dataOffset), 0, 4);
long currentOffset = stream.Position;
stream.Seek(dataOffset, SeekOrigin.Begin);
stream.Write(data, 0, data.Length);
dataOffset += (uint)data.Length;
stream.Seek(currentOffset, SeekOrigin.Begin);
}
}
// Offset to next IFD
ifdoffset = dataOffset;
stream.Write(conv.GetBytes(i == IFDs.Count - 1 ? 0 : ifdoffset), 0, 4);
}
}
/// <summary>
/// Converts the <see cref="ImageFile"/> to a <see cref="System.Drawing.Image"/>.
/// </summary>
/// <returns>Returns a <see cref="System.Drawing.Image"/> containing image data.</returns>
public override Image ToImage()
{
MemoryStream stream = new MemoryStream();
Save(stream);
return Image.FromStream(stream);
}
#endregion
}
}

View File

@@ -1,78 +0,0 @@
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents a TIFF Header.
/// </summary>
internal struct TIFFHeader
{
/// <summary>
/// The byte order of the image file.
/// </summary>
public BitConverterEx.ByteOrder ByteOrder;
/// <summary>
/// TIFF ID. This value should always be 42.
/// </summary>
public byte ID;
/// <summary>
/// The offset to the first IFD section from the
/// start of the TIFF header.
/// </summary>
public uint IFDOffset;
/// <summary>
/// The byte order of the TIFF header itself.
/// </summary>
public BitConverterEx.ByteOrder TIFFHeaderByteOrder;
/// <summary>
/// Initializes a new instance of the <see cref="TIFFHeader"/> struct.
/// </summary>
/// <param name="byteOrder">The byte order.</param>
/// <param name="id">The TIFF ID. This value should always be 42.</param>
/// <param name="ifdOffset">The offset to the first IFD section from the
/// start of the TIFF header.</param>
/// <param name="headerByteOrder">The byte order of the TIFF header itself.</param>
public TIFFHeader(BitConverterEx.ByteOrder byteOrder, byte id, uint ifdOffset, BitConverterEx.ByteOrder headerByteOrder)
{
if (id != 42)
throw new NotValidTIFFHeader();
ByteOrder = byteOrder;
ID = id;
IFDOffset = ifdOffset;
TIFFHeaderByteOrder = headerByteOrder;
}
/// <summary>
/// Returns a <see cref="TIFFHeader"/> initialized from the given byte data.
/// </summary>
/// <param name="data">The data.</param>
/// <param name="offset">The offset into <paramref name="data"/>.</param>
/// <returns>A <see cref="TIFFHeader"/> initialized from the given byte data.</returns>
public static TIFFHeader FromBytes(byte[] data, int offset)
{
TIFFHeader header = new TIFFHeader();
// TIFF header
if (data[offset] == 0x49 && data[offset + 1] == 0x49)
header.ByteOrder = BitConverterEx.ByteOrder.LittleEndian;
else if (data[offset] == 0x4D && data[offset + 1] == 0x4D)
header.ByteOrder = BitConverterEx.ByteOrder.BigEndian;
else
throw new NotValidTIFFHeader();
// TIFF header may have a different byte order
if (BitConverterEx.LittleEndian.ToUInt16(data, offset + 2) == 42)
header.TIFFHeaderByteOrder = BitConverterEx.ByteOrder.LittleEndian;
else if (BitConverterEx.BigEndian.ToUInt16(data, offset + 2) == 42)
header.TIFFHeaderByteOrder = BitConverterEx.ByteOrder.BigEndian;
else
throw new NotValidTIFFHeader();
header.ID = 42;
// IFD offset
header.IFDOffset = BitConverterEx.ToUInt32(data, offset + 4, header.TIFFHeaderByteOrder, BitConverterEx.SystemByteOrder);
return header;
}
}
}

View File

@@ -1,27 +0,0 @@
using System;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Represents a strip of compressed image data in a TIFF file.
/// </summary>
internal class TIFFStrip
{
/// <summary>
/// Compressed image data contained in this strip.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="TIFFStrip"/> class.
/// </summary>
/// <param name="data">The byte array to copy strip from.</param>
/// <param name="offset">The offset to the beginning of strip.</param>
/// <param name="length">The length of strip.</param>
public TIFFStrip(byte[] data, uint offset, uint length)
{
Data = new byte[length];
Array.Copy(data, offset, Data, 0, length);
}
}
}

View File

@@ -1,30 +0,0 @@
using System.IO;
namespace Umbraco.Web.Media.Exif
{
/// <summary>
/// Contains utility functions.
/// </summary>
internal class Utility
{
/// <summary>
/// Reads the entire stream and returns its contents as a byte array.
/// </summary>
/// <param name="stream">The <see cref="System.IO.Stream"/> to read.</param>
/// <returns>Contents of the <paramref name="stream"/> as a byte array.</returns>
public static byte[] GetStreamBytes(Stream stream)
{
using (MemoryStream mem = new MemoryStream())
{
stream.Seek(0, SeekOrigin.Begin);
byte[] b = new byte[32768];
int r;
while ((r = stream.Read(b, 0, b.Length)) > 0)
mem.Write(b, 0, r);
return mem.ToArray();
}
}
}
}

View File

@@ -1,68 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Media;
using Umbraco.Core.Models;
using Umbraco.Web.Composing;
using Umbraco.Web.Media.Exif;
namespace Umbraco.Web.Media
{
public static class ImageHelper
{
/// <summary>
/// Gets the dimensions of an image.
/// </summary>
/// <param name="stream">A stream containing the image bytes.</param>
/// <returns>The dimension of the image.</returns>
/// <remarks>First try with EXIF as it is faster and does not load the entire image
/// in memory. Fallback to GDI which means loading the image in memory and thus
/// use potentially large amounts of memory.</remarks>
public static Size GetDimensions(Stream stream)
{
try
{
//Try to load with exif
var jpgInfo = ImageFile.FromStream(stream);
if (jpgInfo.Format != ImageFileFormat.Unknown
&& jpgInfo.Properties.ContainsKey(ExifTag.PixelYDimension)
&& jpgInfo.Properties.ContainsKey(ExifTag.PixelXDimension))
{
var height = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelYDimension].Value);
var width = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelXDimension].Value);
if (height > 0 && width > 0)
{
return new Size(width, height);
}
}
//we have no choice but to try to read in via GDI
using (var image = Image.FromStream(stream))
{
var fileWidth = image.Width;
var fileHeight = image.Height;
return new Size(fileWidth, fileHeight);
}
}
catch (Exception)
{
//We will just swallow, just means we can't read exif data, we don't want to log an error either
return new Size(Constants.Conventions.Media.DefaultSize, Constants.Conventions.Media.DefaultSize);
}
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Web;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Media;
using umbraco;
namespace Umbraco.Web.Media
{
[Obsolete("This is no longer used and will be removed in future versions")]
public class ImageUrl
{
[Obsolete("Use TryGetImageUrl() instead")]
public static string GetImageUrl(string specifiedSrc, string field, string provider, string parameters, int? nodeId = null)
{
string url;
var found = TryGetImageUrl(specifiedSrc, field, provider, parameters, nodeId, out url);
return found ? url : string.Empty;
}
public static bool TryGetImageUrl(string specifiedSrc, string field, string provider, string parameters, int? nodeId, out string url)
{
var imageUrlProvider = GetProvider(provider);
var parsedParameters = string.IsNullOrEmpty(parameters) ? new NameValueCollection() : HttpUtility.ParseQueryString(parameters);
var queryValues = parsedParameters.Keys.Cast<string>().ToDictionary(key => key, key => parsedParameters[key]);
if (string.IsNullOrEmpty(field))
{
url = imageUrlProvider.GetImageUrlFromFileName(specifiedSrc, queryValues);
return true;
}
else
{
var fieldValue = string.Empty;
if (nodeId.HasValue)
{
var contentFromCache = GetContentFromCache(nodeId.GetValueOrDefault(), field);
if (contentFromCache != null)
{
fieldValue = contentFromCache.ToString();
}
else
{
var p = UmbracoContext.Current.ContentCache.GetById(nodeId.GetValueOrDefault());
var v = p.GetPropertyValue(field);
fieldValue = v == null ? string.Empty : v.ToString();
}
}
else
{
var context = HttpContext.Current;
if (context != null)
{
var elements = context.Items["pageElements"] as Hashtable;
if (elements != null)
{
var value = elements[field];
fieldValue = value != null ? value.ToString() : string.Empty;
}
}
}
if (!string.IsNullOrWhiteSpace(fieldValue))
{
int mediaId;
url = int.TryParse(fieldValue, out mediaId)
? imageUrlProvider.GetImageUrlFromMedia(mediaId, queryValues)
: imageUrlProvider.GetImageUrlFromFileName(fieldValue, queryValues);
return true;
}
}
url = string.Empty;
return false;
}
private static IImageUrlProvider GetProvider(string provider)
{
return ImageUrlProviderResolver.Current.GetProvider(provider);
}
private static object GetContentFromCache(int nodeIdInt, string field)
{
var content = ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem<object>(
string.Format("{0}{1}_{2}", CacheKeys.ContentItemCacheKey, nodeIdInt.ToString(CultureInfo.InvariantCulture), field));
return content;
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Media;
using Umbraco.Core.ObjectResolution;
using Umbraco.Web.Media.ImageUrlProviders;
namespace Umbraco.Web.Media
{
[Obsolete("IImageUrlProvider is no longer used and will be removed in future versions")]
internal sealed class ImageUrlProviderResolver : LazyManyObjectsResolverBase<ImageUrlProviderResolver, IImageUrlProvider>
{
internal ImageUrlProviderResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> value)
: base(serviceProvider, logger, value)
{
}
public IImageUrlProvider GetProvider(string provider)
{
return string.IsNullOrEmpty(provider) ?
Values.First(v => v.Name.Equals(ImageUrlProvider.DefaultName, StringComparison.InvariantCultureIgnoreCase)) :
Values.First(v => v.Name.Equals(provider, StringComparison.InvariantCultureIgnoreCase));
}
}
}

View File

@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Xml.XPath;
using Umbraco.Core.Configuration;
using Umbraco.Core.Media;
using umbraco;
using Umbraco.Core;
namespace Umbraco.Web.Media.ImageUrlProviders
{
[Obsolete("IImageUrlProvider is no longer used and will be removed in future versions")]
public class ImageUrlProvider : IImageUrlProvider
{
public const string DefaultName = "umbracoUpload";
public string Name
{
get { return DefaultName; }
}
public string GetImageUrlFromMedia(int mediaId, IDictionary<string, string> parameters)
{
var url = string.Empty;
var nodeIterator = library.GetMedia(mediaId, false);
if (nodeIterator.Current != null)
{
var filename = GetProperty(nodeIterator, Constants.Conventions.Media.File);
var withThumb = AddThumbInfo(filename, parameters);
url = AddCropInfo(withThumb, parameters);
}
return url;
}
public string GetImageUrlFromFileName(string specifiedSrc, IDictionary<string, string> parameters)
{
var withThumb = AddThumbInfo(specifiedSrc, parameters);
return AddCropInfo(withThumb, parameters);
}
private static string AddThumbInfo(string filename, IDictionary<string, string> parameters)
{
var thumb = string.Empty;
if (parameters.ContainsKey("thumb"))
thumb = parameters["thumb"];
if (!string.IsNullOrEmpty(thumb) && filename.Contains("."))
{
var lastIndexOf = filename.LastIndexOf('.');
var name = filename.Substring(0, lastIndexOf);
var extension = filename.Substring(lastIndexOf, filename.Length - lastIndexOf);
return string.Format("{0}_thumb_{1}{2}", name, thumb, extension);
}
return filename;
}
private static string AddCropInfo(string filename, IDictionary<string, string> parameters)
{
var crop = string.Empty;
if (parameters.ContainsKey("crop"))
crop = parameters["crop"];
if (!string.IsNullOrEmpty(crop) && filename.Contains("."))
{
var lastIndexOf = filename.LastIndexOf('.');
var name = filename.Substring(0, lastIndexOf);
//var extension = filename.Substring(lastIndexOf, filename.Length - lastIndexOf);
//Built in cropper currently always uses jpg as an extension
const string extension = ".jpg";
return string.Format("{0}_{1}{2}", name, crop, extension);
}
return filename;
}
private static string GetProperty(XPathNodeIterator nodeIterator, string fileProp)
{
var xpath = UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema
? string.Format(".//data[@alias = '{0}']", fileProp)
: string.Format(".//{0}", fileProp);
var file = string.Empty;
var selectSingleNode = nodeIterator.Current.SelectSingleNode(xpath);
if (selectSingleNode != null)
file = selectSingleNode.InnerXml;
return file;
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Umbraco.Core;
using Umbraco.Core.Media;
namespace Umbraco.Web.Media.ThumbnailProviders
{
public abstract class AbstractThumbnailProvider : IThumbnailProvider
{
protected abstract IEnumerable<string> SupportedExtensions { get; }
public bool CanProvideThumbnail(string fileUrl)
{
string thumbUrl;
return TryGetThumbnailUrl(fileUrl, out thumbUrl);
}
public string GetThumbnailUrl(string fileUrl)
{
string thumbUrl;
TryGetThumbnailUrl(fileUrl, out thumbUrl);
return thumbUrl;
}
protected bool IsSupportedExtension(string ext)
{
return SupportedExtensions.InvariantContains(ext) ||
SupportedExtensions.InvariantContains("*");
}
protected abstract bool TryGetThumbnailUrl(string fileUrl, out string thumbUrl);
}
}

View File

@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Umbraco.Core.ObjectResolution;
using Umbraco.Core.IO;
namespace Umbraco.Web.Media.ThumbnailProviders
{
[Weight(2000)]
public class FileExtensionIconThumbnailProvider : AbstractThumbnailProvider
{
protected override IEnumerable<string> SupportedExtensions
{
get { return new List<string> { "*" }; }
}
protected override bool TryGetThumbnailUrl(string fileUrl, out string thumbUrl)
{
// Set thumbnail url to empty strin initially
thumbUrl = string.Empty;
// Make sure file has an extension
var ext = Path.GetExtension(fileUrl);
if (string.IsNullOrEmpty(ext))
return false;
// Make sure it has a supported file extension
if (!IsSupportedExtension(ext))
return false;
// Make sure the thumbnail exists
var tmpThumbUrl = IOHelper.ResolveUrl(SystemDirectories.Umbraco + "/images/mediaThumbnails/"+ ext.TrimStart('.') +".png");
if (!File.Exists(IOHelper.MapPath(tmpThumbUrl)))
return false;
// We've got this far, so thumbnail must exist
thumbUrl = tmpThumbUrl;
return true;
}
}
}

View File

@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.IO;
using Umbraco.Core.IO;
using Umbraco.Core.ObjectResolution;
namespace Umbraco.Web.Media.ThumbnailProviders
{
[Weight(1000)]
public class ImageThumbnailProvider : AbstractThumbnailProvider
{
protected override IEnumerable<string> SupportedExtensions
{
get { return new List<string> { ".jpeg", ".jpg", ".gif", ".bmp", ".png", ".tiff", ".tif" }; }
}
protected override bool TryGetThumbnailUrl(string fileUrl, out string thumbUrl)
{
// Set thumbnail url to empty strin initially
thumbUrl = string.Empty;
// Make sure file has an extension
var ext = Path.GetExtension(fileUrl);
if (string.IsNullOrEmpty(ext))
return false;
// Make sure it has a supported file extension
if (!IsSupportedExtension(ext))
return false;
// Make sure the thumbnail exists
var tmpThumbUrl = fileUrl.Replace(ext, "_thumb" + ext);
try
{
var fs = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
var relativeThumbPath = fs.GetRelativePath(tmpThumbUrl);
if (!fs.FileExists(relativeThumbPath))
return false;
}
catch (Exception)
{
// If something odd happens, just return false and move on
return false;
}
// We've got this far, so thumbnail must exist
thumbUrl = tmpThumbUrl;
return true;
}
}
}

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Umbraco.Core.ObjectResolution;
using Umbraco.Core.IO;
namespace Umbraco.Web.Media.ThumbnailProviders
{
[Weight(3000)]
public class MediaTypeIconThumbnailProvider : AbstractThumbnailProvider
{
protected override IEnumerable<string> SupportedExtensions
{
get { return new List<string> { "*" }; }
}
protected override bool TryGetThumbnailUrl(string fileUrl, out string thumbUrl)
{
// Set thumbnail url to empty strin initially
thumbUrl = string.Empty;
// Make sure file has an extension
var ext = Path.GetExtension(fileUrl);
if (string.IsNullOrEmpty(ext))
return false;
// Make sure it has a supported file extension
if (!IsSupportedExtension(ext))
return false;
// Make sure the thumbnail exists
var tmpThumbUrl = IOHelper.ResolveUrl(SystemDirectories.Umbraco + "/images/mediaThumbnails/"+ ext.TrimStart('.') +".png");
if (!File.Exists(IOHelper.MapPath(tmpThumbUrl)))
return false;
// We've got this far, so thumbnail must exist
thumbUrl = tmpThumbUrl;
return true;
}
}
}

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Media;
using Umbraco.Core.ObjectResolution;
using umbraco.BusinessLogic;
using umbraco.BusinessLogic.Utils;
namespace Umbraco.Web.Media.ThumbnailProviders
{
[Obsolete("Thumbnails are generated by ImageProcessor, use that instead")]
public sealed class ThumbnailProvidersResolver : LazyManyObjectsResolverBase<ThumbnailProvidersResolver, IThumbnailProvider>
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="serviceProvider"></param>
/// <param name="logger"></param>
/// <param name="providers"></param>
internal ThumbnailProvidersResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> providers)
: base(serviceProvider, logger, providers)
{
}
/// <summary>
/// Return the providers
/// </summary>
public IEnumerable<IThumbnailProvider> Providers
{
get { return GetSortedValues(); }
}
public string GetThumbnailUrl(string fileUrl)
{
var provider = Providers.FirstOrDefault(x => x.CanProvideThumbnail(fileUrl));
return provider != null ? provider.GetThumbnailUrl(fileUrl) : string.Empty;
}
}
}

View File

@@ -1,14 +0,0 @@
using System.IO;
namespace Umbraco.Web.Media.TypeDetector
{
public class JpegDetector : RasterizedTypeDetector
{
public static bool IsOfType(Stream fileStream)
{
var header = GetFileHeader(fileStream);
return header[0] == 0xff && header[1] == 0xD8;
}
}
}

View File

@@ -1,16 +0,0 @@
using System.IO;
namespace Umbraco.Web.Media.TypeDetector
{
public abstract class RasterizedTypeDetector
{
public static byte[] GetFileHeader(Stream fileStream)
{
fileStream.Seek(0, SeekOrigin.Begin);
byte[] header = new byte[8];
fileStream.Seek(0, SeekOrigin.Begin);
return header;
}
}
}

View File

@@ -1,24 +0,0 @@
using System.IO;
using System.Xml.Linq;
namespace Umbraco.Web.Media.TypeDetector
{
public class SvgDetector
{
public static bool IsOfType(Stream fileStream)
{
var document = new XDocument();
try
{
document = XDocument.Load(fileStream);
}
catch (System.Exception ex)
{
return false;
}
return document.Root?.Name.LocalName == "svg";
}
}
}

View File

@@ -1,24 +0,0 @@
using System.IO;
using System.Text;
namespace Umbraco.Web.Media.TypeDetector
{
public class TIFFDetector
{
public static bool IsOfType(Stream fileStream)
{
string tiffHeader = GetFileHeader(fileStream);
return tiffHeader == "MM\x00\x2a" || tiffHeader == "II\x2a\x00";
}
public static string GetFileHeader(Stream fileStream)
{
var header = RasterizedTypeDetector.GetFileHeader(fileStream);
string tiffHeader = Encoding.ASCII.GetString(header, 0, 4);
return tiffHeader;
}
}
}

View File

@@ -1,146 +0,0 @@
using System;
using System.Drawing;
using System.IO;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
namespace Umbraco.Web.Media
{
/// <summary>
/// Provides methods to manage auto-fill properties for upload fields.
/// </summary>
internal class UploadAutoFillProperties
{
private readonly MediaFileSystem _mediaFileSystem;
private readonly ILogger _logger;
private readonly IContentSection _contentSection;
public UploadAutoFillProperties(MediaFileSystem mediaFileSystem, ILogger logger, IContentSection contentSection)
{
_mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_contentSection = contentSection ?? throw new ArgumentNullException(nameof(contentSection));
}
/// <summary>
/// Resets the auto-fill properties of a content item, for a specified auto-fill configuration.
/// </summary>
/// <param name="content">The content item.</param>
/// <param name="autoFillConfig">The auto-fill configuration.</param>
/// <param name="culture">Variation language.</param>
/// <param name="segment">Variation segment.</param>
public void Reset(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string culture, string segment)
{
if (content == null) throw new ArgumentNullException(nameof(content));
if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig));
ResetProperties(content, autoFillConfig, culture, segment);
}
/// <summary>
/// Populates the auto-fill properties of a content item, for a specified auto-fill configuration.
/// </summary>
/// <param name="content">The content item.</param>
/// <param name="autoFillConfig">The auto-fill configuration.</param>
/// <param name="filepath">The filesystem path to the uploaded file.</param>
/// <remarks>The <paramref name="filepath"/> parameter is the path relative to the filesystem.</remarks>
/// <param name="culture">Variation language.</param>
/// <param name="segment">Variation segment.</param>
public void Populate(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string filepath, string culture, string segment)
{
if (content == null) throw new ArgumentNullException(nameof(content));
if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig));
// no file = reset, file = auto-fill
if (filepath.IsNullOrWhiteSpace())
{
ResetProperties(content, autoFillConfig, culture, segment);
}
else
{
// if anything goes wrong, just reset the properties
try
{
using (var filestream = _mediaFileSystem.OpenFile(filepath))
{
var extension = (Path.GetExtension(filepath) ?? "").TrimStart('.');
var size = _contentSection.IsImageFile(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null;
SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment);
}
}
catch (Exception ex)
{
_logger.Error(typeof(UploadAutoFillProperties), ex, "Could not populate upload auto-fill properties for file '{File}'.", filepath);
ResetProperties(content, autoFillConfig, culture, segment);
}
}
}
/// <summary>
/// Populates the auto-fill properties of a content item.
/// </summary>
/// <param name="content">The content item.</param>
/// <param name="autoFillConfig"></param>
/// <param name="filepath">The filesystem-relative filepath, or null to clear properties.</param>
/// <param name="filestream">The stream containing the file data.</param>
/// <param name="culture">Variation language.</param>
/// <param name="segment">Variation segment.</param>
public void Populate(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string filepath, Stream filestream, string culture, string segment)
{
if (content == null) throw new ArgumentNullException(nameof(content));
if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig));
// no file = reset, file = auto-fill
if (filepath.IsNullOrWhiteSpace() || filestream == null)
{
ResetProperties(content, autoFillConfig, culture, segment);
}
else
{
var extension = (Path.GetExtension(filepath) ?? "").TrimStart('.');
var size = _contentSection.IsImageFile(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null;
SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment);
}
}
private static void SetProperties(IContentBase content, IImagingAutoFillUploadField autoFillConfig, Size? size, long length, string extension, string culture, string segment)
{
if (content == null) throw new ArgumentNullException(nameof(content));
if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig));
if (content.Properties.Contains(autoFillConfig.WidthFieldAlias))
content.Properties[autoFillConfig.WidthFieldAlias].SetValue(size.HasValue ? size.Value.Width.ToInvariantString() : string.Empty, culture, segment);
if (content.Properties.Contains(autoFillConfig.HeightFieldAlias))
content.Properties[autoFillConfig.HeightFieldAlias].SetValue(size.HasValue ? size.Value.Height.ToInvariantString() : string.Empty, culture, segment);
if (content.Properties.Contains(autoFillConfig.LengthFieldAlias))
content.Properties[autoFillConfig.LengthFieldAlias].SetValue(length, culture, segment);
if (content.Properties.Contains(autoFillConfig.ExtensionFieldAlias))
content.Properties[autoFillConfig.ExtensionFieldAlias].SetValue(extension, culture, segment);
}
private static void ResetProperties(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string culture, string segment)
{
if (content == null) throw new ArgumentNullException(nameof(content));
if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig));
if (content.Properties.Contains(autoFillConfig.WidthFieldAlias))
content.Properties[autoFillConfig.WidthFieldAlias].SetValue(string.Empty, culture, segment);
if (content.Properties.Contains(autoFillConfig.HeightFieldAlias))
content.Properties[autoFillConfig.HeightFieldAlias].SetValue(string.Empty, culture, segment);
if (content.Properties.Contains(autoFillConfig.LengthFieldAlias))
content.Properties[autoFillConfig.LengthFieldAlias].SetValue(string.Empty, culture, segment);
if (content.Properties.Contains(autoFillConfig.ExtensionFieldAlias))
content.Properties[autoFillConfig.ExtensionFieldAlias].SetValue(string.Empty, culture, segment);
}
}
}