Browse Source

fix calculation of ICC profile ID and add tests for it

af/merge-core
Johannes Bildstein 8 years ago
parent
commit
b71c8d0c80
  1. 44
      src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs
  2. 39
      tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccProfileTests.cs
  3. 55
      tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs

44
src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs

@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
#if !NETSTANDARD1_1
/// <summary>
/// Calculates the MD5 hash value of an ICC profile header
/// Calculates the MD5 hash value of an ICC profile
/// </summary>
/// <param name="data">The data of which to calculate the hash value</param>
/// <returns>The calculated hash</returns>
@ -117,22 +117,38 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
Guard.NotNull(data, nameof(data));
Guard.IsTrue(data.Length >= 128, nameof(data), "Data length must be at least 128 to be a valid profile header");
byte[] header = new byte[128];
Buffer.BlockCopy(data, 0, header, 0, 128);
const int profileFlagPos = 44;
const int renderingIntentPos = 64;
const int profileIdPos = 84;
// need to copy some values because they need to be zero for the hashing
byte[] temp = new byte[24];
Buffer.BlockCopy(data, profileFlagPos, temp, 0, 4);
Buffer.BlockCopy(data, renderingIntentPos, temp, 4, 4);
Buffer.BlockCopy(data, profileIdPos, temp, 8, 16);
using (var md5 = MD5.Create())
{
// Zero out some values
Array.Clear(header, 44, 4); // Profile flags
Array.Clear(header, 64, 4); // Rendering Intent
Array.Clear(header, 84, 16); // Profile ID
// Calculate hash
byte[] hash = md5.ComputeHash(data);
// Read values from hash
var reader = new IccDataReader(hash);
return reader.ReadProfileId();
try
{
// Zero out some values
Array.Clear(data, profileFlagPos, 4);
Array.Clear(data, renderingIntentPos, 4);
Array.Clear(data, profileIdPos, 16);
// Calculate hash
byte[] hash = md5.ComputeHash(data);
// Read values from hash
var reader = new IccDataReader(hash);
return reader.ReadProfileId();
}
finally
{
Buffer.BlockCopy(temp, 0, data, profileFlagPos, 4);
Buffer.BlockCopy(temp, 4, data, renderingIntentPos, 4);
Buffer.BlockCopy(temp, 8, data, profileIdPos, 16);
}
}
}

39
tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccProfileTests.cs

@ -0,0 +1,39 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.MetaData.Profiles.Icc;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Icc
{
public class IccProfileTests
{
#if !NETSTANDARD1_1
[Theory]
[MemberData(nameof(IccTestDataProfiles.ProfileIdTestData), MemberType = typeof(IccTestDataProfiles))]
public void CalculateHash_WithByteArray_CalculatesProfileHash(byte[] data, IccProfileId expected)
{
IccProfileId result = IccProfile.CalculateHash(data);
Assert.Equal(expected, result);
}
[Fact]
public void CalculateHash_WithByteArray_DoesNotModifyData()
{
byte[] data = IccTestDataProfiles.Profile_Random_Array;
byte[] copy = new byte[data.Length];
Buffer.BlockCopy(data, 0, copy, 0, data.Length);
IccProfileId result = IccProfile.CalculateHash(data);
Assert.Equal(data, copy);
}
#endif
}
}

55
tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs

