diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
index bdcb4c10f..378b6e8b9 100644
--- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
+++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
@@ -21,8 +21,7 @@ namespace SixLabors.ImageSharp.Advanced
/// The Pixel format.
/// The source image.
/// Returns the configuration.
- public static Configuration GetConfiguration(this Image source)
- where TPixel : struct, IPixel
+ public static Configuration GetConfiguration(this Image source)
=> GetConfiguration((IConfigurable)source);
///
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs
index 82af2a671..4922a9200 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs
@@ -30,6 +30,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp
return new BmpDecoderCore(configuration, this).Decode(stream);
}
+ public Image Decode(Configuration configuration, Stream stream) => this.Decode(configuration, stream);
+
///
public IImageInfo Identify(Configuration configuration, Stream stream)
{
diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs
index 6af75f2d0..6498f4aa2 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoder.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs
@@ -44,5 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
var decoder = new GifDecoderCore(configuration, this);
return decoder.Identify(stream);
}
+
+ public Image Decode(Configuration configuration, Stream stream) => this.Decode(configuration, stream);
}
}
diff --git a/src/ImageSharp/Formats/IImageDecoder.cs b/src/ImageSharp/Formats/IImageDecoder.cs
index ffc40314d..625c4efb6 100644
--- a/src/ImageSharp/Formats/IImageDecoder.cs
+++ b/src/ImageSharp/Formats/IImageDecoder.cs
@@ -20,5 +20,7 @@ namespace SixLabors.ImageSharp.Formats
/// The decoded image
Image Decode(Configuration configuration, Stream stream)
where TPixel : struct, IPixel;
+
+ Image Decode(Configuration configuration, Stream stream);
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
index 57b70dd26..7459abec5 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
@@ -38,5 +38,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
return decoder.Identify(stream);
}
}
+
+ public Image Decode(Configuration configuration, Stream stream) => this.Decode(configuration, stream);
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs
index 39dfb1d0b..e8c5ac8e8 100644
--- a/src/ImageSharp/Formats/Png/PngDecoder.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoder.cs
@@ -59,5 +59,7 @@ namespace SixLabors.ImageSharp.Formats.Png
var decoder = new PngDecoderCore(configuration, this);
return decoder.Identify(stream);
}
+
+ public Image Decode(Configuration configuration, Stream stream) => this.Decode(configuration, stream);
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs
index 9e83d173f..36944dc2c 100644
--- a/src/ImageSharp/Image.Decode.cs
+++ b/src/ImageSharp/Image.Decode.cs
@@ -102,6 +102,18 @@ namespace SixLabors.ImageSharp
Image img = decoder.Decode(config, stream);
return (img, format);
}
+
+ private static (Image img, IImageFormat format) Decode(Stream stream, Configuration config)
+ {
+ IImageDecoder decoder = DiscoverDecoder(stream, config, out IImageFormat format);
+ if (decoder is null)
+ {
+ return (null, null);
+ }
+
+ Image img = decoder.Decode(config, stream);
+ return (img, format);
+ }
///
/// Reads the raw image information from the specified stream.
diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs
index b13cef482..80267146d 100644
--- a/src/ImageSharp/Image.FromFile.cs
+++ b/src/ImageSharp/Image.FromFile.cs
@@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp
/// Thrown if the stream is not readable nor seekable.
///
/// A new .
- public static Image Load(string path) => Load(path);
+ public static Image Load(string path) => Load(path);
///
/// Create a new instance of the class from the given file.
@@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp
/// Thrown if the stream is not readable nor seekable.
///
/// A new .
- public static Image Load(string path, out IImageFormat format) => Load(path, out format);
+ public static Image Load(string path, out IImageFormat format) => Load(path, out format);
///
/// Create a new instance of the class from the given file.
@@ -68,19 +68,7 @@ namespace SixLabors.ImageSharp
/// Thrown if the stream is not readable nor seekable.
///
/// A new .
- public static Image Load(Configuration config, string path) => Load(config, path);
-
- ///
- /// Create a new instance of the class from the given file.
- ///
- /// The config for the decoder.
- /// The file path to the image.
- /// The mime type of the decoded image.
- ///
- /// Thrown if the stream is not readable nor seekable.
- ///
- /// A new .
- public static Image Load(Configuration config, string path, out IImageFormat format) => Load(config, path, out format);
+ public static Image Load(Configuration config, string path) => Load(config, path);
///
/// Create a new instance of the class from the given file.
@@ -92,7 +80,7 @@ namespace SixLabors.ImageSharp
/// Thrown if the stream is not readable nor seekable.
///
/// A new .
- public static Image Load(Configuration config, string path, IImageDecoder decoder) => Load(config, path, decoder);
+ public static Image Load(Configuration config, string path, IImageDecoder decoder) => Load(config, path, decoder);
///
/// Create a new instance of the class from the given file.
@@ -103,7 +91,7 @@ namespace SixLabors.ImageSharp
/// Thrown if the stream is not readable nor seekable.
///
/// A new .
- public static Image Load(string path, IImageDecoder decoder) => Load(path, decoder);
+ public static Image Load(string path, IImageDecoder decoder) => Load(path, decoder);
///
/// Create a new instance of the class from the given file.
@@ -174,6 +162,14 @@ namespace SixLabors.ImageSharp
return Load(config, stream, out format);
}
}
+
+ public static Image Load(Configuration config, string path, out IImageFormat format)
+ {
+ using (Stream stream = config.FileSystem.OpenRead(path))
+ {
+ return Load(config, stream, out format);
+ }
+ }
///
/// Create a new instance of the class from the given file.
diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs
index 3236e0007..8848225f5 100644
--- a/src/ImageSharp/Image.FromStream.cs
+++ b/src/ImageSharp/Image.FromStream.cs
@@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp
/// the mime type of the decoded image.
/// Thrown if the stream is not readable.
/// A new .>
- public static Image Load(Stream stream, out IImageFormat format) => Load(stream, out format);
+ public static Image Load(Stream stream, out IImageFormat format) => Load(stream, out format);
///
/// Create a new instance of the class from the given stream.
@@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp
/// The stream containing image information.
/// Thrown if the stream is not readable.
/// A new .>
- public static Image Load(Stream stream) => Load(stream);
+ public static Image Load(Stream stream) => Load(stream);
///
/// Create a new instance of the class from the given stream.
@@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp
/// The decoder.
/// Thrown if the stream is not readable.
/// A new .>
- public static Image Load(Stream stream, IImageDecoder decoder) => Load(stream, decoder);
+ public static Image Load(Stream stream, IImageDecoder decoder) => Load(stream, decoder);
///
/// Create a new instance of the class from the given stream.
@@ -88,18 +88,7 @@ namespace SixLabors.ImageSharp
/// The stream containing image information.
/// Thrown if the stream is not readable.
/// A new .>
- public static Image Load(Configuration config, Stream stream) => Load(config, stream);
-
- ///
- /// Create a new instance of the class from the given stream.
- ///
- /// The config for the decoder.
- /// The stream containing image information.
- /// the mime type of the decoded image.
- /// Thrown if the stream is not readable.
- /// 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) => Load(config, stream);
///
/// Create a new instance of the class from the given stream.
@@ -193,6 +182,28 @@ namespace SixLabors.ImageSharp
throw new NotSupportedException(sb.ToString());
}
+ private static Image Load(Configuration config, Stream stream, out IImageFormat format)
+ {
+ config = config ?? Configuration.Default;
+ (Image img, IImageFormat format) data = WithSeekableStream(config, stream, s => Decode(s, config));
+
+ format = data.format;
+
+ if (data.img != null)
+ {
+ return data.img;
+ }
+
+ var sb = new StringBuilder();
+ sb.AppendLine("Image cannot be loaded. Available decoders:");
+
+ foreach (KeyValuePair val in config.ImageFormatsManager.ImageDecoders)
+ {
+ sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}");
+ }
+
+ throw new NotSupportedException(sb.ToString());
+ }
private static T WithSeekableStream(Configuration config, Stream stream, Func action)
{
diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs
index 00a9a2075..a27f16ab3 100644
--- a/src/ImageSharp/Image.cs
+++ b/src/ImageSharp/Image.cs
@@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using System.IO;
+
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Metadata;
@@ -45,5 +47,39 @@ namespace SixLabors.ImageSharp
public abstract void Dispose();
internal abstract void AcceptVisitor(IImageVisitor visitor);
+
+ ///
+ /// Saves the image to the given stream using the given image encoder.
+ ///
+ /// The stream to save the image to.
+ /// The encoder to save the image with.
+ /// Thrown if the stream or encoder is null.
+ public void Save(Stream stream, IImageEncoder encoder)
+ {
+ Guard.NotNull(stream, nameof(stream));
+ Guard.NotNull(encoder, nameof(encoder));
+
+ EncodeVisitor visitor = new EncodeVisitor(encoder, stream);
+ this.AcceptVisitor(visitor);
+ }
+
+ class EncodeVisitor : IImageVisitor
+ {
+ private readonly IImageEncoder encoder;
+
+ private readonly Stream stream;
+
+ public EncodeVisitor(IImageEncoder encoder, Stream stream)
+ {
+ this.encoder = encoder;
+ this.stream = stream;
+ }
+
+ public void Visit(Image image)
+ where TPixel : struct, IPixel
+ {
+ this.encoder.Encode(image, this.stream);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs
index 5010451b8..3bd60694d 100644
--- a/src/ImageSharp/ImageExtensions.cs
+++ b/src/ImageSharp/ImageExtensions.cs
@@ -23,8 +23,7 @@ namespace SixLabors.ImageSharp
/// The source image.
/// The file path to save the image to.
/// Thrown if the stream is null.
- public static void Save(this Image source, string filePath)
- where TPixel : struct, IPixel
+ public static void Save(this Image source, string filePath)
{
Guard.NotNullOrWhiteSpace(filePath, nameof(filePath));
@@ -67,8 +66,7 @@ namespace SixLabors.ImageSharp
/// The file path to save the image to.
/// The encoder to save the image with.
/// Thrown if the encoder is null.
- public static void Save(this Image source, string filePath, IImageEncoder encoder)
- where TPixel : struct, IPixel
+ public static void Save(this Image source, string filePath, IImageEncoder encoder)
{
Guard.NotNull(encoder, nameof(encoder));
using (Stream fs = source.GetConfiguration().FileSystem.Create(filePath))
@@ -85,8 +83,7 @@ namespace SixLabors.ImageSharp
/// The stream to save the image to.
/// The format to save the image in.
/// Thrown if the stream is null.
- public static void Save(this Image source, Stream stream, IImageFormat format)
- where TPixel : struct, IPixel
+ public static void Save(this Image source, Stream stream, IImageFormat format)
{
Guard.NotNull(format, nameof(format));
IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format);
diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs
index 64ec87c4d..e37f3e4c1 100644
--- a/src/ImageSharp/Image{TPixel}.cs
+++ b/src/ImageSharp/Image{TPixel}.cs
@@ -158,20 +158,6 @@ namespace SixLabors.ImageSharp
set => this.PixelSource.PixelBuffer[x, y] = value;
}
- ///
- /// Saves the image to the given stream using the given image encoder.
- ///
- /// The stream to save the image to.
- /// The encoder to save the image with.
- /// Thrown if the stream or encoder is null.
- public void Save(Stream stream, IImageEncoder encoder)
- {
- Guard.NotNull(stream, nameof(stream));
- Guard.NotNull(encoder, nameof(encoder));
-
- encoder.Encode(this, stream);
- }
-
///
/// Clones the current image
///
diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs
index e3a43a652..c7af8d468 100644
--- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs
+++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs
@@ -42,6 +42,22 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.07F);
+ [Fact]
+ public void Resize_PixelAgnostic()
+ {
+ var filePath = TestFile.GetInputFileFullPath(TestImages.Jpeg.Baseline.Calliphora);
+
+ using (Image image = Image.Load(filePath))
+ {
+ image.Mutate(x => x.Resize(image.Size() / 2));
+ string path = System.IO.Path.Combine(
+ TestEnvironment.CreateOutputDirectory(nameof(ResizeTests)),
+ nameof(this.Resize_PixelAgnostic) + ".png");
+
+ image.Save(path);
+ }
+ }
+
[Theory(
Skip = "Debug only, enable manually"
)]
diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs
index 64357a17e..91e31b356 100644
--- a/tests/ImageSharp.Tests/TestFormat.cs
+++ b/tests/ImageSharp.Tests/TestFormat.cs
@@ -199,6 +199,8 @@ namespace SixLabors.ImageSharp.Tests
}
public bool IsSupportedFileFormat(Span header) => testFormat.IsSupportedFileFormat(header);
+
+ public Image Decode(Configuration configuration, Stream stream) => this.Decode(configuration, stream);
}
public class TestEncoder : ImageSharp.Formats.IImageEncoder
diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
index 3dd330e4d..e81714ddc 100644
--- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
@@ -57,5 +57,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
return result;
}
}
+
+ public Image Decode(Configuration configuration, Stream stream) => this.Decode(configuration, stream);
}
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs
index 7a775c081..2de3c03aa 100644
--- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs
@@ -51,5 +51,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
return new ImageInfo(pixelType, sourceBitmap.Width, sourceBitmap.Height, new ImageMetadata());
}
}
+
+ public Image Decode(Configuration configuration, Stream stream) => this.Decode(configuration, stream);
}
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs
index 4ef6a582c..b49baa5c4 100644
--- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs
@@ -379,6 +379,8 @@ namespace SixLabors.ImageSharp.Tests
this.callerName = name;
invocationCounts[name] = 0;
}
+
+ public Image Decode(Configuration configuration, Stream stream) => this.Decode(configuration, stream);
}
private class TestDecoderWithParameters : IImageDecoder
@@ -416,6 +418,8 @@ namespace SixLabors.ImageSharp.Tests
this.callerName = name;
invocationCounts[name] = 0;
}
+
+ public Image Decode(Configuration configuration, Stream stream) => this.Decode(configuration, stream);
}
}
}
\ No newline at end of file