Skip to content

Commit 26b948d

Browse files
Merge branch 'master' into sp/byte-to-tpixel-wrapping
2 parents d861805 + c4dabd9 commit 26b948d

File tree

6 files changed

+109
-10
lines changed

6 files changed

+109
-10
lines changed

.github/workflows/build-and-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ jobs:
6464
XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit
6565

6666
- name: Update Codecov
67-
uses: codecov/codecov-action@v1.0.7
67+
uses: codecov/codecov-action@v1
6868
if: matrix.options.codecov == true && startsWith(github.repository, 'SixLabors')
6969
with:
7070
flags: unittests

src/ImageSharp/Advanced/AdvancedImageExtensions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ public static class AdvancedImageExtensions
2323
/// </summary>
2424
/// <param name="source">The source image.</param>
2525
/// <param name="filePath">The target file path to save the image to.</param>
26-
/// <returns>The matching encoder.</returns>
26+
/// <exception cref="ArgumentNullException">The file path is null.</exception>
27+
/// <exception cref="NotSupportedException">No encoder available for provided path.</exception>
28+
/// <returns>The matching <see cref="IImageEncoder"/>.</returns>
2729
public static IImageEncoder DetectEncoder(this Image source, string filePath)
2830
{
2931
Guard.NotNull(filePath, nameof(filePath));

src/ImageSharp/ImageExtensions.cs

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,29 @@ namespace SixLabors.ImageSharp
1818
public static partial class ImageExtensions
1919
{
2020
/// <summary>
21-
/// Writes the image to the given stream using the currently loaded image format.
21+
/// Writes the image to the given file path using an encoder detected from the path.
2222
/// </summary>
2323
/// <param name="source">The source image.</param>
2424
/// <param name="path">The file path to save the image to.</param>
2525
/// <exception cref="ArgumentNullException">The path is null.</exception>
26+
/// <exception cref="NotSupportedException">No encoder available for provided path.</exception>
2627
public static void Save(this Image source, string path)
2728
=> source.Save(path, source.DetectEncoder(path));
2829

2930
/// <summary>
30-
/// Writes the image to the given stream using the currently loaded image format.
31+
/// Writes the image to the given file path using an encoder detected from the path.
3132
/// </summary>
3233
/// <param name="source">The source image.</param>
3334
/// <param name="path">The file path to save the image to.</param>
3435
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
3536
/// <exception cref="ArgumentNullException">The path is null.</exception>
37+
/// <exception cref="NotSupportedException">No encoder available for provided path.</exception>
3638
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
3739
public static Task SaveAsync(this Image source, string path, CancellationToken cancellationToken = default)
3840
=> source.SaveAsync(path, source.DetectEncoder(path), cancellationToken);
3941

4042
/// <summary>
41-
/// Writes the image to the given stream using the currently loaded image format.
43+
/// Writes the image to the given file path using the given image encoder.
4244
/// </summary>
4345
/// <param name="source">The source image.</param>
4446
/// <param name="path">The file path to save the image to.</param>
@@ -56,7 +58,7 @@ public static void Save(this Image source, string path, IImageEncoder encoder)
5658
}
5759

5860
/// <summary>
59-
/// Writes the image to the given stream using the currently loaded image format.
61+
/// Writes the image to the given file path using the given image encoder.
6062
/// </summary>
6163
/// <param name="source">The source image.</param>
6264
/// <param name="path">The file path to save the image to.</param>
@@ -73,12 +75,15 @@ public static async Task SaveAsync(
7375
{
7476
Guard.NotNull(path, nameof(path));
7577
Guard.NotNull(encoder, nameof(encoder));
76-
using Stream fs = source.GetConfiguration().FileSystem.Create(path);
77-
await source.SaveAsync(fs, encoder, cancellationToken).ConfigureAwait(false);
78+
79+
using (Stream fs = source.GetConfiguration().FileSystem.Create(path))
80+
{
81+
await source.SaveAsync(fs, encoder, cancellationToken).ConfigureAwait(false);
82+
}
7883
}
7984

8085
/// <summary>
81-
/// Writes the image to the given stream using the currently loaded image format.
86+
/// Writes the image to the given stream using the given image format.
8287
/// </summary>
8388
/// <param name="source">The source image.</param>
8489
/// <param name="stream">The stream to save the image to.</param>
@@ -115,6 +120,50 @@ public static void Save(this Image source, Stream stream, IImageFormat format)
115120
source.Save(stream, encoder);
116121
}
117122

123+
/// <summary>
124+
/// Writes the image to the given stream using the given image format.
125+
/// </summary>
126+
/// <param name="source">The source image.</param>
127+
/// <param name="stream">The stream to save the image to.</param>
128+
/// <param name="format">The format to save the image in.</param>
129+
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
130+
/// <exception cref="ArgumentNullException">The stream is null.</exception>
131+
/// <exception cref="ArgumentNullException">The format is null.</exception>
132+
/// <exception cref="NotSupportedException">The stream is not writable.</exception>
133+
/// <exception cref="NotSupportedException">No encoder available for provided format.</exception>
134+
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
135+
public static Task SaveAsync(
136+
this Image source,
137+
Stream stream,
138+
IImageFormat format,
139+
CancellationToken cancellationToken = default)
140+
{
141+
Guard.NotNull(stream, nameof(stream));
142+
Guard.NotNull(format, nameof(format));
143+
144+
if (!stream.CanWrite)
145+
{
146+
throw new NotSupportedException("Cannot write to the stream.");
147+
}
148+
149+
IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format);
150+
151+
if (encoder is null)
152+
{
153+
var sb = new StringBuilder();
154+
sb.AppendLine("No encoder was found for the provided mime type. Registered encoders include:");
155+
156+
foreach (KeyValuePair<IImageFormat, IImageEncoder> val in source.GetConfiguration().ImageFormatsManager.ImageEncoders)
157+
{
158+
sb.AppendFormat(" - {0} : {1}{2}", val.Key.Name, val.Value.GetType().Name, Environment.NewLine);
159+
}
160+
161+
throw new NotSupportedException(sb.ToString());
162+
}
163+
164+
return source.SaveAsync(stream, encoder, cancellationToken);
165+
}
166+
118167
/// <summary>
119168
/// Returns a Base64 encoded string from the given image.
120169
/// The result is prepended with a Data URI <see href="https://en.wikipedia.org/wiki/Data_URI_scheme"/>

