Browse Source

First pass on ExifWriter spanification

pull/506/head
Jason Nelson 8 years ago
parent
commit
2f5c85d967
  1. 6
      src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs
  2. 2
      src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs
  3. 115
      src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs

6
src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs

@ -19,8 +19,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
/// </summary> /// </summary>
internal sealed class ExifReader internal sealed class ExifReader
{ {
private delegate TDataType ConverterMethod<TDataType>(ReadOnlySpan<byte> data);
private readonly List<ExifTag> invalidTags = new List<ExifTag>(); private readonly List<ExifTag> invalidTags = new List<ExifTag>();
private readonly byte[] exifData; private readonly byte[] exifData;
private int position; private int position;
@ -36,6 +34,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
this.exifData = exifData; this.exifData = exifData;
} }
private delegate TDataType ConverterMethod<TDataType>(ReadOnlySpan<byte> data);
/// <summary> /// <summary>
/// Gets the invalid tags. /// Gets the invalid tags.
/// </summary> /// </summary>
@ -412,7 +412,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
} }
span = new ReadOnlySpan<byte>(this.exifData, this.position, length); span = new ReadOnlySpan<byte>(this.exifData, this.position, length);
this.position += length; this.position += length;
return true; return true;

2
src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs

@ -696,7 +696,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
{ {
return description; return description;
} }
switch (this.DataType) switch (this.DataType)
{ {
case ExifDataType.Ascii: case ExifDataType.Ascii:

115
src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs

@ -2,8 +2,8 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers.Binary;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text; using System.Text;
using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Primitives;
@ -24,10 +24,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
/// </summary> /// </summary>
private ExifParts allowedParts; private ExifParts allowedParts;
private IList<ExifValue> values; private IList<ExifValue> values;
private IList<int> dataOffsets; private List<int> dataOffsets;
private IList<int> ifdIndexes; private List<int> ifdIndexes;
private IList<int> exifIndexes; private List<int> exifIndexes;
private IList<int> gpsIndexes; private List<int> gpsIndexes;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ExifWriter"/> class. /// Initializes a new instance of the <see cref="ExifWriter"/> class.
@ -89,6 +89,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
length += 10 + 4 + 2; length += 10 + 4 + 2;
byte[] result = new byte[length]; byte[] result = new byte[length];
result[0] = (byte)'E'; result[0] = (byte)'E';
result[1] = (byte)'x'; result[1] = (byte)'x';
result[2] = (byte)'i'; result[2] = (byte)'i';
@ -114,9 +115,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
this.values[gpsIndex] = this.values[gpsIndex].WithValue(ifdOffset + ifdLength + exifLength); this.values[gpsIndex] = this.values[gpsIndex].WithValue(ifdOffset + ifdLength + exifLength);
} }
i = Write(BitConverter.GetBytes(ifdOffset), result, i); i = WriteUInt32(ifdOffset, result, i);
i = this.WriteHeaders(this.ifdIndexes, result, i); i = this.WriteHeaders(this.ifdIndexes, result, i);
i = Write(BitConverter.GetBytes(thumbnailOffset), result, i); i = WriteUInt32(thumbnailOffset, result, i);
i = this.WriteData(this.ifdIndexes, result, i); i = this.WriteData(this.ifdIndexes, result, i);
if (exifLength > 0) if (exifLength > 0)
@ -131,18 +132,60 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
i = this.WriteData(this.gpsIndexes, result, i); i = this.WriteData(this.gpsIndexes, result, i);
} }
Write(BitConverter.GetBytes((ushort)0), result, i); WriteUInt16((ushort)0, result, i);
return result; return result;
} }
private static int Write(byte[] source, byte[] destination, int offset) private static unsafe int WriteSingle(float value, Span<byte> destination, int offset)
{
BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(offset, 4), *((int*)&value));
return offset + 4;
}
private static unsafe int WriteDouble(double value, Span<byte> destination, int offset)
{ {
Buffer.BlockCopy(source, 0, destination, offset, source.Length); BinaryPrimitives.WriteInt64LittleEndian(destination.Slice(offset, 8), *((long*)&value));
return offset + 8;
}
private static int Write(ReadOnlySpan<byte> source, Span<byte> destination, int offset)
{
source.CopyTo(destination.Slice(offset, source.Length));
return offset + source.Length; return offset + source.Length;
} }
private static int WriteInt16(short value, Span<byte> destination, int offset)
{
BinaryPrimitives.WriteInt16LittleEndian(destination.Slice(offset, 2), value);
return offset + 2;
}
private static int WriteUInt16(ushort value, Span<byte> destination, int offset)
{
BinaryPrimitives.WriteUInt16LittleEndian(destination.Slice(offset, 2), value);
return offset + 2;
}
private static int WriteUInt32(uint value, Span<byte> destination, int offset)
{
BinaryPrimitives.WriteUInt32LittleEndian(destination.Slice(offset, 4), value);
return offset + 4;
}
private static int WriteInt32(int value, Span<byte> destination, int offset)
{
BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(offset, 4), value);
return offset + 4;
}
private int GetIndex(IList<int> indexes, ExifTag tag) private int GetIndex(IList<int> indexes, ExifTag tag)
{ {
foreach (int index in indexes) foreach (int index in indexes)
@ -163,7 +206,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
{ {
if (((int)this.allowedParts & (int)part) == 0) if (((int)this.allowedParts & (int)part) == 0)
{ {
return new Collection<int>(); return new List<int>();
} }
var result = new List<int>(); var result = new List<int>();
@ -223,7 +266,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
return newOffset; return newOffset;
} }
private int WriteData(IList<int> indexes, byte[] destination, int offset) private int WriteData(List<int> indexes, byte[] destination, int offset)
{ {
if (this.dataOffsets.Count == 0) if (this.dataOffsets.Count == 0)
{ {
@ -238,7 +281,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
ExifValue value = this.values[index]; ExifValue value = this.values[index];
if (value.Length > 4) if (value.Length > 4)
{ {
Write(BitConverter.GetBytes(newOffset - StartIndex), destination, this.dataOffsets[i++]); WriteUInt32((uint)(newOffset - StartIndex), destination, this.dataOffsets[i++]);
newOffset = this.WriteValue(value, destination, newOffset); newOffset = this.WriteValue(value, destination, newOffset);
} }
} }
@ -246,11 +289,11 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
return newOffset; return newOffset;
} }
private int WriteHeaders(IList<int> indexes, byte[] destination, int offset) private int WriteHeaders(List<int> indexes, byte[] destination, int offset)
{ {
this.dataOffsets = new List<int>(); this.dataOffsets = new List<int>();
int newOffset = Write(BitConverter.GetBytes((ushort)indexes.Count), destination, offset); int newOffset = WriteUInt16((ushort)indexes.Count, destination, offset);
if (indexes.Count == 0) if (indexes.Count == 0)
{ {
@ -260,9 +303,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
foreach (int index in indexes) foreach (int index in indexes)
{ {
ExifValue value = this.values[index]; ExifValue value = this.values[index];
newOffset = Write(BitConverter.GetBytes((ushort)value.Tag), destination, newOffset); newOffset = WriteUInt16((ushort)value.Tag, destination, newOffset);
newOffset = Write(BitConverter.GetBytes((ushort)value.DataType), destination, newOffset); newOffset = WriteUInt16((ushort)value.DataType, destination, newOffset);
newOffset = Write(BitConverter.GetBytes((uint)value.NumberOfComponents), destination, newOffset); newOffset = WriteUInt32((uint)value.NumberOfComponents, destination, newOffset);
if (value.Length > 4) if (value.Length > 4)
{ {
@ -279,23 +322,19 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
return newOffset; return newOffset;
} }
private int WriteRational(in Rational value, byte[] destination, int offset) private static void WriteRational(Span<byte> destination, in Rational value)
{ {
Write(BitConverter.GetBytes(value.Numerator), destination, offset); BinaryPrimitives.WriteUInt32LittleEndian(destination.Slice(0, 4), value.Numerator);
Write(BitConverter.GetBytes(value.Denominator), destination, offset + 4); BinaryPrimitives.WriteUInt32LittleEndian(destination.Slice(4, 4), value.Denominator);
return offset + 8;
} }
private int WriteSignedRational(in SignedRational value, byte[] destination, int offset) private static void WriteSignedRational(Span<byte> destination, in SignedRational value)
{ {
Write(BitConverter.GetBytes(value.Numerator), destination, offset); BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(0, 4), value.Numerator);
Write(BitConverter.GetBytes(value.Denominator), destination, offset + 4); BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(4, 4), value.Denominator);
return offset + 8;
} }
private int WriteValue(ExifDataType dataType, object value, byte[] destination, int offset) private int WriteValue(ExifDataType dataType, object value, Span<byte> destination, int offset)
{ {
switch (dataType) switch (dataType)
{ {
@ -306,24 +345,26 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
destination[offset] = (byte)value; destination[offset] = (byte)value;
return offset + 1; return offset + 1;
case ExifDataType.DoubleFloat: case ExifDataType.DoubleFloat:
return Write(BitConverter.GetBytes((double)value), destination, offset); return WriteDouble((double)value, destination, offset);
case ExifDataType.Short: case ExifDataType.Short:
return Write(BitConverter.GetBytes((ushort)value), destination, offset); return WriteUInt16((ushort)value, destination, offset);
case ExifDataType.Long: case ExifDataType.Long:
return Write(BitConverter.GetBytes((uint)value), destination, offset); return WriteUInt32((uint)value, destination, offset);
case ExifDataType.Rational: case ExifDataType.Rational:
return this.WriteRational((Rational)value, destination, offset); WriteRational(destination.Slice(offset, 8), (Rational)value);
return offset + 8;
case ExifDataType.SignedByte: case ExifDataType.SignedByte:
destination[offset] = unchecked((byte)((sbyte)value)); destination[offset] = unchecked((byte)((sbyte)value));
return offset + 1; return offset + 1;
case ExifDataType.SignedLong: case ExifDataType.SignedLong:
return Write(BitConverter.GetBytes((int)value), destination, offset); return WriteInt32((int)value, destination, offset);
case ExifDataType.SignedShort: case ExifDataType.SignedShort:
return Write(BitConverter.GetBytes((short)value), destination, offset); return WriteInt16((short)value, destination, offset);
case ExifDataType.SignedRational: case ExifDataType.SignedRational:
return this.WriteSignedRational((SignedRational)value, destination, offset); WriteSignedRational(destination.Slice(offset, 8), (SignedRational)value);
return offset + 8;
case ExifDataType.SingleFloat: case ExifDataType.SingleFloat:
return Write(BitConverter.GetBytes((float)value), destination, offset); return WriteSingle((float)value, destination, offset);
default: default:
throw new NotImplementedException(); throw new NotImplementedException();
} }

Loading…
Cancel
Save