Browse Source

Jpeg colorspace deduction fix

pull/2177/head
Dmitry Pentin 4 years ago
parent
commit
52ad9c67f6
  1. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
  2. 52
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

2
src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs

@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
} }
} }
var buffer = this.pixelBuffer; Buffer2D<TPixel> buffer = this.pixelBuffer;
this.pixelBuffer = null; this.pixelBuffer = null;
return buffer; return buffer;
} }

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

@ -90,11 +90,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </summary> /// </summary>
private JFifMarker jFif; private JFifMarker jFif;
/// <summary>
/// Whether the image has a JFIF marker. This is needed to determine, if the colorspace is YCbCr.
/// </summary>
private bool hasJFif;
/// <summary> /// <summary>
/// Contains information about the Adobe marker. /// Contains information about the Adobe marker.
/// </summary> /// </summary>
@ -516,8 +511,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
if (componentCount == 3) if (componentCount == 3)
{ {
// We prioritize adobe marker over jfif marker, if somebody really encoded this image with redundant adobe marker,
// then it's most likely an adobe jfif image.
if (!this.adobe.Equals(default)) if (!this.adobe.Equals(default))
{ {
if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYCbCr) if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYCbCr)
@ -529,51 +522,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
{ {
return JpegColorSpace.RGB; return JpegColorSpace.RGB;
} }
// Fallback to the id color deduction: If these values are 1-3 for a 3-channel image, then the image is assumed to be YCbCr.
if (this.Components[2].Id == 3 && this.Components[1].Id == 2 && this.Components[0].Id == 1)
{
return JpegColorSpace.YCbCr;
}
JpegThrowHelper.ThrowNotSupportedColorSpace();
}
if (this.hasJFif)
{
// JFIF implies YCbCr.
return JpegColorSpace.YCbCr;
} }
// Fallback to the id color deduction. // Fallback to YCbCr
// If the component Id's are R, G, B in ASCII the colorspace is RGB and not YCbCr.
// See: https://docs.oracle.com/javase/7/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html#color
if (this.Components[2].Id == 66 && this.Components[1].Id == 71 && this.Components[0].Id == 82)
{
return JpegColorSpace.RGB;
}
// If these values are 1-3 for a 3-channel image, then the image is assumed to be YCbCr.
if (this.Components[2].Id == 3 && this.Components[1].Id == 2 && this.Components[0].Id == 1)
{
return JpegColorSpace.YCbCr;
}
// 3-channel non-subsampled images are assumed to be RGB.
if (this.Components[2].VerticalSamplingFactor == 1 && this.Components[1].VerticalSamplingFactor == 1 && this.Components[0].VerticalSamplingFactor == 1 &&
this.Components[2].HorizontalSamplingFactor == 1 && this.Components[1].HorizontalSamplingFactor == 1 && this.Components[0].HorizontalSamplingFactor == 1)
{
return JpegColorSpace.RGB;
}
// Some images are poorly encoded and contain incorrect colorspace transform metadata.
// We ignore that and always fall back to the default colorspace.
return JpegColorSpace.YCbCr; return JpegColorSpace.YCbCr;
} }
if (componentCount == 4) if (componentCount == 4)
{ {
// jfif images doesn't not support 4 component images, so we only check adobe.
if (!this.adobe.Equals(default)) if (!this.adobe.Equals(default))
{ {
if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYcck) if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYcck)
@ -585,11 +541,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
{ {
return JpegColorSpace.Cmyk; return JpegColorSpace.Cmyk;
} }
JpegThrowHelper.ThrowNotSupportedColorSpace();
} }
// Fallback to cmyk as neither of cmyk nor ycck have 'special' component ids. // Fallback to CMYK
return JpegColorSpace.Cmyk; return JpegColorSpace.Cmyk;
} }
@ -757,8 +711,6 @@ 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 ProcessApplicationHeaderMarker(BufferedReadStream stream, int remaining) private void ProcessApplicationHeaderMarker(BufferedReadStream stream, int remaining)
{ {
this.hasJFif = true;
// We can only decode JFif identifiers. // We can only decode JFif identifiers.
// Some images contain multiple JFIF markers (Issue 1932) so we check to see // Some images contain multiple JFIF markers (Issue 1932) so we check to see
// if it's already been read. // if it's already been read.

Loading…
Cancel
Save