Browse Source

Added component count proper check, comments & decoupled it from actual decoding

pull/1702/head
Dmitry Pentin 5 years ago
parent
commit
24b1ca64d1
  1. 5
      src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs
  2. 5
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs
  3. 43
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  4. 4
      tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs

5
src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs

@ -16,11 +16,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// </summary>
Size ImageSizeInPixels { get; }
/// <summary>
/// Gets the number of components.
/// </summary>
int ComponentCount { get; }
/// <summary>
/// Gets the color space
/// </summary>

5
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs

@ -84,6 +84,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// </summary>
public int McusPerColumn { get; set; }
/// <summary>
/// Gets the color depth, in number of bits per pixel.
/// </summary>
public int BitsPerPixel => this.ComponentCount * this.Precision;
/// <inheritdoc/>
public void Dispose()
{

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

@ -127,11 +127,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </summary>
public int ImageHeight => this.ImageSizeInPixels.Height;
/// <summary>
/// Gets the color depth, in number of bits per pixel.
/// </summary>
public int BitsPerPixel => this.ComponentCount * this.Frame.Precision;
/// <summary>
/// Gets a value indicating whether the metadata should be ignored when the image is being decoded.
/// </summary>
@ -142,9 +137,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </summary>
public ImageMetadata Metadata { get; private set; }
/// <inheritdoc/>
public int ComponentCount { get; private set; }
/// <inheritdoc/>
public JpegColorSpace ColorSpace { get; private set; }
@ -222,7 +214,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
this.InitIptcProfile();
this.InitDerivedMetadataProperties();
return new ImageInfo(new PixelTypeInfo(this.BitsPerPixel), this.ImageWidth, this.ImageHeight, this.Metadata);
return new ImageInfo(new PixelTypeInfo(this.Frame.BitsPerPixel), this.ImageWidth, this.ImageHeight, this.Metadata);
}
/// <summary>
@ -373,14 +365,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// Returns the correct colorspace based on the image component count
/// </summary>
/// <returns>The <see cref="JpegColorSpace"/></returns>
private JpegColorSpace DeduceJpegColorSpace()
private JpegColorSpace DeduceJpegColorSpace(byte componentCount)
{
if (this.ComponentCount == 1)
if (componentCount == 1)
{
return JpegColorSpace.Grayscale;
}
if (this.ComponentCount == 3)
if (componentCount == 3)
{
if (!this.adobe.Equals(default) && this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
{
@ -392,14 +384,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
return JpegColorSpace.YCbCr;
}
if (this.ComponentCount == 4)
if (componentCount == 4)
{
return this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYcck
? JpegColorSpace.Ycck
: JpegColorSpace.Cmyk;
}
JpegThrowHelper.ThrowInvalidImageContentException($"Unsupported color mode. Supported component counts 1, 3, and 4; found {this.ComponentCount}");
JpegThrowHelper.ThrowInvalidImageContentException($"Unsupported color mode. Supported component counts 1, 3, and 4; found {componentCount}");
return default;
}
@ -835,18 +827,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
JpegThrowHelper.ThrowInvalidImageContentException("Only 8-Bit and 12-Bit precision supported.");
}
// 2 byte: height
// 2 byte: Height
int frameHeight = (this.temp[1] << 8) | this.temp[2];
// 2 byte: width
// 2 byte: Width
int frameWidth = (this.temp[3] << 8) | this.temp[4];
// Validity check: width/height > 0 (they are upper-bounded by 2 byte max value so no need to check that)
if (frameHeight == 0 || frameWidth == 0)
{
JpegThrowHelper.ThrowInvalidImageDimensions(this.Frame.PixelWidth, this.Frame.PixelHeight);
JpegThrowHelper.ThrowInvalidImageDimensions(frameWidth, frameHeight);
}
// 1 byte: Number of components
byte componentCount = this.temp[5];
this.ColorSpace = this.DeduceJpegColorSpace(componentCount);
this.Frame = new JpegFrame
{
@ -855,13 +850,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
Precision = precision,
PixelHeight = frameHeight,
PixelWidth = frameWidth,
ComponentCount = this.temp[5]
ComponentCount = componentCount
};
this.ImageSizeInPixels = new Size(this.Frame.PixelWidth, this.Frame.PixelHeight);
this.ComponentCount = this.Frame.ComponentCount;
this.ColorSpace = this.DeduceJpegColorSpace();
this.Metadata.GetJpegMetadata().ColorType = this.ColorSpace == JpegColorSpace.Grayscale ? JpegColorType.Luminance : JpegColorType.YCbCr;
if (!metadataOnly)
@ -869,7 +862,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
remaining -= length;
const int componentBytes = 3;
if (remaining > this.ComponentCount * componentBytes)
if (remaining > componentCount * componentBytes)
{
JpegThrowHelper.ThrowBadMarker("SOFn", remaining);
}
@ -877,14 +870,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
stream.Read(this.temp, 0, remaining);
// No need to pool this. They max out at 4
this.Frame.ComponentIds = new byte[this.ComponentCount];
this.Frame.ComponentOrder = new byte[this.ComponentCount];
this.Frame.Components = new JpegComponent[this.ComponentCount];
this.Frame.ComponentIds = new byte[componentCount];
this.Frame.ComponentOrder = new byte[componentCount];
this.Frame.Components = new JpegComponent[componentCount];
int maxH = 0;
int maxV = 0;
int index = 0;
for (int i = 0; i < this.ComponentCount; i++)
for (int i = 0; i < componentCount; i++)
{
byte hv = this.temp[index + 1];
int h = (hv >> 4) & 15;

4
tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs

@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(TestImages.Jpeg.Baseline.Jpeg400))
{
Assert.Equal(1, decoder.ComponentCount);
Assert.Equal(1, decoder.Frame.ComponentCount);
Assert.Equal(1, decoder.Components.Length);
Size expectedSizeInBlocks = decoder.ImageSizeInPixels.DivideRoundUp(8);
@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile))
{
Assert.Equal(componentCount, decoder.ComponentCount);
Assert.Equal(componentCount, decoder.Frame.ComponentCount);
Assert.Equal(componentCount, decoder.Components.Length);
JpegComponent c0 = decoder.Components[0];

Loading…
Cancel
Save