Browse Source

Align ICC and EXIF API.

af/merge-core
James Jackson-South 8 years ago
parent
commit
d7f6badc19
  1. 80
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  2. 11
      src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs

80
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
private ushort resetInterval; private ushort resetInterval;
/// <summary> /// <summary>
/// Whether the image has a EXIF header /// Whether the image has an EXIF marker
/// </summary> /// </summary>
private bool isExif; private bool isExif;
@ -79,6 +79,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </summary> /// </summary>
private byte[] exifData; private byte[] exifData;
/// <summary>
/// Whether the image has an ICC marker
/// </summary>
private bool isIcc;
/// <summary>
/// Contains ICC data
/// </summary>
private byte[] iccData;
/// <summary> /// <summary>
/// Contains information about the JFIF marker /// Contains information about the JFIF marker
/// </summary> /// </summary>
@ -208,6 +218,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
{ {
this.ParseStream(stream); this.ParseStream(stream);
this.InitExifProfile(); this.InitExifProfile();
this.InitIccProfile();
this.InitDerivedMetaDataProperties(); this.InitDerivedMetaDataProperties();
return this.PostProcessIntoImage<TPixel>(); return this.PostProcessIntoImage<TPixel>();
} }
@ -220,6 +231,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
{ {
this.ParseStream(stream, true); this.ParseStream(stream, true);
this.InitExifProfile(); this.InitExifProfile();
this.InitIccProfile();
this.InitDerivedMetaDataProperties(); this.InitDerivedMetaDataProperties();
return new ImageInfo(new PixelTypeInfo(this.BitsPerPixel), this.ImageWidth, this.ImageHeight, this.MetaData); return new ImageInfo(new PixelTypeInfo(this.BitsPerPixel), this.ImageWidth, this.ImageHeight, this.MetaData);
} }
@ -412,7 +424,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
} }
/// <summary> /// <summary>
/// Initializes the exif profile. /// Initializes the EXIF profile.
/// </summary> /// </summary>
private void InitExifProfile() private void InitExifProfile()
{ {
@ -422,6 +434,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
} }
} }
/// <summary>
/// Initializes the ICC profile.
/// </summary>
private void InitIccProfile()
{
if (this.isIcc)
{
var profile = new IccProfile(this.iccData);
if (profile.CheckIsValid())
{
this.MetaData.IccProfile = profile;
}
}
}
/// <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>
@ -450,11 +477,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
this.MetaData.ResolutionUnits = UnitConverter.ExifProfileToResolutionUnit(this.MetaData.ExifProfile); this.MetaData.ResolutionUnits = UnitConverter.ExifProfileToResolutionUnit(this.MetaData.ExifProfile);
} }
} }
}
if (this.MetaData.IccProfile?.CheckIsValid() == false) /// <summary>
{ /// Extends the profile with additional data.
this.MetaData.IccProfile = null; /// </summary>
} /// <param name="profile">The profile data array.</param>
/// <param name="extension">The array containing addition profile data.</param>
private void ExtendProfile(ref byte[] profile, byte[] extension)
{
int currentLength = profile.Length;
Array.Resize(ref profile, currentLength + extension.Length);
Buffer.BlockCopy(extension, 0, profile, currentLength, extension.Length);
} }
/// <summary> /// <summary>
@ -488,7 +523,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <param name="remaining">The remaining bytes in the segment block.</param> /// <param name="remaining">The remaining bytes in the segment block.</param>
private void ProcessApp1Marker(int remaining) private void ProcessApp1Marker(int remaining)
{ {
if (remaining < 6 || this.IgnoreMetadata) const int Exif00 = 6;
if (remaining < Exif00 || this.IgnoreMetadata)
{ {
// Skip the application header length // Skip the application header length
this.InputStream.Skip(remaining); this.InputStream.Skip(remaining);
@ -503,29 +539,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
this.isExif = true; this.isExif = true;
if (this.exifData == null) if (this.exifData == null)
{ {
// the first 6 bytes (Exif00) will be skipped, because this is Jpeg specific // The first 6 bytes (Exif00) will be skipped, because this is Jpeg specific
this.exifData = profile.Skip(6).ToArray(); this.exifData = profile.Skip(Exif00).ToArray();
} }
else else
{ {
// if the exif information exceeds 64K, it will be split over multiple APP1 markers // If the EXIF information exceeds 64K, it will be split over multiple APP1 markers
this.ExtendExif(profile.Skip(6).ToArray()); this.ExtendProfile(ref this.exifData, profile.Skip(Exif00).ToArray());
} }
} }
} }
/// <summary>
/// Extends the exif profile with additional data.
/// </summary>
/// <param name="bytes">The array containing addition profile data.</param>
private void ExtendExif(byte[] bytes)
{
int currentLength = this.exifData.Length;
Array.Resize(ref this.exifData, currentLength + bytes.Length);
Buffer.BlockCopy(bytes, 0, this.exifData, currentLength, bytes.Length);
}
/// <summary> /// <summary>
/// Processes the App2 marker retrieving any stored ICC profile information /// Processes the App2 marker retrieving any stored ICC profile information
/// </summary> /// </summary>
@ -546,16 +570,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
if (ProfileResolver.IsProfile(identifier, ProfileResolver.IccMarker)) if (ProfileResolver.IsProfile(identifier, ProfileResolver.IccMarker))
{ {
this.isIcc = true;
byte[] profile = new byte[remaining]; byte[] profile = new byte[remaining];
this.InputStream.Read(profile, 0, remaining); this.InputStream.Read(profile, 0, remaining);
if (this.MetaData.IccProfile == null) if (this.iccData == null)
{ {
this.MetaData.IccProfile = new IccProfile(profile); this.iccData = profile;
} }
else else
{ {
this.MetaData.IccProfile.Extend(profile); // If the ICC information exceeds 64K, it will be split over multiple APP2 markers
this.ExtendProfile(ref this.iccData, profile);
} }
} }
else else
@ -670,7 +696,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <param name="remaining">The remaining bytes in the segment block.</param> /// <param name="remaining">The remaining bytes in the segment block.</param>
/// <param name="frameMarker">The current frame marker.</param> /// <param name="frameMarker">The current frame marker.</param>
/// <param name="metadataOnly">Whether to parse metadata only</param> /// <param name="metadataOnly">Whether to parse metadata only</param>
private void ProcessStartOfFrameMarker(int remaining, JpegFileMarker frameMarker, bool metadataOnly) private void ProcessStartOfFrameMarker(int remaining, in JpegFileMarker frameMarker, bool metadataOnly)
{ {
if (this.Frame != null) if (this.Frame != null)
{ {

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

@ -149,17 +149,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
#endif #endif
/// <summary>
/// Extends the profile with additional data.
/// </summary>
/// <param name="bytes">The array containing addition profile data.</param>
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);
}
/// <summary> /// <summary>
/// Checks for signs of a corrupt profile. /// Checks for signs of a corrupt profile.
/// </summary> /// </summary>

Loading…
Cancel
Save