From e5ea99f222a6da1e9d76ea0ab3f769294aeb2f23 Mon Sep 17 00:00:00 2001 From: Toxantron Date: Sun, 19 Feb 2017 21:57:01 +0100 Subject: [PATCH 01/37] Develop with VSCode --- .vscode/tasks.json | 24 ++++++++++++++++++++++++ README.md | 5 +++++ 2 files changed, 29 insertions(+) create mode 100644 .vscode/tasks.json diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000000..aeae5c6ca9 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,24 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "0.1.0", + "command": "dotnet", + "isShellCommand": true, + "args": [], + "tasks": [ + { + "taskName": "build", + "args": [ "src/*/project.json", "-f", "netstandard1.1" ], + "isBuildCommand": true, + "showOutput": "always", + "problemMatcher": "$msCompile" + }, + { + "taskName": "test", + "args": ["tests/ImageSharp.Tests/project.json", "-f", "netcoreapp1.1"], + "isTestCommand": true, + "showOutput": "always", + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index cfbd18de6e..cbe03bb4e1 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,11 @@ If you prefer, you can compile ImageSharp yourself (please do and help!), you'll - [Visual Studio 2015 with Update 3 (or above)](https://www.visualstudio.com/news/releasenotes/vs2015-update3-vs) - The [.NET Core 1.0 SDK Installer](https://www.microsoft.com/net/core#windows) - Non VSCode link. +Alternatively on Linux you can use: + +- [Visual Studio Code](https://code.visualstudio.com/) with [C# Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp) +- [.Net Core 1.1](https://www.microsoft.com/net/core#linuxubuntu) + To clone it locally click the "Clone in Windows" button above or run the following git commands. ```bash From 395505ac66338d9a648fb2095d3ac21b5032e3ab Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sat, 18 Feb 2017 13:16:49 +0100 Subject: [PATCH 02/37] Added options for the decoder. --- src/ImageSharp.Formats.Bmp/BmpDecoder.cs | 2 +- src/ImageSharp.Formats.Gif/GifDecoder.cs | 2 +- src/ImageSharp.Formats.Jpeg/JpegDecoder.cs | 2 +- src/ImageSharp.Formats.Png/PngDecoder.cs | 9 ++---- src/ImageSharp/Formats/DecoderOptions.cs | 18 ++++++++++++ src/ImageSharp/Formats/IDecoderOptions.cs | 18 ++++++++++++ src/ImageSharp/Formats/IImageDecoder.cs | 3 +- src/ImageSharp/Image.cs | 23 +++++++++++---- src/ImageSharp/Image/Image{TColor}.cs | 33 ++++++++++++++-------- 9 files changed, 82 insertions(+), 28 deletions(-) create mode 100644 src/ImageSharp/Formats/DecoderOptions.cs create mode 100644 src/ImageSharp/Formats/IDecoderOptions.cs diff --git a/src/ImageSharp.Formats.Bmp/BmpDecoder.cs b/src/ImageSharp.Formats.Bmp/BmpDecoder.cs index 4b7da38afc..9f490a3a9b 100644 --- a/src/ImageSharp.Formats.Bmp/BmpDecoder.cs +++ b/src/ImageSharp.Formats.Bmp/BmpDecoder.cs @@ -26,7 +26,7 @@ namespace ImageSharp.Formats public class BmpDecoder : IImageDecoder { /// - public void Decode(Image image, Stream stream) + public void Decode(Image image, Stream stream, IDecoderOptions options) where TColor : struct, IPixel { Guard.NotNull(image, "image"); diff --git a/src/ImageSharp.Formats.Gif/GifDecoder.cs b/src/ImageSharp.Formats.Gif/GifDecoder.cs index 76530dc504..aea96bb65f 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoder.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoder.cs @@ -14,7 +14,7 @@ namespace ImageSharp.Formats public class GifDecoder : IImageDecoder { /// - public void Decode(Image image, Stream stream) + public void Decode(Image image, Stream stream, IDecoderOptions options) where TColor : struct, IPixel { new GifDecoderCore().Decode(image, stream); diff --git a/src/ImageSharp.Formats.Jpeg/JpegDecoder.cs b/src/ImageSharp.Formats.Jpeg/JpegDecoder.cs index 435ae51cfd..a399bb6b38 100644 --- a/src/ImageSharp.Formats.Jpeg/JpegDecoder.cs +++ b/src/ImageSharp.Formats.Jpeg/JpegDecoder.cs @@ -14,7 +14,7 @@ namespace ImageSharp.Formats public class JpegDecoder : IImageDecoder { /// - public void Decode(Image image, Stream stream) + public void Decode(Image image, Stream stream, IDecoderOptions options) where TColor : struct, IPixel { Guard.NotNull(image, "image"); diff --git a/src/ImageSharp.Formats.Png/PngDecoder.cs b/src/ImageSharp.Formats.Png/PngDecoder.cs index 088bea5919..9aab6673a9 100644 --- a/src/ImageSharp.Formats.Png/PngDecoder.cs +++ b/src/ImageSharp.Formats.Png/PngDecoder.cs @@ -30,13 +30,8 @@ namespace ImageSharp.Formats /// public class PngDecoder : IImageDecoder { - /// - /// Decodes the image from the specified stream to the . - /// - /// The pixel format. - /// The to decode to. - /// The containing image data. - public void Decode(Image image, Stream stream) + /// + public void Decode(Image image, Stream stream, IDecoderOptions options) where TColor : struct, IPixel { new PngDecoderCore().Decode(image, stream); diff --git a/src/ImageSharp/Formats/DecoderOptions.cs b/src/ImageSharp/Formats/DecoderOptions.cs new file mode 100644 index 0000000000..f25e33d71f --- /dev/null +++ b/src/ImageSharp/Formats/DecoderOptions.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + /// + /// Encapsulates the shared decoder options. + /// + public class DecoderOptions : IDecoderOptions + { + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; set; } + } +} diff --git a/src/ImageSharp/Formats/IDecoderOptions.cs b/src/ImageSharp/Formats/IDecoderOptions.cs new file mode 100644 index 0000000000..460de3eb28 --- /dev/null +++ b/src/ImageSharp/Formats/IDecoderOptions.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + /// + /// Encapsulates the shared decoder options. + /// + public interface IDecoderOptions + { + /// + /// Gets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + bool IgnoreMetadata { get; } + } +} diff --git a/src/ImageSharp/Formats/IImageDecoder.cs b/src/ImageSharp/Formats/IImageDecoder.cs index 28bda7837e..df98870ddd 100644 --- a/src/ImageSharp/Formats/IImageDecoder.cs +++ b/src/ImageSharp/Formats/IImageDecoder.cs @@ -19,7 +19,8 @@ namespace ImageSharp.Formats /// The pixel format. /// The to decode to. /// The containing image data. - void Decode(Image image, Stream stream) + /// The options for the decoder. + void Decode(Image image, Stream stream, IDecoderOptions options) where TColor : struct, IPixel; } } diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs index bdb6b49a92..b1c1252ab4 100644 --- a/src/ImageSharp/Image.cs +++ b/src/ImageSharp/Image.cs @@ -8,6 +8,8 @@ namespace ImageSharp using System.Diagnostics; using System.IO; + using Formats; + /// /// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha /// packed into a single unsigned integer value. @@ -35,12 +37,15 @@ namespace ImageSharp /// /// The stream containing image information. /// + /// + /// The options for the decoder. + /// /// /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(Stream stream, Configuration configuration = null) - : base(stream, configuration) + public Image(Stream stream, IDecoderOptions options = null, Configuration configuration = null) + : base(stream, options, configuration) { } @@ -51,12 +56,15 @@ namespace ImageSharp /// /// A file path to read image information. /// + /// + /// The options for the decoder. + /// /// /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(string filePath, Configuration configuration = null) - : base(filePath, configuration) + public Image(string filePath, IDecoderOptions options = null, Configuration configuration = null) + : base(filePath, options, configuration) { } #endif @@ -67,12 +75,15 @@ namespace ImageSharp /// /// The byte array containing image information. /// + /// + /// The options for the decoder. + /// /// /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(byte[] bytes, Configuration configuration = null) - : base(bytes, configuration) + public Image(byte[] bytes, IDecoderOptions options = null, Configuration configuration = null) + : base(bytes, options, configuration) { } diff --git a/src/ImageSharp/Image/Image{TColor}.cs b/src/ImageSharp/Image/Image{TColor}.cs index bbd839d168..9e4ecba2f5 100644 --- a/src/ImageSharp/Image/Image{TColor}.cs +++ b/src/ImageSharp/Image/Image{TColor}.cs @@ -52,15 +52,18 @@ namespace ImageSharp /// /// The stream containing image information. /// + /// + /// The options for the decoder. + /// /// /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(Stream stream, Configuration configuration = null) + public Image(Stream stream, IDecoderOptions options = null, Configuration configuration = null) : base(configuration) { Guard.NotNull(stream, nameof(stream)); - this.Load(stream); + this.Load(stream, options); } #if !NETSTANDARD1_1 @@ -70,17 +73,20 @@ namespace ImageSharp /// /// The file containing image information. /// + /// + /// The options for the decoder. + /// /// /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(string filePath, Configuration configuration = null) + public Image(string filePath, IDecoderOptions options = null, Configuration configuration = null) : base(configuration) { Guard.NotNull(filePath, nameof(filePath)); using (var fs = File.OpenRead(filePath)) { - this.Load(fs); + this.Load(fs, options); } } #endif @@ -91,18 +97,21 @@ namespace ImageSharp /// /// The byte array containing image information. /// + /// + /// The options for the decoder. + /// /// /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(byte[] bytes, Configuration configuration = null) + public Image(byte[] bytes, IDecoderOptions options = null, Configuration configuration = null) : base(configuration) { Guard.NotNull(bytes, nameof(bytes)); using (MemoryStream stream = new MemoryStream(bytes, false)) { - this.Load(stream); + this.Load(stream, options); } } @@ -397,10 +406,11 @@ namespace ImageSharp /// Loads the image from the given stream. /// /// The stream containing image information. + /// The options for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// - private void Load(Stream stream) + private void Load(Stream stream, IDecoderOptions options) { if (!this.Configuration.ImageFormats.Any()) { @@ -414,7 +424,7 @@ namespace ImageSharp if (stream.CanSeek) { - if (this.Decode(stream)) + if (this.Decode(stream, options)) { return; } @@ -427,7 +437,7 @@ namespace ImageSharp stream.CopyTo(ms); ms.Position = 0; - if (this.Decode(ms)) + if (this.Decode(ms, options)) { return; } @@ -449,10 +459,11 @@ namespace ImageSharp /// Decodes the image stream to the current image. /// /// The stream. + /// The options for the decoder. /// /// The . /// - private bool Decode(Stream stream) + private bool Decode(Stream stream, IDecoderOptions options) { int maxHeaderSize = this.Configuration.MaxHeaderSize; if (maxHeaderSize <= 0) @@ -479,7 +490,7 @@ namespace ImageSharp return false; } - format.Decoder.Decode(this, stream); + format.Decoder.Decode(this, stream, options); this.CurrentImageFormat = format; return true; } From 32481be496245d2917609ca23fcbd8a8ca74b49a Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sat, 18 Feb 2017 18:59:59 +0100 Subject: [PATCH 03/37] Implemented the IDecoderOptions inside the gif decoder. --- src/ImageSharp.Formats.Gif/GifDecoder.cs | 2 +- src/ImageSharp.Formats.Gif/GifDecoderCore.cs | 38 +++++++++++---- src/ImageSharp/Formats/DecoderOptions.cs | 16 ++++++- src/ImageSharp/Formats/IDecoderOptions.cs | 2 +- .../Formats/Gif/GifDecoderCoreTests.cs | 46 +++++++++++++++++++ .../TestImages/Formats/Gif/rings.gif | 4 +- 6 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 tests/ImageSharp.Tests/Formats/Gif/GifDecoderCoreTests.cs diff --git a/src/ImageSharp.Formats.Gif/GifDecoder.cs b/src/ImageSharp.Formats.Gif/GifDecoder.cs index aea96bb65f..42dbf4fc7b 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoder.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoder.cs @@ -17,7 +17,7 @@ namespace ImageSharp.Formats public void Decode(Image image, Stream stream, IDecoderOptions options) where TColor : struct, IPixel { - new GifDecoderCore().Decode(image, stream); + new GifDecoderCore(options).Decode(image, stream); } } } diff --git a/src/ImageSharp.Formats.Gif/GifDecoderCore.cs b/src/ImageSharp.Formats.Gif/GifDecoderCore.cs index 5812b9f297..50d4da0ebc 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoderCore.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoderCore.cs @@ -8,6 +8,7 @@ namespace ImageSharp.Formats using System; using System.Buffers; using System.IO; + using System.Text; /// /// Performs the gif decoding operation. @@ -21,6 +22,11 @@ namespace ImageSharp.Formats /// private readonly byte[] buffer = new byte[16]; + /// + /// The decoder options. + /// + private readonly IDecoderOptions options; + /// /// The image to decode the information to. /// @@ -61,6 +67,15 @@ namespace ImageSharp.Formats /// private GifGraphicsControlExtension graphicsControlExtension; + /// + /// Initializes a new instance of the class. + /// + /// The decoder options. + public GifDecoderCore(IDecoderOptions options) + { + this.options = options ?? DecoderOptions.Default; + } + /// /// Decodes the stream to the image. /// @@ -225,25 +240,32 @@ namespace ImageSharp.Formats /// private void ReadComments() { - int flag; + int length; - while ((flag = this.currentStream.ReadByte()) != 0) + while ((length = this.currentStream.ReadByte()) != 0) { - if (flag > GifConstants.MaxCommentLength) + if (length > GifConstants.MaxCommentLength) + { + throw new ImageFormatException($"Gif comment length '{length}' exceeds max '{GifConstants.MaxCommentLength}'"); + } + + if (this.options.IgnoreMetadata) { - throw new ImageFormatException($"Gif comment length '{flag}' exceeds max '{GifConstants.MaxCommentLength}'"); + this.currentStream.Seek(length, SeekOrigin.Current); + continue; } - byte[] flagBuffer = ArrayPool.Shared.Rent(flag); + byte[] commentsBuffer = ArrayPool.Shared.Rent(length); try { - this.currentStream.Read(flagBuffer, 0, flag); - this.decodedImage.MetaData.Properties.Add(new ImageProperty("Comments", BitConverter.ToString(flagBuffer, 0, flag))); + this.currentStream.Read(commentsBuffer, 0, length); + string comments = Encoding.GetEncoding("ASCII").GetString(commentsBuffer, 0, length); + this.decodedImage.MetaData.Properties.Add(new ImageProperty("Comments", comments)); } finally { - ArrayPool.Shared.Return(flagBuffer); + ArrayPool.Shared.Return(commentsBuffer); } } } diff --git a/src/ImageSharp/Formats/DecoderOptions.cs b/src/ImageSharp/Formats/DecoderOptions.cs index f25e33d71f..a9bb152f12 100644 --- a/src/ImageSharp/Formats/DecoderOptions.cs +++ b/src/ImageSharp/Formats/DecoderOptions.cs @@ -3,13 +3,27 @@ // Licensed under the Apache License, Version 2.0. // -namespace ImageSharp.Formats +namespace ImageSharp { /// /// Encapsulates the shared decoder options. /// public class DecoderOptions : IDecoderOptions { + /// + /// Gets the default decoder options + /// + public static DecoderOptions Default + { + get + { + return new DecoderOptions() + { + IgnoreMetadata = false + }; + } + } + /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. /// diff --git a/src/ImageSharp/Formats/IDecoderOptions.cs b/src/ImageSharp/Formats/IDecoderOptions.cs index 460de3eb28..cdfd90d5e2 100644 --- a/src/ImageSharp/Formats/IDecoderOptions.cs +++ b/src/ImageSharp/Formats/IDecoderOptions.cs @@ -3,7 +3,7 @@ // Licensed under the Apache License, Version 2.0. // -namespace ImageSharp.Formats +namespace ImageSharp { /// /// Encapsulates the shared decoder options. diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderCoreTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderCoreTests.cs new file mode 100644 index 0000000000..758c724005 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderCoreTests.cs @@ -0,0 +1,46 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests +{ + using Xunit; + + public class GifDecoderCoreTests + { + [Fact] + public void Decode_IgnoreMetadataIsFalse_CommentsAreRead() + { + var options = new DecoderOptions() + { + IgnoreMetadata = false + }; + + TestFile testFile = TestFile.Create(TestImages.Gif.Rings); + + using (Image image = new Image(testFile.FilePath, options)) + { + Assert.Equal(1, image.MetaData.Properties.Count); + Assert.Equal("Comments", image.MetaData.Properties[0].Name); + Assert.Equal("ImageSharp", image.MetaData.Properties[0].Value); + } + } + + [Fact] + public void Decode_IgnoreMetadataIsTrue_CommentsAreIgnored() + { + var options = new DecoderOptions() + { + IgnoreMetadata = true + }; + + TestFile testFile = TestFile.Create(TestImages.Gif.Rings); + + using (Image image = new Image(testFile.FilePath, options)) + { + Assert.Equal(0, image.MetaData.Properties.Count); + } + } + } +} diff --git a/tests/ImageSharp.Tests/TestImages/Formats/Gif/rings.gif b/tests/ImageSharp.Tests/TestImages/Formats/Gif/rings.gif index acd5d6339c..a714dbfbbf 100644 --- a/tests/ImageSharp.Tests/TestImages/Formats/Gif/rings.gif +++ b/tests/ImageSharp.Tests/TestImages/Formats/Gif/rings.gif @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:716448da88152225767c024aac498f5b7562b6e8391907cefc9d03dba40050fd -size 53435 +oid sha256:a7b9b5f5056a8d90134d72b462bf37675ab37aa2551ffeae0072037a0a27ad74 +size 53457 From c7ced5bcdfaac6569e94830032de2835a02844a2 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sat, 18 Feb 2017 20:42:10 +0100 Subject: [PATCH 04/37] Implemented the IDecoderOptions inside the jpeg decoder. --- src/ImageSharp.Formats.Jpeg/JpegDecoder.cs | 2 +- .../JpegDecoderCore.cs | 11 ++++- .../Formats/Jpg/JpegDecoderCoreTests.cs | 44 +++++++++++++++++++ .../Formats/Jpg/JpegDecoderTests.cs | 2 +- 4 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderCoreTests.cs diff --git a/src/ImageSharp.Formats.Jpeg/JpegDecoder.cs b/src/ImageSharp.Formats.Jpeg/JpegDecoder.cs index a399bb6b38..eeb371d1e7 100644 --- a/src/ImageSharp.Formats.Jpeg/JpegDecoder.cs +++ b/src/ImageSharp.Formats.Jpeg/JpegDecoder.cs @@ -20,7 +20,7 @@ namespace ImageSharp.Formats Guard.NotNull(image, "image"); Guard.NotNull(stream, "stream"); - using (JpegDecoderCore decoder = new JpegDecoderCore()) + using (JpegDecoderCore decoder = new JpegDecoderCore(options)) { decoder.Decode(image, stream, false); } diff --git a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs index 6577876828..19b3df5368 100644 --- a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs @@ -37,6 +37,11 @@ namespace ImageSharp.Formats public InputProcessor InputProcessor; #pragma warning restore SA401 + /// + /// The decoder options. + /// + private readonly IDecoderOptions options; + /// /// The App14 marker color-space /// @@ -85,8 +90,10 @@ namespace ImageSharp.Formats /// /// Initializes a new instance of the class. /// - public JpegDecoderCore() + /// The decoder options. + public JpegDecoderCore(IDecoderOptions options) { + this.options = options ?? DecoderOptions.Default; this.HuffmanTrees = HuffmanTree.CreateHuffmanTrees(); this.QuantizationTables = new Block8x8F[MaxTq + 1]; this.Temp = new byte[2 * Block8x8F.ScalarCount]; @@ -958,7 +965,7 @@ namespace ImageSharp.Formats private void ProcessApp1Marker(int remaining, Image image) where TColor : struct, IPixel { - if (remaining < 6) + if (remaining < 6 || this.options.IgnoreMetadata) { this.InputProcessor.Skip(remaining); return; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderCoreTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderCoreTests.cs new file mode 100644 index 0000000000..18d9e3acfb --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderCoreTests.cs @@ -0,0 +1,44 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests +{ + using Xunit; + + public class JpegDecoderCoreTests + { + [Fact] + public void Decode_IgnoreMetadataIsFalse_ExifProfileIsRead() + { + var options = new DecoderOptions() + { + IgnoreMetadata = false + }; + + TestFile testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan); + + using (Image image = new Image(testFile.FilePath, options)) + { + Assert.NotNull(image.MetaData.ExifProfile); + } + } + + [Fact] + public void Decode_IgnoreMetadataIsTrue_ExifProfileIgnored() + { + var options = new DecoderOptions() + { + IgnoreMetadata = true + }; + + TestFile testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan); + + using (Image image = new Image(testFile.FilePath, options)) + { + Assert.Null(image.MetaData.ExifProfile); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 71ce4e1652..b8ec9d49ea 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -90,7 +90,7 @@ namespace ImageSharp.Tests ms.Seek(0, SeekOrigin.Begin); Image mirror = provider.Factory.CreateImage(1, 1); - using (JpegDecoderCore decoder = new JpegDecoderCore()) + using (JpegDecoderCore decoder = new JpegDecoderCore(null)) { decoder.Decode(mirror, ms, true); From 966648ed0cbf1bc2f3de9455365659f8c53a2399 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sat, 18 Feb 2017 21:41:47 +0100 Subject: [PATCH 05/37] Use constructor instead of property to get the default decoder options. --- src/ImageSharp.Formats.Gif/GifDecoderCore.cs | 2 +- .../JpegDecoderCore.cs | 2 +- src/ImageSharp/Formats/DecoderOptions.cs | 28 ++++++++++++++----- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp.Formats.Gif/GifDecoderCore.cs b/src/ImageSharp.Formats.Gif/GifDecoderCore.cs index 50d4da0ebc..2a0d53bde7 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoderCore.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoderCore.cs @@ -73,7 +73,7 @@ namespace ImageSharp.Formats /// The decoder options. public GifDecoderCore(IDecoderOptions options) { - this.options = options ?? DecoderOptions.Default; + this.options = options ?? new DecoderOptions(); } /// diff --git a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs index 19b3df5368..f1b85fa0bf 100644 --- a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs @@ -93,7 +93,7 @@ namespace ImageSharp.Formats /// The decoder options. public JpegDecoderCore(IDecoderOptions options) { - this.options = options ?? DecoderOptions.Default; + this.options = options ?? new DecoderOptions(); this.HuffmanTrees = HuffmanTree.CreateHuffmanTrees(); this.QuantizationTables = new Block8x8F[MaxTq + 1]; this.Temp = new byte[2 * Block8x8F.ScalarCount]; diff --git a/src/ImageSharp/Formats/DecoderOptions.cs b/src/ImageSharp/Formats/DecoderOptions.cs index a9bb152f12..4755ddcb66 100644 --- a/src/ImageSharp/Formats/DecoderOptions.cs +++ b/src/ImageSharp/Formats/DecoderOptions.cs @@ -11,22 +11,36 @@ namespace ImageSharp public class DecoderOptions : IDecoderOptions { /// - /// Gets the default decoder options + /// Initializes a new instance of the class. /// - public static DecoderOptions Default + public DecoderOptions() { - get + this.InitializeWithDefaults(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The decoder options + protected DecoderOptions(IDecoderOptions options) + { + if (options == null) { - return new DecoderOptions() - { - IgnoreMetadata = false - }; + this.InitializeWithDefaults(); + return; } + + this.IgnoreMetadata = options.IgnoreMetadata; } /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. /// public bool IgnoreMetadata { get; set; } + + private void InitializeWithDefaults() + { + this.IgnoreMetadata = false; + } } } From b27fa62a6af44e76e3d70d305db8356f78a2a45f Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sat, 18 Feb 2017 21:42:11 +0100 Subject: [PATCH 06/37] Implemented the IDecoderOptions inside the png decoder. --- .../IPngDecoderOptions.cs | 20 ++++++ src/ImageSharp.Formats.Png/PngDecoder.cs | 4 +- src/ImageSharp.Formats.Png/PngDecoderCore.cs | 23 ++++++- .../PngDecoderOptions.cs | 62 +++++++++++++++++ .../Formats/Png/PngDecoderCoreTests.cs | 66 +++++++++++++++++++ 5 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 src/ImageSharp.Formats.Png/IPngDecoderOptions.cs create mode 100644 src/ImageSharp.Formats.Png/PngDecoderOptions.cs create mode 100644 tests/ImageSharp.Tests/Formats/Png/PngDecoderCoreTests.cs diff --git a/src/ImageSharp.Formats.Png/IPngDecoderOptions.cs b/src/ImageSharp.Formats.Png/IPngDecoderOptions.cs new file mode 100644 index 0000000000..f60f3d1cd3 --- /dev/null +++ b/src/ImageSharp.Formats.Png/IPngDecoderOptions.cs @@ -0,0 +1,20 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System.Text; + + /// + /// Encapsulates the png decoder options. + /// + public interface IPngDecoderOptions : IDecoderOptions + { + /// + /// Gets the encoding that should be used when reading text chunks. + /// + Encoding TextEncoding { get; } + } +} diff --git a/src/ImageSharp.Formats.Png/PngDecoder.cs b/src/ImageSharp.Formats.Png/PngDecoder.cs index 9aab6673a9..c731ae4480 100644 --- a/src/ImageSharp.Formats.Png/PngDecoder.cs +++ b/src/ImageSharp.Formats.Png/PngDecoder.cs @@ -34,7 +34,9 @@ namespace ImageSharp.Formats public void Decode(Image image, Stream stream, IDecoderOptions options) where TColor : struct, IPixel { - new PngDecoderCore().Decode(image, stream); + IPngDecoderOptions pngOptions = PngDecoderOptions.Create(options); + + new PngDecoderCore(pngOptions).Decode(image, stream); } } } diff --git a/src/ImageSharp.Formats.Png/PngDecoderCore.cs b/src/ImageSharp.Formats.Png/PngDecoderCore.cs index 47b09d5ffb..4a5ad36482 100644 --- a/src/ImageSharp.Formats.Png/PngDecoderCore.cs +++ b/src/ImageSharp.Formats.Png/PngDecoderCore.cs @@ -64,6 +64,11 @@ namespace ImageSharp.Formats /// private readonly char[] chars = new char[4]; + /// + /// The decoder options. + /// + private readonly IPngDecoderOptions options; + /// /// Reusable crc for validating chunks. /// @@ -120,6 +125,15 @@ namespace ImageSharp.Formats ColorTypes.Add((int)PngColorType.RgbWithAlpha, new byte[] { 8 }); } + /// + /// Initializes a new instance of the class. + /// + /// The decoder options. + public PngDecoderCore(IPngDecoderOptions options) + { + this.options = options ?? new PngDecoderOptions(); + } + /// /// Gets or sets the png color type /// @@ -763,6 +777,11 @@ namespace ImageSharp.Formats private void ReadTextChunk(Image image, byte[] data, int length) where TColor : struct, IPixel { + if (this.options.IgnoreMetadata) + { + return; + } + int zeroIndex = 0; for (int i = 0; i < length; i++) @@ -774,8 +793,8 @@ namespace ImageSharp.Formats } } - string name = Encoding.Unicode.GetString(data, 0, zeroIndex); - string value = Encoding.Unicode.GetString(data, zeroIndex + 1, length - zeroIndex - 1); + string name = this.options.TextEncoding.GetString(data, 0, zeroIndex); + string value = this.options.TextEncoding.GetString(data, zeroIndex + 1, length - zeroIndex - 1); image.MetaData.Properties.Add(new ImageProperty(name, value)); } diff --git a/src/ImageSharp.Formats.Png/PngDecoderOptions.cs b/src/ImageSharp.Formats.Png/PngDecoderOptions.cs new file mode 100644 index 0000000000..07c0c2739e --- /dev/null +++ b/src/ImageSharp.Formats.Png/PngDecoderOptions.cs @@ -0,0 +1,62 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System.Text; + + /// + /// Encapsulates the png decoder options. + /// + public sealed class PngDecoderOptions : DecoderOptions, IPngDecoderOptions + { + private static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); + + /// + /// Initializes a new instance of the class. + /// + public PngDecoderOptions() + { + this.InitializeWithDefaults(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The options for the decoder. + private PngDecoderOptions(IDecoderOptions options) + : base(options) + { + this.InitializeWithDefaults(); + } + + /// + /// Gets or sets the encoding that should be used when reading text chunks. + /// + public Encoding TextEncoding { get; set; } + + /// + /// Converts the options to a instance with a cast + /// or by creating a new instance with the specfied options. + /// + /// The options for the decoder. + /// The options for the png decoder. + internal static IPngDecoderOptions Create(IDecoderOptions options) + { + IPngDecoderOptions pngOptions = options as IPngDecoderOptions; + if (pngOptions != null) + { + return pngOptions; + } + + return new PngDecoderOptions(options); + } + + private void InitializeWithDefaults() + { + this.TextEncoding = DefaultEncoding; + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderCoreTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderCoreTests.cs new file mode 100644 index 0000000000..3ee2ea826b --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderCoreTests.cs @@ -0,0 +1,66 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests +{ + using System.Text; + using Xunit; + + using ImageSharp.Formats; + + public class PngDecoderCoreTests + { + [Fact] + public void Decode_IgnoreMetadataIsFalse_TextChunckIsRead() + { + var options = new PngDecoderOptions() + { + IgnoreMetadata = false + }; + + TestFile testFile = TestFile.Create(TestImages.Png.Blur); + + using (Image image = new Image(testFile.FilePath, options)) + { + Assert.Equal(1, image.MetaData.Properties.Count); + Assert.Equal("Software", image.MetaData.Properties[0].Name); + Assert.Equal("paint.net 4.0.6", image.MetaData.Properties[0].Value); + } + } + + [Fact] + public void Decode_IgnoreMetadataIsTrue_TextChunksAreIgnored() + { + var options = new PngDecoderOptions() + { + IgnoreMetadata = true + }; + + TestFile testFile = TestFile.Create(TestImages.Png.Blur); + + using (Image image = new Image(testFile.FilePath, options)) + { + Assert.Equal(0, image.MetaData.Properties.Count); + } + } + + [Fact] + public void Decode_TextEncodingSetToUnicode_TextIsReadWithCorrectEncoding() + { + var options = new PngDecoderOptions() + { + TextEncoding = Encoding.Unicode + }; + + TestFile testFile = TestFile.Create(TestImages.Png.Blur); + + using (Image image = new Image(testFile.FilePath, options)) + { + Assert.Equal(1, image.MetaData.Properties.Count); + Assert.Equal("潓瑦慷敲", image.MetaData.Properties[0].Name); + } + } + } +} \ No newline at end of file From 6878997af77f4b9406ad7f0c4d9c429df494f7db Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sat, 18 Feb 2017 21:56:56 +0100 Subject: [PATCH 07/37] Also allow specification of the text encoding inside the gif decoder. --- src/ImageSharp.Formats.Gif/GifDecoder.cs | 4 +- src/ImageSharp.Formats.Gif/GifDecoderCore.cs | 8 +-- .../GifDecoderOptions.cs | 62 +++++++++++++++++++ .../IGifDecoderOptions.cs | 20 ++++++ .../Formats/Gif/GifDecoderCoreTests.cs | 20 ++++++ 5 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 src/ImageSharp.Formats.Gif/GifDecoderOptions.cs create mode 100644 src/ImageSharp.Formats.Gif/IGifDecoderOptions.cs diff --git a/src/ImageSharp.Formats.Gif/GifDecoder.cs b/src/ImageSharp.Formats.Gif/GifDecoder.cs index 42dbf4fc7b..ce97689e99 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoder.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoder.cs @@ -17,7 +17,9 @@ namespace ImageSharp.Formats public void Decode(Image image, Stream stream, IDecoderOptions options) where TColor : struct, IPixel { - new GifDecoderCore(options).Decode(image, stream); + IGifDecoderOptions gifOptions = GifDecoderOptions.Create(options); + + new GifDecoderCore(gifOptions).Decode(image, stream); } } } diff --git a/src/ImageSharp.Formats.Gif/GifDecoderCore.cs b/src/ImageSharp.Formats.Gif/GifDecoderCore.cs index 2a0d53bde7..3ab0e6ca8b 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoderCore.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoderCore.cs @@ -25,7 +25,7 @@ namespace ImageSharp.Formats /// /// The decoder options. /// - private readonly IDecoderOptions options; + private readonly IGifDecoderOptions options; /// /// The image to decode the information to. @@ -71,9 +71,9 @@ namespace ImageSharp.Formats /// Initializes a new instance of the class. /// /// The decoder options. - public GifDecoderCore(IDecoderOptions options) + public GifDecoderCore(IGifDecoderOptions options) { - this.options = options ?? new DecoderOptions(); + this.options = options ?? new GifDecoderOptions(); } /// @@ -260,7 +260,7 @@ namespace ImageSharp.Formats try { this.currentStream.Read(commentsBuffer, 0, length); - string comments = Encoding.GetEncoding("ASCII").GetString(commentsBuffer, 0, length); + string comments = this.options.TextEncoding.GetString(commentsBuffer, 0, length); this.decodedImage.MetaData.Properties.Add(new ImageProperty("Comments", comments)); } finally diff --git a/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs b/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs new file mode 100644 index 0000000000..8bff3e38d6 --- /dev/null +++ b/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs @@ -0,0 +1,62 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System.Text; + + /// + /// Encapsulates the gif decoder options. + /// + public sealed class GifDecoderOptions : DecoderOptions, IGifDecoderOptions + { + private static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); + + /// + /// Initializes a new instance of the class. + /// + public GifDecoderOptions() + { + this.InitializeWithDefaults(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The options for the decoder. + private GifDecoderOptions(IDecoderOptions options) + : base(options) + { + this.InitializeWithDefaults(); + } + + /// + /// Gets the encoding that should be used when reading comments. + /// + public Encoding TextEncoding { get; set; } + + /// + /// Converts the options to a instance with a cast + /// or by creating a new instance with the specfied options. + /// + /// The options for the decoder. + /// The options for the png decoder. + internal static IGifDecoderOptions Create(IDecoderOptions options) + { + IGifDecoderOptions gifOptions = options as IGifDecoderOptions; + if (gifOptions != null) + { + return gifOptions; + } + + return new GifDecoderOptions(options); + } + + private void InitializeWithDefaults() + { + this.TextEncoding = DefaultEncoding; + } + } +} diff --git a/src/ImageSharp.Formats.Gif/IGifDecoderOptions.cs b/src/ImageSharp.Formats.Gif/IGifDecoderOptions.cs new file mode 100644 index 0000000000..dd94a616fe --- /dev/null +++ b/src/ImageSharp.Formats.Gif/IGifDecoderOptions.cs @@ -0,0 +1,20 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System.Text; + + /// + /// Encapsulates the gif decoder options. + /// + public interface IGifDecoderOptions : IDecoderOptions + { + /// + /// Gets the encoding that should be used when reading comments. + /// + Encoding TextEncoding { get; } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderCoreTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderCoreTests.cs index 758c724005..3e3010cfc0 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderCoreTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderCoreTests.cs @@ -5,8 +5,11 @@ namespace ImageSharp.Tests { + using System.Text; using Xunit; + using ImageSharp.Formats; + public class GifDecoderCoreTests { [Fact] @@ -42,5 +45,22 @@ namespace ImageSharp.Tests Assert.Equal(0, image.MetaData.Properties.Count); } } + + [Fact] + public void Decode_TextEncodingSetToUnicode_TextIsReadWithCorrectEncoding() + { + var options = new GifDecoderOptions() + { + TextEncoding = Encoding.Unicode + }; + + TestFile testFile = TestFile.Create(TestImages.Gif.Rings); + + using (Image image = new Image(testFile.FilePath, options)) + { + Assert.Equal(1, image.MetaData.Properties.Count); + Assert.Equal("浉条卥慨灲", image.MetaData.Properties[0].Value); + } + } } } From 839ca54291a2fc77510b42551b9de8005753a83d Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 19 Feb 2017 09:52:01 +0100 Subject: [PATCH 08/37] StyleCop fix. --- src/ImageSharp.Formats.Gif/GifDecoderOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs b/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs index 8bff3e38d6..e2506db708 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs @@ -33,7 +33,7 @@ namespace ImageSharp.Formats } /// - /// Gets the encoding that should be used when reading comments. + /// Gets or sets the encoding that should be used when reading comments. /// public Encoding TextEncoding { get; set; } From 68ac2112691f2a6c2f663aac4984e805ed0a8626 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 19 Feb 2017 14:51:52 +0100 Subject: [PATCH 09/37] Added options for the encoder. --- src/ImageSharp.Formats.Bmp/BmpEncoder.cs | 2 +- src/ImageSharp.Formats.Gif/GifEncoder.cs | 2 +- src/ImageSharp.Formats.Jpeg/JpegEncoder.cs | 2 +- src/ImageSharp.Formats.Png/PngEncoder.cs | 2 +- src/ImageSharp/Formats/EncoderOptions.cs | 46 ++++++++++++++++++++++ src/ImageSharp/Formats/IEncoderOptions.cs | 18 +++++++++ src/ImageSharp/Formats/IImageEncoder.cs | 3 +- src/ImageSharp/Image/Image{TColor}.cs | 16 ++++---- 8 files changed, 79 insertions(+), 12 deletions(-) create mode 100644 src/ImageSharp/Formats/EncoderOptions.cs create mode 100644 src/ImageSharp/Formats/IEncoderOptions.cs diff --git a/src/ImageSharp.Formats.Bmp/BmpEncoder.cs b/src/ImageSharp.Formats.Bmp/BmpEncoder.cs index 6edaf178bc..ea13422721 100644 --- a/src/ImageSharp.Formats.Bmp/BmpEncoder.cs +++ b/src/ImageSharp.Formats.Bmp/BmpEncoder.cs @@ -20,7 +20,7 @@ namespace ImageSharp.Formats public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; /// - public void Encode(Image image, Stream stream) + public void Encode(Image image, Stream stream, IEncoderOptions options) where TColor : struct, IPixel { BmpEncoderCore encoder = new BmpEncoderCore(); diff --git a/src/ImageSharp.Formats.Gif/GifEncoder.cs b/src/ImageSharp.Formats.Gif/GifEncoder.cs index de7e03322d..402d2d09a1 100644 --- a/src/ImageSharp.Formats.Gif/GifEncoder.cs +++ b/src/ImageSharp.Formats.Gif/GifEncoder.cs @@ -32,7 +32,7 @@ namespace ImageSharp.Formats public IQuantizer Quantizer { get; set; } /// - public void Encode(Image image, Stream stream) + public void Encode(Image image, Stream stream, IEncoderOptions options) where TColor : struct, IPixel { GifEncoderCore encoder = new GifEncoderCore diff --git a/src/ImageSharp.Formats.Jpeg/JpegEncoder.cs b/src/ImageSharp.Formats.Jpeg/JpegEncoder.cs index 07d9b24cd9..46972cd93d 100644 --- a/src/ImageSharp.Formats.Jpeg/JpegEncoder.cs +++ b/src/ImageSharp.Formats.Jpeg/JpegEncoder.cs @@ -61,7 +61,7 @@ namespace ImageSharp.Formats } /// - public void Encode(Image image, Stream stream) + public void Encode(Image image, Stream stream, IEncoderOptions options) where TColor : struct, IPixel { // Ensure that quality can be set but has a fallback. diff --git a/src/ImageSharp.Formats.Png/PngEncoder.cs b/src/ImageSharp.Formats.Png/PngEncoder.cs index ba790f4ae9..8d9c4bc085 100644 --- a/src/ImageSharp.Formats.Png/PngEncoder.cs +++ b/src/ImageSharp.Formats.Png/PngEncoder.cs @@ -56,7 +56,7 @@ namespace ImageSharp.Formats public bool WriteGamma { get; set; } /// - public void Encode(Image image, Stream stream) + public void Encode(Image image, Stream stream, IEncoderOptions options) where TColor : struct, IPixel { PngEncoderCore encoder = new PngEncoderCore diff --git a/src/ImageSharp/Formats/EncoderOptions.cs b/src/ImageSharp/Formats/EncoderOptions.cs new file mode 100644 index 0000000000..1f92927f14 --- /dev/null +++ b/src/ImageSharp/Formats/EncoderOptions.cs @@ -0,0 +1,46 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + /// + /// Encapsulates the shared encoder options. + /// + public class EncoderOptions : IEncoderOptions + { + /// + /// Initializes a new instance of the class. + /// + public EncoderOptions() + { + this.InitializeWithDefaults(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The encoder options + protected EncoderOptions(IEncoderOptions options) + { + if (options == null) + { + this.InitializeWithDefaults(); + return; + } + + this.IgnoreMetadata = options.IgnoreMetadata; + } + + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded. + /// + public bool IgnoreMetadata { get; set; } + + private void InitializeWithDefaults() + { + this.IgnoreMetadata = false; + } + } +} diff --git a/src/ImageSharp/Formats/IEncoderOptions.cs b/src/ImageSharp/Formats/IEncoderOptions.cs new file mode 100644 index 0000000000..0fd3d1c438 --- /dev/null +++ b/src/ImageSharp/Formats/IEncoderOptions.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + /// + /// Encapsulates the shared encoder options. + /// + public interface IEncoderOptions + { + /// + /// Gets a value indicating whether the metadata should be ignored when the image is being encoded. + /// + bool IgnoreMetadata { get; } + } +} diff --git a/src/ImageSharp/Formats/IImageEncoder.cs b/src/ImageSharp/Formats/IImageEncoder.cs index 0ba56477ac..918f0d273c 100644 --- a/src/ImageSharp/Formats/IImageEncoder.cs +++ b/src/ImageSharp/Formats/IImageEncoder.cs @@ -19,7 +19,8 @@ namespace ImageSharp.Formats /// The pixel format. /// The to encode from. /// The to encode the image data to. - void Encode(Image image, Stream stream) + /// The options for the encoder. + void Encode(Image image, Stream stream, IEncoderOptions options) where TColor : struct, IPixel; } } diff --git a/src/ImageSharp/Image/Image{TColor}.cs b/src/ImageSharp/Image/Image{TColor}.cs index 9e4ecba2f5..d8890f5faf 100644 --- a/src/ImageSharp/Image/Image{TColor}.cs +++ b/src/ImageSharp/Image/Image{TColor}.cs @@ -206,12 +206,13 @@ namespace ImageSharp /// Saves the image to the given stream using the currently loaded image format. /// /// The stream to save the image to. + /// The options for the encoder. /// Thrown if the stream is null. /// The - public Image Save(Stream stream) + public Image Save(Stream stream, IEncoderOptions options = null) { Guard.NotNull(stream, nameof(stream)); - this.CurrentImageFormat.Encoder.Encode(this, stream); + this.CurrentImageFormat.Encoder.Encode(this, stream, options); return this; } @@ -220,13 +221,13 @@ namespace ImageSharp /// /// The stream to save the image to. /// The format to save the image as. - /// Thrown if the stream or format is null. + /// The options for the encoder. /// The - public Image Save(Stream stream, IImageFormat format) + public Image Save(Stream stream, IImageFormat format, IEncoderOptions options = null) { Guard.NotNull(stream, nameof(stream)); Guard.NotNull(format, nameof(format)); - format.Encoder.Encode(this, stream); + format.Encoder.Encode(this, stream, options); return this; } @@ -235,15 +236,16 @@ namespace ImageSharp /// /// The stream to save the image to. /// The encoder to save the image with. + /// The options for the encoder. /// Thrown if the stream or encoder is null. /// /// The . /// - public Image Save(Stream stream, IImageEncoder encoder) + public Image Save(Stream stream, IImageEncoder encoder, IEncoderOptions options = null) { Guard.NotNull(stream, nameof(stream)); Guard.NotNull(encoder, nameof(encoder)); - encoder.Encode(this, stream); + encoder.Encode(this, stream, options); // Reset to the start of the stream. if (stream.CanSeek) From 9ac270c6d64be2df9e472f6fd449003997efc5bc Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 19 Feb 2017 14:55:42 +0100 Subject: [PATCH 10/37] Added overloads to the decoder that use the coder specific options. --- src/ImageSharp.Formats.Gif/GifDecoder.cs | 15 ++++++++++++++- src/ImageSharp.Formats.Png/PngDecoder.cs | 15 ++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp.Formats.Gif/GifDecoder.cs b/src/ImageSharp.Formats.Gif/GifDecoder.cs index ce97689e99..88a3d5e437 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoder.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoder.cs @@ -19,7 +19,20 @@ namespace ImageSharp.Formats { IGifDecoderOptions gifOptions = GifDecoderOptions.Create(options); - new GifDecoderCore(gifOptions).Decode(image, stream); + this.Decode(image, stream, gifOptions); + } + + /// + /// Decodes the image from the specified stream to the . + /// + /// The pixel format. + /// The to decode to. + /// The containing image data. + /// The options for the decoder. + public void Decode(Image image, Stream stream, IGifDecoderOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + new GifDecoderCore(options).Decode(image, stream); } } } diff --git a/src/ImageSharp.Formats.Png/PngDecoder.cs b/src/ImageSharp.Formats.Png/PngDecoder.cs index c731ae4480..658de9e664 100644 --- a/src/ImageSharp.Formats.Png/PngDecoder.cs +++ b/src/ImageSharp.Formats.Png/PngDecoder.cs @@ -36,7 +36,20 @@ namespace ImageSharp.Formats { IPngDecoderOptions pngOptions = PngDecoderOptions.Create(options); - new PngDecoderCore(pngOptions).Decode(image, stream); + this.Decode(image, stream, pngOptions); + } + + /// + /// Decodes the image from the specified stream to the . + /// + /// The pixel format. + /// The to decode to. + /// The containing image data. + /// The options for the decoder. + public void Decode(Image image, Stream stream, IPngDecoderOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + new PngDecoderCore(options).Decode(image, stream); } } } From 01d2f42cdd823225eca69658825a1f278392f55c Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 19 Feb 2017 15:01:44 +0100 Subject: [PATCH 11/37] Nicer initialization of the options. --- src/ImageSharp.Formats.Gif/GifDecoderOptions.cs | 9 +-------- src/ImageSharp.Formats.Png/PngDecoderOptions.cs | 9 +-------- src/ImageSharp/Formats/DecoderOptions.cs | 15 +++------------ src/ImageSharp/Formats/EncoderOptions.cs | 15 +++------------ 4 files changed, 8 insertions(+), 40 deletions(-) diff --git a/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs b/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs index e2506db708..ff8ad19df8 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs @@ -19,7 +19,6 @@ namespace ImageSharp.Formats /// public GifDecoderOptions() { - this.InitializeWithDefaults(); } /// @@ -29,13 +28,12 @@ namespace ImageSharp.Formats private GifDecoderOptions(IDecoderOptions options) : base(options) { - this.InitializeWithDefaults(); } /// /// Gets or sets the encoding that should be used when reading comments. /// - public Encoding TextEncoding { get; set; } + public Encoding TextEncoding { get; set; } = DefaultEncoding; /// /// Converts the options to a instance with a cast @@ -53,10 +51,5 @@ namespace ImageSharp.Formats return new GifDecoderOptions(options); } - - private void InitializeWithDefaults() - { - this.TextEncoding = DefaultEncoding; - } } } diff --git a/src/ImageSharp.Formats.Png/PngDecoderOptions.cs b/src/ImageSharp.Formats.Png/PngDecoderOptions.cs index 07c0c2739e..8630cd1b09 100644 --- a/src/ImageSharp.Formats.Png/PngDecoderOptions.cs +++ b/src/ImageSharp.Formats.Png/PngDecoderOptions.cs @@ -19,7 +19,6 @@ namespace ImageSharp.Formats /// public PngDecoderOptions() { - this.InitializeWithDefaults(); } /// @@ -29,13 +28,12 @@ namespace ImageSharp.Formats private PngDecoderOptions(IDecoderOptions options) : base(options) { - this.InitializeWithDefaults(); } /// /// Gets or sets the encoding that should be used when reading text chunks. /// - public Encoding TextEncoding { get; set; } + public Encoding TextEncoding { get; set; } = DefaultEncoding; /// /// Converts the options to a instance with a cast @@ -53,10 +51,5 @@ namespace ImageSharp.Formats return new PngDecoderOptions(options); } - - private void InitializeWithDefaults() - { - this.TextEncoding = DefaultEncoding; - } } } diff --git a/src/ImageSharp/Formats/DecoderOptions.cs b/src/ImageSharp/Formats/DecoderOptions.cs index 4755ddcb66..5257b07b39 100644 --- a/src/ImageSharp/Formats/DecoderOptions.cs +++ b/src/ImageSharp/Formats/DecoderOptions.cs @@ -15,7 +15,6 @@ namespace ImageSharp /// public DecoderOptions() { - this.InitializeWithDefaults(); } /// @@ -24,23 +23,15 @@ namespace ImageSharp /// The decoder options protected DecoderOptions(IDecoderOptions options) { - if (options == null) + if (options != null) { - this.InitializeWithDefaults(); - return; + this.IgnoreMetadata = options.IgnoreMetadata; } - - this.IgnoreMetadata = options.IgnoreMetadata; } /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. /// - public bool IgnoreMetadata { get; set; } - - private void InitializeWithDefaults() - { - this.IgnoreMetadata = false; - } + public bool IgnoreMetadata { get; set; } = false; } } diff --git a/src/ImageSharp/Formats/EncoderOptions.cs b/src/ImageSharp/Formats/EncoderOptions.cs index 1f92927f14..27a7e9781d 100644 --- a/src/ImageSharp/Formats/EncoderOptions.cs +++ b/src/ImageSharp/Formats/EncoderOptions.cs @@ -15,7 +15,6 @@ namespace ImageSharp /// public EncoderOptions() { - this.InitializeWithDefaults(); } /// @@ -24,23 +23,15 @@ namespace ImageSharp /// The encoder options protected EncoderOptions(IEncoderOptions options) { - if (options == null) + if (options != null) { - this.InitializeWithDefaults(); - return; + this.IgnoreMetadata = options.IgnoreMetadata; } - - this.IgnoreMetadata = options.IgnoreMetadata; } /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded. /// - public bool IgnoreMetadata { get; set; } - - private void InitializeWithDefaults() - { - this.IgnoreMetadata = false; - } + public bool IgnoreMetadata { get; set; } = false; } } From df963df9cbb73798e5cb05c2e3b4c24cef71e20a Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 19 Feb 2017 15:08:05 +0100 Subject: [PATCH 12/37] Minor comment change. --- src/ImageSharp.Formats.Gif/GifDecoderOptions.cs | 4 ++-- src/ImageSharp.Formats.Gif/IGifDecoderOptions.cs | 2 +- src/ImageSharp.Formats.Png/IPngDecoderOptions.cs | 2 +- src/ImageSharp.Formats.Png/PngDecoderOptions.cs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs b/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs index ff8ad19df8..8184c19d3f 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Formats using System.Text; /// - /// Encapsulates the gif decoder options. + /// Encapsulates the options for the . /// public sealed class GifDecoderOptions : DecoderOptions, IGifDecoderOptions { @@ -40,7 +40,7 @@ namespace ImageSharp.Formats /// or by creating a new instance with the specfied options. /// /// The options for the decoder. - /// The options for the png decoder. + /// The options for the . internal static IGifDecoderOptions Create(IDecoderOptions options) { IGifDecoderOptions gifOptions = options as IGifDecoderOptions; diff --git a/src/ImageSharp.Formats.Gif/IGifDecoderOptions.cs b/src/ImageSharp.Formats.Gif/IGifDecoderOptions.cs index dd94a616fe..729bf1d111 100644 --- a/src/ImageSharp.Formats.Gif/IGifDecoderOptions.cs +++ b/src/ImageSharp.Formats.Gif/IGifDecoderOptions.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Formats using System.Text; /// - /// Encapsulates the gif decoder options. + /// Encapsulates the options for the . /// public interface IGifDecoderOptions : IDecoderOptions { diff --git a/src/ImageSharp.Formats.Png/IPngDecoderOptions.cs b/src/ImageSharp.Formats.Png/IPngDecoderOptions.cs index f60f3d1cd3..cc6d194bfc 100644 --- a/src/ImageSharp.Formats.Png/IPngDecoderOptions.cs +++ b/src/ImageSharp.Formats.Png/IPngDecoderOptions.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Formats using System.Text; /// - /// Encapsulates the png decoder options. + /// Encapsulates the options for the . /// public interface IPngDecoderOptions : IDecoderOptions { diff --git a/src/ImageSharp.Formats.Png/PngDecoderOptions.cs b/src/ImageSharp.Formats.Png/PngDecoderOptions.cs index 8630cd1b09..83716e5d1b 100644 --- a/src/ImageSharp.Formats.Png/PngDecoderOptions.cs +++ b/src/ImageSharp.Formats.Png/PngDecoderOptions.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Formats using System.Text; /// - /// Encapsulates the png decoder options. + /// Encapsulates the options for the . /// public sealed class PngDecoderOptions : DecoderOptions, IPngDecoderOptions { @@ -40,7 +40,7 @@ namespace ImageSharp.Formats /// or by creating a new instance with the specfied options. /// /// The options for the decoder. - /// The options for the png decoder. + /// The options for the . internal static IPngDecoderOptions Create(IDecoderOptions options) { IPngDecoderOptions pngOptions = options as IPngDecoderOptions; From c56ab2fdab2fe9924f00fd93dece182766f60f3c Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 19 Feb 2017 15:32:16 +0100 Subject: [PATCH 13/37] Added extra overload for TestFile.CreateImage and used it in the tests. --- .../Formats/Gif/GifDecoderCoreTests.cs | 6 +++--- .../Formats/Jpg/JpegDecoderCoreTests.cs | 4 ++-- .../Formats/Png/PngDecoderCoreTests.cs | 6 +++--- tests/ImageSharp.Tests/TestFile.cs | 12 ++++++++++++ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderCoreTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderCoreTests.cs index 3e3010cfc0..e1e3e94b09 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderCoreTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderCoreTests.cs @@ -22,7 +22,7 @@ namespace ImageSharp.Tests TestFile testFile = TestFile.Create(TestImages.Gif.Rings); - using (Image image = new Image(testFile.FilePath, options)) + using (Image image = testFile.CreateImage(options)) { Assert.Equal(1, image.MetaData.Properties.Count); Assert.Equal("Comments", image.MetaData.Properties[0].Name); @@ -40,7 +40,7 @@ namespace ImageSharp.Tests TestFile testFile = TestFile.Create(TestImages.Gif.Rings); - using (Image image = new Image(testFile.FilePath, options)) + using (Image image = testFile.CreateImage(options)) { Assert.Equal(0, image.MetaData.Properties.Count); } @@ -56,7 +56,7 @@ namespace ImageSharp.Tests TestFile testFile = TestFile.Create(TestImages.Gif.Rings); - using (Image image = new Image(testFile.FilePath, options)) + using (Image image = testFile.CreateImage(options)) { Assert.Equal(1, image.MetaData.Properties.Count); Assert.Equal("浉条卥慨灲", image.MetaData.Properties[0].Value); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderCoreTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderCoreTests.cs index 18d9e3acfb..38d2a455e9 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderCoreTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderCoreTests.cs @@ -19,7 +19,7 @@ namespace ImageSharp.Tests TestFile testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan); - using (Image image = new Image(testFile.FilePath, options)) + using (Image image = testFile.CreateImage(options)) { Assert.NotNull(image.MetaData.ExifProfile); } @@ -35,7 +35,7 @@ namespace ImageSharp.Tests TestFile testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan); - using (Image image = new Image(testFile.FilePath, options)) + using (Image image = testFile.CreateImage(options)) { Assert.Null(image.MetaData.ExifProfile); } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderCoreTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderCoreTests.cs index 3ee2ea826b..766172ec65 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderCoreTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderCoreTests.cs @@ -22,7 +22,7 @@ namespace ImageSharp.Tests TestFile testFile = TestFile.Create(TestImages.Png.Blur); - using (Image image = new Image(testFile.FilePath, options)) + using (Image image = testFile.CreateImage(options)) { Assert.Equal(1, image.MetaData.Properties.Count); Assert.Equal("Software", image.MetaData.Properties[0].Name); @@ -40,7 +40,7 @@ namespace ImageSharp.Tests TestFile testFile = TestFile.Create(TestImages.Png.Blur); - using (Image image = new Image(testFile.FilePath, options)) + using (Image image = testFile.CreateImage(options)) { Assert.Equal(0, image.MetaData.Properties.Count); } @@ -56,7 +56,7 @@ namespace ImageSharp.Tests TestFile testFile = TestFile.Create(TestImages.Png.Blur); - using (Image image = new Image(testFile.FilePath, options)) + using (Image image = testFile.CreateImage(options)) { Assert.Equal(1, image.MetaData.Properties.Count); Assert.Equal("潓瑦慷敲", image.MetaData.Properties[0].Name); diff --git a/tests/ImageSharp.Tests/TestFile.cs b/tests/ImageSharp.Tests/TestFile.cs index 891a45cec9..0c9cc5f47c 100644 --- a/tests/ImageSharp.Tests/TestFile.cs +++ b/tests/ImageSharp.Tests/TestFile.cs @@ -130,6 +130,18 @@ namespace ImageSharp.Tests return new Image(this.image); } + /// + /// Creates a new image. + /// + /// The options for the decoder. + /// + /// The . + /// + public Image CreateImage(IDecoderOptions options) + { + return new Image(this.Bytes, options); + } + /// /// Gets the correct path to the formats directory. /// From 0ace64794a001cd97b4ab4100e14f9a152c7b5cb Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 19 Feb 2017 19:02:21 +0100 Subject: [PATCH 14/37] Added options argument to the filePath overloads. --- src/ImageSharp/Image/Image{TColor}.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Image/Image{TColor}.cs b/src/ImageSharp/Image/Image{TColor}.cs index d8890f5faf..69b99ce13a 100644 --- a/src/ImageSharp/Image/Image{TColor}.cs +++ b/src/ImageSharp/Image/Image{TColor}.cs @@ -261,9 +261,10 @@ namespace ImageSharp /// Saves the image to the given stream using the currently loaded image format. /// /// The file path to save the image to. + /// The options for the encoder. /// Thrown if the stream is null. /// The - public Image Save(string filePath) + public Image Save(string filePath, IEncoderOptions options = null) { string ext = Path.GetExtension(filePath).Trim('.'); IImageFormat format = this.Configuration.ImageFormats.SingleOrDefault(f => f.SupportedExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase)); @@ -280,9 +281,10 @@ namespace ImageSharp /// /// The file path to save the image to. /// The format to save the image as. + /// The options for the encoder. /// Thrown if the format is null. /// The - public Image Save(string filePath, IImageFormat format) + public Image Save(string filePath, IImageFormat format, IEncoderOptions options = null) { Guard.NotNull(format, nameof(format)); using (FileStream fs = File.Create(filePath)) @@ -296,9 +298,10 @@ namespace ImageSharp /// /// The file path to save the image to. /// The encoder to save the image with. + /// The options for the encoder. /// Thrown if the encoder is null. /// The - public Image Save(string filePath, IImageEncoder encoder) + public Image Save(string filePath, IImageEncoder encoder, IEncoderOptions options = null) { Guard.NotNull(encoder, nameof(encoder)); using (FileStream fs = File.Create(filePath)) From 26aec54e05a57f4b204fefb1972c3b3eda97ab48 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 19 Feb 2017 19:02:55 +0100 Subject: [PATCH 15/37] Implemented the IEncoderOptions inside the bmp encoder. --- src/ImageSharp.Formats.Bmp/BmpEncoder.cs | 24 ++++++--- src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs | 24 +++++---- .../BmpEncoderOptions.cs | 51 +++++++++++++++++++ .../IBmpEncoderOptions.cs | 18 +++++++ .../Formats/Bmp/BitmapTests.cs | 6 +-- 5 files changed, 103 insertions(+), 20 deletions(-) create mode 100644 src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs create mode 100644 src/ImageSharp.Formats.Bmp/IBmpEncoderOptions.cs diff --git a/src/ImageSharp.Formats.Bmp/BmpEncoder.cs b/src/ImageSharp.Formats.Bmp/BmpEncoder.cs index ea13422721..2c0bb5b5d5 100644 --- a/src/ImageSharp.Formats.Bmp/BmpEncoder.cs +++ b/src/ImageSharp.Formats.Bmp/BmpEncoder.cs @@ -14,17 +14,27 @@ namespace ImageSharp.Formats /// The encoder can currently only write 24-bit rgb images to streams. public class BmpEncoder : IImageEncoder { - /// - /// Gets or sets the number of bits per pixel. - /// - public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; - /// public void Encode(Image image, Stream stream, IEncoderOptions options) where TColor : struct, IPixel { - BmpEncoderCore encoder = new BmpEncoderCore(); - encoder.Encode(image, stream, this.BitsPerPixel); + IBmpEncoderOptions bmpOptions = BmpEncoderOptions.Create(options); + + this.Encode(image, stream, bmpOptions); + } + + /// + /// Encodes the image to the specified stream from the . + /// + /// The pixel format. + /// The to encode from. + /// The to encode the image data to. + /// The options for the encoder. + public void Encode(Image image, Stream stream, IBmpEncoderOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + BmpEncoderCore encoder = new BmpEncoderCore(options); + encoder.Encode(image, stream); } } } diff --git a/src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs b/src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs index 02d270a0ad..9696eb66dd 100644 --- a/src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs @@ -16,34 +16,40 @@ namespace ImageSharp.Formats internal sealed class BmpEncoderCore { /// - /// The number of bits per pixel. + /// The options for the encoder. /// - private BmpBitsPerPixel bmpBitsPerPixel; + private IBmpEncoderOptions options; /// /// The amount to pad each row by. /// private int padding; + /// + /// Initializes a new instance of the class. + /// + /// The options for the encoder. + public BmpEncoderCore(IBmpEncoderOptions options) + { + this.options = options ?? new BmpEncoderOptions(); + } + /// /// Encodes the image to the specified stream from the . /// /// The pixel format. /// The to encode from. /// The to encode the image data to. - /// The - public void Encode(ImageBase image, Stream stream, BmpBitsPerPixel bitsPerPixel) + public void Encode(ImageBase image, Stream stream) where TColor : struct, IPixel { Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - this.bmpBitsPerPixel = bitsPerPixel; - // Cast to int will get the bytes per pixel - short bpp = (short)(8 * (int)bitsPerPixel); + short bpp = (short)(8 * (int)this.options.BitsPerPixel); int bytesPerLine = 4 * (((image.Width * bpp) + 31) / 32); - this.padding = bytesPerLine - (image.Width * (int)bitsPerPixel); + this.padding = bytesPerLine - (image.Width * (int)this.options.BitsPerPixel); // Do not use IDisposable pattern here as we want to preserve the stream. EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); @@ -128,7 +134,7 @@ namespace ImageSharp.Formats { using (PixelAccessor pixels = image.Lock()) { - switch (this.bmpBitsPerPixel) + switch (this.options.BitsPerPixel) { case BmpBitsPerPixel.Pixel32: this.Write32Bit(writer, pixels); diff --git a/src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs b/src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs new file mode 100644 index 0000000000..f0106b4815 --- /dev/null +++ b/src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs @@ -0,0 +1,51 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + /// + /// Encapsulates the options for the . + /// + public sealed class BmpEncoderOptions : EncoderOptions, IBmpEncoderOptions + { + /// + /// Initializes a new instance of the class. + /// + public BmpEncoderOptions() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The options for the encoder. + private BmpEncoderOptions(IEncoderOptions options) + : base(options) + { + } + + /// + /// Gets or sets the number of bits per pixel. + /// + public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; + + /// + /// Converts the options to a instance with a cast + /// or by creating a new instance with the specfied options. + /// + /// The options for the encoder. + /// The options for the . + internal static IBmpEncoderOptions Create(IEncoderOptions options) + { + IBmpEncoderOptions bmpOptions = options as IBmpEncoderOptions; + if (bmpOptions != null) + { + return bmpOptions; + } + + return new BmpEncoderOptions(options); + } + } +} diff --git a/src/ImageSharp.Formats.Bmp/IBmpEncoderOptions.cs b/src/ImageSharp.Formats.Bmp/IBmpEncoderOptions.cs new file mode 100644 index 0000000000..6cf37cbae3 --- /dev/null +++ b/src/ImageSharp.Formats.Bmp/IBmpEncoderOptions.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + /// + /// Encapsulates the options for the . + /// + public interface IBmpEncoderOptions : IEncoderOptions + { + /// + /// Gets the number of bits per pixel. + /// + BmpBitsPerPixel BitsPerPixel { get; } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BitmapTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BitmapTests.cs index c1275335d2..7579cc86e5 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BitmapTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BitmapTests.cs @@ -7,8 +7,6 @@ using ImageSharp.Formats; namespace ImageSharp.Tests { - using System.IO; - using Xunit; public class BitmapTests : FileTestBase @@ -16,7 +14,7 @@ namespace ImageSharp.Tests public static readonly TheoryData BitsPerPixel = new TheoryData { - BmpBitsPerPixel.Pixel24 , + BmpBitsPerPixel.Pixel24, BmpBitsPerPixel.Pixel32 }; @@ -31,7 +29,7 @@ namespace ImageSharp.Tests string filename = file.GetFileNameWithoutExtension(bitsPerPixel); using (Image image = file.CreateImage()) { - image.Save($"{path}/{filename}.bmp", new BmpEncoder { BitsPerPixel = bitsPerPixel }); + image.Save($"{path}/{filename}.bmp", new BmpEncoderOptions { BitsPerPixel = bitsPerPixel }); } } } From 20a295afeca79cb83a0046f15a7a24957e9eaeef Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 19 Feb 2017 19:11:05 +0100 Subject: [PATCH 16/37] Comment fixes. --- src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs | 2 +- src/ImageSharp.Formats.Gif/GifDecoderOptions.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs b/src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs index f0106b4815..2c06d8a665 100644 --- a/src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs +++ b/src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs @@ -32,7 +32,7 @@ namespace ImageSharp.Formats public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; /// - /// Converts the options to a instance with a cast + /// Converts the options to a instance with a cast /// or by creating a new instance with the specfied options. /// /// The options for the encoder. diff --git a/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs b/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs index 8184c19d3f..5932425e5a 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs @@ -36,7 +36,7 @@ namespace ImageSharp.Formats public Encoding TextEncoding { get; set; } = DefaultEncoding; /// - /// Converts the options to a instance with a cast + /// Converts the options to a instance with a cast /// or by creating a new instance with the specfied options. /// /// The options for the decoder. From 5d71c2ceaed113b402f77b09791aeb82445ec335 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 19 Feb 2017 19:16:09 +0100 Subject: [PATCH 17/37] Options should be readonly. --- src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs b/src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs index 9696eb66dd..df62fb6f40 100644 --- a/src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs @@ -18,7 +18,7 @@ namespace ImageSharp.Formats /// /// The options for the encoder. /// - private IBmpEncoderOptions options; + private readonly IBmpEncoderOptions options; /// /// The amount to pad each row by. From 216191656464130b979eabc91c56f7e47e77aa81 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 19 Feb 2017 21:41:56 +0100 Subject: [PATCH 18/37] Implemented the IEncoderOptions inside the gif encoder. --- src/ImageSharp.Formats.Gif/GifConstants.cs | 14 +++- src/ImageSharp.Formats.Gif/GifDecoderCore.cs | 2 +- .../GifDecoderOptions.cs | 4 +- src/ImageSharp.Formats.Gif/GifEncoder.cs | 37 ++++------ src/ImageSharp.Formats.Gif/GifEncoderCore.cs | 68 +++++++++++++----- .../GifEncoderOptions.cs | 71 +++++++++++++++++++ .../IGifEncoderOptions.cs | 38 ++++++++++ src/ImageSharp.Formats.Gif/ImageExtensions.cs | 11 ++- .../Formats/Gif/GifEncoderCoreTests.cs | 67 +++++++++++++++++ 9 files changed, 264 insertions(+), 48 deletions(-) create mode 100644 src/ImageSharp.Formats.Gif/GifEncoderOptions.cs create mode 100644 src/ImageSharp.Formats.Gif/IGifEncoderOptions.cs create mode 100644 tests/ImageSharp.Tests/Formats/Gif/GifEncoderCoreTests.cs diff --git a/src/ImageSharp.Formats.Gif/GifConstants.cs b/src/ImageSharp.Formats.Gif/GifConstants.cs index 5334bcba37..4af291c2ba 100644 --- a/src/ImageSharp.Formats.Gif/GifConstants.cs +++ b/src/ImageSharp.Formats.Gif/GifConstants.cs @@ -5,10 +5,12 @@ namespace ImageSharp.Formats { + using System.Text; + /// /// Constants that define specific points within a gif. /// - internal sealed class GifConstants + internal static class GifConstants { /// /// The file type. @@ -50,6 +52,11 @@ namespace ImageSharp.Formats /// public const byte CommentLabel = 0xFE; + /// + /// The name of the property inside the image properties for the comments. + /// + public const string Comments = "Comments"; + /// /// The maximum comment length. /// @@ -79,5 +86,10 @@ namespace ImageSharp.Formats /// The end introducer trailer ;. /// public const byte EndIntroducer = 0x3B; + + /// + /// Gets the default encoding to use when reading comments. + /// + public static Encoding DefaultEncoding { get; } = Encoding.GetEncoding("ASCII"); } } diff --git a/src/ImageSharp.Formats.Gif/GifDecoderCore.cs b/src/ImageSharp.Formats.Gif/GifDecoderCore.cs index 3ab0e6ca8b..ab1edc2c76 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoderCore.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoderCore.cs @@ -261,7 +261,7 @@ namespace ImageSharp.Formats { this.currentStream.Read(commentsBuffer, 0, length); string comments = this.options.TextEncoding.GetString(commentsBuffer, 0, length); - this.decodedImage.MetaData.Properties.Add(new ImageProperty("Comments", comments)); + this.decodedImage.MetaData.Properties.Add(new ImageProperty(GifConstants.Comments, comments)); } finally { diff --git a/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs b/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs index 5932425e5a..8722c5fe8f 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs @@ -12,8 +12,6 @@ namespace ImageSharp.Formats /// public sealed class GifDecoderOptions : DecoderOptions, IGifDecoderOptions { - private static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); - /// /// Initializes a new instance of the class. /// @@ -33,7 +31,7 @@ namespace ImageSharp.Formats /// /// Gets or sets the encoding that should be used when reading comments. /// - public Encoding TextEncoding { get; set; } = DefaultEncoding; + public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding; /// /// Converts the options to a instance with a cast diff --git a/src/ImageSharp.Formats.Gif/GifEncoder.cs b/src/ImageSharp.Formats.Gif/GifEncoder.cs index 402d2d09a1..34027ee0cc 100644 --- a/src/ImageSharp.Formats.Gif/GifEncoder.cs +++ b/src/ImageSharp.Formats.Gif/GifEncoder.cs @@ -8,40 +8,31 @@ namespace ImageSharp.Formats using System; using System.IO; - using ImageSharp.Quantizers; - /// /// Image encoder for writing image data to a stream in gif format. /// public class GifEncoder : IImageEncoder { - /// - /// Gets or sets the quality of output for images. - /// - /// For gifs the value ranges from 1 to 256. - public int Quality { get; set; } + /// + public void Encode(Image image, Stream stream, IEncoderOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + IGifEncoderOptions gifOptions = GifEncoderOptions.Create(options); - /// - /// Gets or sets the transparency threshold. - /// - public byte Threshold { get; set; } = 128; + this.Encode(image, stream, gifOptions); + } /// - /// Gets or sets the quantizer for reducing the color count. + /// Encodes the image to the specified stream from the . /// - public IQuantizer Quantizer { get; set; } - - /// - public void Encode(Image image, Stream stream, IEncoderOptions options) + /// The pixel format. + /// The to encode from. + /// The to encode the image data to. + /// The options for the encoder. + public void Encode(Image image, Stream stream, IGifEncoderOptions options) where TColor : struct, IPixel { - GifEncoderCore encoder = new GifEncoderCore - { - Quality = this.Quality, - Quantizer = this.Quantizer, - Threshold = this.Threshold - }; - + GifEncoderCore encoder = new GifEncoderCore(options); encoder.Encode(image, stream); } } diff --git a/src/ImageSharp.Formats.Gif/GifEncoderCore.cs b/src/ImageSharp.Formats.Gif/GifEncoderCore.cs index 36cf614d94..2c9a0c8b0b 100644 --- a/src/ImageSharp.Formats.Gif/GifEncoderCore.cs +++ b/src/ImageSharp.Formats.Gif/GifEncoderCore.cs @@ -24,20 +24,23 @@ namespace ImageSharp.Formats private readonly byte[] buffer = new byte[16]; /// - /// The number of bits requires to store the image palette. + /// The options for the encoder. /// - private int bitDepth; + private readonly IGifEncoderOptions options; /// - /// Gets or sets the quality of output for images. + /// The number of bits requires to store the image palette. /// - /// For gifs the value ranges from 1 to 256. - public int Quality { get; set; } + private int bitDepth; /// - /// Gets or sets the transparency threshold. + /// Initializes a new instance of the class. /// - public byte Threshold { get; set; } = 128; + /// The options for the encoder. + public GifEncoderCore(IGifEncoderOptions options) + { + this.options = options ?? new GifEncoderOptions(); + } /// /// Gets or sets the quantizer for reducing the color count. @@ -56,23 +59,20 @@ namespace ImageSharp.Formats Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - if (this.Quantizer == null) - { - this.Quantizer = new OctreeQuantizer(); - } + this.Quantizer = this.options.Quantizer ?? new OctreeQuantizer(); // Do not use IDisposable pattern here as we want to preserve the stream. EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); // Ensure that quality can be set but has a fallback. - int quality = this.Quality > 0 ? this.Quality : image.MetaData.Quality; - this.Quality = quality > 0 ? quality.Clamp(1, 256) : 256; + int quality = this.options.Quality > 0 ? this.options.Quality : image.MetaData.Quality; + quality = quality > 0 ? quality.Clamp(1, 256) : 256; // Get the number of bits. - this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(this.Quality); + this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quality); // Quantize the image returning a palette. - QuantizedImage quantized = ((IQuantizer)this.Quantizer).Quantize(image, this.Quality); + QuantizedImage quantized = ((IQuantizer)this.Quantizer).Quantize(image, quality); int index = this.GetTransparentIndex(quantized); @@ -84,6 +84,7 @@ namespace ImageSharp.Formats // Write the first frame. this.WriteGraphicalControlExtension(image, writer, index); + this.WriteComments(image, writer); this.WriteImageDescriptor(image, writer); this.WriteColorTable(quantized, writer); this.WriteImageData(quantized, writer); @@ -97,7 +98,7 @@ namespace ImageSharp.Formats for (int i = 0; i < image.Frames.Count; i++) { ImageFrame frame = image.Frames[i]; - QuantizedImage quantizedFrame = ((IQuantizer)this.Quantizer).Quantize(frame, this.Quality); + QuantizedImage quantizedFrame = ((IQuantizer)this.Quantizer).Quantize(frame, quality); this.WriteGraphicalControlExtension(frame, writer, this.GetTransparentIndex(quantizedFrame)); this.WriteImageDescriptor(frame, writer); @@ -106,7 +107,7 @@ namespace ImageSharp.Formats } } - // TODO: Write Comments extension etc + // TODO: Write extension etc writer.Write(GifConstants.EndIntroducer); } @@ -229,6 +230,39 @@ namespace ImageSharp.Formats } } + /// + /// Writes the image comments to the stream. + /// + /// The pixel format. + /// The to be encoded. + /// The stream to write to. + private void WriteComments(Image image, EndianBinaryWriter writer) + where TColor : struct, IPackedPixel, IEquatable + { + if (this.options.IgnoreMetadata == true) + { + return; + } + + ImageProperty property = image.MetaData.Properties.FirstOrDefault(p => p.Name == GifConstants.Comments); + if (property == null || string.IsNullOrEmpty(property.Value)) + { + return; + } + + byte[] comments = this.options.TextEncoding.GetBytes(property.Value); + + int count = Math.Min(comments.Length, 255); + + this.buffer[0] = GifConstants.ExtensionIntroducer; + this.buffer[1] = GifConstants.CommentLabel; + this.buffer[2] = (byte)count; + + writer.Write(this.buffer, 0, 3); + writer.Write(comments, 0, count); + writer.Write(GifConstants.Terminator); + } + /// /// Writes the graphics control extension to the stream. /// diff --git a/src/ImageSharp.Formats.Gif/GifEncoderOptions.cs b/src/ImageSharp.Formats.Gif/GifEncoderOptions.cs new file mode 100644 index 0000000000..94cad9603c --- /dev/null +++ b/src/ImageSharp.Formats.Gif/GifEncoderOptions.cs @@ -0,0 +1,71 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System.Text; + + using Quantizers; + + /// + /// Encapsulates the options for the . + /// + public sealed class GifEncoderOptions : EncoderOptions, IGifEncoderOptions + { + /// + /// Initializes a new instance of the class. + /// + public GifEncoderOptions() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The options for the encoder. + private GifEncoderOptions(IEncoderOptions options) + : base(options) + { + } + + /// + /// Gets or sets the encoding that should be used when writing comments. + /// + public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding; + + /// + /// Gets or sets the quality of output for images. + /// + /// For gifs the value ranges from 1 to 256. + public int Quality { get; set; } + + /// + /// Gets or sets the transparency threshold. + /// + public byte Threshold { get; set; } = 128; + + /// + /// Gets or sets the quantizer for reducing the color count. + /// + public IQuantizer Quantizer { get; set; } + + /// + /// Converts the options to a instance with a + /// cast or by creating a new instance with the specfied options. + /// + /// The options for the encoder. + /// The options for the . + internal static IGifEncoderOptions Create(IEncoderOptions options) + { + IGifEncoderOptions gifOptions = options as IGifEncoderOptions; + if (gifOptions != null) + { + return gifOptions; + } + + return new GifEncoderOptions(options); + } + } +} diff --git a/src/ImageSharp.Formats.Gif/IGifEncoderOptions.cs b/src/ImageSharp.Formats.Gif/IGifEncoderOptions.cs new file mode 100644 index 0000000000..c1d6b7ad86 --- /dev/null +++ b/src/ImageSharp.Formats.Gif/IGifEncoderOptions.cs @@ -0,0 +1,38 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System.Text; + + using Quantizers; + + /// + /// Encapsulates the options for the . + /// + public interface IGifEncoderOptions : IEncoderOptions + { + /// + /// Gets the encoding that should be used when writing comments. + /// + Encoding TextEncoding { get; } + + /// + /// Gets the quality of output for images. + /// + /// For gifs the value ranges from 1 to 256. + int Quality { get; } + + /// + /// Gets the transparency threshold. + /// + byte Threshold { get; } + + /// + /// Gets the quantizer for reducing the color count. + /// + IQuantizer Quantizer { get; } + } +} diff --git a/src/ImageSharp.Formats.Gif/ImageExtensions.cs b/src/ImageSharp.Formats.Gif/ImageExtensions.cs index e0ec2e8c84..dcf4ab29a5 100644 --- a/src/ImageSharp.Formats.Gif/ImageExtensions.cs +++ b/src/ImageSharp.Formats.Gif/ImageExtensions.cs @@ -21,13 +21,18 @@ namespace ImageSharp /// The pixel format. /// The image this method extends. /// The stream to save the image to. - /// The quality to save the image to representing the number of colors. Between 1 and 256. + /// The options for the encoder. /// Thrown if the stream is null. /// /// The . /// - public static Image SaveAsGif(this Image source, Stream stream, int quality = 256) + public static Image SaveAsGif(this Image source, Stream stream, IGifEncoderOptions options = null) where TColor : struct, IPixel - => source.Save(stream, new GifEncoder { Quality = quality }); + { + GifEncoder encoder = new GifEncoder(); + encoder.Encode(source, stream, options); + + return source; + } } } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderCoreTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderCoreTests.cs new file mode 100644 index 0000000000..6f163bc6e7 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderCoreTests.cs @@ -0,0 +1,67 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests +{ + using System.IO; + using Xunit; + + using ImageSharp.Formats; + + public class GifEncoderCoreTests + { + [Fact] + public void Encode_IgnoreMetadataIsFalse_CommentsAreWritten() + { + var options = new EncoderOptions() + { + IgnoreMetadata = false + }; + + TestFile testFile = TestFile.Create(TestImages.Gif.Rings); + + using (Image input = testFile.CreateImage()) + { + using (MemoryStream memStream = new MemoryStream()) + { + input.Save(memStream, new GifFormat(), options); + + memStream.Position = 0; + using (Image output = new Image(memStream)) + { + Assert.Equal(1, output.MetaData.Properties.Count); + Assert.Equal("Comments", output.MetaData.Properties[0].Name); + Assert.Equal("ImageSharp", output.MetaData.Properties[0].Value); + } + } + } + } + + [Fact] + public void Encode_IgnoreMetadataIsTrue_CommentsAreNotWritten() + { + var options = new GifEncoderOptions() + { + IgnoreMetadata = true + }; + + TestFile testFile = TestFile.Create(TestImages.Gif.Rings); + + using (Image input = testFile.CreateImage()) + { + using (MemoryStream memStream = new MemoryStream()) + { + input.SaveAsGif(memStream, options); + + memStream.Position = 0; + using (Image output = new Image(memStream)) + { + Assert.Equal(0, output.MetaData.Properties.Count); + } + } + } + } + } +} From de7aa060540ded3bb35f60a179ff4a43395ab935 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 19 Feb 2017 21:58:48 +0100 Subject: [PATCH 19/37] Build fixes due to re-base. --- src/ImageSharp.Formats.Bmp/BmpEncoder.cs | 2 +- src/ImageSharp.Formats.Gif/GifDecoder.cs | 2 +- src/ImageSharp.Formats.Gif/GifEncoder.cs | 2 +- src/ImageSharp.Formats.Gif/GifEncoderCore.cs | 2 +- src/ImageSharp.Formats.Png/PngDecoder.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp.Formats.Bmp/BmpEncoder.cs b/src/ImageSharp.Formats.Bmp/BmpEncoder.cs index 2c0bb5b5d5..d0a3550f6f 100644 --- a/src/ImageSharp.Formats.Bmp/BmpEncoder.cs +++ b/src/ImageSharp.Formats.Bmp/BmpEncoder.cs @@ -31,7 +31,7 @@ namespace ImageSharp.Formats /// The to encode the image data to. /// The options for the encoder. public void Encode(Image image, Stream stream, IBmpEncoderOptions options) - where TColor : struct, IPackedPixel, IEquatable + where TColor : struct, IPixel { BmpEncoderCore encoder = new BmpEncoderCore(options); encoder.Encode(image, stream); diff --git a/src/ImageSharp.Formats.Gif/GifDecoder.cs b/src/ImageSharp.Formats.Gif/GifDecoder.cs index 88a3d5e437..b1e8ba928d 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoder.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoder.cs @@ -30,7 +30,7 @@ namespace ImageSharp.Formats /// The containing image data. /// The options for the decoder. public void Decode(Image image, Stream stream, IGifDecoderOptions options) - where TColor : struct, IPackedPixel, IEquatable + where TColor : struct, IPixel { new GifDecoderCore(options).Decode(image, stream); } diff --git a/src/ImageSharp.Formats.Gif/GifEncoder.cs b/src/ImageSharp.Formats.Gif/GifEncoder.cs index 34027ee0cc..cc8516ed9d 100644 --- a/src/ImageSharp.Formats.Gif/GifEncoder.cs +++ b/src/ImageSharp.Formats.Gif/GifEncoder.cs @@ -15,7 +15,7 @@ namespace ImageSharp.Formats { /// public void Encode(Image image, Stream stream, IEncoderOptions options) - where TColor : struct, IPackedPixel, IEquatable + where TColor : struct, IPixel { IGifEncoderOptions gifOptions = GifEncoderOptions.Create(options); diff --git a/src/ImageSharp.Formats.Gif/GifEncoderCore.cs b/src/ImageSharp.Formats.Gif/GifEncoderCore.cs index 2c9a0c8b0b..38cbba8500 100644 --- a/src/ImageSharp.Formats.Gif/GifEncoderCore.cs +++ b/src/ImageSharp.Formats.Gif/GifEncoderCore.cs @@ -237,7 +237,7 @@ namespace ImageSharp.Formats /// The to be encoded. /// The stream to write to. private void WriteComments(Image image, EndianBinaryWriter writer) - where TColor : struct, IPackedPixel, IEquatable + where TColor : struct, IPixel { if (this.options.IgnoreMetadata == true) { diff --git a/src/ImageSharp.Formats.Png/PngDecoder.cs b/src/ImageSharp.Formats.Png/PngDecoder.cs index 658de9e664..d527e1654d 100644 --- a/src/ImageSharp.Formats.Png/PngDecoder.cs +++ b/src/ImageSharp.Formats.Png/PngDecoder.cs @@ -47,7 +47,7 @@ namespace ImageSharp.Formats /// The containing image data. /// The options for the decoder. public void Decode(Image image, Stream stream, IPngDecoderOptions options) - where TColor : struct, IPackedPixel, IEquatable + where TColor : struct, IPixel { new PngDecoderCore(options).Decode(image, stream); } From 98f18cbfeb542fd62338ca7670d39fc972c689dc Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Mon, 20 Feb 2017 07:14:23 +0100 Subject: [PATCH 20/37] Added extra test for trimming comments. --- .../Formats/Gif/GifEncoderCoreTests.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderCoreTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderCoreTests.cs index 6f163bc6e7..0e8e21780f 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderCoreTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderCoreTests.cs @@ -63,5 +63,28 @@ namespace ImageSharp.Tests } } } + + [Fact] + public void Encode_CommentIsToLong_CommentIsTrimmed() + { + using (Image input = new Image(1, 1)) + { + string comments = new string('c', 256); + input.MetaData.Properties.Add(new ImageProperty("Comments", comments)); + + using (MemoryStream memStream = new MemoryStream()) + { + input.Save(memStream, new GifFormat()); + + memStream.Position = 0; + using (Image output = new Image(memStream)) + { + Assert.Equal(1, output.MetaData.Properties.Count); + Assert.Equal("Comments", output.MetaData.Properties[0].Name); + Assert.Equal(255, output.MetaData.Properties[0].Value.Length); + } + } + } + } } } From e429b812ccf9a755f06bdedb8201304ae34432fc Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Mon, 20 Feb 2017 23:37:08 +0100 Subject: [PATCH 21/37] Implemented the IEncoderOptions inside the jpeg encoder. --- .../IJpegEncoderOptions.cs | 29 +++++++ .../ImageExtensions.cs | 11 ++- src/ImageSharp.Formats.Jpeg/JpegEncoder.cs | 75 ++++--------------- .../JpegEncoderCore.cs | 40 +++++++--- .../JpegEncoderOptions.cs | 62 +++++++++++++++ .../Formats/Jpg/JpegDecoderTests.cs | 5 +- .../Formats/Jpg/JpegEncoderTests.cs | 67 +++++++++++++++-- .../Formats/Jpg/JpegProfilingBenchmarks.cs | 5 +- .../TestUtilities/ImagingTestCaseUtility.cs | 5 +- 9 files changed, 209 insertions(+), 90 deletions(-) create mode 100644 src/ImageSharp.Formats.Jpeg/IJpegEncoderOptions.cs create mode 100644 src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs diff --git a/src/ImageSharp.Formats.Jpeg/IJpegEncoderOptions.cs b/src/ImageSharp.Formats.Jpeg/IJpegEncoderOptions.cs new file mode 100644 index 0000000000..7d62dd4ef9 --- /dev/null +++ b/src/ImageSharp.Formats.Jpeg/IJpegEncoderOptions.cs @@ -0,0 +1,29 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + /// + /// Encapsulates the options for the . + /// + public interface IJpegEncoderOptions : IEncoderOptions + { + /// + /// Gets the quality, that will be used to encode the image. Quality + /// index must be between 0 and 100 (compression from max to min). + /// + /// + /// If the quality is less than or equal to 80, the subsampling ratio will switch to + /// + /// The quality of the jpg image from 0 to 100. + int Quality { get; } + + /// + /// Gets the subsample ration, that will be used to encode the image. + /// + /// The subsample ratio of the jpg image. + JpegSubsample? Subsample { get; } + } +} diff --git a/src/ImageSharp.Formats.Jpeg/ImageExtensions.cs b/src/ImageSharp.Formats.Jpeg/ImageExtensions.cs index 2cbba02a90..311bcc6435 100644 --- a/src/ImageSharp.Formats.Jpeg/ImageExtensions.cs +++ b/src/ImageSharp.Formats.Jpeg/ImageExtensions.cs @@ -21,13 +21,18 @@ namespace ImageSharp /// The pixel format. /// The image this method extends. /// The stream to save the image to. - /// The quality to save the image to. Between 1 and 100. + /// The options for the encoder. /// Thrown if the stream is null. /// /// The . /// - public static Image SaveAsJpeg(this Image source, Stream stream, int quality = 75) + public static Image SaveAsJpeg(this Image source, Stream stream, IJpegEncoderOptions options = null) where TColor : struct, IPixel - => source.Save(stream, new JpegEncoder { Quality = quality }); + { + JpegEncoder encoder = new JpegEncoder(); + encoder.Encode(source, stream, options); + + return source; + } } } diff --git a/src/ImageSharp.Formats.Jpeg/JpegEncoder.cs b/src/ImageSharp.Formats.Jpeg/JpegEncoder.cs index 46972cd93d..2f2823fa28 100644 --- a/src/ImageSharp.Formats.Jpeg/JpegEncoder.cs +++ b/src/ImageSharp.Formats.Jpeg/JpegEncoder.cs @@ -5,7 +5,6 @@ namespace ImageSharp.Formats { - using System; using System.IO; /// @@ -13,73 +12,27 @@ namespace ImageSharp.Formats /// public class JpegEncoder : IImageEncoder { - /// - /// The quality used to encode the image. - /// - private int quality = 75; - - /// - /// The subsamples scheme used to encode the image. - /// - private JpegSubsample subsample = JpegSubsample.Ratio420; - - /// - /// Whether subsampling has been specifically set. - /// - private bool subsampleSet; - - /// - /// Gets or sets the quality, that will be used to encode the image. Quality - /// index must be between 0 and 100 (compression from max to min). - /// - /// - /// If the quality is less than or equal to 80, the subsampling ratio will switch to - /// - /// The quality of the jpg image from 0 to 100. - public int Quality + /// + public void Encode(Image image, Stream stream, IEncoderOptions options) + where TColor : struct, IPixel { - get { return this.quality; } - set { this.quality = value.Clamp(1, 100); } + IJpegEncoderOptions gifOptions = JpegEncoderOptions.Create(options); + + this.Encode(image, stream, gifOptions); } /// - /// Gets or sets the subsample ration, that will be used to encode the image. + /// Encodes the image to the specified stream from the . /// - /// The subsample ratio of the jpg image. - public JpegSubsample Subsample - { - get - { - return this.subsample; - } - - set - { - this.subsample = value; - this.subsampleSet = true; - } - } - - /// - public void Encode(Image image, Stream stream, IEncoderOptions options) + /// The pixel format. + /// The to encode from. + /// The to encode the image data to. + /// The options for the encoder. + public void Encode(Image image, Stream stream, IJpegEncoderOptions options) where TColor : struct, IPixel { - // Ensure that quality can be set but has a fallback. - if (image.MetaData.Quality > 0) - { - this.Quality = image.MetaData.Quality; - } - - JpegEncoderCore encode = new JpegEncoderCore(); - if (this.subsampleSet) - { - encode.Encode(image, stream, this.Quality, this.Subsample); - } - else - { - // Use 4:2:0 Subsampling at quality < 91% for reduced filesize. - encode.Encode(image, stream, this.Quality, this.Quality >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420); - } + JpegEncoderCore encode = new JpegEncoderCore(options); + encode.Encode(image, stream); } } } diff --git a/src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs b/src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs index 0309af1299..66f400c017 100644 --- a/src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs @@ -118,6 +118,11 @@ namespace ImageSharp.Formats /// private readonly byte[] huffmanBuffer = new byte[179]; + /// + /// The options for the encoder. + /// + private readonly IJpegEncoderOptions options; + /// /// The accumulated bits to write to the stream. /// @@ -148,15 +153,22 @@ namespace ImageSharp.Formats /// private JpegSubsample subsample; + /// + /// Initializes a new instance of the class. + /// + /// The options for the encoder. + public JpegEncoderCore(IJpegEncoderOptions options) + { + this.options = options ?? new JpegEncoderOptions(); + } + /// /// Encode writes the image to the jpeg baseline format with the given options. /// /// The pixel format. /// The image to write from. /// The stream to write to. - /// The quality. - /// The subsampling mode. - public void Encode(Image image, Stream stream, int quality, JpegSubsample sample) + public void Encode(Image image, Stream stream) where TColor : struct, IPixel { Guard.NotNull(image, nameof(image)); @@ -168,18 +180,17 @@ namespace ImageSharp.Formats throw new ImageFormatException($"Image is too large to encode at {image.Width}x{image.Height}."); } - this.outputStream = stream; - this.subsample = sample; - - if (quality < 1) + // Ensure that quality can be set but has a fallback. + int quality = this.options.Quality > 0 ? this.options.Quality : image.MetaData.Quality; + if (quality == 0) { - quality = 1; + quality = 75; } - if (quality > 100) - { - quality = 100; - } + quality = quality.Clamp(1, 100); + + this.outputStream = stream; + this.subsample = this.options.Subsample ?? (quality >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420); // Convert from a quality rating to a scaling factor. int scale; @@ -706,6 +717,11 @@ namespace ImageSharp.Formats private void WriteProfiles(Image image) where TColor : struct, IPixel { + if (this.options.IgnoreMetadata) + { + return; + } + image.MetaData.SyncProfiles(); this.WriteProfile(image.MetaData.ExifProfile); } diff --git a/src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs b/src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs new file mode 100644 index 0000000000..6be36627c4 --- /dev/null +++ b/src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs @@ -0,0 +1,62 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + /// + /// Encapsulates the options for the . + /// + public sealed class JpegEncoderOptions : EncoderOptions, IJpegEncoderOptions + { + /// + /// Initializes a new instance of the class. + /// + public JpegEncoderOptions() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The options for the encoder. + private JpegEncoderOptions(IEncoderOptions options) + : base(options) + { + } + + /// + /// Gets or sets the quality, that will be used to encode the image. Quality + /// index must be between 0 and 100 (compression from max to min). + /// + /// + /// If the quality is less than or equal to 80, the subsampling ratio will switch to + /// + /// The quality of the jpg image from 0 to 100. + public int Quality { get; set; } + + /// + /// Gets or sets the subsample ration, that will be used to encode the image. + /// + /// The subsample ratio of the jpg image. + public JpegSubsample? Subsample { get; set; } + + /// + /// Converts the options to a instance with a + /// cast or by creating a new instance with the specfied options. + /// + /// The options for the encoder. + /// The options for the . + internal static IJpegEncoderOptions Create(IEncoderOptions options) + { + IJpegEncoderOptions jpegOptions = options as IJpegEncoderOptions; + if (jpegOptions != null) + { + return jpegOptions; + } + + return new JpegEncoderOptions(options); + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index b8ec9d49ea..476de95ff1 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -61,12 +61,13 @@ namespace ImageSharp.Tests byte[] data; using (Image image = provider.GetImage()) { - JpegEncoder encoder = new JpegEncoder() { Subsample = subsample, Quality = quality }; + JpegEncoder encoder = new JpegEncoder(); + JpegEncoderOptions options = new JpegEncoderOptions { Subsample = subsample, Quality = quality }; data = new byte[65536]; using (MemoryStream ms = new MemoryStream(data)) { - image.Save(ms, encoder); + image.Save(ms, encoder, options); } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index 6518c3e6b6..741e785c0c 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -38,11 +38,12 @@ namespace ImageSharp.Tests { image.MetaData.Quality = quality; image.MetaData.ExifProfile = null; // Reduce the size of the file - JpegEncoder encoder = new JpegEncoder { Subsample = subsample, Quality = quality }; + JpegEncoder encoder = new JpegEncoder(); + JpegEncoderOptions options = new JpegEncoderOptions { Subsample = subsample, Quality = quality }; provider.Utility.TestName += $"{subsample}_Q{quality}"; provider.Utility.SaveTestOutputFile(image, "png"); - provider.Utility.SaveTestOutputFile(image, "jpg", encoder); + provider.Utility.SaveTestOutputFile(image, "jpg", encoder, options); } } @@ -59,13 +60,63 @@ namespace ImageSharp.Tests using (FileStream outputStream = File.OpenWrite(utility.GetTestOutputFileName("jpg"))) { - JpegEncoder encoder = new JpegEncoder() - { - Subsample = subSample, - Quality = quality - }; + JpegEncoder encoder = new JpegEncoder(); - image.Save(outputStream, encoder); + image.Save(outputStream, encoder, new JpegEncoderOptions() + { + Subsample = subSample, + Quality = quality + }); + } + } + } + + [Fact] + public void Encode_IgnoreMetadataIsFalse_ExifProfileIsWritten() + { + var options = new EncoderOptions() + { + IgnoreMetadata = false + }; + + TestFile testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan); + + using (Image input = testFile.CreateImage()) + { + using (MemoryStream memStream = new MemoryStream()) + { + input.Save(memStream, new JpegFormat(), options); + + memStream.Position = 0; + using (Image output = new Image(memStream)) + { + Assert.NotNull(output.MetaData.ExifProfile); + } + } + } + } + + [Fact] + public void Encode_IgnoreMetadataIsTrue_ExifProfileIgnored() + { + var options = new JpegEncoderOptions() + { + IgnoreMetadata = true + }; + + TestFile testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan); + + using (Image input = testFile.CreateImage()) + { + using (MemoryStream memStream = new MemoryStream()) + { + input.SaveAsJpeg(memStream, options); + + memStream.Position = 0; + using (Image output = new Image(memStream)) + { + Assert.Null(output.MetaData.ExifProfile); + } } } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs index bfe1f1e76c..50e678bf08 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs @@ -81,8 +81,9 @@ namespace ImageSharp.Tests { foreach (Image img in testImages) { - JpegEncoder encoder = new JpegEncoder() { Quality = quality, Subsample = subsample }; - img.Save(ms, encoder); + JpegEncoder encoder = new JpegEncoder(); + JpegEncoderOptions options = new JpegEncoderOptions { Quality = quality, Subsample = subsample }; + img.Save(ms, encoder, options); ms.Seek(0, SeekOrigin.Begin); } }, diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 54be62d37d..38429b2786 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -75,7 +75,8 @@ namespace ImageSharp.Tests /// The image instance /// The requested extension /// Optional encoder - public void SaveTestOutputFile(Image image, string extension = null, IImageEncoder encoder = null) + /// Optional encoder options + public void SaveTestOutputFile(Image image, string extension = null, IImageEncoder encoder = null, IEncoderOptions options = null) where TColor : struct, IPixel { string path = this.GetTestOutputFileName(extension); @@ -86,7 +87,7 @@ namespace ImageSharp.Tests using (var stream = File.OpenWrite(path)) { - image.Save(stream, encoder); + image.Save(stream, encoder, options); } } From 1b4b8043bc57f73579ef61ef90030fe978de8714 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Mon, 20 Feb 2017 23:40:34 +0100 Subject: [PATCH 22/37] Renamed test classes. --- .../{BitmapTests.cs => BmpEncoderTests.cs} | 4 +- ...DecoderCoreTests.cs => GifDecoderTests.cs} | 4 +- ...EncoderCoreTests.cs => GifEncoderTests.cs} | 4 +- .../Formats/Jpg/JpegDecoderCoreTests.cs | 44 ------------------- .../Formats/Jpg/JpegDecoderTests.cs | 32 ++++++++++++++ ...DecoderCoreTests.cs => PngDecoderTests.cs} | 4 +- .../Png/{PngTests.cs => PngEncoderTests.cs} | 6 +-- 7 files changed, 42 insertions(+), 56 deletions(-) rename tests/ImageSharp.Tests/Formats/Bmp/{BitmapTests.cs => BmpEncoderTests.cs} (89%) rename tests/ImageSharp.Tests/Formats/Gif/{GifDecoderCoreTests.cs => GifDecoderTests.cs} (94%) rename tests/ImageSharp.Tests/Formats/Gif/{GifEncoderCoreTests.cs => GifEncoderTests.cs} (96%) delete mode 100644 tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderCoreTests.cs rename tests/ImageSharp.Tests/Formats/Png/{PngDecoderCoreTests.cs => PngDecoderTests.cs} (94%) rename tests/ImageSharp.Tests/Formats/Png/{PngTests.cs => PngEncoderTests.cs} (91%) diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BitmapTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs similarity index 89% rename from tests/ImageSharp.Tests/Formats/Bmp/BitmapTests.cs rename to tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs index 7579cc86e5..497abb7d56 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BitmapTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -9,7 +9,7 @@ namespace ImageSharp.Tests { using Xunit; - public class BitmapTests : FileTestBase + public class BmpEncoderTests : FileTestBase { public static readonly TheoryData BitsPerPixel = new TheoryData diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderCoreTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs similarity index 94% rename from tests/ImageSharp.Tests/Formats/Gif/GifDecoderCoreTests.cs rename to tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index e1e3e94b09..b874a1585f 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderCoreTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -10,7 +10,7 @@ namespace ImageSharp.Tests using ImageSharp.Formats; - public class GifDecoderCoreTests + public class GifDecoderTests { [Fact] public void Decode_IgnoreMetadataIsFalse_CommentsAreRead() diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderCoreTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs similarity index 96% rename from tests/ImageSharp.Tests/Formats/Gif/GifEncoderCoreTests.cs rename to tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index 0e8e21780f..da1323627f 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderCoreTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -10,7 +10,7 @@ namespace ImageSharp.Tests using ImageSharp.Formats; - public class GifEncoderCoreTests + public class GifEncoderTests { [Fact] public void Encode_IgnoreMetadataIsFalse_CommentsAreWritten() diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderCoreTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderCoreTests.cs deleted file mode 100644 index 38d2a455e9..0000000000 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderCoreTests.cs +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Tests -{ - using Xunit; - - public class JpegDecoderCoreTests - { - [Fact] - public void Decode_IgnoreMetadataIsFalse_ExifProfileIsRead() - { - var options = new DecoderOptions() - { - IgnoreMetadata = false - }; - - TestFile testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan); - - using (Image image = testFile.CreateImage(options)) - { - Assert.NotNull(image.MetaData.ExifProfile); - } - } - - [Fact] - public void Decode_IgnoreMetadataIsTrue_ExifProfileIgnored() - { - var options = new DecoderOptions() - { - IgnoreMetadata = true - }; - - TestFile testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan); - - using (Image image = testFile.CreateImage(options)) - { - Assert.Null(image.MetaData.ExifProfile); - } - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 476de95ff1..7cb9a7cf23 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -121,5 +121,37 @@ namespace ImageSharp.Tests Assert.Equal(72, image.MetaData.VerticalResolution); } } + + [Fact] + public void Decode_IgnoreMetadataIsFalse_ExifProfileIsRead() + { + var options = new DecoderOptions() + { + IgnoreMetadata = false + }; + + TestFile testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan); + + using (Image image = testFile.CreateImage(options)) + { + Assert.NotNull(image.MetaData.ExifProfile); + } + } + + [Fact] + public void Decode_IgnoreMetadataIsTrue_ExifProfileIgnored() + { + var options = new DecoderOptions() + { + IgnoreMetadata = true + }; + + TestFile testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan); + + using (Image image = testFile.CreateImage(options)) + { + Assert.Null(image.MetaData.ExifProfile); + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderCoreTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs similarity index 94% rename from tests/ImageSharp.Tests/Formats/Png/PngDecoderCoreTests.cs rename to tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 766172ec65..921530806c 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderCoreTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -10,7 +10,7 @@ namespace ImageSharp.Tests using ImageSharp.Formats; - public class PngDecoderCoreTests + public class PngDecoderTests { [Fact] public void Decode_IgnoreMetadataIsFalse_TextChunckIsRead() diff --git a/tests/ImageSharp.Tests/Formats/Png/PngTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs similarity index 91% rename from tests/ImageSharp.Tests/Formats/Png/PngTests.cs rename to tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 5ba00eb4d3..49be751391 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -10,11 +10,9 @@ namespace ImageSharp.Tests using System.IO; using System.Threading.Tasks; - using Formats; - using Xunit; - public class PngTests : FileTestBase + public class PngEncoderTests : FileTestBase { [Fact] public void ImageCanSaveIndexedPng() From ce2e1292871431e542b2fdbe96c32f391296bb83 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Tue, 21 Feb 2017 21:59:06 +0100 Subject: [PATCH 23/37] Implemented the IEncoderOptions inside the png encoder. --- .../IPngEncoderOptions.cs | 54 +++++++++++ src/ImageSharp.Formats.Png/ImageExtensions.cs | 14 +-- src/ImageSharp.Formats.Png/PngDecoderCore.cs | 1 - src/ImageSharp.Formats.Png/PngEncoder.cs | 68 +++----------- src/ImageSharp.Formats.Png/PngEncoderCore.cs | 91 +++++++++---------- .../PngEncoderOptions.cs | 88 ++++++++++++++++++ 6 files changed, 206 insertions(+), 110 deletions(-) create mode 100644 src/ImageSharp.Formats.Png/IPngEncoderOptions.cs create mode 100644 src/ImageSharp.Formats.Png/PngEncoderOptions.cs diff --git a/src/ImageSharp.Formats.Png/IPngEncoderOptions.cs b/src/ImageSharp.Formats.Png/IPngEncoderOptions.cs new file mode 100644 index 0000000000..0008080d3f --- /dev/null +++ b/src/ImageSharp.Formats.Png/IPngEncoderOptions.cs @@ -0,0 +1,54 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using Quantizers; + + /// + /// Encapsulates the options for the . + /// + public interface IPngEncoderOptions : IEncoderOptions + { + /// + /// Gets the quality of output for images. + /// + int Quality { get; } + + /// + /// Gets the png color type + /// + PngColorType PngColorType { get; } + + /// + /// Gets the compression level 1-9. + /// + int CompressionLevel { get; } + + /// + /// Gets the gamma value, that will be written + /// the the stream, when the property + /// is set to true. + /// + /// The gamma value of the image. + float Gamma { get; } + + /// + /// Gets quantizer for reducing the color count. + /// + IQuantizer Quantizer { get; } + + /// + /// Gets the transparency threshold. + /// + byte Threshold { get; } + + /// + /// Gets a value indicating whether this instance should write + /// gamma information to the stream. + /// + bool WriteGamma { get; } + } +} diff --git a/src/ImageSharp.Formats.Png/ImageExtensions.cs b/src/ImageSharp.Formats.Png/ImageExtensions.cs index dcb1c988b7..f08ab8ee71 100644 --- a/src/ImageSharp.Formats.Png/ImageExtensions.cs +++ b/src/ImageSharp.Formats.Png/ImageExtensions.cs @@ -5,7 +5,6 @@ namespace ImageSharp { - using System; using System.IO; using Formats; @@ -21,15 +20,18 @@ namespace ImageSharp /// The pixel format. /// The image this method extends. /// The stream to save the image to. - /// The quality to save the image to representing the number of colors. - /// Anything equal to 256 and below will cause the encoder to save the image in an indexed format. - /// + /// The options for the encoder. /// Thrown if the stream is null. /// /// The . /// - public static Image SaveAsPng(this Image source, Stream stream, int quality = int.MaxValue) + public static Image SaveAsPng(this Image source, Stream stream, IPngEncoderOptions options = null) where TColor : struct, IPixel - => source.Save(stream, new PngEncoder { Quality = quality }); + { + PngEncoder encoder = new PngEncoder(); + encoder.Encode(source, stream, options); + + return source; + } } } diff --git a/src/ImageSharp.Formats.Png/PngDecoderCore.cs b/src/ImageSharp.Formats.Png/PngDecoderCore.cs index 4a5ad36482..076770ce51 100644 --- a/src/ImageSharp.Formats.Png/PngDecoderCore.cs +++ b/src/ImageSharp.Formats.Png/PngDecoderCore.cs @@ -10,7 +10,6 @@ namespace ImageSharp.Formats using System.Collections.Generic; using System.IO; using System.Linq; - using System.Text; using static ComparableExtensions; diff --git a/src/ImageSharp.Formats.Png/PngEncoder.cs b/src/ImageSharp.Formats.Png/PngEncoder.cs index 8d9c4bc085..e583f381fb 100644 --- a/src/ImageSharp.Formats.Png/PngEncoder.cs +++ b/src/ImageSharp.Formats.Png/PngEncoder.cs @@ -5,72 +5,34 @@ namespace ImageSharp.Formats { - using System; using System.IO; - using ImageSharp.Quantizers; - /// /// Image encoder for writing image data to a stream in png format. /// public class PngEncoder : IImageEncoder { - /// - /// Gets or sets the quality of output for images. - /// - public int Quality { get; set; } - - /// - /// Gets or sets the png color type - /// - public PngColorType PngColorType { get; set; } = PngColorType.RgbWithAlpha; - - /// - /// Gets or sets the compression level 1-9. - /// Defaults to 6. - /// - public int CompressionLevel { get; set; } = 6; - - /// - /// Gets or sets the gamma value, that will be written - /// the the stream, when the property - /// is set to true. The default value is 2.2F. - /// - /// The gamma value of the image. - public float Gamma { get; set; } = 2.2F; - - /// - /// Gets or sets quantizer for reducing the color count. - /// - public IQuantizer Quantizer { get; set; } + /// + public void Encode(Image image, Stream stream, IEncoderOptions options) + where TColor : struct, IPixel + { + IPngEncoderOptions pngOptions = PngEncoderOptions.Create(options); - /// - /// Gets or sets the transparency threshold. - /// - public byte Threshold { get; set; } = 0; + this.Encode(image, stream, pngOptions); + } /// - /// Gets or sets a value indicating whether this instance should write - /// gamma information to the stream. The default value is false. + /// Encodes the image to the specified stream from the . /// - public bool WriteGamma { get; set; } - - /// - public void Encode(Image image, Stream stream, IEncoderOptions options) + /// The pixel format. + /// The to encode from. + /// The to encode the image data to. + /// The options for the encoder. + public void Encode(Image image, Stream stream, IPngEncoderOptions options) where TColor : struct, IPixel { - PngEncoderCore encoder = new PngEncoderCore - { - CompressionLevel = this.CompressionLevel, - Gamma = this.Gamma, - Quality = this.Quality, - PngColorType = this.PngColorType, - Quantizer = this.Quantizer, - WriteGamma = this.WriteGamma, - Threshold = this.Threshold - }; - - encoder.Encode(image, stream); + PngEncoderCore encode = new PngEncoderCore(options); + encode.Encode(image, stream); } } } diff --git a/src/ImageSharp.Formats.Png/PngEncoderCore.cs b/src/ImageSharp.Formats.Png/PngEncoderCore.cs index 2324853cba..8a00c40b2e 100644 --- a/src/ImageSharp.Formats.Png/PngEncoderCore.cs +++ b/src/ImageSharp.Formats.Png/PngEncoderCore.cs @@ -40,6 +40,11 @@ namespace ImageSharp.Formats /// private readonly Crc32 crc = new Crc32(); + /// + /// The options for the encoder. + /// + private readonly IPngEncoderOptions options; + /// /// Contains the raw pixel data from an indexed image. /// @@ -86,44 +91,28 @@ namespace ImageSharp.Formats private byte[] paeth; /// - /// Gets or sets the quality of output for images. - /// - public int Quality { get; set; } - - /// - /// Gets or sets the png color type + /// The quality of output for images. /// - public PngColorType PngColorType { get; set; } + private int quality; /// - /// Gets or sets the compression level 1-9. - /// Defaults to 6. + /// The png color type. /// - public int CompressionLevel { get; set; } = 6; + private PngColorType pngColorType; /// - /// Gets or sets a value indicating whether this instance should write - /// gamma information to the stream. The default value is false. + /// The quantizer for reducing the color count. /// - public bool WriteGamma { get; set; } + private IQuantizer quantizer; /// - /// Gets or sets the gamma value, that will be written - /// the the stream, when the property - /// is set to true. The default value is 2.2F. + /// Initializes a new instance of the class. /// - /// The gamma value of the image. - public float Gamma { get; set; } = 2.2F; - - /// - /// Gets or sets the quantizer for reducing the color count. - /// - public IQuantizer Quantizer { get; set; } - - /// - /// Gets or sets the transparency threshold. - /// - public byte Threshold { get; set; } + /// The options for the encoder. + public PngEncoderCore(IPngEncoderOptions options) + { + this.options = options ?? new PngEncoderOptions(); + } /// /// Encodes the image to the specified stream from the . @@ -153,23 +142,25 @@ namespace ImageSharp.Formats stream.Write(this.chunkDataBuffer, 0, 8); // Ensure that quality can be set but has a fallback. - int quality = this.Quality > 0 ? this.Quality : image.MetaData.Quality; - this.Quality = quality > 0 ? quality.Clamp(1, int.MaxValue) : int.MaxValue; + this.quality = this.options.Quality > 0 ? this.options.Quality : image.MetaData.Quality; + this.quality = this.quality > 0 ? this.quality.Clamp(1, int.MaxValue) : int.MaxValue; + + this.pngColorType = this.options.PngColorType; // Set correct color type if the color count is 256 or less. - if (this.Quality <= 256) + if (this.quality <= 256) { - this.PngColorType = PngColorType.Palette; + this.pngColorType = PngColorType.Palette; } - if (this.PngColorType == PngColorType.Palette && this.Quality > 256) + if (this.pngColorType == PngColorType.Palette && this.quality > 256) { - this.Quality = 256; + this.quality = 256; } // Set correct bit depth. - this.bitDepth = this.Quality <= 256 - ? (byte)ImageMaths.GetBitsNeededForColorDepth(this.Quality).Clamp(1, 8) + this.bitDepth = this.quality <= 256 + ? (byte)ImageMaths.GetBitsNeededForColorDepth(this.quality).Clamp(1, 8) : (byte)8; // Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk @@ -188,7 +179,7 @@ namespace ImageSharp.Formats { Width = image.Width, Height = image.Height, - ColorType = (byte)this.PngColorType, + ColorType = (byte)this.pngColorType, BitDepth = this.bitDepth, FilterMethod = 0, // None CompressionMethod = 0, @@ -198,7 +189,7 @@ namespace ImageSharp.Formats this.WriteHeaderChunk(stream, header); // Collect the indexed pixel data - if (this.PngColorType == PngColorType.Palette) + if (this.pngColorType == PngColorType.Palette) { this.CollectIndexedBytes(image, stream, header); } @@ -334,7 +325,7 @@ namespace ImageSharp.Formats private byte[] EncodePixelRow(PixelAccessor pixels, int row, byte[] previousScanline, byte[] rawScanline, byte[] result) where TColor : struct, IPixel { - switch (this.PngColorType) + switch (this.pngColorType) { case PngColorType.Palette: Buffer.BlockCopy(this.palettePixelData, row * rawScanline.Length, rawScanline, 0, rawScanline.Length); @@ -362,7 +353,7 @@ namespace ImageSharp.Formats private byte[] GetOptimalFilteredScanline(byte[] rawScanline, byte[] previousScanline, byte[] result) { // Palette images don't compress well with adaptive filtering. - if (this.PngColorType == PngColorType.Palette || this.bitDepth < 8) + if (this.pngColorType == PngColorType.Palette || this.bitDepth < 8) { NoneFilter.Encode(rawScanline, result); return result; @@ -436,7 +427,7 @@ namespace ImageSharp.Formats /// The private int CalculateBytesPerPixel() { - switch (this.PngColorType) + switch (this.pngColorType) { case PngColorType.Grayscale: return 1; @@ -488,18 +479,18 @@ namespace ImageSharp.Formats private QuantizedImage WritePaletteChunk(Stream stream, PngHeader header, ImageBase image) where TColor : struct, IPixel { - if (this.Quality > 256) + if (this.quality > 256) { return null; } - if (this.Quantizer == null) + if (this.quantizer == null) { - this.Quantizer = new OctreeQuantizer(); + this.quantizer = new OctreeQuantizer(); } // Quantize the image returning a palette. This boxing is icky. - QuantizedImage quantized = ((IQuantizer)this.Quantizer).Quantize(image, this.Quality); + QuantizedImage quantized = ((IQuantizer)this.quantizer).Quantize(image, this.quality); // Grab the palette and write it to the stream. TColor[] palette = quantized.Palette; @@ -524,7 +515,7 @@ namespace ImageSharp.Formats colorTable[offset + 1] = bytes[1]; colorTable[offset + 2] = bytes[2]; - if (alpha <= this.Threshold) + if (alpha <= this.options.Threshold) { transparentPixels.Add((byte)offset); } @@ -578,9 +569,9 @@ namespace ImageSharp.Formats /// The containing image data. private void WriteGammaChunk(Stream stream) { - if (this.WriteGamma) + if (this.options.WriteGamma) { - int gammaValue = (int)(this.Gamma * 100000F); + int gammaValue = (int)(this.options.Gamma * 100000F); byte[] size = BitConverter.GetBytes(gammaValue); @@ -608,7 +599,7 @@ namespace ImageSharp.Formats int resultLength = bytesPerScanline + 1; byte[] result = new byte[resultLength]; - if (this.PngColorType != PngColorType.Palette) + if (this.pngColorType != PngColorType.Palette) { this.sub = new byte[resultLength]; this.up = new byte[resultLength]; @@ -622,7 +613,7 @@ namespace ImageSharp.Formats try { memoryStream = new MemoryStream(); - using (ZlibDeflateStream deflateStream = new ZlibDeflateStream(memoryStream, this.CompressionLevel)) + using (ZlibDeflateStream deflateStream = new ZlibDeflateStream(memoryStream, this.options.CompressionLevel)) { for (int y = 0; y < this.height; y++) { diff --git a/src/ImageSharp.Formats.Png/PngEncoderOptions.cs b/src/ImageSharp.Formats.Png/PngEncoderOptions.cs new file mode 100644 index 0000000000..9e6e851de1 --- /dev/null +++ b/src/ImageSharp.Formats.Png/PngEncoderOptions.cs @@ -0,0 +1,88 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using Quantizers; + + /// + /// Encapsulates the options for the . + /// + public sealed class PngEncoderOptions : EncoderOptions, IPngEncoderOptions + { + /// + /// Initializes a new instance of the class. + /// + public PngEncoderOptions() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The options for the encoder. + private PngEncoderOptions(IEncoderOptions options) + : base(options) + { + } + + /// + /// Gets or sets the quality of output for images. + /// + public int Quality { get; set; } + + /// + /// Gets or sets the png color type + /// + public PngColorType PngColorType { get; set; } = PngColorType.RgbWithAlpha; + + /// + /// Gets or sets the compression level 1-9. + /// Defaults to 6. + /// + public int CompressionLevel { get; set; } = 6; + + /// + /// Gets or sets the gamma value, that will be written + /// the the stream, when the property + /// is set to true. The default value is 2.2F. + /// + /// The gamma value of the image. + public float Gamma { get; set; } = 2.2F; + + /// + /// Gets or sets quantizer for reducing the color count. + /// + public IQuantizer Quantizer { get; set; } + + /// + /// Gets or sets the transparency threshold. + /// + public byte Threshold { get; set; } = 0; + + /// + /// Gets or sets a value indicating whether this instance should write + /// gamma information to the stream. The default value is false. + /// + public bool WriteGamma { get; set; } + + /// + /// Converts the options to a instance with a + /// cast or by creating a new instance with the specfied options. + /// + /// The options for the encoder. + /// The options for the . + internal static IPngEncoderOptions Create(IEncoderOptions options) + { + IPngEncoderOptions pngOptions = options as IPngEncoderOptions; + if (pngOptions != null) + { + return pngOptions; + } + + return new PngEncoderOptions(options); + } + } +} From 35fb2974dc9f987ad842aa27bb0ebb442677d824 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Wed, 22 Feb 2017 17:24:01 +0100 Subject: [PATCH 24/37] Refactored the Create method for the encoder/decoder options. --- src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs | 8 +------- src/ImageSharp.Formats.Gif/GifDecoderOptions.cs | 8 +------- src/ImageSharp.Formats.Gif/GifEncoderOptions.cs | 8 +------- src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs | 8 +------- src/ImageSharp.Formats.Png/PngDecoderOptions.cs | 8 +------- src/ImageSharp.Formats.Png/PngEncoderOptions.cs | 8 +------- 6 files changed, 6 insertions(+), 42 deletions(-) diff --git a/src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs b/src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs index 2c06d8a665..a0f9ff8e05 100644 --- a/src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs +++ b/src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs @@ -39,13 +39,7 @@ namespace ImageSharp.Formats /// The options for the . internal static IBmpEncoderOptions Create(IEncoderOptions options) { - IBmpEncoderOptions bmpOptions = options as IBmpEncoderOptions; - if (bmpOptions != null) - { - return bmpOptions; - } - - return new BmpEncoderOptions(options); + return options as IBmpEncoderOptions ?? new BmpEncoderOptions(options); } } } diff --git a/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs b/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs index 8722c5fe8f..bc7709f759 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs @@ -41,13 +41,7 @@ namespace ImageSharp.Formats /// The options for the . internal static IGifDecoderOptions Create(IDecoderOptions options) { - IGifDecoderOptions gifOptions = options as IGifDecoderOptions; - if (gifOptions != null) - { - return gifOptions; - } - - return new GifDecoderOptions(options); + return options as IGifDecoderOptions ?? new GifDecoderOptions(options); } } } diff --git a/src/ImageSharp.Formats.Gif/GifEncoderOptions.cs b/src/ImageSharp.Formats.Gif/GifEncoderOptions.cs index 94cad9603c..5d7c6e40b6 100644 --- a/src/ImageSharp.Formats.Gif/GifEncoderOptions.cs +++ b/src/ImageSharp.Formats.Gif/GifEncoderOptions.cs @@ -59,13 +59,7 @@ namespace ImageSharp.Formats /// The options for the . internal static IGifEncoderOptions Create(IEncoderOptions options) { - IGifEncoderOptions gifOptions = options as IGifEncoderOptions; - if (gifOptions != null) - { - return gifOptions; - } - - return new GifEncoderOptions(options); + return options as IGifEncoderOptions ?? new GifEncoderOptions(options); } } } diff --git a/src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs b/src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs index 6be36627c4..454afa6ae2 100644 --- a/src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs +++ b/src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs @@ -50,13 +50,7 @@ namespace ImageSharp.Formats /// The options for the . internal static IJpegEncoderOptions Create(IEncoderOptions options) { - IJpegEncoderOptions jpegOptions = options as IJpegEncoderOptions; - if (jpegOptions != null) - { - return jpegOptions; - } - - return new JpegEncoderOptions(options); + return options as IJpegEncoderOptions ?? new JpegEncoderOptions(options); } } } diff --git a/src/ImageSharp.Formats.Png/PngDecoderOptions.cs b/src/ImageSharp.Formats.Png/PngDecoderOptions.cs index 83716e5d1b..e8990ec456 100644 --- a/src/ImageSharp.Formats.Png/PngDecoderOptions.cs +++ b/src/ImageSharp.Formats.Png/PngDecoderOptions.cs @@ -43,13 +43,7 @@ namespace ImageSharp.Formats /// The options for the . internal static IPngDecoderOptions Create(IDecoderOptions options) { - IPngDecoderOptions pngOptions = options as IPngDecoderOptions; - if (pngOptions != null) - { - return pngOptions; - } - - return new PngDecoderOptions(options); + return options as IPngDecoderOptions ?? new PngDecoderOptions(options); } } } diff --git a/src/ImageSharp.Formats.Png/PngEncoderOptions.cs b/src/ImageSharp.Formats.Png/PngEncoderOptions.cs index 9e6e851de1..2891f1974e 100644 --- a/src/ImageSharp.Formats.Png/PngEncoderOptions.cs +++ b/src/ImageSharp.Formats.Png/PngEncoderOptions.cs @@ -76,13 +76,7 @@ namespace ImageSharp.Formats /// The options for the . internal static IPngEncoderOptions Create(IEncoderOptions options) { - IPngEncoderOptions pngOptions = options as IPngEncoderOptions; - if (pngOptions != null) - { - return pngOptions; - } - - return new PngEncoderOptions(options); + return options as IPngEncoderOptions ?? new PngEncoderOptions(options); } } } From 347dcaa82599216c4015ea574af5b713636dcc46 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Wed, 22 Feb 2017 17:47:26 +0100 Subject: [PATCH 25/37] Fixed text in comments. --- src/ImageSharp.Formats.Jpeg/IJpegEncoderOptions.cs | 3 --- src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/ImageSharp.Formats.Jpeg/IJpegEncoderOptions.cs b/src/ImageSharp.Formats.Jpeg/IJpegEncoderOptions.cs index 7d62dd4ef9..a545179653 100644 --- a/src/ImageSharp.Formats.Jpeg/IJpegEncoderOptions.cs +++ b/src/ImageSharp.Formats.Jpeg/IJpegEncoderOptions.cs @@ -14,9 +14,6 @@ namespace ImageSharp.Formats /// Gets the quality, that will be used to encode the image. Quality /// index must be between 0 and 100 (compression from max to min). /// - /// - /// If the quality is less than or equal to 80, the subsampling ratio will switch to - /// /// The quality of the jpg image from 0 to 100. int Quality { get; } diff --git a/src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs b/src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs index 454afa6ae2..73e483164c 100644 --- a/src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs +++ b/src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs @@ -31,7 +31,7 @@ namespace ImageSharp.Formats /// index must be between 0 and 100 (compression from max to min). /// /// - /// If the quality is less than or equal to 80, the subsampling ratio will switch to + /// If the quality is less than or equal to 90, the subsampling ratio will switch to /// /// The quality of the jpg image from 0 to 100. public int Quality { get; set; } From 48baea5ffef6dfb3eefb592b7a3c58acacb28b64 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Wed, 22 Feb 2017 17:50:03 +0100 Subject: [PATCH 26/37] Added missing initialization of the quantizer field. --- src/ImageSharp.Formats.Png/PngEncoderCore.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ImageSharp.Formats.Png/PngEncoderCore.cs b/src/ImageSharp.Formats.Png/PngEncoderCore.cs index 8a00c40b2e..7950d260c7 100644 --- a/src/ImageSharp.Formats.Png/PngEncoderCore.cs +++ b/src/ImageSharp.Formats.Png/PngEncoderCore.cs @@ -146,6 +146,7 @@ namespace ImageSharp.Formats this.quality = this.quality > 0 ? this.quality.Clamp(1, int.MaxValue) : int.MaxValue; this.pngColorType = this.options.PngColorType; + this.quantizer = this.options.Quantizer; // Set correct color type if the color count is 256 or less. if (this.quality <= 256) From 052ecdc337c40fef91535e952c9f97e880be8389 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Wed, 22 Feb 2017 18:12:35 +0100 Subject: [PATCH 27/37] Changed optional arguments into overloads. --- src/ImageSharp.Formats.Gif/ImageExtensions.cs | 18 +- .../ImageExtensions.cs | 18 +- src/ImageSharp.Formats.Png/ImageExtensions.cs | 18 +- src/ImageSharp/Image.cs | 132 ++++++++++- src/ImageSharp/Image/Image{TColor}.cs | 215 +++++++++++++++++- tests/ImageSharp.Tests/Image/ImageTests.cs | 2 +- 6 files changed, 387 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp.Formats.Gif/ImageExtensions.cs b/src/ImageSharp.Formats.Gif/ImageExtensions.cs index dcf4ab29a5..1ba03ed351 100644 --- a/src/ImageSharp.Formats.Gif/ImageExtensions.cs +++ b/src/ImageSharp.Formats.Gif/ImageExtensions.cs @@ -15,6 +15,22 @@ namespace ImageSharp /// public static partial class ImageExtensions { + /// + /// Saves the image to the given stream with the gif format. + /// + /// The pixel format. + /// The image this method extends. + /// The stream to save the image to. + /// Thrown if the stream is null. + /// + /// The . + /// + public static Image SaveAsGif(this Image source, Stream stream) + where TColor : struct, IPixel + { + return SaveAsGif(source, stream, null); + } + /// /// Saves the image to the given stream with the gif format. /// @@ -26,7 +42,7 @@ namespace ImageSharp /// /// The . /// - public static Image SaveAsGif(this Image source, Stream stream, IGifEncoderOptions options = null) + public static Image SaveAsGif(this Image source, Stream stream, IGifEncoderOptions options) where TColor : struct, IPixel { GifEncoder encoder = new GifEncoder(); diff --git a/src/ImageSharp.Formats.Jpeg/ImageExtensions.cs b/src/ImageSharp.Formats.Jpeg/ImageExtensions.cs index 311bcc6435..351275ebb7 100644 --- a/src/ImageSharp.Formats.Jpeg/ImageExtensions.cs +++ b/src/ImageSharp.Formats.Jpeg/ImageExtensions.cs @@ -15,6 +15,22 @@ namespace ImageSharp /// public static partial class ImageExtensions { + /// + /// Saves the image to the given stream with the jpeg format. + /// + /// The pixel format. + /// The image this method extends. + /// The stream to save the image to. + /// Thrown if the stream is null. + /// + /// The . + /// + public static Image SaveAsJpeg(this Image source, Stream stream) + where TColor : struct, IPixel + { + return SaveAsJpeg(source, stream, null); + } + /// /// Saves the image to the given stream with the jpeg format. /// @@ -26,7 +42,7 @@ namespace ImageSharp /// /// The . /// - public static Image SaveAsJpeg(this Image source, Stream stream, IJpegEncoderOptions options = null) + public static Image SaveAsJpeg(this Image source, Stream stream, IJpegEncoderOptions options) where TColor : struct, IPixel { JpegEncoder encoder = new JpegEncoder(); diff --git a/src/ImageSharp.Formats.Png/ImageExtensions.cs b/src/ImageSharp.Formats.Png/ImageExtensions.cs index f08ab8ee71..79e96175c1 100644 --- a/src/ImageSharp.Formats.Png/ImageExtensions.cs +++ b/src/ImageSharp.Formats.Png/ImageExtensions.cs @@ -14,6 +14,22 @@ namespace ImageSharp /// public static partial class ImageExtensions { + /// + /// Saves the image to the given stream with the png format. + /// + /// The pixel format. + /// The image this method extends. + /// The stream to save the image to. + /// Thrown if the stream is null. + /// + /// The . + /// + public static Image SaveAsPng(this Image source, Stream stream) + where TColor : struct, IPixel + { + return SaveAsPng(source, stream, null); + } + /// /// Saves the image to the given stream with the png format. /// @@ -25,7 +41,7 @@ namespace ImageSharp /// /// The . /// - public static Image SaveAsPng(this Image source, Stream stream, IPngEncoderOptions options = null) + public static Image SaveAsPng(this Image source, Stream stream, IPngEncoderOptions options) where TColor : struct, IPixel { PngEncoder encoder = new PngEncoder(); diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs index b1c1252ab4..af31eff792 100644 --- a/src/ImageSharp/Image.cs +++ b/src/ImageSharp/Image.cs @@ -31,6 +31,48 @@ namespace ImageSharp { } + /// + /// Initializes a new instance of the class. + /// + /// + /// The stream containing image information. + /// + /// Thrown if the is null. + public Image(Stream stream) + : base(stream, null, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The stream containing image information. + /// + /// + /// The options for the decoder. + /// + /// Thrown if the is null. + public Image(Stream stream, IDecoderOptions options) + : base(stream, options, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The stream containing image information. + /// + /// + /// The configuration providing initialization code which allows extending the library. + /// + /// Thrown if the is null. + public Image(Stream stream, Configuration configuration) + : base(stream, null, configuration) + { + } + /// /// Initializes a new instance of the class. /// @@ -44,12 +86,54 @@ namespace ImageSharp /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(Stream stream, IDecoderOptions options = null, Configuration configuration = null) + public Image(Stream stream, IDecoderOptions options, Configuration configuration) : base(stream, options, configuration) { } #if !NETSTANDARD1_1 + /// + /// Initializes a new instance of the class. + /// + /// + /// A file path to read image information. + /// + /// Thrown if the is null. + public Image(string filePath) + : base(filePath, null, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A file path to read image information. + /// + /// + /// The options for the decoder. + /// + /// Thrown if the is null. + public Image(string filePath, IDecoderOptions options) + : base(filePath, options, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A file path to read image information. + /// + /// + /// The configuration providing initialization code which allows extending the library. + /// + /// Thrown if the is null. + public Image(string filePath, Configuration configuration) + : base(filePath, null, configuration) + { + } + /// /// Initializes a new instance of the class. /// @@ -63,12 +147,54 @@ namespace ImageSharp /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(string filePath, IDecoderOptions options = null, Configuration configuration = null) + public Image(string filePath, IDecoderOptions options, Configuration configuration) : base(filePath, options, configuration) { } #endif + /// + /// Initializes a new instance of the class. + /// + /// + /// The byte array containing image information. + /// + /// Thrown if the is null. + public Image(byte[] bytes) + : base(bytes, null, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The byte array containing image information. + /// + /// + /// The options for the decoder. + /// + /// Thrown if the is null. + public Image(byte[] bytes, IDecoderOptions options) + : base(bytes, options, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The byte array containing image information. + /// + /// + /// The configuration providing initialization code which allows extending the library. + /// + /// Thrown if the is null. + public Image(byte[] bytes, Configuration configuration) + : base(bytes, null, configuration) + { + } + /// /// Initializes a new instance of the class. /// @@ -82,7 +208,7 @@ namespace ImageSharp /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(byte[] bytes, IDecoderOptions options = null, Configuration configuration = null) + public Image(byte[] bytes, IDecoderOptions options, Configuration configuration) : base(bytes, options, configuration) { } diff --git a/src/ImageSharp/Image/Image{TColor}.cs b/src/ImageSharp/Image/Image{TColor}.cs index 69b99ce13a..27dee54342 100644 --- a/src/ImageSharp/Image/Image{TColor}.cs +++ b/src/ImageSharp/Image/Image{TColor}.cs @@ -46,6 +46,48 @@ namespace ImageSharp this.CurrentImageFormat = this.Configuration.ImageFormats.First(); } + /// + /// Initializes a new instance of the class. + /// + /// + /// The stream containing image information. + /// + /// Thrown if the is null. + public Image(Stream stream) + : this(stream, null, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The stream containing image information. + /// + /// + /// The options for the decoder. + /// + /// Thrown if the is null. + public Image(Stream stream, IDecoderOptions options) + : this(stream, options, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The stream containing image information. + /// + /// + /// The configuration providing initialization code which allows extending the library. + /// + /// Thrown if the is null. + public Image(Stream stream, Configuration configuration) + : this(stream, null, configuration) + { + } + /// /// Initializes a new instance of the class. /// @@ -59,7 +101,7 @@ namespace ImageSharp /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(Stream stream, IDecoderOptions options = null, Configuration configuration = null) + public Image(Stream stream, IDecoderOptions options, Configuration configuration) : base(configuration) { Guard.NotNull(stream, nameof(stream)); @@ -67,6 +109,48 @@ namespace ImageSharp } #if !NETSTANDARD1_1 + /// + /// Initializes a new instance of the class. + /// + /// + /// The file containing image information. + /// + /// Thrown if the is null. + public Image(string filePath) + : this(filePath, null, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The file containing image information. + /// + /// + /// The options for the decoder. + /// + /// Thrown if the is null. + public Image(string filePath, IDecoderOptions options) + : this(filePath, options, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The file containing image information. + /// + /// + /// The configuration providing initialization code which allows extending the library. + /// + /// Thrown if the is null. + public Image(string filePath, Configuration configuration) + : this(filePath, null, configuration) + { + } + /// /// Initializes a new instance of the class. /// @@ -80,7 +164,7 @@ namespace ImageSharp /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(string filePath, IDecoderOptions options = null, Configuration configuration = null) + public Image(string filePath, IDecoderOptions options, Configuration configuration) : base(configuration) { Guard.NotNull(filePath, nameof(filePath)); @@ -91,6 +175,48 @@ namespace ImageSharp } #endif + /// + /// Initializes a new instance of the class. + /// + /// + /// The byte array containing image information. + /// + /// Thrown if the is null. + public Image(byte[] bytes) + : this(bytes, null, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The byte array containing image information. + /// + /// + /// The options for the decoder. + /// + /// Thrown if the is null. + public Image(byte[] bytes, IDecoderOptions options) + : this(bytes, options, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The byte array containing image information. + /// + /// + /// The configuration providing initialization code which allows extending the library. + /// + /// Thrown if the is null. + public Image(byte[] bytes, Configuration configuration) + : this(bytes, null, configuration) + { + } + /// /// Initializes a new instance of the class. /// @@ -104,7 +230,7 @@ namespace ImageSharp /// The configuration providing initialization code which allows extending the library. /// /// Thrown if the is null. - public Image(byte[] bytes, IDecoderOptions options = null, Configuration configuration = null) + public Image(byte[] bytes, IDecoderOptions options, Configuration configuration) : base(configuration) { Guard.NotNull(bytes, nameof(bytes)); @@ -202,6 +328,17 @@ namespace ImageSharp } } + /// + /// Saves the image to the given stream using the currently loaded image format. + /// + /// The stream to save the image to. + /// Thrown if the stream is null. + /// The + public Image Save(Stream stream) + { + return this.Save(stream, (IEncoderOptions)null); + } + /// /// Saves the image to the given stream using the currently loaded image format. /// @@ -209,13 +346,24 @@ namespace ImageSharp /// The options for the encoder. /// Thrown if the stream is null. /// The - public Image Save(Stream stream, IEncoderOptions options = null) + public Image Save(Stream stream, IEncoderOptions options) { Guard.NotNull(stream, nameof(stream)); this.CurrentImageFormat.Encoder.Encode(this, stream, options); return this; } + /// + /// Saves the image to the given stream using the given image format. + /// + /// The stream to save the image to. + /// The format to save the image as. + /// The + public Image Save(Stream stream, IImageFormat format) + { + return this.Save(stream, format, null); + } + /// /// Saves the image to the given stream using the given image format. /// @@ -223,7 +371,7 @@ namespace ImageSharp /// The format to save the image as. /// The options for the encoder. /// The - public Image Save(Stream stream, IImageFormat format, IEncoderOptions options = null) + public Image Save(Stream stream, IImageFormat format, IEncoderOptions options) { Guard.NotNull(stream, nameof(stream)); Guard.NotNull(format, nameof(format)); @@ -231,6 +379,20 @@ namespace ImageSharp return this; } + /// + /// 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. + /// + /// The . + /// + public Image Save(Stream stream, IImageEncoder encoder) + { + return this.Save(stream, encoder, null); + } + /// /// Saves the image to the given stream using the given image encoder. /// @@ -241,7 +403,7 @@ namespace ImageSharp /// /// The . /// - public Image Save(Stream stream, IImageEncoder encoder, IEncoderOptions options = null) + public Image Save(Stream stream, IImageEncoder encoder, IEncoderOptions options) { Guard.NotNull(stream, nameof(stream)); Guard.NotNull(encoder, nameof(encoder)); @@ -257,6 +419,17 @@ namespace ImageSharp } #if !NETSTANDARD1_1 + /// + /// Saves the image to the given stream using the currently loaded image format. + /// + /// The file path to save the image to. + /// Thrown if the stream is null. + /// The + public Image Save(string filePath) + { + return this.Save(filePath, (IEncoderOptions)null); + } + /// /// Saves the image to the given stream using the currently loaded image format. /// @@ -264,7 +437,7 @@ namespace ImageSharp /// The options for the encoder. /// Thrown if the stream is null. /// The - public Image Save(string filePath, IEncoderOptions options = null) + public Image Save(string filePath, IEncoderOptions options) { string ext = Path.GetExtension(filePath).Trim('.'); IImageFormat format = this.Configuration.ImageFormats.SingleOrDefault(f => f.SupportedExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase)); @@ -276,6 +449,18 @@ namespace ImageSharp return this.Save(filePath, format); } + /// + /// Saves the image to the given stream using the currently loaded image format. + /// + /// The file path to save the image to. + /// The format to save the image as. + /// Thrown if the format is null. + /// The + public Image Save(string filePath, IImageFormat format) + { + return this.Save(filePath, format, null); + } + /// /// Saves the image to the given stream using the currently loaded image format. /// @@ -284,7 +469,7 @@ namespace ImageSharp /// The options for the encoder. /// Thrown if the format is null. /// The - public Image Save(string filePath, IImageFormat format, IEncoderOptions options = null) + public Image Save(string filePath, IImageFormat format, IEncoderOptions options) { Guard.NotNull(format, nameof(format)); using (FileStream fs = File.Create(filePath)) @@ -293,6 +478,18 @@ namespace ImageSharp } } + /// + /// Saves the image to the given stream using the currently loaded image format. + /// + /// The file path to save the image to. + /// The encoder to save the image with. + /// Thrown if the encoder is null. + /// The + public Image Save(string filePath, IImageEncoder encoder) + { + return this.Save(filePath, encoder, null); + } + /// /// Saves the image to the given stream using the currently loaded image format. /// @@ -301,7 +498,7 @@ namespace ImageSharp /// The options for the encoder. /// Thrown if the encoder is null. /// The - public Image Save(string filePath, IImageEncoder encoder, IEncoderOptions options = null) + public Image Save(string filePath, IImageEncoder encoder, IEncoderOptions options) { Guard.NotNull(encoder, nameof(encoder)); using (FileStream fs = File.Create(filePath)) diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index aea4330c68..0ed724fadc 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -59,7 +59,7 @@ namespace ImageSharp.Tests ArgumentNullException ex = Assert.Throws( () => { - new Image(null); + new Image((string) null); }); } From c45b94548935d4bbb936f189f080a3a39eef645c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 23 Feb 2017 11:07:21 +1100 Subject: [PATCH 28/37] Fix #115 --- src/ImageSharp.Formats.Png/PngDecoderCore.cs | 9 +++------ tests/ImageSharp.Tests/FileTestBase.cs | 3 ++- tests/ImageSharp.Tests/TestImages.cs | 9 +++++---- .../TestImages/Formats/Png/chunklength2.png | 3 +++ 4 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 tests/ImageSharp.Tests/TestImages/Formats/Png/chunklength2.png diff --git a/src/ImageSharp.Formats.Png/PngDecoderCore.cs b/src/ImageSharp.Formats.Png/PngDecoderCore.cs index 076770ce51..a7765342e9 100644 --- a/src/ImageSharp.Formats.Png/PngDecoderCore.cs +++ b/src/ImageSharp.Formats.Png/PngDecoderCore.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Formats using System.Collections.Generic; using System.IO; using System.Linq; + using System.Runtime.CompilerServices; using static ComparableExtensions; @@ -945,12 +946,7 @@ namespace ImageSharp.Formats private void ReadChunkLength(PngChunk chunk) { int numBytes = this.currentStream.Read(this.chunkLengthBuffer, 0, 4); - if (numBytes > 1 && numBytes <= 3) - { - throw new ImageFormatException("Image stream is not valid!"); - } - - if (numBytes <= 1) + if (numBytes < 4) { chunk.Length = -1; return; @@ -966,6 +962,7 @@ namespace ImageSharp.Formats /// /// Th current pass index /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] private int ComputeColumnsAdam7(int pass) { int width = this.header.Width; diff --git a/tests/ImageSharp.Tests/FileTestBase.cs b/tests/ImageSharp.Tests/FileTestBase.cs index b147e97e88..765ff3a423 100644 --- a/tests/ImageSharp.Tests/FileTestBase.cs +++ b/tests/ImageSharp.Tests/FileTestBase.cs @@ -30,7 +30,8 @@ namespace ImageSharp.Tests TestFile.Create(TestImages.Bmp.Car), // TestFile.Create(TestImages.Bmp.Neg_height), // Perf: Enable for local testing only TestFile.Create(TestImages.Png.Splash), - // TestFile.Create(TestImages.Png.ChunkLength), // Perf: Enable for local testing only + // TestFile.Create(TestImages.Png.ChunkLength1), // Perf: Enable for local testing only + // TestFile.Create(TestImages.Png.ChunkLength2), // Perf: Enable for local testing only // TestFile.Create(TestImages.Png.Powerpoint), // Perf: Enable for local testing only // TestFile.Create(TestImages.Png.Blur), // Perf: Enable for local testing only // TestFile.Create(TestImages.Png.Indexed), // Perf: Enable for local testing only diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 4924cc1dee..f0a0e8dd81 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -25,18 +25,19 @@ namespace ImageSharp.Tests public const string SplashInterlaced = "Png/splash-interlaced.png"; public const string Interlaced = "Png/interlaced.png"; - // filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html + // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html public const string Filter0 = "Png/filter0.png"; public const string Filter1 = "Png/filter1.png"; public const string Filter2 = "Png/filter2.png"; public const string Filter3 = "Png/filter3.png"; public const string Filter4 = "Png/filter4.png"; - // filter changing per scanline + // Filter changing per scanline public const string FilterVar = "Png/filterVar.png"; - // Chunk length of 1 by end marker - public const string ChunkLength = "Png/chunklength1.png"; + // Odd chunk lengths + public const string ChunkLength1 = "Png/chunklength1.png"; + public const string ChunkLength2 = "Png/chunklength2.png"; } public static class Jpeg diff --git a/tests/ImageSharp.Tests/TestImages/Formats/Png/chunklength2.png b/tests/ImageSharp.Tests/TestImages/Formats/Png/chunklength2.png new file mode 100644 index 0000000000..85929cb1ef --- /dev/null +++ b/tests/ImageSharp.Tests/TestImages/Formats/Png/chunklength2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b508f05da9f50edd87ed387abc8222620682ef2f59f036fd66ac7cbaf95ffe44 +size 12181 From ab0c5d01c9706f390d80bc966ea31e5db04d416a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 23 Feb 2017 11:07:28 +1100 Subject: [PATCH 29/37] Inline filters --- src/ImageSharp.Formats.Png/Filters/AverageFilter.cs | 5 +++++ src/ImageSharp.Formats.Png/Filters/NoneFilter.cs | 3 +++ src/ImageSharp.Formats.Png/Filters/PaethFilter.cs | 4 ++++ src/ImageSharp.Formats.Png/Filters/SubFilter.cs | 4 ++++ src/ImageSharp.Formats.Png/Filters/UpFilter.cs | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/src/ImageSharp.Formats.Png/Filters/AverageFilter.cs b/src/ImageSharp.Formats.Png/Filters/AverageFilter.cs index d5f8107082..b4ec499469 100644 --- a/src/ImageSharp.Formats.Png/Filters/AverageFilter.cs +++ b/src/ImageSharp.Formats.Png/Filters/AverageFilter.cs @@ -5,6 +5,8 @@ namespace ImageSharp.Formats { + using System.Runtime.CompilerServices; + /// /// The Average filter uses the average of the two neighboring pixels (left and above) to predict /// the value of a pixel. @@ -19,6 +21,7 @@ namespace ImageSharp.Formats /// The previous scanline. /// The number of bytes per scanline /// The bytes per pixel. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Decode(byte[] scanline, byte[] previousScanline, int bytesPerScanline, int bytesPerPixel) { // Average(x) + floor((Raw(x-bpp)+Prior(x))/2) @@ -42,6 +45,7 @@ namespace ImageSharp.Formats /// The previous scanline. /// The filtered scanline result. /// The bytes per pixel. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Encode(byte[] scanline, byte[] previousScanline, byte[] result, int bytesPerPixel) { // Average(x) = Raw(x) - floor((Raw(x-bpp)+Prior(x))/2) @@ -67,6 +71,7 @@ namespace ImageSharp.Formats /// The left byte /// The above byte /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int Average(byte left, byte above) { return (left + above) >> 1; diff --git a/src/ImageSharp.Formats.Png/Filters/NoneFilter.cs b/src/ImageSharp.Formats.Png/Filters/NoneFilter.cs index e5787a9442..5abd892964 100644 --- a/src/ImageSharp.Formats.Png/Filters/NoneFilter.cs +++ b/src/ImageSharp.Formats.Png/Filters/NoneFilter.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Formats { using System; + using System.Runtime.CompilerServices; /// /// The None filter, the scanline is transmitted unmodified; it is only necessary to @@ -19,6 +20,7 @@ namespace ImageSharp.Formats /// /// The scanline to decode /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] Decode(byte[] scanline) { // No change required. @@ -30,6 +32,7 @@ namespace ImageSharp.Formats /// /// The scanline to encode /// The filtered scanline result. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Encode(byte[] scanline, byte[] result) { // Insert a byte before the data. diff --git a/src/ImageSharp.Formats.Png/Filters/PaethFilter.cs b/src/ImageSharp.Formats.Png/Filters/PaethFilter.cs index ff208f3d77..a43d4f0802 100644 --- a/src/ImageSharp.Formats.Png/Filters/PaethFilter.cs +++ b/src/ImageSharp.Formats.Png/Filters/PaethFilter.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Formats { using System; + using System.Runtime.CompilerServices; /// /// The Paeth filter computes a simple linear function of the three neighboring pixels (left, above, upper left), @@ -22,6 +23,7 @@ namespace ImageSharp.Formats /// The previous scanline. /// The number of bytes per scanline /// The bytes per pixel. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Decode(byte[] scanline, byte[] previousScanline, int bytesPerScanline, int bytesPerPixel) { // Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp)) @@ -46,6 +48,7 @@ namespace ImageSharp.Formats /// The previous scanline. /// The filtered scanline result. /// The bytes per pixel. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Encode(byte[] scanline, byte[] previousScanline, byte[] result, int bytesPerPixel) { // Paeth(x) = Raw(x) - PaethPredictor(Raw(x-bpp), Prior(x), Prior(x - bpp)) @@ -76,6 +79,7 @@ namespace ImageSharp.Formats /// /// The . /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static byte PaethPredicator(byte left, byte above, byte upperLeft) { int p = left + above - upperLeft; diff --git a/src/ImageSharp.Formats.Png/Filters/SubFilter.cs b/src/ImageSharp.Formats.Png/Filters/SubFilter.cs index 65e86f4f10..4610ed0ae4 100644 --- a/src/ImageSharp.Formats.Png/Filters/SubFilter.cs +++ b/src/ImageSharp.Formats.Png/Filters/SubFilter.cs @@ -5,6 +5,8 @@ namespace ImageSharp.Formats { + using System.Runtime.CompilerServices; + /// /// The Sub filter transmits the difference between each byte and the value of the corresponding byte /// of the prior pixel. @@ -18,6 +20,7 @@ namespace ImageSharp.Formats /// The scanline to decode /// The number of bytes per scanline /// The bytes per pixel. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Decode(byte[] scanline, int bytesPerScanline, int bytesPerPixel) { // Sub(x) + Raw(x-bpp) @@ -37,6 +40,7 @@ namespace ImageSharp.Formats /// The scanline to encode /// The filtered scanline result. /// The bytes per pixel. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Encode(byte[] scanline, byte[] result, int bytesPerPixel) { // Sub(x) = Raw(x) - Raw(x-bpp) diff --git a/src/ImageSharp.Formats.Png/Filters/UpFilter.cs b/src/ImageSharp.Formats.Png/Filters/UpFilter.cs index 036862ddce..525f50d0ff 100644 --- a/src/ImageSharp.Formats.Png/Filters/UpFilter.cs +++ b/src/ImageSharp.Formats.Png/Filters/UpFilter.cs @@ -5,6 +5,8 @@ namespace ImageSharp.Formats { + using System.Runtime.CompilerServices; + /// /// The Up filter is just like the Sub filter except that the pixel immediately above the current pixel, /// rather than just to its left, is used as the predictor. @@ -18,6 +20,7 @@ namespace ImageSharp.Formats /// The scanline to decode /// The previous scanline. /// The number of bytes per scanline + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Decode(byte[] scanline, byte[] previousScanline, int bytesPerScanline) { // Up(x) + Prior(x) @@ -39,6 +42,7 @@ namespace ImageSharp.Formats /// The scanline to encode /// The previous scanline. /// The filtered scanline result. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Encode(byte[] scanline, byte[] previousScanline, byte[] result) { // Up(x) = Raw(x) - Prior(x) From f6be42a48690a8e168bc9d9aee2d4471956235ff Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 24 Feb 2017 00:44:06 +1100 Subject: [PATCH 30/37] Branding.... No PR on this one. I AM THE ABSOLUTE RULER!! :tongue: --- build/icons/imagesharp-logo-128.png | 4 +- build/icons/imagesharp-logo-256.png | 4 +- build/icons/imagesharp-logo-32.png | 4 +- build/icons/imagesharp-logo-512.png | 4 +- build/icons/imagesharp-logo-64.png | 4 +- build/icons/imagesharp-logo.png | 4 +- build/icons/imagesharp-logo.svg | 60 +---------------------------- 7 files changed, 13 insertions(+), 71 deletions(-) diff --git a/build/icons/imagesharp-logo-128.png b/build/icons/imagesharp-logo-128.png index 81e29fee5b..a7be6e512b 100644 --- a/build/icons/imagesharp-logo-128.png +++ b/build/icons/imagesharp-logo-128.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:01f79400a4a77c764273a97fbc76982546e88510fa4cc64a7b2e83e265b0e141 -size 2490 +oid sha256:7ae6327b2d554c25640756650865eeb5e96aa5bd58b3922ae5247400dc516ed0 +size 6622 diff --git a/build/icons/imagesharp-logo-256.png b/build/icons/imagesharp-logo-256.png index 5b78542cba..2fbd57d8c8 100644 --- a/build/icons/imagesharp-logo-256.png +++ b/build/icons/imagesharp-logo-256.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5598d4cb5bad33aefc1084c4f389b071143a59505f00f7b7831c81254f1140f8 -size 4225 +oid sha256:a78ad79663c58544bba12b431ed83659e60a12a4fcb9b358e7a1c22bc76034bc +size 14020 diff --git a/build/icons/imagesharp-logo-32.png b/build/icons/imagesharp-logo-32.png index 31e32300da..3a8e28e854 100644 --- a/build/icons/imagesharp-logo-32.png +++ b/build/icons/imagesharp-logo-32.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:536e75abeaa2c35f34a95d34bee4f8bd13cf5514a979960566945da4ec8827d1 -size 979 +oid sha256:a911690b45b1614ca0dcd08d09ec4d257edc244ccc352e6384370cc197cac1e0 +size 1479 diff --git a/build/icons/imagesharp-logo-512.png b/build/icons/imagesharp-logo-512.png index ee02fb650d..eabef882fa 100644 --- a/build/icons/imagesharp-logo-512.png +++ b/build/icons/imagesharp-logo-512.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c8288a69f4182b25e04ba6419b452c6cdbca0013856352c0aeb08abc67f67e4d -size 7951 +oid sha256:1381533f41d07c6d3d2604e20c605cd7dd70654056cffd73e67bdc75353476b2 +size 31672 diff --git a/build/icons/imagesharp-logo-64.png b/build/icons/imagesharp-logo-64.png index 9919f97d6c..a45ea0afcb 100644 --- a/build/icons/imagesharp-logo-64.png +++ b/build/icons/imagesharp-logo-64.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ab6d98a7a55caf570016a62a2f4d72842e22cbe03460ad60a4dc196b7b1d303 -size 1698 +oid sha256:d28e405019add224bd0156332e16e152c6b3822de406c7d5a79cc78e15396a8f +size 3143 diff --git a/build/icons/imagesharp-logo.png b/build/icons/imagesharp-logo.png index 0f80ceeaa6..e0ab59b8df 100644 --- a/build/icons/imagesharp-logo.png +++ b/build/icons/imagesharp-logo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f20a3b2613811efa3455ee65b532284d88636d8796ee2279c08a584aa01744e -size 19129 +oid sha256:6d21730b397705c2312383d1f7c3f614d2bc2daecf3f9b667f8cbf48a679b4da +size 59600 diff --git a/build/icons/imagesharp-logo.svg b/build/icons/imagesharp-logo.svg index 9638e9785b..2df3cc80ce 100644 --- a/build/icons/imagesharp-logo.svg +++ b/build/icons/imagesharp-logo.svg @@ -1,59 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file From 3f16b57988d032c6e51f15536619e53c358d1b47 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 24 Feb 2017 07:56:09 +1100 Subject: [PATCH 31/37] Re export images [skip ci] --- build/icons/imagesharp-logo-128.png | 4 ++-- build/icons/imagesharp-logo-256.png | 4 ++-- build/icons/imagesharp-logo-32.png | 4 ++-- build/icons/imagesharp-logo-512.png | 4 ++-- build/icons/imagesharp-logo-64.png | 4 ++-- build/icons/imagesharp-logo.png | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/build/icons/imagesharp-logo-128.png b/build/icons/imagesharp-logo-128.png index a7be6e512b..d9ae997bad 100644 --- a/build/icons/imagesharp-logo-128.png +++ b/build/icons/imagesharp-logo-128.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ae6327b2d554c25640756650865eeb5e96aa5bd58b3922ae5247400dc516ed0 -size 6622 +oid sha256:47f14bb7d24f7228cd8833d8d1881a72750b2c7813f391bd2a0dd0eeea936841 +size 6569 diff --git a/build/icons/imagesharp-logo-256.png b/build/icons/imagesharp-logo-256.png index 2fbd57d8c8..f1e67dd78b 100644 --- a/build/icons/imagesharp-logo-256.png +++ b/build/icons/imagesharp-logo-256.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a78ad79663c58544bba12b431ed83659e60a12a4fcb9b358e7a1c22bc76034bc -size 14020 +oid sha256:757ec2f45cc5f9c2083fc65a236100f1a7776eee16bd1095a550e05783106a9f +size 13949 diff --git a/build/icons/imagesharp-logo-32.png b/build/icons/imagesharp-logo-32.png index 3a8e28e854..80435989ad 100644 --- a/build/icons/imagesharp-logo-32.png +++ b/build/icons/imagesharp-logo-32.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a911690b45b1614ca0dcd08d09ec4d257edc244ccc352e6384370cc197cac1e0 -size 1479 +oid sha256:0f3a5375ce20321c2cfdc888a21dcb629d3e6a85641df5cca7c66e5b2a5f70f6 +size 1439 diff --git a/build/icons/imagesharp-logo-512.png b/build/icons/imagesharp-logo-512.png index eabef882fa..a5f880e3af 100644 --- a/build/icons/imagesharp-logo-512.png +++ b/build/icons/imagesharp-logo-512.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1381533f41d07c6d3d2604e20c605cd7dd70654056cffd73e67bdc75353476b2 -size 31672 +oid sha256:0e4cd18406375999c2bee1c39ad439b37f9524485d6e247ab0f14d2eb90a65f3 +size 31256 diff --git a/build/icons/imagesharp-logo-64.png b/build/icons/imagesharp-logo-64.png index a45ea0afcb..f59e202bf9 100644 --- a/build/icons/imagesharp-logo-64.png +++ b/build/icons/imagesharp-logo-64.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d28e405019add224bd0156332e16e152c6b3822de406c7d5a79cc78e15396a8f -size 3143 +oid sha256:fa25e5dbe84f942107a1c29f4f68ff2a73f497412ae91b6e60fc5464bc9b5f05 +size 3132 diff --git a/build/icons/imagesharp-logo.png b/build/icons/imagesharp-logo.png index e0ab59b8df..e0f1854ccb 100644 --- a/build/icons/imagesharp-logo.png +++ b/build/icons/imagesharp-logo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6d21730b397705c2312383d1f7c3f614d2bc2daecf3f9b667f8cbf48a679b4da -size 59600 +oid sha256:e4217fe820af06a593903441f0719cab1ca650fd4de795f0e6808c4240a89819 +size 59646 From a97e6c9ec8180eea04c70ae95b18e8a814d17f4f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 24 Feb 2017 09:15:09 +1100 Subject: [PATCH 32/37] Update readme [skip ci] --- README.md | 2 +- build/icons/imagesharp-logo-heading.png | 3 +++ features.md | 16 +++++++++++++--- 3 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 build/icons/imagesharp-logo-heading.png diff --git a/README.md b/README.md index cbe03bb4e1..9d5c9788a7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# ImageSharp +# ImageSharp **ImageSharp** is a new cross-platform 2D graphics API designed to allow the processing of images without the use of `System.Drawing`. diff --git a/build/icons/imagesharp-logo-heading.png b/build/icons/imagesharp-logo-heading.png new file mode 100644 index 0000000000..4cd4e03909 --- /dev/null +++ b/build/icons/imagesharp-logo-heading.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f79e49b0965696c2106dc3654aa18ae7334e07d2e691c0b96acddb8150c25a88 +size 8609 diff --git a/features.md b/features.md index 764d7c4a62..6bc5630eed 100644 --- a/features.md +++ b/features.md @@ -10,13 +10,23 @@ We've achieved a lot so far and hope to do a lot more in the future. We're alway - [x] Bmp (Read: 32bit, 24bit, 16 bit. Write: 32bit, 24bit just now) - [x] Png (Read: Rgb, Rgba, Grayscale, Grayscale + alpha, Palette. Write: Rgb, Rgba, Grayscale, Grayscale + alpha, Palette) Supports interlaced decoding - [x] Gif (Includes animated) - - [ ] Tiff + - [ ] Tiff (Help needed) - **Metadata** - [x] EXIF Read/Write (Jpeg just now) -- **Quantizers (IQuantizer with alpha channel support + thresholding)** +- **Quantizers (IQuantizer with alpha channel support, dithering, and thresholding)** - [x] Octree - [x] Xiaolin Wu - [x] Palette +- **DIthering (Error diffusion and Ordered)** + - [x] Atkinson + - [x] Burks + - [x] FloydSteinburg + - [x] JarvisJudiceNinke + - [x] Sieera2 + - [x] Sierra3 + - [x] SerraLite + - [x] Bayer + - [x] Ordered - **Basic color structs with implicit operators.** - [x] Color - 32bit color in RGBA order (IPackedPixel\). - [x] Bgra32 @@ -133,5 +143,5 @@ We've achieved a lot so far and hope to do a lot more in the future. We're alway - [x] DrawImage - [ ] Gradient brush (Need help) - **DrawingText** - - [x] DrawString (Single variant support just now, no italic,bold) + - [ ] DrawString (In-progress. Single variant support just now, no italic,bold) - Other stuff I haven't thought of. \ No newline at end of file From f0089cff96f5a3ca4770d02ba2f67a88ab942a6c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 24 Feb 2017 09:20:25 +1100 Subject: [PATCH 33/37] Reduce logo height [skip ci] --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 9d5c9788a7..87708cf05d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -# ImageSharp **ImageSharp** is a new cross-platform 2D graphics API designed to allow the processing of images without the use of `System.Drawing`. From 525c1cf98d18c394251026cb2efcdf6984627c6b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 24 Feb 2017 09:20:45 +1100 Subject: [PATCH 34/37] Drop px [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 87708cf05d..d44a15bfd4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ +# ImageSharp **ImageSharp** is a new cross-platform 2D graphics API designed to allow the processing of images without the use of `System.Drawing`. From 2032017dbf2c080176fab3e4eedc37e0e54bec8a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 25 Feb 2017 13:58:02 +1100 Subject: [PATCH 35/37] Prevent logo squish on mobile [skip ci] --- README.md | 2 +- build/icons/imagesharp-logo-heading.png | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d44a15bfd4..9d5c9788a7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# ImageSharp +# ImageSharp **ImageSharp** is a new cross-platform 2D graphics API designed to allow the processing of images without the use of `System.Drawing`. diff --git a/build/icons/imagesharp-logo-heading.png b/build/icons/imagesharp-logo-heading.png index 4cd4e03909..20779215fd 100644 --- a/build/icons/imagesharp-logo-heading.png +++ b/build/icons/imagesharp-logo-heading.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f79e49b0965696c2106dc3654aa18ae7334e07d2e691c0b96acddb8150c25a88 -size 8609 +oid sha256:bf2335642c6fd291befa0b203dbfb3387d99434369399b35aeea037c0f9eba45 +size 10474 From c2904aa234be00d62ac59cb58a02b1795d5cfd29 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 25 Feb 2017 17:46:20 +0000 Subject: [PATCH 36/37] Update SixLabors.Shapes version --- src/ImageSharp.Drawing.Paths/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp.Drawing.Paths/project.json b/src/ImageSharp.Drawing.Paths/project.json index bf6b1fae8f..b761233c37 100644 --- a/src/ImageSharp.Drawing.Paths/project.json +++ b/src/ImageSharp.Drawing.Paths/project.json @@ -44,7 +44,7 @@ "ImageSharp.Drawing": { "target": "project" }, - "SixLabors.Shapes": "0.1.0-alpha0005", + "SixLabors.Shapes": "0.1.0-alpha0006", "StyleCop.Analyzers": { "version": "1.0.0", "type": "build" From c3e6980609883bc6433473541c6f2751480c3ac9 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 25 Feb 2017 17:59:11 +0000 Subject: [PATCH 37/37] Fix drawing on transparent background --- src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs | 1 - src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs | 1 - tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs index 913293ff34..95f4ab4726 100644 --- a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs @@ -110,7 +110,6 @@ namespace ImageSharp.Drawing.Processors Vector4 sourceVector = color.Color.ToVector4(); Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity); - finalColor.W = backgroundVector.W; TColor packed = default(TColor); packed.PackFromVector4(finalColor); diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index fed97275d6..4f468c7070 100644 --- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -202,7 +202,6 @@ namespace ImageSharp.Drawing.Processors Vector4 sourceVector = applicator[x, y].ToVector4(); Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity); - finalColor.W = backgroundVector.W; TColor packed = default(TColor); packed.PackFromVector4(finalColor); diff --git a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs index a41afd3334..1d3ead81f2 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs @@ -32,7 +32,6 @@ namespace ImageSharp.Tests.Drawing using (FileStream output = File.OpenWrite($"{path}/Simple.png")) { image - .BackgroundColor(Color.Blue) .FillPolygon(Color.HotPink, simplePath, new GraphicsOptions(true)) .Save(output); } @@ -45,7 +44,7 @@ namespace ImageSharp.Tests.Drawing Assert.Equal(Color.HotPink, sourcePixels[50, 50]); - Assert.Equal(Color.Blue, sourcePixels[2, 2]); + Assert.NotEqual(Color.HotPink, sourcePixels[2, 2]); } } }