diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
index fc2a9130e..13c51db24 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
@@ -1000,7 +1000,14 @@ namespace ImageSharp.Formats
byte[] profile = new byte[remaining];
this.InputProcessor.ReadFull(profile, 0, remaining);
- metadata.IccProfiles.Add(new IccProfile(profile));
+ if (metadata.IccProfile == null)
+ {
+ metadata.IccProfile = new IccProfile(profile);
+ }
+ else
+ {
+ metadata.IccProfile.Extend(profile);
+ }
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
index 4dddd25ed..b65a56e73 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
@@ -700,42 +700,60 @@ namespace ImageSharp.Formats
}
///
- /// Writes the ICC profiles.
+ /// Writes the ICC profile.
///
- /// The list of ICC profiles.
+ /// The ICC profile to write.
///
/// Thrown if any of the ICC profiles size exceeds the limit
///
- private void WriteICCProfiles(IList iccProfiles)
+ private void WriteIccProfile(IccProfile iccProfile)
{
// Just incase someone set the value to null by accident.
- if (iccProfiles == null || !iccProfiles.Any())
+ if (iccProfile == null)
{
return;
}
+ const int IccOverheadLength = 14;
const int Max = 65533;
- int count = iccProfiles.Count;
+ const int MaxData = Max - IccOverheadLength;
- for (int i = 1; i <= count; i++)
+ byte[] data = iccProfile.ToByteArray();
+
+ if (data == null || data.Length == 0)
{
- byte[] data = iccProfiles[i - 1]?.ToByteArray();
+ return;
+ }
- if (data == null || data.Length == 0)
- {
- continue;
- }
+ // Calculate the number of markers we'll need, rounding up of course
+ int dataLength = data.Length;
+ int count = dataLength / MaxData;
- if (data.Length > Max)
+ if (count * MaxData != dataLength)
+ {
+ count++;
+ }
+
+ // Per spec, counting starts at 1.
+ int current = 1;
+ int offset = 0;
+
+ while (dataLength > 0)
+ {
+ int length = dataLength; // Number of bytes to write.
+
+ if (length > MaxData)
{
- throw new ImageFormatException($"ICC profile size exceeds limit. nameof{Max}");
+ length = MaxData;
}
+ dataLength -= length;
+
this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = JpegConstants.Markers.APP2; // Application Marker
- int length = data.Length + 16;
- this.buffer[2] = (byte)((length >> 8) & 0xFF);
- this.buffer[3] = (byte)(length & 0xFF);
+ int markerLength = length + 16;
+ this.buffer[2] = (byte)((markerLength >> 8) & 0xFF);
+ this.buffer[3] = (byte)(markerLength & 0xFF);
this.outputStream.Write(this.buffer, 0, 4);
@@ -751,11 +769,14 @@ namespace ImageSharp.Formats
this.buffer[9] = (byte)'L';
this.buffer[10] = (byte)'E';
this.buffer[11] = 0x00;
- this.buffer[12] = (byte)i; // The position within the collection.
+ this.buffer[12] = (byte)current; // The position within the collection.
this.buffer[13] = (byte)count; // The total number of profiles.
- this.outputStream.Write(this.buffer, 0, 14);
- this.outputStream.Write(data, 0, data.Length);
+ this.outputStream.Write(this.buffer, 0, IccOverheadLength);
+ this.outputStream.Write(data, offset, length);
+
+ current++;
+ offset += length;
}
}
@@ -774,7 +795,7 @@ namespace ImageSharp.Formats
image.MetaData.SyncProfiles();
this.WriteExifProfile(image.MetaData.ExifProfile);
- this.WriteICCProfiles(image.MetaData.IccProfiles);
+ this.WriteIccProfile(image.MetaData.IccProfile);
}
///
diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs
index b02dc6270..91ea9ac4b 100644
--- a/src/ImageSharp/MetaData/ImageMetaData.cs
+++ b/src/ImageSharp/MetaData/ImageMetaData.cs
@@ -6,7 +6,6 @@
namespace ImageSharp
{
using System.Collections.Generic;
- using System.Linq;
using ImageSharp.Formats;
///
@@ -61,36 +60,23 @@ namespace ImageSharp
this.Properties.Add(new ImageProperty(property));
}
- if (other.ExifProfile != null)
- {
- this.ExifProfile = new ExifProfile(other.ExifProfile);
- }
- else
- {
- this.ExifProfile = null;
- }
+ this.ExifProfile = other.ExifProfile != null
+ ? new ExifProfile(other.ExifProfile)
+ : null;
- if (other.IccProfiles != null && other.IccProfiles.Any())
- {
- this.IccProfiles = new List(other.IccProfiles);
- }
- else
- {
- this.IccProfiles = new List();
- }
+ this.IccProfile = other.IccProfile != null
+ ? new IccProfile(other.IccProfile)
+ : null;
}
///
- /// Gets or sets the resolution of the image in x- direction. It is defined as
- /// number of dots per inch and should be an positive value.
+ /// Gets or sets the resolution of the image in x- direction.
+ /// It is defined as the number of dots per inch and should be an positive value.
///
/// The density of the image in x- direction.
public double HorizontalResolution
{
- get
- {
- return this.horizontalResolution;
- }
+ get => this.horizontalResolution;
set
{
@@ -102,16 +88,13 @@ namespace ImageSharp
}
///
- /// Gets or sets the resolution of the image in y- direction. It is defined as
- /// number of dots per inch and should be an positive value.
+ /// Gets or sets the resolution of the image in y- direction.
+ /// It is defined as the number of dots per inch and should be an positive value.
///
/// The density of the image in y- direction.
public double VerticalResolution
{
- get
- {
- return this.verticalResolution;
- }
+ get => this.verticalResolution;
set
{
@@ -130,7 +113,7 @@ namespace ImageSharp
///
/// Gets or sets the list of ICC profiles.
///
- public IList IccProfiles { get; set; } = new List();
+ public IccProfile IccProfile { get; set; }
///
public int FrameDelay { get; set; }
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs
index e00604416..13a15b483 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs
@@ -7,6 +7,8 @@ namespace ImageSharp
{
using System.Numerics;
+ using ImageSharp.Memory;
+
///
/// Provides methods to write ICC data types
///
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs
index 2701ffcb1..978d5bc24 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs
@@ -5,9 +5,9 @@
namespace ImageSharp
{
+ using System;
using System.Collections.Generic;
#if !NETSTANDARD1_1
- using System;
using System.Security.Cryptography;
#endif
@@ -19,7 +19,7 @@ namespace ImageSharp
///
/// The byte array to read the ICC profile from
///
- private readonly byte[] data;
+ private byte[] data;
///
/// The backing file for the property
@@ -35,7 +35,7 @@ namespace ImageSharp
/// Initializes a new instance of the class.
///
public IccProfile()
- : this(null)
+ : this((byte[])null)
{
}
@@ -48,6 +48,20 @@ namespace ImageSharp
this.data = data;
}
+ ///
+ /// Initializes a new instance of the class
+ /// by making a copy from another ICC profile.
+ ///
+ /// The other ICC profile, where the clone should be made from.
+ /// is null.>
+ public IccProfile(IccProfile other)
+ {
+ Guard.NotNull(other, nameof(other));
+
+ // TODO: Do we need to copy anything else?
+ this.data = other.data;
+ }
+
///
/// Initializes a new instance of the class.
///
@@ -73,10 +87,7 @@ namespace ImageSharp
return this.header;
}
- set
- {
- this.header = value;
- }
+ set => this.header = value;
}
///
@@ -106,7 +117,7 @@ namespace ImageSharp
byte[] header = new byte[128];
Buffer.BlockCopy(data, 0, header, 0, 128);
- using (MD5 md5 = MD5.Create())
+ using (var md5 = MD5.Create())
{
// Zero out some values
Array.Clear(header, 44, 4); // Profile flags
@@ -117,20 +128,31 @@ namespace ImageSharp
byte[] hash = md5.ComputeHash(data);
// Read values from hash
- IccDataReader reader = new IccDataReader(hash);
+ var reader = new IccDataReader(hash);
return reader.ReadProfileId();
}
}
#endif
+ ///
+ /// Extends the profile with additional data.
+ ///
+ /// The array containing addition profile data.
+ public void Extend(byte[] bytes)
+ {
+ int currentLength = this.data.Length;
+ Array.Resize(ref this.data, currentLength + bytes.Length);
+ Buffer.BlockCopy(bytes, 0, this.data, currentLength, bytes.Length);
+ }
+
///
/// Converts this instance to a byte array.
///
/// The
public byte[] ToByteArray()
{
- IccWriter writer = new IccWriter();
+ var writer = new IccWriter();
return writer.Write(this);
}
@@ -147,7 +169,7 @@ namespace ImageSharp
return;
}
- IccReader reader = new IccReader();
+ var reader = new IccReader();
this.header = reader.ReadHeader(this.data);
}
@@ -164,7 +186,7 @@ namespace ImageSharp
return;
}
- IccReader reader = new IccReader();
+ var reader = new IccReader();
this.entries = new List(reader.ReadTagData(this.data));
}
}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccMatrixProcessElement.cs b/src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccMatrixProcessElement.cs
index e4f5362b4..259f71489 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccMatrixProcessElement.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccMatrixProcessElement.cs
@@ -8,6 +8,8 @@ namespace ImageSharp
using System;
using System.Linq;
+ using ImageSharp.Memory;
+
///
/// A matrix element to process data
///
diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.MatrixTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.MatrixTests.cs
index b254f3c2c..61b5d57ff 100644
--- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.MatrixTests.cs
+++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.MatrixTests.cs
@@ -6,6 +6,9 @@
namespace ImageSharp.Tests.Icc
{
using System.Numerics;
+
+ using ImageSharp.Memory;
+
using Xunit;
public class IccDataWriterMatrixTests
diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataMatrix.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataMatrix.cs
index 0a1be5154..78e493829 100644
--- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataMatrix.cs
+++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataMatrix.cs
@@ -7,6 +7,8 @@ using System.Numerics;
namespace ImageSharp.Tests
{
+ using ImageSharp.Memory;
+
internal static class IccTestDataMatrix
{
#region 2D