Browse Source

Merge branch 'master' into sp/byte-to-tpixel-wrapping

js/color-alpha-handling
James Jackson-South 6 years ago
committed by GitHub
parent
commit
ac8af6355a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .github/workflows/build-and-test.yml
  2. 4
      src/ImageSharp/Advanced/AdvancedImageExtensions.cs
  3. 63
      src/ImageSharp/ImageExtensions.cs
  4. 6
      src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs
  5. 31
      tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs
  6. 13
      tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs

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

@ -64,7 +64,7 @@ jobs:
XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit
- name: Update Codecov
uses: codecov/codecov-action@v1.0.7
uses: codecov/codecov-action@v1
if: matrix.options.codecov == true && startsWith(github.repository, 'SixLabors')
with:
flags: unittests

4
src/ImageSharp/Advanced/AdvancedImageExtensions.cs

@ -23,7 +23,9 @@ namespace SixLabors.ImageSharp.Advanced
/// </summary>
/// <param name="source">The source image.</param>
/// <param name="filePath">The target file path to save the image to.</param>
/// <returns>The matching encoder.</returns>
/// <exception cref="ArgumentNullException">The file path is null.</exception>
/// <exception cref="NotSupportedException">No encoder available for provided path.</exception>
/// <returns>The matching <see cref="IImageEncoder"/>.</returns>
public static IImageEncoder DetectEncoder(this Image source, string filePath)
{
Guard.NotNull(filePath, nameof(filePath));

63
src/ImageSharp/ImageExtensions.cs

@ -18,27 +18,29 @@ namespace SixLabors.ImageSharp
public static partial class ImageExtensions
{
/// <summary>
/// Writes the image to the given stream using the currently loaded image format.
/// Writes the image to the given file path using an encoder detected from the path.
/// </summary>
/// <param name="source">The source image.</param>
/// <param name="path">The file path to save the image to.</param>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="NotSupportedException">No encoder available for provided path.</exception>
public static void Save(this Image source, string path)
=> source.Save(path, source.DetectEncoder(path));
/// <summary>
/// Writes the image to the given stream using the currently loaded image format.
/// Writes the image to the given file path using an encoder detected from the path.
/// </summary>
/// <param name="source">The source image.</param>
/// <param name="path">The file path to save the image to.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="NotSupportedException">No encoder available for provided path.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static Task SaveAsync(this Image source, string path, CancellationToken cancellationToken = default)
=> source.SaveAsync(path, source.DetectEncoder(path), cancellationToken);
/// <summary>
/// Writes the image to the given stream using the currently loaded image format.
/// Writes the image to the given file path using the given image encoder.
/// </summary>
/// <param name="source">The source image.</param>
/// <param name="path">The file path to save the image to.</param>
@ -56,7 +58,7 @@ namespace SixLabors.ImageSharp
}
/// <summary>
/// Writes the image to the given stream using the currently loaded image format.
/// Writes the image to the given file path using the given image encoder.
/// </summary>
/// <param name="source">The source image.</param>
/// <param name="path">The file path to save the image to.</param>
@ -73,12 +75,15 @@ namespace SixLabors.ImageSharp
{
Guard.NotNull(path, nameof(path));
Guard.NotNull(encoder, nameof(encoder));
using Stream fs = source.GetConfiguration().FileSystem.Create(path);
await source.SaveAsync(fs, encoder, cancellationToken).ConfigureAwait(false);
using (Stream fs = source.GetConfiguration().FileSystem.Create(path))
{
await source.SaveAsync(fs, encoder, cancellationToken).ConfigureAwait(false);
}
}
/// <summary>
/// Writes the image to the given stream using the currently loaded image format.
/// Writes the image to the given stream using the given image format.
/// </summary>
/// <param name="source">The source image.</param>
/// <param name="stream">The stream to save the image to.</param>
@ -115,6 +120,50 @@ namespace SixLabors.ImageSharp
source.Save(stream, encoder);
}
/// <summary>
/// Writes the image to the given stream using the given image format.
/// </summary>
/// <param name="source">The source image.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="format">The format to save the image in.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="ArgumentNullException">The format is null.</exception>
/// <exception cref="NotSupportedException">The stream is not writable.</exception>
/// <exception cref="NotSupportedException">No encoder available for provided format.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static Task SaveAsync(
this Image source,
Stream stream,
IImageFormat format,
CancellationToken cancellationToken = default)
{
Guard.NotNull(stream, nameof(stream));
Guard.NotNull(format, nameof(format));
if (!stream.CanWrite)
{
throw new NotSupportedException("Cannot write to the stream.");
}
IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format);
if (encoder is null)
{
var sb = new StringBuilder();
sb.AppendLine("No encoder was found for the provided mime type. Registered encoders include:");
foreach (KeyValuePair<IImageFormat, IImageEncoder> val in source.GetConfiguration().ImageFormatsManager.ImageEncoders)
{
sb.AppendFormat(" - {0} : {1}{2}", val.Key.Name, val.Value.GetType().Name, Environment.NewLine);
}
throw new NotSupportedException(sb.ToString());
}
return source.SaveAsync(stream, encoder, cancellationToken);
}
/// <summary>
/// Returns a Base64 encoded string from the given image.
/// The result is prepended with a Data URI <see href="https://en.wikipedia.org/wiki/Data_URI_scheme"/>

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

