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. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers.Binary;
using System.Text; using System.Text;
using static SixLabors.ImageSharp.Metadata.Profiles.Exif.EncodedString;
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
{ {
internal static class ExifConstants 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[] public static ReadOnlySpan<byte> LittleEndianByteOrderMarker => new byte[]
{ {
(byte)'I', (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 // UTF-8 is better than ASCII, UTF-8 encodes the ASCII codes the same way
public static Encoding DefaultEncoding => Encoding.UTF8; 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)) if (this.TryReadSpan(buffer))
{ {
object value = this.ConvertValue(tag.DataType, buffer, tag.NumberOfComponents > 1 || tag.Exif.IsArray); 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); this.Add(values, tag.Exif, value);
} }
} }
@ -269,12 +274,15 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
case ExifDataType.Ascii: case ExifDataType.Ascii:
return this.ConvertToString(buffer); return this.ConvertToString(buffer);
case ExifDataType.Byte: case ExifDataType.Byte:
{
if (!isArray) if (!isArray)
{ {
return this.ConvertToByte(buffer); return this.ConvertToByte(buffer);
} }
return buffer.ToArray(); return ExifEncodedStringHelpers.TryCreate(buffer, out EncodedString encodedString) ? encodedString : buffer.ToArray();
}
case ExifDataType.DoubleFloat: case ExifDataType.DoubleFloat:
if (!isArray) if (!isArray)
{ {
@ -355,19 +363,15 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
return ToArray(dataType, buffer, this.ConvertToUInt64); return ToArray(dataType, buffer, this.ConvertToUInt64);
case ExifDataType.Undefined: case ExifDataType.Undefined:
{
if (!isArray) if (!isArray)
{ {
return this.ConvertToByte(buffer); return this.ConvertToByte(buffer);
} }
// ext processing return ExifEncodedStringHelpers.TryCreate(buffer, out EncodedString encodedString) ? encodedString : buffer.ToArray();
if (ExifConstants.TryDetect(buffer, out EncodedString.CharacterCode code)) }
{
string text = ExifConstants.GetEncoding(code).GetString(buffer.Slice(ExifConstants.CharacterCodeBytesLength));
return new EncodedString(code, text);
}
return buffer.ToArray();
default: default:
throw new NotSupportedException($"Data type {dataType} is not supported."); 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) if (value is EncodedString encodedString)
{ {
return (uint)ExifConstants.GetEncoding(encodedString.Code).GetByteCount(encodedString.Text) + 8; return ExifEncodedStringHelpers.GetDataLength(encodedString);
} }
if (value is Array arrayValue) if (value is Array arrayValue)
@ -387,11 +387,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
case ExifDataType.Undefined: case ExifDataType.Undefined:
if (value is EncodedString encodedString) if (value is EncodedString encodedString)
{ {
ReadOnlySpan<byte> codeBytes = ExifConstants.GetCodeBytes(encodedString.Code); ReadOnlySpan<byte> codeBytes = ExifEncodedStringHelpers.GetCodeBytes(encodedString.Code);
codeBytes.CopyTo(destination.Slice(offset)); codeBytes.CopyTo(destination.Slice(offset));
offset += codeBytes.Length; 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)); dataBytes.CopyTo(destination.Slice(offset));
offset += dataBytes.Length; offset += dataBytes.Length;

Loading…
Cancel
Save