diff --git a/src/ImageSharp/Image/Image.FromStream.cs b/src/ImageSharp/Image/Image.FromStream.cs index 62668dd023..30d8014233 100644 --- a/src/ImageSharp/Image/Image.FromStream.cs +++ b/src/ImageSharp/Image/Image.FromStream.cs @@ -20,10 +20,15 @@ namespace SixLabors.ImageSharp /// /// The image stream to read the header from. /// The mime type or null if none found. - public static IImageFormat DetectFormat(Stream stream) - { - return DetectFormat(null, stream); - } + public static IImageFormat DetectFormat(Stream stream) => DetectFormat(null, stream); + + /// + /// By reading the header on the provided stream this calculates the images mime type. + /// + /// The image stream to read the header from. + /// The position in the stream to use for reading. + /// The mime type or null if none found. + public static IImageFormat DetectFormat(Stream stream, ReadOrigin origin) => DetectFormat(null, stream, origin); /// /// By reading the header on the provided stream this calculates the images mime type. @@ -31,10 +36,17 @@ namespace SixLabors.ImageSharp /// The configuration. /// The image stream to read the header from. /// The mime type or null if none found. - public static IImageFormat DetectFormat(Configuration config, Stream stream) - { - return WithSeekableStream(stream, s => InternalDetectFormat(s, config ?? Configuration.Default)); - } + public static IImageFormat DetectFormat(Configuration config, Stream stream) => DetectFormat(config, stream, ReadOrigin.Begin); + + /// + /// By reading the header on the provided stream this calculates the images mime type. + /// + /// The configuration. + /// The image stream to read the header from. + /// The position in the stream to use for reading. + /// The mime type or null if none found. + public static IImageFormat DetectFormat(Configuration config, Stream stream, ReadOrigin origin) + => WithSeekableStream(stream, origin, s => InternalDetectFormat(s, config ?? Configuration.Default)); /// /// By reading the header on the provided stream this reads the raw image information. @@ -46,10 +58,7 @@ namespace SixLabors.ImageSharp /// /// The or null if suitable info detector not found. /// - public static IImageInfo Identify(Stream stream) - { - return Identify(null, stream); - } + public static IImageInfo Identify(Stream stream) => Identify(null, stream); /// /// Reads the raw image information from the specified stream without fully decoding it. @@ -62,10 +71,20 @@ namespace SixLabors.ImageSharp /// /// The or null if suitable info detector is not found. /// - public static IImageInfo Identify(Configuration config, Stream stream) - { - return WithSeekableStream(stream, s => InternalIdentity(s, config ?? Configuration.Default)); - } + public static IImageInfo Identify(Configuration config, Stream stream) => Identify(config, stream, ReadOrigin.Begin); + + /// + /// Reads the raw image information from the specified stream without fully decoding it. + /// + /// The configuration. + /// The image stream to read the information from. + /// The position in the stream to use for reading. + /// Thrown if the stream is not readable. + /// + /// The or null if suitable info detector is not found. + /// + public static IImageInfo Identify(Configuration config, Stream stream, ReadOrigin origin) + => WithSeekableStream(stream, origin, s => InternalIdentity(s, config ?? Configuration.Default)); /// /// Create a new instance of the class from the given stream. @@ -120,7 +139,8 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is not readable nor seekable. /// /// A new .> - public static Image Load(Configuration config, Stream stream, out IImageFormat format) => Load(config, stream, out format); + public static Image Load(Configuration config, Stream stream, out IImageFormat format) + => Load(config, stream, out format); /// /// Create a new instance of the class from the given stream. @@ -133,9 +153,7 @@ namespace SixLabors.ImageSharp /// A new .> public static Image Load(Stream stream) where TPixel : struct, IPixel - { - return Load(null, stream); - } + => Load(null, stream); /// /// Create a new instance of the class from the given stream. @@ -149,9 +167,7 @@ namespace SixLabors.ImageSharp /// A new .> public static Image Load(Stream stream, out IImageFormat format) where TPixel : struct, IPixel - { - return Load(null, stream, out format); - } + => Load(null, stream, out format); /// /// Create a new instance of the class from the given stream. @@ -165,9 +181,22 @@ namespace SixLabors.ImageSharp /// A new .> public static Image Load(Stream stream, IImageDecoder decoder) where TPixel : struct, IPixel - { - return WithSeekableStream(stream, s => decoder.Decode(Configuration.Default, s)); - } + => Load(stream, ReadOrigin.Begin, decoder); + + /// + /// Create a new instance of the class from the given stream. + /// + /// The stream containing image information. + /// The position in the stream to use for reading. + /// The decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The pixel format. + /// A new .> + public static Image Load(Stream stream, ReadOrigin origin, IImageDecoder decoder) + where TPixel : struct, IPixel + => WithSeekableStream(stream, origin, s => decoder.Decode(Configuration.Default, s)); /// /// Create a new instance of the class from the given stream. @@ -182,9 +211,23 @@ namespace SixLabors.ImageSharp /// A new .> public static Image Load(Configuration config, Stream stream, IImageDecoder decoder) where TPixel : struct, IPixel - { - return WithSeekableStream(stream, s => decoder.Decode(config, s)); - } + => Load(config, stream, ReadOrigin.Begin, decoder); + + /// + /// Create a new instance of the class from the given stream. + /// + /// The Configuration. + /// The stream containing image information. + /// The position in the stream to use for reading. + /// The decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The pixel format. + /// A new .> + public static Image Load(Configuration config, Stream stream, ReadOrigin origin, IImageDecoder decoder) + where TPixel : struct, IPixel + => WithSeekableStream(stream, origin, s => decoder.Decode(config, s)); /// /// Create a new instance of the class from the given stream. @@ -198,9 +241,22 @@ namespace SixLabors.ImageSharp /// A new .> public static Image Load(Configuration config, Stream stream) where TPixel : struct, IPixel - { - return Load(config, stream, out var _); - } + => Load(config, stream, out IImageFormat _); + + /// + /// Create a new instance of the class from the given stream. + /// + /// The configuration options. + /// The stream containing image information. + /// The position in the stream to use for reading. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The pixel format. + /// A new .> + public static Image Load(Configuration config, Stream stream, ReadOrigin origin) + where TPixel : struct, IPixel + => Load(config, stream, origin, out IImageFormat _); /// /// Create a new instance of the class from the given stream. @@ -214,10 +270,26 @@ namespace SixLabors.ImageSharp /// The pixel format. /// A new .> public static Image Load(Configuration config, Stream stream, out IImageFormat format) - where TPixel : struct, IPixel + where TPixel : struct, IPixel + => Load(config, stream, ReadOrigin.Begin, out format); + + /// + /// Create a new instance of the class from the given stream. + /// + /// The configuration options. + /// The stream containing image information. + /// The position in the stream to use for reading. + /// the mime type of the decoded image. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The pixel format. + /// A new .> + public static Image Load(Configuration config, Stream stream, ReadOrigin origin, out IImageFormat format) + where TPixel : struct, IPixel { config = config ?? Configuration.Default; - (Image img, IImageFormat format) data = WithSeekableStream(stream, s => Decode(s, config)); + (Image img, IImageFormat format) data = WithSeekableStream(stream, origin, s => Decode(s, config)); format = data.format; @@ -237,7 +309,7 @@ namespace SixLabors.ImageSharp throw new NotSupportedException(stringBuilder.ToString()); } - private static T WithSeekableStream(Stream stream, Func action) + private static T WithSeekableStream(Stream stream, ReadOrigin origin, Func action) { if (!stream.CanRead) { @@ -246,9 +318,19 @@ namespace SixLabors.ImageSharp if (stream.CanSeek) { + if (origin == ReadOrigin.Begin) + { + stream.Position = 0; + } + return action(stream); } + if (origin == ReadOrigin.Current) + { + throw new NotSupportedException("Cannot seek within the stream."); + } + // We want to be able to load images from things like HttpContext.Request.Body using (var memoryStream = new MemoryStream()) { diff --git a/src/ImageSharp/Image/ReadOrigin.cs b/src/ImageSharp/Image/ReadOrigin.cs new file mode 100644 index 0000000000..f17bc82f18 --- /dev/null +++ b/src/ImageSharp/Image/ReadOrigin.cs @@ -0,0 +1,21 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp +{ + /// + /// Specifies the position in a stream to use for reading. + /// + public enum ReadOrigin + { + /// + /// Specifies the beginning of a stream. + /// + Begin, + + /// + /// Specifies the current position within a stream. + /// + Current + } +}