Browse Source

Intial stubs of files needed for webp encoding

pull/1552/head
Brian Popow 6 years ago
parent
commit
7b9d4ce269
  1. 2
      src/ImageSharp/Advanced/AotCompilerTools.cs
  2. 12
      src/ImageSharp/Formats/WebP/BitWriter/Vp8BitWriter.cs
  3. 12
      src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs
  4. 12
      src/ImageSharp/Formats/WebP/IWebPEncoderOptions.cs
  5. 36
      src/ImageSharp/Formats/WebP/ImageExtensions.cs
  6. 23
      src/ImageSharp/Formats/WebP/WebPEncoder.cs
  7. 53
      src/ImageSharp/Formats/WebP/WebPEncoderCore.cs
  8. 1
      src/ImageSharp/Formats/WebP/WebpConfigurationModule.cs
  9. 46
      tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs
  10. 9
      tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs
  11. 3
      tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs
  12. 4
      tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs
  13. 4
      tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs
  14. 4
      tests/Images/Input/WebP/earth_lossless.webp
  15. 4
      tests/Images/Input/WebP/earth_lossy.webp

2
src/ImageSharp/Advanced/AotCompilerTools.cs

@ -94,6 +94,8 @@ namespace SixLabors.ImageSharp.Advanced
AotCodec<TPixel>(new Formats.Bmp.BmpDecoder(), new Formats.Bmp.BmpEncoder());
AotCodec<TPixel>(new Formats.Gif.GifDecoder(), new Formats.Gif.GifEncoder());
AotCodec<TPixel>(new Formats.Jpeg.JpegDecoder(), new Formats.Jpeg.JpegEncoder());
AotCodec<TPixel>(new Formats.Tga.TgaDecoder(), new Formats.Tga.TgaEncoder());
AotCodec<TPixel>(new Formats.WebP.WebPDecoder(), new Formats.WebP.WebPEncoder());
// TODO: Do the discovery work to figure out what works and what doesn't.
}

12
src/ImageSharp/Formats/WebP/BitWriter/Vp8BitWriter.cs

@ -0,0 +1,12 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the GNU Affero General Public License, Version 3.
namespace SixLabors.ImageSharp.Formats.WebP.BitWriter
{
/// <summary>
/// A bit writer for writing lossless webp streams.
/// </summary>
internal class Vp8BitWriter
{
}
}

12
src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs

@ -0,0 +1,12 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the GNU Affero General Public License, Version 3.
namespace SixLabors.ImageSharp.Formats.WebP.BitWriter
{
/// <summary>
/// A bit writer for writing lossless webp streams.
/// </summary>
internal class Vp8LBitWriter
{
}
}

12
src/ImageSharp/Formats/WebP/IWebPEncoderOptions.cs

@ -0,0 +1,12 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the GNU Affero General Public License, Version 3.
namespace SixLabors.ImageSharp.Formats.WebP
{
/// <summary>
/// Configuration options for use during webp encoding.
/// </summary>
internal interface IWebPEncoderOptions
{
}
}

36
src/ImageSharp/Formats/WebP/ImageExtensions.cs

@ -0,0 +1,36 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.WebP;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Extension methods for the <see cref="Image"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Saves the image to the given stream with the webp format.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsWebp(this Image source, Stream stream) => SaveAsWebp(source, stream, null);
/// <summary>
/// Saves the image to the given stream with the webp format.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The options for the encoder.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsWebp(this Image source, Stream stream, WebPEncoder encoder) =>
source.Save(
stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(WebPFormat.Instance));
}
}

23
src/ImageSharp/Formats/WebP/WebPEncoder.cs

@ -0,0 +1,23 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.WebP
{
/// <summary>
/// Image encoder for writing an image to a stream in the WebP format.
/// </summary>
public sealed class WebPEncoder : IImageEncoder, IWebPEncoderOptions
{
/// <inheritdoc/>
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
var encoder = new WebPEncoderCore(this, image.GetMemoryAllocator());
encoder.Encode(image, stream);
}
}
}

53
src/ImageSharp/Formats/WebP/WebPEncoderCore.cs