@ -29,8 +29,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// Initializes a new instance of the <see cref="BokehBlurProcessor"/> class.
/// </summary>
public BokehBlurProcessor()
: this(DefaultRadius, DefaultComponents, DefaultGamma)
{
this.Radius = DefaultRadius;
this.Components = DefaultComponents;
this.Gamma = DefaultGamma;
}
/// <summary>
@ -47,6 +49,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// </param>
public BokehBlurProcessor(int radius, int components, float gamma)
{
Guard.MustBeGreaterThan(radius, 0, nameof(radius));
Guard.MustBeBetweenOrEqualTo(components, 1, 6, nameof(components));
Guard.MustBeGreaterThanOrEqualTo(gamma, 1, nameof(gamma));
this.Radius = radius;

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

@ -72,6 +72,37 @@ namespace SixLabors.ImageSharp.Tests
}
}
[Theory]
[InlineData("test.png", "image/png")]
[InlineData("test.tga", "image/tga")]
[InlineData("test.bmp", "image/bmp")]
[InlineData("test.jpg", "image/jpeg")]
[InlineData("test.gif", "image/gif")]
public async Task SaveStreamWithMime(string filename, string mimeType)
{
using (var image = new Image<Rgba32>(5, 5))
{
string ext = Path.GetExtension(filename);
IImageFormat format = image.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext);
Assert.Equal(mimeType, format.DefaultMimeType);
using (var stream = new MemoryStream())
{
var asyncStream = new AsyncStreamWrapper(stream, () => false);
await image.SaveAsync(asyncStream, format);
stream.Position = 0;
(Image Image, IImageFormat Format) imf = await Image.LoadWithFormatAsync(stream);
Assert.Equal(format, imf.Format);
Assert.Equal(mimeType, imf.Format.DefaultMimeType);
imf.Image.Dispose();
}
}
}
[Fact]
public async Task ThrowsWhenDisposed()
{

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

@ -35,6 +35,19 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution
0.02565295+0.01611732j 0.0153483+0.01605112j 0.00698622+0.01370844j
0.00135338+0.00998296j -0.00152245+0.00604545j -0.00227282+0.002851j ]]";
[Theory]
[InlineData(-10, 2, 3f)]
[InlineData(-1, 2, 3f)]
[InlineData(0, 2, 3f)]
[InlineData(20, -1, 3f)]
[InlineData(20, -0, 3f)]
[InlineData(20, 4, -10f)]
[InlineData(20, 4, 0f)]
public void VerifyBokehBlurProcessorArguments_Fail(int radius, int components, float gamma)
{
Assert.Throws<ArgumentOutOfRangeException>(() => new BokehBlurProcessor(radius, components, gamma));
}
[Fact]
public void VerifyComplexComponents()
{

Loading…
Cancel
Save