Browse Source

Merge pull request #249 from JBildstein/iccreadwrite-improve

Read and write duplicate ICC tag data entries only once
af/merge-core
James Jackson-South 9 years ago
committed by GitHub
parent
commit
c8579dc359
  1. 16
      src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs
  2. 25
      src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs
  3. 14
      tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs
  4. 12
      tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccWriterTests.cs
  5. 103
      tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs

16
src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs

@ -5,6 +5,8 @@
namespace ImageSharp namespace ImageSharp
{ {
using System.Collections.Generic;
/// <summary> /// <summary>
/// Reads and parses ICC data from a byte array /// Reads and parses ICC data from a byte array
/// </summary> /// </summary>
@ -85,9 +87,21 @@ namespace ImageSharp
{ {
IccTagTableEntry[] tagTable = this.ReadTagTable(reader); IccTagTableEntry[] tagTable = this.ReadTagTable(reader);
IccTagDataEntry[] entries = new IccTagDataEntry[tagTable.Length]; IccTagDataEntry[] entries = new IccTagDataEntry[tagTable.Length];
var store = new Dictionary<uint, IccTagDataEntry>();
for (int i = 0; i < tagTable.Length; i++) for (int i = 0; i < tagTable.Length; i++)
{ {
IccTagDataEntry entry = reader.ReadTagDataEntry(tagTable[i]); IccTagDataEntry entry;
uint offset = tagTable[i].Offset;
if (store.ContainsKey(offset))
{
entry = store[offset];
}
else
{
entry = reader.ReadTagDataEntry(tagTable[i]);
store.Add(offset, entry);
}
entry.TagSignature = tagTable[i].Signature; entry.TagSignature = tagTable[i].Signature;
entries[i] = entry; entries[i] = entry;
} }

25
src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs

@ -5,6 +5,7 @@
namespace ImageSharp namespace ImageSharp
{ {
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -76,30 +77,18 @@ namespace ImageSharp
private IccTagTableEntry[] WriteTagData(IccDataWriter writer, List<IccTagDataEntry> entries) private IccTagTableEntry[] WriteTagData(IccDataWriter writer, List<IccTagDataEntry> entries)
{ {
var inData = new List<IccTagDataEntry>(entries); IEnumerable<IGrouping<IccTagDataEntry, IccTagDataEntry>> grouped = entries.GroupBy(t => t);
var dupData = new List<IccTagDataEntry[]>();
while (inData.Count > 0)
{
IccTagDataEntry[] items = inData.Where(t => inData[0].Equals(t)).ToArray();
dupData.Add(items);
foreach (IccTagDataEntry item in items)
{
inData.Remove(item);
}
}
var table = new List<IccTagTableEntry>();
// (Header size) + (entry count) + (nr of entries) * (size of table entry) // (Header size) + (entry count) + (nr of entries) * (size of table entry)
writer.SetIndex(128 + 4 + (entries.Count * 12)); writer.SetIndex(128 + 4 + (entries.Count * 12));
foreach (IccTagDataEntry[] entry in dupData) var table = new List<IccTagTableEntry>();
foreach (IGrouping<IccTagDataEntry, IccTagDataEntry> group in grouped)
{ {
writer.WriteTagDataEntry(entry[0], out IccTagTableEntry tentry); writer.WriteTagDataEntry(group.Key, out IccTagTableEntry tableEntry);
foreach (IccTagDataEntry item in entry) foreach (IccTagDataEntry item in group)
{ {
table.Add(new IccTagTableEntry(item.TagSignature, tentry.Offset, tentry.DataSize)); table.Add(new IccTagTableEntry(item.TagSignature, tableEntry.Offset, tableEntry.DataSize));
} }
} }

14
tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs

@ -10,7 +10,7 @@ namespace ImageSharp.Tests.Icc
public class IccReaderTests public class IccReaderTests
{ {
[Fact] [Fact]
public void ReadProfile() public void ReadProfile_NoEntries()
{ {
IccReader reader = CreateReader(); IccReader reader = CreateReader();
@ -40,6 +40,18 @@ namespace ImageSharp.Tests.Icc
Assert.Equal(header.Version, expected.Version); Assert.Equal(header.Version, expected.Version);
} }
[Fact]
public void ReadProfile_DuplicateEntry()
{
IccReader reader = CreateReader();
IccProfile output = reader.Read(IccTestDataProfiles.Profile_Random_Array);
Assert.Equal(2, output.Entries.Count);
Assert.True(ReferenceEquals(output.Entries[0], output.Entries[1]));
}
private IccReader CreateReader() private IccReader CreateReader()
{ {
return new IccReader(); return new IccReader();

12
tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccWriterTests.cs

@ -10,7 +10,7 @@ namespace ImageSharp.Tests.Icc
public class IccWriterTests public class IccWriterTests
{ {
[Fact] [Fact]
public void WriteProfile() public void WriteProfile_NoEntries()
{ {
IccWriter writer = CreateWriter(); IccWriter writer = CreateWriter();
@ -23,6 +23,16 @@ namespace ImageSharp.Tests.Icc
Assert.Equal(IccTestDataProfiles.Header_Random_Array, output); Assert.Equal(IccTestDataProfiles.Header_Random_Array, output);
} }
[Fact]
public void WriteProfile_DuplicateEntry()
{
IccWriter writer = CreateWriter();
byte[] output = writer.Write(IccTestDataProfiles.Profile_Random_Val);
Assert.Equal(IccTestDataProfiles.Profile_Random_Array, output);
}
private IccWriter CreateWriter() private IccWriter CreateWriter()
{ {
return new IccWriter(); return new IccWriter();

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

@ -10,28 +10,31 @@ namespace ImageSharp.Tests
{ {
internal static class IccTestDataProfiles internal static class IccTestDataProfiles
{ {
public static readonly IccProfileHeader Header_Random_Write = new IccProfileHeader public static readonly IccProfileHeader Header_Random_Write = CreateHeaderRandomValue(
562, // should be overwritten
new IccProfileId(1, 2, 3, 4), // should be overwritten
"ijkl"); // should be overwritten to "acsp"
public static readonly IccProfileHeader Header_Random_Read = CreateHeaderRandomValue(132,
#if !NETSTANDARD1_1
new IccProfileId(2931428592, 418415738, 3086756963, 2237536530),
#else
IccProfileId.Zero,
#endif
"acsp");
public static readonly byte[] Header_Random_Array = CreateHeaderRandomArray(132, 0, new byte[]
{ {
Class = IccProfileClass.DisplayDevice, #if !NETSTANDARD1_1
CmmType = "abcd", 0xAE, 0xBA, 0x0C, 0xF0, 0x18, 0xF0, 0x84, 0x7A, 0xB7, 0xFC, 0x2C, 0x63, 0x85, 0x5E, 0x19, 0x12,
CreationDate = new DateTime(1990, 11, 26, 7, 21, 42), #else
CreatorSignature = "dcba", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
DataColorSpace = IccColorSpaceType.Rgb, #endif
DeviceAttributes = IccDeviceAttribute.ChromaBlackWhite | IccDeviceAttribute.OpacityTransparent, });
DeviceManufacturer = 123456789u,
DeviceModel = 987654321u,
FileSignature = "ijkl", // should be overwritten to "acsp"
Flags = IccProfileFlag.Embedded | IccProfileFlag.Independent,
Id = new IccProfileId(1, 2, 3, 4), // should be overwritten
PcsIlluminant = new Vector3(4, 5, 6),
PrimaryPlatformSignature = IccPrimaryPlatformType.MicrosoftCorporation,
ProfileConnectionSpace = IccColorSpaceType.CieXyz,
RenderingIntent = IccRenderingIntent.AbsoluteColorimetric,
Size = 562, // should be overwritten
Version = new Version(4, 3, 0),
};
public static readonly IccProfileHeader Header_Random_Read = new IccProfileHeader public static IccProfileHeader CreateHeaderRandomValue(uint size, IccProfileId id, string fileSignature)
{
return new IccProfileHeader
{ {
Class = IccProfileClass.DisplayDevice, Class = IccProfileClass.DisplayDevice,
CmmType = "abcd", CmmType = "abcd",
@ -52,13 +55,17 @@ namespace ImageSharp.Tests
PrimaryPlatformSignature = IccPrimaryPlatformType.MicrosoftCorporation, PrimaryPlatformSignature = IccPrimaryPlatformType.MicrosoftCorporation,
ProfileConnectionSpace = IccColorSpaceType.CieXyz, ProfileConnectionSpace = IccColorSpaceType.CieXyz,
RenderingIntent = IccRenderingIntent.AbsoluteColorimetric, RenderingIntent = IccRenderingIntent.AbsoluteColorimetric,
Size = 132, Size = size,
Version = new Version(4, 3, 0), Version = new Version(4, 3, 0),
}; };
}
public static readonly byte[] Header_Random_Array = public static byte[] CreateHeaderRandomArray(uint size, uint nrOfEntries, byte[] profileId)
{
return ArrayHelper.Concat(
new byte[]
{ {
0x00, 0x00, 0x00, 0x84, // Size (132) (byte)(size >> 24), (byte)(size >> 16), (byte)(size >> 8), (byte)size, // Size
0x61, 0x62, 0x63, 0x64, // CmmType 0x61, 0x62, 0x63, 0x64, // CmmType
0x04, 0x30, 0x00, 0x00, // Version 0x04, 0x30, 0x00, 0x00, // Version
0x6D, 0x6E, 0x74, 0x72, // Class 0x6D, 0x6E, 0x74, 0x72, // Class
@ -74,19 +81,53 @@ namespace ImageSharp.Tests
0x00, 0x00, 0x00, 0x03, // RenderingIntent 0x00, 0x00, 0x00, 0x03, // RenderingIntent
0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, // PcsIlluminant 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, // PcsIlluminant
0x64, 0x63, 0x62, 0x61, // CreatorSignature 0x64, 0x63, 0x62, 0x61, // CreatorSignature
},
#if !NETSTANDARD1_1 profileId,
0xAE, 0xBA, 0x0C, 0xF0, 0x18, 0xF0, 0x84, 0x7A, 0xB7, 0xFC, 0x2C, 0x63, 0x85, 0x5E, 0x19, 0x12, // Id new byte[]
#else {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Id
#endif
// Padding // Padding
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Nr of tag table entries (0) // Nr of tag table entries (0)
0x00, 0x00, 0x00, 0x00, (byte)(nrOfEntries >> 24), (byte)(nrOfEntries >> 16), (byte)(nrOfEntries >> 8), (byte)nrOfEntries
}; });
}
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
}),
new byte[]
{
0x00, 0x00, 0x00, 0x00, // tag signature (Unknown)
0x00, 0x00, 0x00, 0x9C, // tag offset (156)
0x00, 0x00, 0x00, 0x0C, // tag size (12)
0x00, 0x00, 0x00, 0x00, // tag signature (Unknown)
0x00, 0x00, 0x00, 0x9C, // tag offset (156)
0x00, 0x00, 0x00, 0x0C, // tag size (12)
},
IccTestDataTagDataEntry.TagDataEntryHeader_UnknownArr,
IccTestDataTagDataEntry.Unknown_Arr
);
public static IccProfile Profile_Random_Val = new IccProfile(CreateHeaderRandomValue(168,
#if !NETSTANDARD1_1
new IccProfileId(0xA9718FC1, 0x1E2D641B, 0x10F47D6A, 0x5BF6ACB9),
#else
IccProfileId.Zero,
#endif
"acsp"),
new IccTagDataEntry[]
{
IccTestDataTagDataEntry.Unknown_Val,
IccTestDataTagDataEntry.Unknown_Val
});
} }
} }

Loading…
Cancel
Save