|
|
|
@ -407,10 +407,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Returns the correct colorspace based on the image component count.
|
|
|
|
/// Returns the correct colorspace based on the image component count and the jpeg frame component id's.
|
|
|
|
/// </summary>
|
|
|
|
/// <returns>The <see cref="JpegColorSpace"/></returns>
|
|
|
|
private JpegColorSpace DeduceJpegColorSpace(byte componentCount) |
|
|
|
private JpegColorSpace DeduceJpegColorSpace(byte componentCount, JpegComponent[] components) |
|
|
|
{ |
|
|
|
if (componentCount == 1) |
|
|
|
{ |
|
|
|
@ -424,6 +424,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg |
|
|
|
return JpegColorSpace.RGB; |
|
|
|
} |
|
|
|
|
|
|
|
// If the component Id's are R, G, B in ASCII the colorspace is RGB and not YCbCr.
|
|
|
|
if (components[2].Id == 66 && components[1].Id == 71 && components[0].Id == 82) |
|
|
|
{ |
|
|
|
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; |
|
|
|
@ -898,60 +904,60 @@ namespace SixLabors.ImageSharp.Formats.Jpeg |
|
|
|
|
|
|
|
// 1 byte: Number of components
|
|
|
|
byte componentCount = this.temp[5]; |
|
|
|
this.ColorSpace = this.DeduceJpegColorSpace(componentCount); |
|
|
|
|
|
|
|
this.Metadata.GetJpegMetadata().ColorType = this.ColorSpace == JpegColorSpace.Grayscale ? JpegColorType.Luminance : JpegColorType.YCbCr; |
|
|
|
|
|
|
|
this.Frame = new JpegFrame(frameMarker, precision, frameWidth, frameHeight, componentCount); |
|
|
|
|
|
|
|
if (!metadataOnly) |
|
|
|
remaining -= length; |
|
|
|
|
|
|
|
// Validate: remaining part must be equal to components * 3
|
|
|
|
const int componentBytes = 3; |
|
|
|
if (remaining != componentCount * componentBytes) |
|
|
|
{ |
|
|
|
remaining -= length; |
|
|
|
JpegThrowHelper.ThrowBadMarker("SOFn", remaining); |
|
|
|
} |
|
|
|
|
|
|
|
// Validate: remaining part must be equal to components * 3
|
|
|
|
const int componentBytes = 3; |
|
|
|
if (remaining != componentCount * componentBytes) |
|
|
|
{ |
|
|
|
JpegThrowHelper.ThrowBadMarker("SOFn", remaining); |
|
|
|
} |
|
|
|
// components*3 bytes: component data
|
|
|
|
stream.Read(this.temp, 0, remaining); |
|
|
|
|
|
|
|
// No need to pool this. They max out at 4
|
|
|
|
this.Frame.ComponentIds = new byte[componentCount]; |
|
|
|
this.Frame.ComponentOrder = new byte[componentCount]; |
|
|
|
this.Frame.Components = new JpegComponent[componentCount]; |
|
|
|
|
|
|
|
// components*3 bytes: component data
|
|
|
|
stream.Read(this.temp, 0, remaining); |
|
|
|
int maxH = 0; |
|
|
|
int maxV = 0; |
|
|
|
int index = 0; |
|
|
|
for (int i = 0; i < componentCount; i++) |
|
|
|
{ |
|
|
|
byte hv = this.temp[index + 1]; |
|
|
|
int h = (hv >> 4) & 15; |
|
|
|
int v = hv & 15; |
|
|
|
|
|
|
|
// No need to pool this. They max out at 4
|
|
|
|
this.Frame.ComponentIds = new byte[componentCount]; |
|
|
|
this.Frame.ComponentOrder = new byte[componentCount]; |
|
|
|
this.Frame.Components = new JpegComponent[componentCount]; |
|
|
|
if (maxH < h) |
|
|
|
{ |
|
|
|
maxH = h; |
|
|
|
} |
|
|
|
|
|
|
|
int maxH = 0; |
|
|
|
int maxV = 0; |
|
|
|
int index = 0; |
|
|
|
for (int i = 0; i < componentCount; i++) |
|
|
|
if (maxV < v) |
|
|
|
{ |
|
|
|
byte hv = this.temp[index + 1]; |
|
|
|
int h = (hv >> 4) & 15; |
|
|
|
int v = hv & 15; |
|
|
|
maxV = v; |
|
|
|
} |
|
|
|
|
|
|
|
if (maxH < h) |
|
|
|
{ |
|
|
|
maxH = h; |
|
|
|
} |
|
|
|
var component = new JpegComponent(this.Configuration.MemoryAllocator, this.Frame, this.temp[index], h, v, this.temp[index + 2], i); |
|
|
|
|
|
|
|
if (maxV < v) |
|
|
|
{ |
|
|
|
maxV = v; |
|
|
|
} |
|
|
|
this.Frame.Components[i] = component; |
|
|
|
this.Frame.ComponentIds[i] = component.Id; |
|
|
|
|
|
|
|
var component = new JpegComponent(this.Configuration.MemoryAllocator, this.Frame, this.temp[index], h, v, this.temp[index + 2], i); |
|
|
|
index += componentBytes; |
|
|
|
} |
|
|
|
|
|
|
|
this.Frame.Components[i] = component; |
|
|
|
this.Frame.ComponentIds[i] = component.Id; |
|
|
|
this.ColorSpace = this.DeduceJpegColorSpace(componentCount, this.Frame.Components); |
|
|
|
|
|
|
|
index += componentBytes; |
|
|
|
} |
|
|
|
this.Metadata.GetJpegMetadata().ColorType = this.ColorSpace == JpegColorSpace.Grayscale ? JpegColorType.Luminance : JpegColorType.YCbCr; |
|
|
|
|
|
|
|
if (!metadataOnly) |
|
|
|
{ |
|
|
|
this.Frame.Init(maxH, maxV); |
|
|
|
|
|
|
|
this.scanDecoder.InjectFrameData(this.Frame, this); |
|
|
|
} |
|
|
|
} |
|
|
|
|