diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs
index a1fe6444b..ab376ee3c 100644
--- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs
+++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs
@@ -37,6 +37,11 @@ namespace ImageSharp.Formats.Jpg
///
private const int DcTableIndex = 0;
+ ///
+ /// The current component index
+ ///
+ public int ComponentIndex;
+
///
/// X coordinate of the current block, in units of 8x8. (The third block in the first row has (bx, by) = (2, 0))
///
@@ -72,11 +77,6 @@ namespace ImageSharp.Formats.Jpg
///
private int componentScanCount;
- ///
- /// The current component index
- ///
- private int componentIndex;
-
///
/// Horizontal sampling factor at the current component index
///
@@ -103,11 +103,23 @@ namespace ImageSharp.Formats.Jpg
/// Pointer to on the stack
/// The instance
/// The remaining bytes in the segment block.
- public static void Init(JpegScanDecoder* p, JpegDecoderCore decoder, int remaining)
+ public static void InitStreamReading(JpegScanDecoder* p, JpegDecoderCore decoder, int remaining)
+ {
+ Init(p);
+ p->InitStreamReadingImpl(decoder, remaining);
+ }
+
+ public static void Init(JpegScanDecoder* p)
{
p->data = ComputationData.Create();
p->pointers = new DataPointers(&p->data);
- p->InitImpl(decoder, remaining);
+ }
+
+ public void LoadMemento(ref DecodedBlockMemento memento)
+ {
+ this.bx = memento.Bx;
+ this.by = memento.By;
+ this.data.Block = memento.Block;
}
///
@@ -148,9 +160,9 @@ namespace ImageSharp.Formats.Jpg
{
for (int scanIndex = 0; scanIndex < this.componentScanCount; scanIndex++)
{
- this.componentIndex = this.pointers.ComponentScan[scanIndex].ComponentIndex;
- this.hi = decoder.ComponentArray[this.componentIndex].HorizontalFactor;
- int vi = decoder.ComponentArray[this.componentIndex].VerticalFactor;
+ this.ComponentIndex = this.pointers.ComponentScan[scanIndex].ComponentIndex;
+ this.hi = decoder.ComponentArray[this.ComponentIndex].HorizontalFactor;
+ int vi = decoder.ComponentArray[this.ComponentIndex].VerticalFactor;
for (int j = 0; j < this.hi * vi; j++)
{
@@ -172,7 +184,7 @@ namespace ImageSharp.Formats.Jpg
}
this.ReadBlock(decoder, scanIndex);
- this.ProcessBlock(decoder);
+ //this.ProcessBlock(decoder);
}
// for j
@@ -219,7 +231,7 @@ namespace ImageSharp.Formats.Jpg
/// The instance
public void ProcessBlock(JpegDecoderCore decoder)
{
- int qtIndex = decoder.ComponentArray[this.componentIndex].Selector;
+ int qtIndex = decoder.ComponentArray[this.ComponentIndex].Selector;
this.data.QuantiazationTable = decoder.QuantizationTables[qtIndex];
Block8x8F* b = this.pointers.Block;
@@ -228,7 +240,7 @@ namespace ImageSharp.Formats.Jpg
DCT.TransformIDCT(ref *b, ref *this.pointers.Temp1, ref *this.pointers.Temp2);
- var destChannel = decoder.GetDestinationChannel(this.componentIndex);
+ var destChannel = decoder.GetDestinationChannel(this.ComponentIndex);
var destArea = destChannel.GetOffsetedSubAreaForBlock(this.bx, this.by);
destArea.LoadColorsFrom(this.pointers.Temp1, this.pointers.Temp2);
}
@@ -239,11 +251,11 @@ namespace ImageSharp.Formats.Jpg
}
///
- /// The implementation part of as an instance method.
+ /// The implementation part of as an instance method.
///
/// The
/// The remaining bytes
- private void InitImpl(JpegDecoderCore decoder, int remaining)
+ private void InitStreamReadingImpl(JpegDecoderCore decoder, int remaining)
{
if (decoder.ComponentCount == 0)
{
@@ -313,7 +325,7 @@ namespace ImageSharp.Formats.Jpg
private void ReadBlock(JpegDecoderCore decoder, int scanIndex)
{
int blockIndex = this.GetBlockIndex(decoder);
- this.data.Block = decoder.DecodedBlocks[this.componentIndex][blockIndex].Block;
+ this.data.Block = decoder.DecodedBlocks[this.ComponentIndex][blockIndex].Block;
var b = this.pointers.Block;
DecoderErrorCode errorCode;
@@ -344,10 +356,10 @@ namespace ImageSharp.Formats.Jpg
int deltaDC = decoder.Bits.ReceiveExtend(value, decoder);
- this.pointers.Dc[this.componentIndex] += deltaDC;
+ this.pointers.Dc[this.ComponentIndex] += deltaDC;
// b[0] = dc[compIndex] << al;
- Block8x8F.SetScalarAt(b, 0, this.pointers.Dc[this.componentIndex] << this.al);
+ Block8x8F.SetScalarAt(b, 0, this.pointers.Dc[this.ComponentIndex] << this.al);
}
if (zig <= this.zigEnd && this.eobRun > 0)
@@ -399,7 +411,7 @@ namespace ImageSharp.Formats.Jpg
}
}
- DecodedBlockMemento[] blocks = decoder.DecodedBlocks[this.componentIndex];
+ DecodedBlockMemento[] blocks = decoder.DecodedBlocks[this.ComponentIndex];
DecodedBlockMemento.Store(blocks, blockIndex, this.bx, this.by, ref *b);
}
diff --git a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs
index 30367e93e..f8adedd26 100644
--- a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs
@@ -175,8 +175,89 @@ namespace ImageSharp.Formats
/// The pixel format.
/// The image, where the data should be set to.
/// The stream, where the image should be.
- /// Whether to decode metadata only.
- public void Decode(Image image, Stream stream, bool configOnly)
+ /// Whether to decode metadata only.
+ public void Decode(Image image, Stream stream, bool metadataOnly)
+ where TColor : struct, IPackedPixel, IEquatable
+ {
+ this.ProcessStream(image, stream, metadataOnly);
+ if (metadataOnly) return;
+ this.ConvertBlocksToImagePixels(image);
+ }
+
+ private void ConvertBlocksToImagePixels(Image image)
+ where TColor : struct, IPackedPixel, IEquatable
+ {
+ this.ProcessBlocks();
+
+ if (this.grayImage.IsInitialized)
+ {
+ this.ConvertFromGrayScale(this.ImageWidth, this.ImageHeight, image);
+ }
+ else if (this.ycbcrImage != null)
+ {
+ if (this.ComponentCount == 4)
+ {
+ if (!this.adobeTransformValid)
+ {
+ throw new ImageFormatException(
+ "Unknown color model: 4-component JPEG doesn't have Adobe APP14 metadata");
+ }
+
+ // See http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
+ // See https://docs.oracle.com/javase/8/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html
+ // TODO: YCbCrA?
+ if (this.adobeTransform == JpegConstants.Adobe.ColorTransformYcck)
+ {
+ this.ConvertFromYcck(this.ImageWidth, this.ImageHeight, image);
+ }
+ else if (this.adobeTransform == JpegConstants.Adobe.ColorTransformUnknown)
+ {
+ // Assume CMYK
+ this.ConvertFromCmyk(this.ImageWidth, this.ImageHeight, image);
+ }
+
+ return;
+ }
+
+ if (this.ComponentCount == 3)
+ {
+ if (this.IsRGB())
+ {
+ this.ConvertFromRGB(this.ImageWidth, this.ImageHeight, image);
+ return;
+ }
+
+ this.ConvertFromYCbCr(this.ImageWidth, this.ImageHeight, image);
+ return;
+ }
+
+ throw new ImageFormatException("JpegDecoder only supports RGB, CMYK and Grayscale color spaces.");
+ }
+ else
+ {
+ throw new ImageFormatException("Missing SOS marker.");
+ }
+ }
+
+ private void ProcessBlocks()
+ where TColor : struct, IPackedPixel, IEquatable
+ {
+ JpegScanDecoder scanDecoder = default(JpegScanDecoder);
+ JpegScanDecoder.Init(&scanDecoder);
+
+ for(int componentIndex = 0; componentIndex < this.ComponentCount; componentIndex++)
+ {
+ scanDecoder.ComponentIndex = componentIndex;
+ DecodedBlockMemento[] blockArray = this.DecodedBlocks[componentIndex];
+ for (int i = 0; i < blockArray.Length; i++)
+ {
+ scanDecoder.LoadMemento(ref blockArray[i]);
+ scanDecoder.ProcessBlock(this);
+ }
+ }
+ }
+
+ private void ProcessStream(Image image, Stream stream, bool metadataOnly)
where TColor : struct, IPackedPixel, IEquatable
{
this.InputStream = stream;
@@ -265,14 +346,14 @@ namespace ImageSharp.Formats
case JpegConstants.Markers.SOF2:
this.IsProgressive = marker == JpegConstants.Markers.SOF2;
this.ProcessStartOfFrameMarker(remaining);
- if (configOnly && this.isJfif)
+ if (metadataOnly && this.isJfif)
{
return;
}
break;
case JpegConstants.Markers.DHT:
- if (configOnly)
+ if (metadataOnly)
{
this.Skip(remaining);
}
@@ -283,7 +364,7 @@ namespace ImageSharp.Formats
break;
case JpegConstants.Markers.DQT:
- if (configOnly)
+ if (metadataOnly)
{
this.Skip(remaining);
}
@@ -294,7 +375,7 @@ namespace ImageSharp.Formats
break;
case JpegConstants.Markers.SOS:
- if (configOnly)
+ if (metadataOnly)
{
return;
}
@@ -310,7 +391,7 @@ namespace ImageSharp.Formats
break;
case JpegConstants.Markers.DRI:
- if (configOnly)
+ if (metadataOnly)
{
this.Skip(remaining);
}
@@ -348,55 +429,6 @@ namespace ImageSharp.Formats
break;
}
}
-
- if (this.grayImage.IsInitialized)
- {
- this.ConvertFromGrayScale(this.ImageWidth, this.ImageHeight, image);
- }
- else if (this.ycbcrImage != null)
- {
- if (this.ComponentCount == 4)
- {
- if (!this.adobeTransformValid)
- {
- throw new ImageFormatException(
- "Unknown color model: 4-component JPEG doesn't have Adobe APP14 metadata");
- }
-
- // See http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
- // See https://docs.oracle.com/javase/8/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html
- // TODO: YCbCrA?
- if (this.adobeTransform == JpegConstants.Adobe.ColorTransformYcck)
- {
- this.ConvertFromYcck(this.ImageWidth, this.ImageHeight, image);
- }
- else if (this.adobeTransform == JpegConstants.Adobe.ColorTransformUnknown)
- {
- // Assume CMYK
- this.ConvertFromCmyk(this.ImageWidth, this.ImageHeight, image);
- }
-
- return;
- }
-
- if (this.ComponentCount == 3)
- {
- if (this.IsRGB())
- {
- this.ConvertFromRGB(this.ImageWidth, this.ImageHeight, image);
- return;
- }
-
- this.ConvertFromYCbCr(this.ImageWidth, this.ImageHeight, image);
- return;
- }
-
- throw new ImageFormatException("JpegDecoder only supports RGB, CMYK and Grayscale color spaces.");
- }
- else
- {
- throw new ImageFormatException("Missing SOS marker.");
- }
}
///
@@ -1453,7 +1485,7 @@ namespace ImageSharp.Formats
private void ProcessStartOfScan(int remaining)
{
JpegScanDecoder scan = default(JpegScanDecoder);
- JpegScanDecoder.Init(&scan, this, remaining);
+ JpegScanDecoder.InitStreamReading(&scan, this, remaining);
this.Bits = default(Bits);
this.MakeImage();
scan.ReadBlocks(this);