@ -0,0 +1,53 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.WebP
{
/// <summary>
/// Image encoder for writing an image to a stream in the WebP format.
/// </summary>
internal sealed class WebPEncoderCore
{
/// <summary>
/// Used for allocating memory during processing operations.
/// </summary>
private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// The global configuration.
/// </summary>
private Configuration configuration;
/// <summary>
/// Initializes a new instance of the <see cref="WebPEncoderCore"/> class.
/// </summary>
/// <param name="options">The encoder options.</param>
/// <param name="memoryAllocator">The memory manager.</param>
public WebPEncoderCore(IWebPEncoderOptions options, MemoryAllocator memoryAllocator)
{
this.memoryAllocator = memoryAllocator;
}
/// <summary>
/// Encodes the image to the specified stream from the <see cref="ImageFrame{TPixel}"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageFrame{TPixel}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
this.configuration = image.GetConfiguration();
ImageMetadata metadata = image.Metadata;
}
}
}

1
src/ImageSharp/Formats/WebP/WebpConfigurationModule.cs

@ -12,6 +12,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
public void Configure(Configuration configuration)
{
configuration.ImageFormatsManager.SetDecoder(WebPFormat.Instance, new WebPDecoder());
configuration.ImageFormatsManager.SetEncoder(WebPFormat.Instance, new WebPEncoder());
configuration.ImageFormatsManager.AddImageFormatDetector(new WebPImageFormatDetector());
}
}

46
tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs

@ -67,28 +67,30 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
return image.Height;
}
/* Results 18.03.2020
* BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18362
Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.1.200
[Host] : .NET Core 3.1.2 (CoreCLR 4.700.20.6602, CoreFX 4.700.20.6702), X64 RyuJIT
Job-TLYXIR : .NET Framework 4.8 (4.8.4121.0), X64 RyuJIT
Job-HPKRXU : .NET Core 2.1.16 (CoreCLR 4.6.28516.03, CoreFX 4.6.28516.10), X64 RyuJIT
Job-OBFQMR : .NET Core 3.1.2 (CoreCLR 4.700.20.6602, CoreFX 4.700.20.6702), X64 RyuJIT
| Method | Runtime | TestImageLossy | TestImageLossless | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|--------------------------- |-------------- |--------------------- |--------------------- |----------:|----------:|---------:|-----------:|----------:|----------:|-------------:|
| 'Magick Lossy WebP' | .NET 4.7.2 | WebP/(...).webp [21] | WebP/(...).webp [24] | 70.37 ms | 9.234 ms | 0.506 ms | - | - | - | 32.05 KB |
| 'ImageSharp Lossy Webp' | .NET 4.7.2 | WebP/(...).webp [21] | WebP/(...).webp [24] | 211.77 ms | 8.055 ms | 0.442 ms | 19000.0000 | - | - | 82297.31 KB |
| 'Magick Lossless WebP' | .NET 4.7.2 | WebP/(...).webp [21] | WebP/(...).webp [24] | 49.35 ms | 1.099 ms | 0.060 ms | - | - | - | 15.32 KB |
| 'ImageSharp Lossless Webp' | .NET 4.7.2 | WebP/(...).webp [21] | WebP/(...).webp [24] | 494.34 ms | 5.505 ms | 0.302 ms | 2000.0000 | 1000.0000 | 1000.0000 | 151801.78 KB |
| 'Magick Lossy WebP' | .NET Core 2.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 70.21 ms | 1.440 ms | 0.079 ms | - | - | - | 14.8 KB |
| 'ImageSharp Lossy Webp' | .NET Core 2.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 142.32 ms | 6.046 ms | 0.331 ms | 9000.0000 | - | - | 40610.23 KB |
| 'Magick Lossless WebP' | .NET Core 2.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 49.44 ms | 0.258 ms | 0.014 ms | - | - | - | 14.3 KB |
| 'ImageSharp Lossless Webp' | .NET Core 2.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 206.45 ms | 11.093 ms | 0.608 ms | 2666.6667 | 1666.6667 | 1000.0000 | 151758.87 KB |
| 'Magick Lossy WebP' | .NET Core 3.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 69.69 ms | 1.147 ms | 0.063 ms | - | - | - | 14.42 KB |
| 'ImageSharp Lossy Webp' | .NET Core 3.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 121.72 ms | 2.373 ms | 0.130 ms | 9000.0000 | - | - | 40050.06 KB |
| 'Magick Lossless WebP' | .NET Core 3.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 49.37 ms | 1.865 ms | 0.102 ms | - | - | - | 14.27 KB |
| 'ImageSharp Lossless Webp' | .NET Core 3.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 194.03 ms | 37.759 ms | 2.070 ms | 2000.0000 | 1000.0000 | 1000.0000 | 151756.38 KB |
/* Results 15.05.2020
* BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18362
Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.1.202
[Host] : .NET Core 3.1.4 (CoreCLR 4.700.20.20201, CoreFX 4.700.20.22101), X64 RyuJIT
Job-AQFZAV : .NET Framework 4.8 (4.8.4180.0), X64 RyuJIT
Job-YCDAPQ : .NET Core 2.1.18 (CoreCLR 4.6.28801.04, CoreFX 4.6.28802.05), X64 RyuJIT
Job-WMTYOZ : .NET Core 3.1.4 (CoreCLR 4.700.20.20201, CoreFX 4.700.20.22101), X64 RyuJIT
IterationCount=3 LaunchCount=1 WarmupCount=3
| Method | Runtime | TestImageLossy | TestImageLossless | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|--------------------------- |-------------- |--------------------- |--------------------- |-----------:|----------:|--------:|----------:|----------:|------:|-------------:|
| 'Magick Lossy WebP' | .NET 4.7.2 | WebP/(...).webp [21] | WebP/(...).webp [24] | 125.2 ms | 7.93 ms | 0.43 ms | - | - | - | 18.05 KB |
| 'ImageSharp Lossy Webp' | .NET 4.7.2 | WebP/(...).webp [21] | WebP/(...).webp [24] | 1,102.1 ms | 67.88 ms | 3.72 ms | 2000.0000 | - | - | 11835.55 KB |
| 'Magick Lossless WebP' | .NET 4.7.2 | WebP/(...).webp [21] | WebP/(...).webp [24] | 183.6 ms | 7.11 ms | 0.39 ms | - | - | - | 18.71 KB |
| 'ImageSharp Lossless Webp' | .NET 4.7.2 | WebP/(...).webp [21] | WebP/(...).webp [24] | 1,820.1 ms | 68.66 ms | 3.76 ms | 4000.0000 | 1000.0000 | - | 223765.64 KB |
| 'Magick Lossy WebP' | .NET Core 2.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 124.7 ms | 1.92 ms | 0.11 ms | - | - | - | 15.97 KB |
| 'ImageSharp Lossy Webp' | .NET Core 2.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 739.0 ms | 39.51 ms | 2.17 ms | 2000.0000 | - | - | 11802.98 KB |
| 'Magick Lossless WebP' | .NET Core 2.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 184.0 ms | 21.65 ms | 1.19 ms | - | - | - | 17.96 KB |
| 'ImageSharp Lossless Webp' | .NET Core 2.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 618.3 ms | 16.33 ms | 0.90 ms | 4000.0000 | 1000.0000 | - | 223699.11 KB |
| 'Magick Lossy WebP' | .NET Core 3.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 125.6 ms | 17.51 ms | 0.96 ms | - | - | - | 16.1 KB |
| 'ImageSharp Lossy Webp' | .NET Core 3.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 768.4 ms | 114.73 ms | 6.29 ms | 2000.0000 | - | - | 11802.89 KB |
| 'Magick Lossless WebP' | .NET Core 3.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 183.6 ms | 3.32 ms | 0.18 ms | - | - | - | 17 KB |
| 'ImageSharp Lossless Webp' | .NET Core 3.1 | WebP/(...).webp [21] | WebP/(...).webp [24] | 621.3 ms | 12.12 ms | 0.66 ms | 4000.0000 | 1000.0000 | - | 223698.75 KB |
*/
}
}

9
tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs

@ -127,6 +127,11 @@ namespace SixLabors.ImageSharp.Tests.Formats
{
image.SaveAsTga(output);
}
using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.webp")))
{
image.SaveAsWebp(output);
}
}
}
}
@ -174,6 +179,8 @@ namespace SixLabors.ImageSharp.Tests.Formats
[InlineData(100, 100, "tga")]
[InlineData(100, 10, "tga")]
[InlineData(10, 100, "tga")]
[InlineData(100, 10, "webp")]
[InlineData(10, 100, "webp")]
public void CanIdentifyImageLoadedFromBytes(int width, int height, string extension)
{
using (var image = Image.LoadPixelData(new Rgba32[width * height], width, height))
@ -200,7 +207,7 @@ namespace SixLabors.ImageSharp.Tests.Formats
[Fact]
public void IdentifyReturnsNullWithInvalidStream()
{
byte[] invalid = new byte[10];
var invalid = new byte[10];
using (var memoryStream = new MemoryStream(invalid))
{

3
tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs

@ -11,6 +11,7 @@ using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Formats.WebP;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
@ -36,12 +37,14 @@ namespace SixLabors.ImageSharp.Tests.Formats
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<JpegEncoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<GifEncoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<TgaEncoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<WebPEncoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<PngDecoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<BmpDecoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<JpegDecoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<BmpDecoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<TgaDecoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<WebPDecoder>().Count());
}
[Fact]

4
tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs

@ -9,6 +9,7 @@ using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Formats.WebP;
using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
namespace SixLabors.ImageSharp.Tests
@ -55,7 +56,8 @@ namespace SixLabors.ImageSharp.Tests
var cfg = new Configuration(
new JpegConfigurationModule(),
new GifConfigurationModule(),
new TgaConfigurationModule());
new TgaConfigurationModule(),
new WebPConfigurationModule());
// Magick codecs should work on all platforms
IImageEncoder pngEncoder = IsWindows ? (IImageEncoder)SystemDrawingReferenceEncoder.Png : new PngEncoder();

4
tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs

@ -9,6 +9,7 @@ using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.WebP;
using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
using Xunit;
@ -81,6 +82,7 @@ namespace SixLabors.ImageSharp.Tests
[InlineData("lol/Rofl.bmp", typeof(SystemDrawingReferenceDecoder))]
[InlineData("lol/Baz.JPG", typeof(JpegDecoder))]
[InlineData("lol/Baz.gif", typeof(GifDecoder))]
[InlineData("lol/foobar.webp", typeof(MagickReferenceDecoder))]
public void GetReferenceDecoder_ReturnsCorrectDecoders_Windows(string fileName, Type expectedDecoderType)
{
if (TestEnvironment.IsLinux)
@ -97,6 +99,7 @@ namespace SixLabors.ImageSharp.Tests
[InlineData("lol/Rofl.bmp", typeof(BmpEncoder))]
[InlineData("lol/Baz.JPG", typeof(JpegEncoder))]
[InlineData("lol/Baz.gif", typeof(GifEncoder))]
[InlineData("lol/foobar.webp", typeof(WebPEncoder))]
public void GetReferenceEncoder_ReturnsCorrectEncoders_Linux(string fileName, Type expectedEncoderType)
{
if (!TestEnvironment.IsLinux)
@ -113,6 +116,7 @@ namespace SixLabors.ImageSharp.Tests
[InlineData("lol/Rofl.bmp", typeof(MagickReferenceDecoder))]
[InlineData("lol/Baz.JPG", typeof(JpegDecoder))]
[InlineData("lol/Baz.gif", typeof(GifDecoder))]
[InlineData("lol/foobar.webp", typeof(MagickReferenceDecoder))]
public void GetReferenceDecoder_ReturnsCorrectDecoders_Linux(string fileName, Type expectedDecoderType)
{
if (!TestEnvironment.IsLinux)

4
tests/Images/Input/WebP/earth_lossless.webp

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1ea7fad78cd68e27c1616f4a99de52397f5485259c7adbd674a5c9a362885216
size 2447273
oid sha256:35e61613388342baac7f39a4a3c3ae32587a065505269115a134592eee9563b8
size 7813062

4
tests/Images/Input/WebP/earth_lossy.webp

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:71263c0db7b8cd2e787b8554fd40aff1d46a753646fb2062966ca07ac040e841
size 852402
oid sha256:c45c068709fa3f878564d399e539636b9e42926291dde683adb7bb5d98c2c680
size 467258

Loading…
Cancel
Save