@ -9,6 +9,27 @@ namespace SixLabors.ImageSharp.Tests
{
internal static class IccTestDataProfiles
{
public static readonly IccProfileId Header_Random_Id_Value = new IccProfileId(0x84A8D460, 0xC716B6F3, 0x9B0E4C3D, 0xAB95F838);
public static readonly IccProfileId Profile_Random_Id_Value = new IccProfileId(0x917D6DE6, 0x84C958D1, 0x3BB0F5BB, 0xADD1134F);
public static readonly byte[] Header_Random_Id_Array =
{
#if !NETSTANDARD1_1
0x84, 0xA8, 0xD4, 0x60, 0xC7, 0x16, 0xB6, 0xF3, 0x9B, 0x0E, 0x4C, 0x3D, 0xAB, 0x95, 0xF8, 0x38,
#else
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#endif
};
public static readonly byte[] Profile_Random_Id_Array =
{
#if !NETSTANDARD1_1
0x91, 0x7D, 0x6D, 0xE6, 0x84, 0xC9, 0x58, 0xD1, 0x3B, 0xB0, 0xF5, 0xBB, 0xAD, 0xD1, 0x13, 0x4F,
#else
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#endif
};
public static readonly IccProfileHeader Header_Random_Write = CreateHeaderRandomValue(
562, // should be overwritten
new IccProfileId(1, 2, 3, 4), // should be overwritten
@ -16,20 +37,13 @@ namespace SixLabors.ImageSharp.Tests
public static readonly IccProfileHeader Header_Random_Read = CreateHeaderRandomValue(132,
#if !NETSTANDARD1_1
new IccProfileId(2931428592, 418415738, 3086756963, 2237536530),
Header_Random_Id_Value,
#else
IccProfileId.Zero,
#endif
"acsp");
public static readonly byte[] Header_Random_Array = CreateHeaderRandomArray(132, 0, new byte[]
{
#if !NETSTANDARD1_1
0xAE, 0xBA, 0x0C, 0xF0, 0x18, 0xF0, 0x84, 0x7A, 0xB7, 0xFC, 0x2C, 0x63, 0x85, 0x5E, 0x19, 0x12,
#else
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#endif
});
public static readonly byte[] Header_Random_Array = CreateHeaderRandomArray(132, 0, Header_Random_Id_Array);
public static IccProfileHeader CreateHeaderRandomValue(uint size, IccProfileId id, string fileSignature)
{
@ -45,11 +59,7 @@ namespace SixLabors.ImageSharp.Tests
DeviceModel = 987654321u,
FileSignature = "acsp",
Flags = IccProfileFlag.Embedded | IccProfileFlag.Independent,
#if !NETSTANDARD1_1
Id = new IccProfileId(2931428592, 418415738, 3086756963, 2237536530),
#else
Id = IccProfileId.Zero,
#endif
Id = id,
PcsIlluminant = new Vector3(4, 5, 6),
PrimaryPlatformSignature = IccPrimaryPlatformType.MicrosoftCorporation,
ProfileConnectionSpace = IccColorSpaceType.CieXyz,
@ -94,14 +104,7 @@ namespace SixLabors.ImageSharp.Tests
});
}
public static byte[] Profile_Random_Array = ArrayHelper.Concat(CreateHeaderRandomArray(168, 2, new byte[]
{
#if !NETSTANDARD1_1
0xA9, 0x71, 0x8F, 0xC1, 0x1E, 0x2D, 0x64, 0x1B, 0x10, 0xF4, 0x7D, 0x6A, 0x5B, 0xF6, 0xAC, 0xB9
#else
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#endif
}),
public static byte[] Profile_Random_Array = ArrayHelper.Concat(CreateHeaderRandomArray(168, 2, Profile_Random_Id_Array),
new byte[]
{
0x00, 0x00, 0x00, 0x00, // tag signature (Unknown)
@ -118,7 +121,7 @@ namespace SixLabors.ImageSharp.Tests
public static IccProfile Profile_Random_Val = new IccProfile(CreateHeaderRandomValue(168,
#if !NETSTANDARD1_1
new IccProfileId(0xA9718FC1, 0x1E2D641B, 0x10F47D6A, 0x5BF6ACB9),
Profile_Random_Id_Value,
#else
IccProfileId.Zero,
#endif
@ -128,5 +131,11 @@ namespace SixLabors.ImageSharp.Tests
IccTestDataTagDataEntry.Unknown_Val,
IccTestDataTagDataEntry.Unknown_Val
});
public static object[][] ProfileIdTestData =
{
new object[] { Header_Random_Array, Header_Random_Id_Value },
new object[] { Profile_Random_Array, Profile_Random_Id_Value },
};
}
}

Loading…
Cancel
Save