Browse Source

Testable code

pull/348/head
James Jackson-South 9 years ago
parent
commit
6c7af0c4a6
  1. 59
      src/ImageSharp/Formats/Jpeg/Common/Decoder/ProfileResolver.cs
  2. 69
      src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegConstants.cs
  3. 21
      src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs
  4. 79
      tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs

59
src/ImageSharp/Formats/Jpeg/Common/Decoder/ProfileResolver.cs

@ -0,0 +1,59 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
{
/// <summary>
/// Provides methods for identifying metadata and color profiles within jpeg images.
/// </summary>
internal static class ProfileResolver
{
/// <summary>
/// Describes the EXIF specific markers
/// </summary>
public static readonly byte[] JFifMarker = ToAsciiBytes("JFIF\0");
/// <summary>
/// Describes the EXIF specific markers
/// </summary>
public static readonly byte[] IccMarker = ToAsciiBytes("ICC_PROFILE\0");
/// <summary>
/// Describes the ICC specific markers
/// </summary>
public static readonly byte[] ExifMarker = ToAsciiBytes("Exif\0\0");
/// <summary>
/// Describes Adobe specific markers <see href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe"/>
/// </summary>
public static readonly byte[] AdobeMarker = ToAsciiBytes("Adobe");
/// <summary>
/// Returns a value indicating whether the passed bytes are a match to the profile identifer
/// </summary>
/// <param name="bytesToCheck">The bytes to check</param>
/// <param name="profileIdentifier">The profile identifier</param>
/// <returns>The <see cref="bool"/></returns>
public static bool IsProfile(Span<byte> bytesToCheck, Span<byte> profileIdentifier)
{
return bytesToCheck.Length >= profileIdentifier.Length
&& bytesToCheck.Slice(0, profileIdentifier.Length).SequenceEqual(profileIdentifier);
}
// No Encoding.ASCII nor Linq.Select on NetStandard 1.1
private static byte[] ToAsciiBytes(string str)
{
int length = str.Length;
byte[] bytes = new byte[length];
char[] chars = str.ToCharArray();
for (int i = 0; i < length; i++)
{
bytes[i] = (byte)chars[i];
}
return bytes;
}
}
}

69
src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegConstants.cs

@ -25,49 +25,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// </summary> /// </summary>
public static readonly IEnumerable<string> FileExtensions = new[] { "jpg", "jpeg", "jfif" }; public static readonly IEnumerable<string> FileExtensions = new[] { "jpg", "jpeg", "jfif" };
/// <summary>
/// Descibes the various header identifers for metadata profiles
/// </summary>
/// <remarks>
/// Encoding ASCII isn't available for NetStandard 1.1
/// </remarks>
internal static class ProfileIdentifiers
{
/// <summary>
/// Describes the EXIF specific markers
/// </summary>
public static readonly byte[] JFifMarker = ToAsciiBytes("JFIF\0");
/// <summary>
/// Describes the EXIF specific markers
/// </summary>
public static readonly byte[] IccMarker = ToAsciiBytes("ICC_PROFILE\0");
/// <summary>
/// Describes the ICC specific markers
/// </summary>
public static readonly byte[] ExifMarker = ToAsciiBytes("Exif\0\0");
/// <summary>
/// Describes Adobe specific markers <see href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe"/>
/// </summary>
public static readonly byte[] AdobeMarker = ToAsciiBytes("Adobe");
// No Linq Select on NetStandard 1.1
private static byte[] ToAsciiBytes(string str)
{
int length = str.Length;
byte[] bytes = new byte[length];
char[] chars = str.ToCharArray();
for (int i = 0; i < length; i++)
{
bytes[i] = (byte)chars[i];
}
return bytes;
}
}
/// <summary> /// <summary>
/// Describes common Jpeg markers /// Describes common Jpeg markers
/// </summary> /// </summary>
@ -208,32 +165,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
public const byte APP15 = 0xef; public const byte APP15 = 0xef;
} }
/// <summary>
/// Contains JFIF specific markers
/// </summary>
public static class JFif
{
/// <summary>
/// Represents J in ASCII
/// </summary>
public const byte J = 0x4A;
/// <summary>
/// Represents F in ASCII
/// </summary>
public const byte F = 0x46;
/// <summary>
/// Represents I in ASCII
/// </summary>
public const byte I = 0x49;
/// <summary>
/// Represents the null "0" marker
/// </summary>
public const byte Null = 0x0;
}
/// <summary> /// <summary>
/// Describes Adobe specific markers <see href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe"/> /// Describes Adobe specific markers <see href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe"/>
/// </summary> /// </summary>

