From 549e61f2f4a49563cb8993d81d57993b58bcd2e2 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 24 Jun 2017 00:03:01 +1000 Subject: [PATCH] Experiment with new file marker finder --- src/ImageSharp/Formats/Jpeg/JpegDecoder.cs | 2 +- .../Formats/Jpeg/Port/JpegDecoderCore.cs | 50 +++++++++++++++++-- .../ImageSharp.Benchmarks/Image/DecodeJpeg.cs | 1 + 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs index 117edb225..33d82ace8 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs @@ -21,7 +21,7 @@ namespace ImageSharp.Formats { Guard.NotNull(stream, "stream"); - // using (JpegDecoderCore decoder = new JpegDecoderCore(options, configuration)) + // using (var decoder = new JpegDecoderCore(options, configuration)) // { // return decoder.Decode(stream); // } diff --git a/src/ImageSharp/Formats/Jpeg/Port/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/Port/JpegDecoderCore.cs index 8d3cec616..4bb93151a 100644 --- a/src/ImageSharp/Formats/Jpeg/Port/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/Port/JpegDecoderCore.cs @@ -185,6 +185,45 @@ namespace ImageSharp.Formats.Jpeg.Port return new FileMarker(newMarker, newPos, true); } + /// + /// Finds the next file marker within the byte stream. Used for testing. Slower as it only reads on byte at a time + /// + /// The input stream + /// The + public static FileMarker FindNextFileMarkerNew(Stream stream) + { + while (true) + { + int value = stream.ReadByte(); + + if (value == -1) + { + // We've reached the end of the stream + return new FileMarker(JpegConstants.Markers.EOI, (int)stream.Length, true); + } + + byte prefix = (byte)value; + byte suffix = JpegConstants.Markers.Prefix; + + // According to Section B.1.1.2: + // "Any marker may optionally be preceded by any number of fill bytes, which are bytes assigned code 0xFF." + while (prefix == JpegConstants.Markers.Prefix && suffix == JpegConstants.Markers.Prefix) + { + value = stream.ReadByte(); + + if (value == -1) + { + // We've reached the end of the stream + return new FileMarker(JpegConstants.Markers.EOI, (int)stream.Length, true); + } + + suffix = (byte)value; + } + + return new FileMarker((ushort)((prefix << 8) | suffix), (int)(stream.Position - 2)); + } + } + /// /// Decodes the image from the specified and sets /// the data to image. @@ -205,9 +244,9 @@ namespace ImageSharp.Formats.Jpeg.Port /// public void Dispose() { - this.frame.Dispose(); - this.components.Dispose(); - this.quantizationTables.Dispose(); + this.frame?.Dispose(); + this.components?.Dispose(); + this.quantizationTables?.Dispose(); // Set large fields to null. this.frame = null; @@ -315,13 +354,14 @@ namespace ImageSharp.Formats.Jpeg.Port { // Rewind that last bytes we read this.InputStream.Position -= 2; + break; } - break; + throw new ImageFormatException($"Unknown Marker {fileMarker.Marker} at {fileMarker.Position}"); } // Read on. TODO: Test this on damaged images. - fileMarker = FindNextFileMarker(this.InputStream); + fileMarker = FindNextFileMarkerNew(this.InputStream); } this.width = this.frame.SamplesPerLine; diff --git a/tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs index 56771bcf5..28c7d461c 100644 --- a/tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs @@ -14,6 +14,7 @@ namespace ImageSharp.Benchmarks.Image using CoreSize = ImageSharp.Size; + [Config(typeof(Config))] public class DecodeJpeg : BenchmarkBase { private byte[] jpegBytes;