Browse Source

Add IFileSystem

af/merge-core
Scott Williams 9 years ago
parent
commit
c3367c4d9c
  1. 8
      src/ImageSharp/Configuration.cs
  2. 31
      src/ImageSharp/IO/IFileSystem.cs
  3. 27
      src/ImageSharp/IO/LocalFileSystem.cs
  4. 42
      src/ImageSharp/Image/Image{TColor}.cs
  5. 12
      tests/ImageSharp.Tests/ConfigurationTests.cs
  6. 53
      tests/ImageSharp.Tests/IO/LocalFileSystem.cs
  7. 48
      tests/ImageSharp.Tests/Image/ImageSaveTests.cs
  8. 39
      tests/ImageSharp.Tests/Image/SaveWatchingImage.cs

8
src/ImageSharp/Configuration.cs

@ -12,6 +12,7 @@ namespace ImageSharp
using System.Threading.Tasks;
using Formats;
using ImageSharp.IO;
/// <summary>
/// Provides initialization code which allows extending the library.
@ -53,6 +54,13 @@ namespace ImageSharp
/// </summary>
internal int MaxHeaderSize { get; private set; }
#if !NETSTANDARD1_1
/// <summary>
/// Helper for accessing the local file system.
/// </summary>
internal IFileSystem FileSystem { get; set; } = new LocalFileSystem();
#endif
/// <summary>
/// Adds a new <see cref="IImageFormat"/> to the collection of supported image formats.
/// </summary>

31
src/ImageSharp/IO/IFileSystem.cs

@ -0,0 +1,31 @@
// <copyright file="Endianness.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using System.IO;
namespace ImageSharp.IO
{
#if !NETSTANDARD1_1
/// <summary>
/// A simple interface representing the filesystem.
/// </summary>
public interface IFileSystem
{
/// <summary>
/// Returns a readable stream as defined by the path.
/// </summary>
/// <param name="path">Path to the file to open.</param>
/// <returns>A stream representing the file to open.</returns>
Stream OpenRead(string path);
/// <summary>
/// Creates or opens a file and returns it as a writeable stream as defined by the path.
/// </summary>
/// <param name="path">Path to the file to open.</param>
/// <returns>A stream representing the file to open.</returns>
Stream OpenWrite(string path);
}
#endif
}

27
src/ImageSharp/IO/LocalFileSystem.cs

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace ImageSharp.IO
{
#if !NETSTANDARD1_1
/// <summary>
/// A wrapper around the local File apis.
/// </summary>
public class LocalFileSystem : IFileSystem
{
/// <inheritdoc/>
public Stream OpenRead(string path)
{
return File.OpenRead(path);
}
/// <inheritdoc/>
public Stream OpenWrite(string path)
{
return File.OpenWrite(path);
}
}
#endif
}

42
src/ImageSharp/Image/Image{TColor}.cs

@ -168,7 +168,7 @@ namespace ImageSharp
: base(configuration)
{
Guard.NotNull(filePath, nameof(filePath));
using (FileStream fs = File.OpenRead(filePath))
using (Stream fs = File.OpenRead(filePath))
{
this.Load(fs, options);
}
@ -349,7 +349,7 @@ namespace ImageSharp
public Image<TColor> Save(Stream stream, IEncoderOptions options)
{
Guard.NotNull(stream, nameof(stream));
this.CurrentImageFormat.Encoder.Encode(this, stream, options);
this.SaveInternal(stream, this.CurrentImageFormat?.Encoder, options);
return this;
}
@ -373,9 +373,10 @@ namespace ImageSharp
/// <returns>The <see cref="Image{TColor}"/></returns>
public Image<TColor> Save(Stream stream, IImageFormat format, IEncoderOptions options)
{
Guard.NotNull(stream, nameof(stream));
Guard.NotNull(format, nameof(format));
format.Encoder.Encode(this, stream, options);
this.SaveInternal(stream, format.Encoder, options);
return this;
}
@ -405,15 +406,7 @@ namespace ImageSharp
/// </returns>
public Image<TColor> Save(Stream stream, IImageEncoder encoder, IEncoderOptions options)
{
Guard.NotNull(stream, nameof(stream));
Guard.NotNull(encoder, nameof(encoder));
encoder.Encode(this, stream, options);
// Reset to the start of the stream.
if (stream.CanSeek)
{
stream.Position = 0;
}
this.SaveInternal(stream, encoder, options);
return this;
}
@ -569,6 +562,29 @@ namespace ImageSharp
return target;
}
/// <summary>
/// Internally saves the image to the given stream using the given image encoder and options.
/// Can be used by overridden by tests to verify save opperations.
/// </summary>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <param name="options">The options for the encoder.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream or encoder is null.</exception>
internal virtual void SaveInternal(Stream stream, IImageEncoder encoder, IEncoderOptions options)
{
Guard.NotNull(stream, nameof(stream));
Guard.NotNull(encoder, nameof(encoder));
long startOfStream = stream.Position;
encoder.Encode(this, stream, options);
// Reset to the start of the stream.
if (stream.CanSeek)
{
stream.Position = startOfStream;
}
}
/// <summary>
/// Creates a new <see cref="ImageFrame{TColor}"/> from this instance
/// </summary>

