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
+ }
+}