src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ public sealed class BokehBlurProcessor : IImageProcessor
2929
/// Initializes a new instance of the <see cref="BokehBlurProcessor"/> class.
3030
/// </summary>
3131
public BokehBlurProcessor()
32-
: this(DefaultRadius, DefaultComponents, DefaultGamma)
3332
{
33+
this.Radius = DefaultRadius;
34+
this.Components = DefaultComponents;
35+
this.Gamma = DefaultGamma;
3436
}
3537

3638
/// <summary>
@@ -47,6 +49,8 @@ public BokehBlurProcessor()
4749
/// </param>
4850
public BokehBlurProcessor(int radius, int components, float gamma)
4951
{
52+
Guard.MustBeGreaterThan(radius, 0, nameof(radius));
53+
Guard.MustBeBetweenOrEqualTo(components, 1, 6, nameof(components));
5054
Guard.MustBeGreaterThanOrEqualTo(gamma, 1, nameof(gamma));
5155

5256
this.Radius = radius;

tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,37 @@ public async Task SetEncoding()
7272
}
7373
}
7474

75+
[Theory]
76+
[InlineData("test.png", "image/png")]
77+
[InlineData("test.tga", "image/tga")]
78+
[InlineData("test.bmp", "image/bmp")]
79+
[InlineData("test.jpg", "image/jpeg")]
80+
[InlineData("test.gif", "image/gif")]
81+
public async Task SaveStreamWithMime(string filename, string mimeType)
82+
{
83+
using (var image = new Image<Rgba32>(5, 5))
84+
{
85+
string ext = Path.GetExtension(filename);
86+
IImageFormat format = image.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext);
87+
Assert.Equal(mimeType, format.DefaultMimeType);
88+
89+
using (var stream = new MemoryStream())
90+
{
91+
var asyncStream = new AsyncStreamWrapper(stream, () => false);
92+
await image.SaveAsync(asyncStream, format);
93+
94+
stream.Position = 0;
95+
96+
(Image Image, IImageFormat Format) imf = await Image.LoadWithFormatAsync(stream);
97+
98+
Assert.Equal(format, imf.Format);
99+
Assert.Equal(mimeType, imf.Format.DefaultMimeType);
100+
101+
imf.Image.Dispose();
102+
}
103+
}
104+
}
105+
75106
[Fact]
76107
public async Task ThrowsWhenDisposed()
77108
{

tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,19 @@ [[ 0.00451261+0.0165137j 0.02161237-0.00299122j 0.00387479-0.02682816j
3535
0.02565295+0.01611732j 0.0153483+0.01605112j 0.00698622+0.01370844j
3636
0.00135338+0.00998296j -0.00152245+0.00604545j -0.00227282+0.002851j ]]";
3737

38+
[Theory]
39+
[InlineData(-10, 2, 3f)]
40+
[InlineData(-1, 2, 3f)]
41+
[InlineData(0, 2, 3f)]
42+
[InlineData(20, -1, 3f)]
43+
[InlineData(20, -0, 3f)]
44+
[InlineData(20, 4, -10f)]
45+
[InlineData(20, 4, 0f)]
46+
public void VerifyBokehBlurProcessorArguments_Fail(int radius, int components, float gamma)
47+
{
48+
Assert.Throws<ArgumentOutOfRangeException>(() => new BokehBlurProcessor(radius, components, gamma));
49+
}
50+
3851
[Fact]
3952
public void VerifyComplexComponents()
4053
{

0 commit comments

Comments
 (0)