21
src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -395,18 +394,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.InitDerivedMetaDataProperties(); this.InitDerivedMetaDataProperties();
} }
/// <summary>
/// Returns a value indicating whether the passed bytes are a match to the profile identifer
/// </summary>
/// <param name="bytesToCheck">The bytes to check</param>
/// <param name="profileIdentifier">The profile identifier</param>
/// <returns>The <see cref="bool"/></returns>
private static bool IsProfile(Span<byte> bytesToCheck, Span<byte> profileIdentifier)
{
return bytesToCheck.Length >= profileIdentifier.Length
&& bytesToCheck.Slice(0, profileIdentifier.Length).SequenceEqual(profileIdentifier);
}
/// <summary> /// <summary>
/// Assigns derived metadata properties to <see cref="MetaData"/>, eg. horizontal and vertical resolution if it has a JFIF header. /// Assigns derived metadata properties to <see cref="MetaData"/>, eg. horizontal and vertical resolution if it has a JFIF header.
/// </summary> /// </summary>
@ -447,7 +434,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.InputProcessor.ReadFull(this.Temp, 0, 13); this.InputProcessor.ReadFull(this.Temp, 0, 13);
remaining -= 13; remaining -= 13;
if (IsProfile(this.Temp, OrigJpegConstants.ProfileIdentifiers.JFifMarker)) if (ProfileResolver.IsProfile(this.Temp, ProfileResolver.JFifMarker))
{ {
this.isJFif = true; this.isJFif = true;
this.jFifHorizontalResolution = (short)((this.Temp[8] << 8) | this.Temp[9]); this.jFifHorizontalResolution = (short)((this.Temp[8] << 8) | this.Temp[9]);
@ -475,7 +462,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
byte[] profile = new byte[remaining]; byte[] profile = new byte[remaining];
this.InputProcessor.ReadFull(profile, 0, remaining); this.InputProcessor.ReadFull(profile, 0, remaining);
if (IsProfile(profile, OrigJpegConstants.ProfileIdentifiers.ExifMarker)) if (ProfileResolver.IsProfile(profile, ProfileResolver.ExifMarker))
{ {
this.isExif = true; this.isExif = true;
this.MetaData.ExifProfile = new ExifProfile(profile); this.MetaData.ExifProfile = new ExifProfile(profile);
@ -500,7 +487,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.InputProcessor.ReadFull(identifier, 0, Icclength); this.InputProcessor.ReadFull(identifier, 0, Icclength);
remaining -= Icclength; // We have read it by this point remaining -= Icclength; // We have read it by this point
if (IsProfile(identifier, OrigJpegConstants.ProfileIdentifiers.IccMarker)) if (ProfileResolver.IsProfile(identifier, ProfileResolver.IccMarker))
{ {
byte[] profile = new byte[remaining]; byte[] profile = new byte[remaining];
this.InputProcessor.ReadFull(profile, 0, remaining); this.InputProcessor.ReadFull(profile, 0, remaining);
@ -538,7 +525,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.InputProcessor.ReadFull(this.Temp, 0, 12); this.InputProcessor.ReadFull(this.Temp, 0, 12);
remaining -= 12; remaining -= 12;
if (IsProfile(this.Temp, OrigJpegConstants.ProfileIdentifiers.AdobeMarker)) if (ProfileResolver.IsProfile(this.Temp, ProfileResolver.AdobeMarker))
{ {
this.isAdobe = true; this.isAdobe = true;
this.adobeColorTransform = this.Temp[11]; this.adobeColorTransform = this.Temp[11];

79
tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs

@ -0,0 +1,79 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
using System.Text;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
using Xunit;
public class ProfileResolverTests
{
private static readonly byte[] JFifMarker = Encoding.ASCII.GetBytes("JFIF\0");
private static readonly byte[] ExifMarker = Encoding.ASCII.GetBytes("Exif\0\0");
private static readonly byte[] IccMarker = Encoding.ASCII.GetBytes("ICC_PROFILE\0");
private static readonly byte[] AdobeMarker = Encoding.ASCII.GetBytes("Adobe");
[Fact]
public void ProfileResolverHasCorrectJFifMarker()
{
Assert.Equal(JFifMarker, ProfileResolver.JFifMarker);
}
[Fact]
public void ProfileResolverHasCorrectExifMarker()
{
Assert.Equal(ExifMarker, ProfileResolver.ExifMarker);
}
[Fact]
public void ProfileResolverHasCorrectIccMarker()
{
Assert.Equal(IccMarker, ProfileResolver.IccMarker);
}
[Fact]
public void ProfileResolverHasCorrectAdobeMarker()
{
Assert.Equal(AdobeMarker, ProfileResolver.AdobeMarker);
}
[Fact]
public void ProfileResolverCanResolveJFifMarker()
{
Assert.True(ProfileResolver.IsProfile(JFifMarker, ProfileResolver.JFifMarker));
}
[Fact]
public void ProfileResolverCanResolveExifMarker()
{
Assert.True(ProfileResolver.IsProfile(ExifMarker, ProfileResolver.ExifMarker));
}
[Fact]
public void ProfileResolverCanResolveIccMarker()
{
Assert.True(ProfileResolver.IsProfile(IccMarker, ProfileResolver.IccMarker));
}
[Fact]
public void ProfileResolverCanResolveAdobeMarker()
{
Assert.True(ProfileResolver.IsProfile(AdobeMarker, ProfileResolver.AdobeMarker));
}
[Fact]
public void ProfileResolverCorrectlyReportsNonMarker()
{
Assert.False(ProfileResolver.IsProfile(IccMarker, ProfileResolver.AdobeMarker));
}
[Fact]
public void ProfileResolverCanHandleIncorrectLength()
{
Assert.False(ProfileResolver.IsProfile(AdobeMarker, ProfileResolver.IccMarker));
}
}
}
Loading…
Cancel
Save