12
tests/ImageSharp.Tests/ConfigurationTests.cs

@ -10,7 +10,7 @@ namespace ImageSharp.Tests
using System.Linq;
using ImageSharp.Formats;
using ImageSharp.IO;
using Xunit;
/// <summary>
@ -18,6 +18,16 @@ namespace ImageSharp.Tests
/// </summary>
public class ConfigurationTests
{
[Fact]
public void DefaultsToLocalFileSystem()
{
var configuration = Configuration.CreateDefaultInstance();
ImageSharp.IO.IFileSystem fs = configuration.FileSystem;
Assert.IsType<LocalFileSystem>(fs);
}
[Fact]
public void IfAutoloadWellknwonFormatesIsTrueAllFormateAreLoaded()
{

53
tests/ImageSharp.Tests/IO/LocalFileSystem.cs

@ -0,0 +1,53 @@
// <copyright file="LittleEndianBitConverterTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Tests.IO
{
using System;
using System.IO;
using ImageSharp.IO;
using Xunit;
public class LocalFileSystemTests
{
[Fact]
public void OpenRead()
{
string path = Path.GetTempFileName();
string testData = Guid.NewGuid().ToString();
File.WriteAllText(path, testData);
LocalFileSystem fs = new LocalFileSystem();
using (var r = new StreamReader(fs.OpenRead(path)))
{
string data = r.ReadToEnd();
Assert.Equal(testData, data);
}
File.Delete(path);
}
[Fact]
public void OpenWrite()
{
string path = Path.GetTempFileName();
string testData = Guid.NewGuid().ToString();
LocalFileSystem fs = new LocalFileSystem();
using (var r = new StreamWriter(fs.OpenWrite(path)))
{
r.Write(testData);
}
string data = File.ReadAllText(path);
Assert.Equal(testData, data);
File.Delete(path);
}
}
}

48
tests/ImageSharp.Tests/Image/ImageSaveTests.cs

@ -0,0 +1,48 @@
// <copyright file="PixelAccessorTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Tests
{
using System;
using System.IO;
using System.Linq;
using ImageSharp.Formats;
using ImageSharp.IO;
using Moq;
using Xunit;
/// <summary>
/// Tests the <see cref="Image"/> class.
/// </summary>
public class ImageSaveTests : IDisposable
{
private readonly SaveWatchingImage Image;
private readonly Mock<IFileSystem> fileSystem;
public ImageSaveTests()
{
this.fileSystem = new Mock<IFileSystem>();
this.Image = new SaveWatchingImage(1, 1, this.fileSystem.Object);
}
[Fact]
public void SavePath()
{
Stream stream = new MemoryStream();
this.fileSystem.Setup(x => x.OpenWrite("path")).Returns(stream);
this.Image.Save("path");
SaveWatchingImage.OperationDetails operation = this.Image.Saves.Single();
Assert.Equal(stream, operation.stream);
Assert.Equal(this.Image.CurrentImageFormat.Encoder, operation.encoder);
Assert.Null(operation.options);
}
public void Dispose()
{
this.Image.Dispose();
}
}
}

39
tests/ImageSharp.Tests/Image/SaveWatchingImage.cs

@ -0,0 +1,39 @@

namespace ImageSharp.Tests
{
using System;
using System.IO;
using ImageSharp;
using Processing;
using System.Collections.Generic;
using ImageSharp.Formats;
using ImageSharp.IO;
/// <summary>
/// Watches but does not actually run the processors against the image.
/// </summary>
/// <seealso cref="ImageSharp.Image{ImageSharp.Color}" />
public class SaveWatchingImage : Image<Color>
{
public List<OperationDetails> Saves { get; } = new List<OperationDetails>();
public SaveWatchingImage(int width, int height, IFileSystem fs = null)
: base(width, height, Configuration.CreateDefaultInstance())
{
//switch out the file system for tests
this.Configuration.FileSystem = fs ?? this.Configuration.FileSystem;
}
internal override void SaveInternal(Stream stream, IImageEncoder encoder, IEncoderOptions options)
{
}
public struct OperationDetails
{
public Stream stream;
public IImageEncoder encoder;
public IEncoderOptions options;
}
}
}
Loading…
Cancel
Save