Browse Source

small refactory EncodedString methods

pull/1935/head
Ildar Khayrutdinov 4 years ago
parent
commit
c71b2aac4e
  1. 65
      src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs
  2. 92
      src/ImageSharp/Metadata/Profiles/Exif/ExifEncodedStringHelpers.cs
  3. 20
      src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs
  4. 6
      src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs

65
src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs

@ -2,21 +2,12 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers.Binary;
using System.Text;
using static SixLabors.ImageSharp.Metadata.Profiles.Exif.EncodedString;
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
{
internal static class ExifConstants
{
public const int CharacterCodeBytesLength = 8;
private const ulong AsciiCode = 0x_41_53_43_49_49_00_00_00;
private const ulong JISCode = 0x_4A_49_53_00_00_00_00_00;
private const ulong UnicodeCode = 0x_55_4E_49_43_4F_44_45_00;
private const ulong UndefinedCode = 0x_00_00_00_00_00_00_00_00;
public static ReadOnlySpan<byte> LittleEndianByteOrderMarker => new byte[]
{
(byte)'I',
@ -35,61 +26,5 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
// UTF-8 is better than ASCII, UTF-8 encodes the ASCII codes the same way
public static Encoding DefaultEncoding => Encoding.UTF8;
public static Encoding JIS0208Encoding => Encoding.GetEncoding(932);
private static ReadOnlySpan<byte> AsciiCodeBytes => new byte[] { 0x41, 0x53, 0x43, 0x49, 0x49, 0, 0, 0 };
private static ReadOnlySpan<byte> JISCodeBytes => new byte[] { 0x4A, 0x49, 0x53, 0, 0, 0, 0, 0 };
private static ReadOnlySpan<byte> UnicodeCodeBytes => new byte[] { 0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0 };
private static ReadOnlySpan<byte> UndefinedCodeBytes => new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
public static bool TryDetect(ReadOnlySpan<byte> buffer, out CharacterCode code)
{
if (buffer.Length >= CharacterCodeBytesLength)
{
ulong test = BinaryPrimitives.ReadUInt64LittleEndian(buffer);
switch (test)
{
case AsciiCode:
code = CharacterCode.ASCII;
return true;
case JISCode:
code = CharacterCode.JIS;
return true;
case UnicodeCode:
code = CharacterCode.Unicode;
return true;
case UndefinedCode:
code = CharacterCode.Undefined;
return true;
default:
break;
}
}
code = default;
return false;
}
public static ReadOnlySpan<byte> GetCodeBytes(CharacterCode code) => code switch
{
CharacterCode.ASCII => AsciiCodeBytes,
CharacterCode.JIS => JISCodeBytes,
CharacterCode.Unicode => UnicodeCodeBytes,
CharacterCode.Undefined => UndefinedCodeBytes,
_ => UndefinedCodeBytes
};
public static Encoding GetEncoding(CharacterCode code) => code switch
{
CharacterCode.ASCII => Encoding.ASCII,
CharacterCode.JIS => JIS0208Encoding,
CharacterCode.Unicode => Encoding.Unicode,
CharacterCode.Undefined => Encoding.UTF8,
_ => Encoding.UTF8
};
}
}

92
src/ImageSharp/Metadata/Profiles/Exif/ExifEncodedStringHelpers.cs

@ -0,0 +1,92 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers.Binary;
using System.Text;
using static SixLabors.ImageSharp.Metadata.Profiles.Exif.EncodedString;
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
{
internal static class ExifEncodedStringHelpers
{
public const int CharacterCodeBytesLength = 8;
private const ulong AsciiCode = 0x_41_53_43_49_49_00_00_00;
private const ulong JISCode = 0x_4A_49_53_00_00_00_00_00;
private const ulong UnicodeCode = 0x_55_4E_49_43_4F_44_45_00;
private const ulong UndefinedCode = 0x_00_00_00_00_00_00_00_00;
private static ReadOnlySpan<byte> AsciiCodeBytes => new byte[] { 0x41, 0x53, 0x43, 0x49, 0x49, 0, 0, 0 };
private static ReadOnlySpan<byte> JISCodeBytes => new byte[] { 0x4A, 0x49, 0x53, 0, 0, 0, 0, 0 };
private static ReadOnlySpan<byte> UnicodeCodeBytes => new byte[] { 0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0 };
private static ReadOnlySpan<byte> UndefinedCodeBytes => new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
private static Encoding JIS0208Encoding => Encoding.GetEncoding(932);
private static bool TryDetect(ReadOnlySpan<byte> buffer, out CharacterCode code)
{
if (buffer.Length >= CharacterCodeBytesLength)
{
ulong test = BinaryPrimitives.ReadUInt64LittleEndian(buffer);
switch (test)
{
case AsciiCode:
code = CharacterCode.ASCII;
return true;
case JISCode:
code = CharacterCode.JIS;
return true;
case UnicodeCode:
code = CharacterCode.Unicode;
return true;
case UndefinedCode:
code = CharacterCode.Undefined;
return true;
default:
break;
}
}
code = default;
return false;
}
public static ReadOnlySpan<byte> GetCodeBytes(CharacterCode code) => code switch
{
CharacterCode.ASCII => AsciiCodeBytes,
CharacterCode.JIS => JISCodeBytes,
CharacterCode.Unicode => UnicodeCodeBytes,
CharacterCode.Undefined => UndefinedCodeBytes,
_ => UndefinedCodeBytes
};
public static Encoding GetEncoding(CharacterCode code) => code switch
{
CharacterCode.ASCII => Encoding.ASCII,
CharacterCode.JIS => JIS0208Encoding,
CharacterCode.Unicode => Encoding.Unicode,
CharacterCode.Undefined => Encoding.UTF8,
_ => Encoding.UTF8
};
public static bool TryCreate(ReadOnlySpan<byte> buffer, out EncodedString encodedString)
{
if (TryDetect(buffer, out CharacterCode code))
{
string text = GetEncoding(code).GetString(buffer.Slice(CharacterCodeBytesLength));
encodedString = new EncodedString(code, text);
return true;
}
encodedString = default;
return false;
}
public static uint GetDataLength(EncodedString encodedString) =>
(uint)GetEncoding(encodedString.Code).GetByteCount(encodedString.Text) + CharacterCodeBytesLength;
}
}

20
src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs

@ -220,6 +220,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
if (this.TryReadSpan(buffer))
{
object value = this.ConvertValue(tag.DataType, buffer, tag.NumberOfComponents > 1 || tag.Exif.IsArray);
if (value is EncodedString)
{
// Console.WriteLine("EncodedString tag: " + (ushort)tag.Exif.Tag);
}
this.Add(values, tag.Exif, value);
}
}
@ -269,12 +274,15 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
case ExifDataType.Ascii:
return this.ConvertToString(buffer);
case ExifDataType.Byte:
{
if (!isArray)
{
return this.ConvertToByte(buffer);
}
return buffer.ToArray();
return ExifEncodedStringHelpers.TryCreate(buffer, out EncodedString encodedString) ? encodedString : buffer.ToArray();
}
case ExifDataType.DoubleFloat:
if (!isArray)
{
@ -355,19 +363,15 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
return ToArray(dataType, buffer, this.ConvertToUInt64);
case ExifDataType.Undefined:
{
if (!isArray)
{
return this.ConvertToByte(buffer);
}
// ext processing
if (ExifConstants.TryDetect(buffer, out EncodedString.CharacterCode code))
{
string text = ExifConstants.GetEncoding(code).GetString(buffer.Slice(ExifConstants.CharacterCodeBytesLength));
return new EncodedString(code, text);
}
return ExifEncodedStringHelpers.TryCreate(buffer, out EncodedString encodedString) ? encodedString : buffer.ToArray();
}
return buffer.ToArray();
default:
throw new NotSupportedException($"Data type {dataType} is not supported.");
}

6
src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs

@ -281,7 +281,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
if (value is EncodedString encodedString)
{
return (uint)ExifConstants.GetEncoding(encodedString.Code).GetByteCount(encodedString.Text) + 8;
return ExifEncodedStringHelpers.GetDataLength(encodedString);
}
if (value is Array arrayValue)
@ -387,11 +387,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
case ExifDataType.Undefined:
if (value is EncodedString encodedString)
{
ReadOnlySpan<byte> codeBytes = ExifConstants.GetCodeBytes(encodedString.Code);
ReadOnlySpan<byte> codeBytes = ExifEncodedStringHelpers.GetCodeBytes(encodedString.Code);
codeBytes.CopyTo(destination.Slice(offset));
offset += codeBytes.Length;
ReadOnlySpan<byte> dataBytes = ExifConstants.GetEncoding(encodedString.Code).GetBytes(encodedString.Text);
ReadOnlySpan<byte> dataBytes = ExifEncodedStringHelpers.GetEncoding(encodedString.Code).GetBytes(encodedString.Text);
dataBytes.CopyTo(destination.Slice(offset));
offset += dataBytes.Length;

Loading…
Cancel
Save