From 14ec39e17e79dabb6725cd084d32bc8b8780b8aa Mon Sep 17 00:00:00 2001 From: ascensio Date: Mon, 17 Jul 2017 16:38:22 +0200 Subject: [PATCH 01/19] closes #269 --- .../Processors/Transforms/RotateProcessor.cs | 2 +- .../Image/ImageRotationTests.cs | 54 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 tests/ImageSharp.Tests/Image/ImageRotationTests.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index e6b1d180f..d563d072a 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -79,7 +79,7 @@ namespace ImageSharp.Processing.Processors return; } - this.processMatrix = Matrix3x2Extensions.CreateRotation(-this.Angle, new Point(0, 0)); + this.processMatrix = Matrix3x2Extensions.CreateRotationDegrees(-this.Angle, new Point(0, 0)); if (this.Expand) { this.CreateNewCanvas(sourceRectangle, this.processMatrix); diff --git a/tests/ImageSharp.Tests/Image/ImageRotationTests.cs b/tests/ImageSharp.Tests/Image/ImageRotationTests.cs new file mode 100644 index 000000000..44fa458fa --- /dev/null +++ b/tests/ImageSharp.Tests/Image/ImageRotationTests.cs @@ -0,0 +1,54 @@ +using SixLabors.Primitives; +using Xunit; + +namespace ImageSharp.Tests +{ + public class ImageRotationTests + { + [Fact] + public void RotateImageByMinus90Degrees() + { + (Size original, Size rotated) = Rotate(-90); + Assert.Equal(new Size(original.Height, original.Width), rotated); + } + + [Fact] + public void RotateImageBy90Degrees() + { + (Size original, Size rotated) = Rotate(90); + Assert.Equal(new Size(original.Height, original.Width), rotated); + } + + [Fact] + public void RotateImageBy180Degrees() + { + (Size original, Size rotated) = Rotate(180); + Assert.Equal(original, rotated); + } + + [Fact] + public void RotateImageBy270Degrees() + { + (Size original, Size rotated) = Rotate(270); + Assert.Equal(new Size(original.Height, original.Width), rotated); + } + + [Fact] + public void RotateImageBy360Degrees() + { + (Size original, Size rotated) = Rotate(360); + Assert.Equal(original, rotated); + } + + private static (Size original, Size rotated) Rotate(int angle) + { + TestFile file = TestFile.Create(TestImages.Bmp.Car); + using (Image image = Image.Load(file.FilePath)) + { + Size expected = image.Bounds.Size; + image.Rotate(angle); + return (expected, image.Bounds.Size); + } + } + } +} From 2232b47e1c52858f71d87638c11e3bbd76d8ffba Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Tue, 18 Jul 2017 20:42:00 +0100 Subject: [PATCH 02/19] fix concurrency issues in config --- src/ImageSharp/Configuration.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 226d45132..a9322467c 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -35,14 +35,14 @@ namespace ImageSharp private readonly ConcurrentDictionary mimeTypeDecoders = new ConcurrentDictionary(); /// - /// The list of supported s. + /// The list of supported s. /// - private readonly List imageFormatDetectors = new List(); + private readonly ConcurrentBag imageFormats = new ConcurrentBag(); /// - /// The list of supported s. + /// The list of supported s. /// - private readonly HashSet imageFormats = new HashSet(); + private ConcurrentBag imageFormatDetectors = new ConcurrentBag(); /// /// Initializes a new instance of the class. @@ -181,7 +181,7 @@ namespace ImageSharp /// public void ClearImageFormatDetectors() { - this.imageFormatDetectors.Clear(); + this.imageFormatDetectors = new ConcurrentBag(); } /// From 74b0d0aff2e1f1a5ea44e42d1773b17111ac4cbb Mon Sep 17 00:00:00 2001 From: Nikita Balabaev Date: Fri, 28 Jul 2017 18:31:10 +0700 Subject: [PATCH 03/19] fix #277 --- src/ImageSharp/Formats/Bmp/BmpFormat.cs | 2 +- src/ImageSharp/Formats/Gif/GifFormat.cs | 2 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 20 +++++++++---------- src/ImageSharp/Formats/Png/PngFormat.cs | 2 +- .../Formats/Png/PngDecoderTests.cs | 2 +- tests/ImageSharp.Tests/TestImages.cs | 1 + .../Formats/Png/rgb-48bpp-interlaced.png | 3 +++ 7 files changed, 18 insertions(+), 14 deletions(-) create mode 100644 tests/ImageSharp.Tests/TestImages/Formats/Png/rgb-48bpp-interlaced.png diff --git a/src/ImageSharp/Formats/Bmp/BmpFormat.cs b/src/ImageSharp/Formats/Bmp/BmpFormat.cs index fb65f34d7..bd25eb9b7 100644 --- a/src/ImageSharp/Formats/Bmp/BmpFormat.cs +++ b/src/ImageSharp/Formats/Bmp/BmpFormat.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Formats using System.Collections.Generic; /// - /// Registers the image encoders, decoders and mime type detectors for the jpeg format. + /// Registers the image encoders, decoders and mime type detectors for the bmp format. /// internal sealed class BmpFormat : IImageFormat { diff --git a/src/ImageSharp/Formats/Gif/GifFormat.cs b/src/ImageSharp/Formats/Gif/GifFormat.cs index ea7b72d32..744aadff9 100644 --- a/src/ImageSharp/Formats/Gif/GifFormat.cs +++ b/src/ImageSharp/Formats/Gif/GifFormat.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Formats using System.Collections.Generic; /// - /// Registers the image encoders, decoders and mime type detectors for the jpeg format. + /// Registers the image encoders, decoders and mime type detectors for the gif format. /// internal sealed class GifFormat : IImageFormat { diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index e6f19b915..467d41ff4 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -825,14 +825,14 @@ namespace ImageSharp.Formats using (var compressed = new Buffer(length)) { // TODO: Should we use pack from vector here instead? - this.From16BitTo8Bit(new Span(defilteredScanline), compressed, length); - for (int x = pixelOffset, o = 1; + this.From16BitTo8Bit(new Span(defilteredScanline, 1), compressed, length); + for (int x = pixelOffset, o = 0; x < this.header.Width; - x += increment, o += this.bytesPerPixel) + x += increment, o += 3) { rgba.R = compressed[o]; - rgba.G = compressed[o + this.bytesPerSample]; - rgba.B = compressed[o + (2 * this.bytesPerSample)]; + rgba.G = compressed[o + 1]; + rgba.B = compressed[o + 2]; color.PackFromRgba32(rgba); rowSpan[x] = color; @@ -862,13 +862,13 @@ namespace ImageSharp.Formats using (var compressed = new Buffer(length)) { // TODO: Should we use pack from vector here instead? - this.From16BitTo8Bit(new Span(defilteredScanline), compressed, length); - for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel) + this.From16BitTo8Bit(new Span(defilteredScanline, 1), compressed, length); + for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 4) { rgba.R = compressed[o]; - rgba.G = compressed[o + this.bytesPerSample]; - rgba.B = compressed[o + (2 * this.bytesPerSample)]; - rgba.A = compressed[o + (3 * this.bytesPerSample)]; + rgba.G = compressed[o + 1]; + rgba.B = compressed[o + 2]; + rgba.A = compressed[o + 3]; color.PackFromRgba32(rgba); rowSpan[x] = color; diff --git a/src/ImageSharp/Formats/Png/PngFormat.cs b/src/ImageSharp/Formats/Png/PngFormat.cs index 551b4a8c7..6df2aa7c5 100644 --- a/src/ImageSharp/Formats/Png/PngFormat.cs +++ b/src/ImageSharp/Formats/Png/PngFormat.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Formats using System.Collections.Generic; /// - /// Registers the image encoders, decoders and mime type detectors for the jpeg format. + /// Registers the image encoders, decoders and mime type detectors for the png format. /// internal sealed class PngFormat : IImageFormat { diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 6d82b5374..ee8a2ee55 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -18,7 +18,7 @@ namespace ImageSharp.Tests public static readonly string[] TestFiles = { TestImages.Png.Splash, TestImages.Png.Indexed, TestImages.Png.Interlaced, TestImages.Png.FilterVar, - TestImages.Png.Bad.ChunkLength1, TestImages.Png.Bad.ChunkLength2, TestImages.Png.Rgb48Bpp + TestImages.Png.Bad.ChunkLength1, TestImages.Png.Bad.ChunkLength2, TestImages.Png.Rgb48Bpp, TestImages.Png.Rgb48BppInterlaced }; [Theory] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index f35720f19..3479457cf 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -26,6 +26,7 @@ namespace ImageSharp.Tests public const string SplashInterlaced = "Png/splash-interlaced.png"; public const string Interlaced = "Png/interlaced.png"; public const string Rgb48Bpp = "Png/rgb-48bpp.png"; + public const string Rgb48BppInterlaced = "Png/rgb-48bpp-interlaced.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html public const string Filter0 = "Png/filter0.png"; diff --git a/tests/ImageSharp.Tests/TestImages/Formats/Png/rgb-48bpp-interlaced.png b/tests/ImageSharp.Tests/TestImages/Formats/Png/rgb-48bpp-interlaced.png new file mode 100644 index 000000000..d19d44ea4 --- /dev/null +++ b/tests/ImageSharp.Tests/TestImages/Formats/Png/rgb-48bpp-interlaced.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:79d1705ef6438d90dc145068141d4e32c1cf1cd5cf17c7b90b7ecb12967016bd +size 69952 From 687f273500de9d44edb565411f356e081944a306 Mon Sep 17 00:00:00 2001 From: Devedse Date: Sun, 6 Aug 2017 02:31:28 +0200 Subject: [PATCH 04/19] Added failing test for issue 288 --- .../ImageSharp.Tests/Image/ImageLoadTests.cs | 60 ++++++++++++------- tests/ImageSharp.Tests/TestImages.cs | 5 +- .../TestImages/Formats/Png/vim16x16_1.png | 3 + .../TestImages/Formats/Png/vim16x16_2.png | 3 + 4 files changed, 47 insertions(+), 24 deletions(-) create mode 100644 tests/ImageSharp.Tests/TestImages/Formats/Png/vim16x16_1.png create mode 100644 tests/ImageSharp.Tests/TestImages/Formats/Png/vim16x16_2.png diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs index bb64ceda3..d821f4bc7 100644 --- a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs @@ -10,7 +10,6 @@ namespace ImageSharp.Tests using ImageSharp.Formats; using ImageSharp.IO; - using ImageSharp.PixelFormats; using Moq; using Xunit; @@ -44,7 +43,8 @@ namespace ImageSharp.Tests this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny())) - .Callback((c, s) => { + .Callback((c, s) => + { using (var ms = new MemoryStream()) { s.CopyTo(ms); @@ -76,7 +76,7 @@ namespace ImageSharp.Tests [Fact] public void LoadFromStream() { - Image img = Image.Load(this.DataStream); + Image img = Image.Load(this.DataStream); Assert.NotNull(img); @@ -87,12 +87,11 @@ namespace ImageSharp.Tests public void LoadFromNoneSeekableStream() { NoneSeekableStream stream = new NoneSeekableStream(this.DataStream); - Image img = Image.Load(stream); + Image img = Image.Load(stream); Assert.NotNull(img); TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); - } [Fact] @@ -104,20 +103,18 @@ namespace ImageSharp.Tests Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); - } - + [Fact] public void LoadFromStreamWithConfig() { Stream stream = new MemoryStream(); - Image img = Image.Load(this.LocalConfiguration, stream); + Image img = Image.Load(this.LocalConfiguration, stream); Assert.NotNull(img); this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream)); - } [Fact] @@ -130,7 +127,6 @@ namespace ImageSharp.Tests Assert.Equal(this.returnImage, img); this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream)); - } @@ -138,7 +134,7 @@ namespace ImageSharp.Tests public void LoadFromStreamWithDecoder() { Stream stream = new MemoryStream(); - Image img = Image.Load(stream, this.localDecoder.Object); + Image img = Image.Load(stream, this.localDecoder.Object); Assert.NotNull(img); this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream)); @@ -158,13 +154,11 @@ namespace ImageSharp.Tests [Fact] public void LoadFromBytes() { - Image img = Image.Load(this.DataStream.ToArray()); + Image img = Image.Load(this.DataStream.ToArray()); Assert.NotNull(img); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); - } [Fact] @@ -182,7 +176,7 @@ namespace ImageSharp.Tests [Fact] public void LoadFromBytesWithConfig() { - Image img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray()); + Image img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray()); Assert.NotNull(img); @@ -207,7 +201,7 @@ namespace ImageSharp.Tests [Fact] public void LoadFromBytesWithDecoder() { - Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object); + Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object); Assert.NotNull(img); this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny())); @@ -228,13 +222,11 @@ namespace ImageSharp.Tests [Fact] public void LoadFromFile() { - Image img = Image.Load(this.DataStream); + Image img = Image.Load(this.DataStream); Assert.NotNull(img); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); - } [Fact] @@ -251,12 +243,11 @@ namespace ImageSharp.Tests [Fact] public void LoadFromFileWithConfig() { - Image img = Image.Load(this.LocalConfiguration, this.FilePath); + Image img = Image.Load(this.LocalConfiguration, this.FilePath); Assert.NotNull(img); this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream)); - } [Fact] @@ -273,7 +264,7 @@ namespace ImageSharp.Tests [Fact] public void LoadFromFileWithDecoder() { - Image img = Image.Load(this.FilePath, this.localDecoder.Object); + Image img = Image.Load(this.FilePath, this.localDecoder.Object); Assert.NotNull(img); this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream)); @@ -305,7 +296,6 @@ namespace ImageSharp.Tests Assert.Equal(Rgba32.White, px[1, 0]); Assert.Equal(Rgba32.Black, px[1, 1]); - } } @@ -327,7 +317,31 @@ namespace ImageSharp.Tests Assert.Equal(Rgba32.White, px[1, 0]); Assert.Equal(Rgba32.Black, px[1, 1]); + } + } + [Fact] + public void TestThatTwoImagesAreEqual() + { + var image1Provider = TestImageProvider.File(TestImages.Png.VimImage1); + var image2Provider = TestImageProvider.File(TestImages.Png.VimImage2); + + using (Image img1 = image1Provider.GetImage()) + using (Image img2 = image2Provider.GetImage()) + { + Assert.Equal(img1.Width, img2.Width); + Assert.Equal(img1.Height, img2.Height); + + for (int y = 0; y < img1.Height; y++) + { + for (int x = 0; x < img1.Width; x++) + { + Rgba32 pixel1 = img1[x, y]; + Rgba32 pixel2 = img2[x, y]; + + Assert.Equal(pixel1, pixel2); + } + } } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 3479457cf..7d552d109 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -38,6 +38,9 @@ namespace ImageSharp.Tests // Filter changing per scanline public const string FilterVar = "Png/filterVar.png"; + public const string VimImage1 = "Png/vim16x16_1.png"; + public const string VimImage2 = "Png/vim16x16_2.png"; + public static class Bad { // Odd chunk lengths @@ -50,7 +53,7 @@ namespace ImageSharp.Tests P1, Pd, Blur, Splash, Cross, Powerpoint, SplashInterlaced, Interlaced, Filter0, Filter1, Filter2, Filter3, Filter4, - FilterVar + FilterVar, VimImage1, VimImage2 }; } diff --git a/tests/ImageSharp.Tests/TestImages/Formats/Png/vim16x16_1.png b/tests/ImageSharp.Tests/TestImages/Formats/Png/vim16x16_1.png new file mode 100644 index 000000000..a55a1a73d --- /dev/null +++ b/tests/ImageSharp.Tests/TestImages/Formats/Png/vim16x16_1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c9f8ecc9936ef3ce54f5b9b2aac816b9539b753236c53e249cde0f2791aa4712 +size 226 diff --git a/tests/ImageSharp.Tests/TestImages/Formats/Png/vim16x16_2.png b/tests/ImageSharp.Tests/TestImages/Formats/Png/vim16x16_2.png new file mode 100644 index 000000000..39d42c88f --- /dev/null +++ b/tests/ImageSharp.Tests/TestImages/Formats/Png/vim16x16_2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:491ef70e69f63c2d5b48680faebd5b008267850b426f512878854bb1e971eba0 +size 292 From f892f78f293796564ed0118a137649931025b1a2 Mon Sep 17 00:00:00 2001 From: JimBobSquarePants Date: Tue, 8 Aug 2017 15:37:56 +1000 Subject: [PATCH 05/19] Fix failing test --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 467d41ff4..cdbd3a689 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -688,19 +688,11 @@ namespace ImageSharp.Formats // channel and we should try to read it. for (int x = 0; x < this.header.Width; x++) { - int index = newScanline[x + 1]; + int index = newScanline[x]; int pixelOffset = index * 3; rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; - - if (rgba.A > 0) - { - rgba.Rgb = pal.GetRgb24(pixelOffset); - } - else - { - rgba = default(Rgba32); - } + rgba.Rgb = pal.GetRgb24(pixelOffset); color.PackFromRgba32(rgba); row[x] = color; @@ -712,7 +704,7 @@ namespace ImageSharp.Formats for (int x = 0; x < this.header.Width; x++) { - int index = newScanline[x + 1]; + int index = newScanline[x]; int pixelOffset = index * 3; rgba.Rgb = pal.GetRgb24(pixelOffset); From d9552060c7bc97e4d2bbfa6c0dc3245b2a72b5d6 Mon Sep 17 00:00:00 2001 From: JimBobSquarePants Date: Tue, 8 Aug 2017 16:22:30 +1000 Subject: [PATCH 06/19] Disable smoke test --- .../Formats/Png/PngSmokeTests.cs | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs index bac340a71..c977f5fb5 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs @@ -40,25 +40,27 @@ namespace ImageSharp.Tests.Formats.Png } } - [Theory] - [WithTestPatternImages(100, 100, PixelTypes.Rgba32)] - public void CanSaveIndexedPng(TestImageProvider provider) - where TPixel : struct, IPixel - { - // does saving a file then repoening mean both files are identical??? - using (Image image = provider.GetImage()) - using (MemoryStream ms = new MemoryStream()) - { - // image.Save(provider.Utility.GetTestOutputFileName("bmp")); - image.Save(ms, new PngEncoder() { PaletteSize = 256 }); - ms.Position = 0; - using (Image img2 = Image.Load(ms, new PngDecoder())) - { - // img2.Save(provider.Utility.GetTestOutputFileName("bmp", "_loaded"), new BmpEncoder()); - ImageComparer.CheckSimilarity(image, img2, 0.03f); - } - } - } + // JJS: Disabled for now as the decoder now correctly decodes the full pixel components if the + // paletted image has alpha of 0 + //[Theory] + //[WithTestPatternImages(100, 100, PixelTypes.Rgba32)] + //public void CanSaveIndexedPng(TestImageProvider provider) + // where TPixel : struct, IPixel + //{ + // // does saving a file then repoening mean both files are identical??? + // using (Image image = provider.GetImage()) + // using (MemoryStream ms = new MemoryStream()) + // { + // // image.Save(provider.Utility.GetTestOutputFileName("bmp")); + // image.Save(ms, new PngEncoder() { PaletteSize = 256 }); + // ms.Position = 0; + // using (Image img2 = Image.Load(ms, new PngDecoder())) + // { + // // img2.Save(provider.Utility.GetTestOutputFileName("bmp", "_loaded"), new BmpEncoder()); + // ImageComparer.CheckSimilarity(image, img2, 0.03f); + // } + // } + //} // JJS: Commented out for now since the test does not take into lossy nature of indexing. //[Theory] From 9be8649a8e2202a93b94bcbbb81121acf6d12722 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Thu, 10 Aug 2017 09:10:22 +0200 Subject: [PATCH 07/19] Only throw exceptions when the CRC of a critical chunk is incorrect. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 13 ++- .../Formats/Png/PngDecoderTests.cs | 87 ++++++++++++++++--- 2 files changed, 86 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index cdbd3a689..95211c5f3 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -306,6 +306,15 @@ namespace ImageSharp.Formats return result; } + private static bool IsCriticalChunk(PngChunk chunk) + { + return + chunk.Type == PngChunkTypes.Header || + chunk.Type == PngChunkTypes.Palette || + chunk.Type == PngChunkTypes.Data || + chunk.Type == PngChunkTypes.End; + } + /// /// Reads the data chunk containing physical dimension data. /// @@ -1017,9 +1026,9 @@ namespace ImageSharp.Formats this.crc.Update(this.chunkTypeBuffer); this.crc.Update(chunk.Data, 0, chunk.Length); - if (this.crc.Value != chunk.Crc) + if (this.crc.Value != chunk.Crc && IsCriticalChunk(chunk)) { - throw new ImageFormatException("CRC Error. PNG Image chunk is corrupt!"); + throw new ImageFormatException($"CRC Error. PNG {chunk.Type} chunk is corrupt!"); } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index ee8a2ee55..3c335441a 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -3,14 +3,15 @@ // Licensed under the Apache License, Version 2.0. // +using System.IO; +using System.IO.Compression; +using System.Text; +using ImageSharp.Formats; +using ImageSharp.PixelFormats; +using Xunit; + namespace ImageSharp.Tests { - using System.Text; - using Xunit; - - using ImageSharp.Formats; - using ImageSharp.PixelFormats; - public class PngDecoderTests { private const PixelTypes PixelTypes = Tests.PixelTypes.Rgba32 | Tests.PixelTypes.RgbaVector | Tests.PixelTypes.Argb32; @@ -35,12 +36,12 @@ namespace ImageSharp.Tests [Fact] public void Decode_IgnoreMetadataIsFalse_TextChunckIsRead() { - PngDecoder options = new PngDecoder() + var options = new PngDecoder() { IgnoreMetadata = false }; - TestFile testFile = TestFile.Create(TestImages.Png.Blur); + var testFile = TestFile.Create(TestImages.Png.Blur); using (Image image = testFile.CreateImage(options)) { @@ -53,12 +54,12 @@ namespace ImageSharp.Tests [Fact] public void Decode_IgnoreMetadataIsTrue_TextChunksAreIgnored() { - PngDecoder options = new PngDecoder() + var options = new PngDecoder() { IgnoreMetadata = true }; - TestFile testFile = TestFile.Create(TestImages.Png.Blur); + var testFile = TestFile.Create(TestImages.Png.Blur); using (Image image = testFile.CreateImage(options)) { @@ -69,12 +70,12 @@ namespace ImageSharp.Tests [Fact] public void Decode_TextEncodingSetToUnicode_TextIsReadWithCorrectEncoding() { - PngDecoder options = new PngDecoder() + var options = new PngDecoder() { TextEncoding = Encoding.Unicode }; - TestFile testFile = TestFile.Create(TestImages.Png.Blur); + var testFile = TestFile.Create(TestImages.Png.Blur); using (Image image = testFile.CreateImage(options)) { @@ -82,5 +83,67 @@ namespace ImageSharp.Tests Assert.Equal("潓瑦慷敲", image.MetaData.Properties[0].Name); } } + + [Theory] + [InlineData(PngChunkTypes.Header)] + [InlineData(PngChunkTypes.Palette)] + // [InlineData(PngChunkTypes.Data)] //TODO: Figure out how to test this + [InlineData(PngChunkTypes.End)] + public void Decode_IncorrectCRCForCriticalChunk_ExceptionIsThrown(string chunkName) + { + using (var memStream = new MemoryStream()) + { + memStream.Skip(8); + + WriteChunk(memStream, chunkName); + + CompressStream(memStream); + + var decoder = new PngDecoder(); + + ImageFormatException exception = Assert.Throws(() => + { + decoder.Decode(null, memStream); + }); + + Assert.Equal($"CRC Error. PNG {chunkName} chunk is corrupt!", exception.Message); + } + } + + [Theory] + [InlineData(PngChunkTypes.Gamma)] + [InlineData(PngChunkTypes.PaletteAlpha)] + [InlineData(PngChunkTypes.Physical)] + //[InlineData(PngChunkTypes.Text)] //TODO: Figure out how to test this + public void Decode_IncorrectCRCForNonCriticalChunk_ExceptionIsThrown(string chunkName) + { + using (var memStream = new MemoryStream()) + { + memStream.Skip(8); + + WriteChunk(memStream, chunkName); + + CompressStream(memStream); + + var decoder = new PngDecoder(); + decoder.Decode(null, memStream); + } + } + + private static void WriteChunk(MemoryStream memStream, string chunkName) + { + memStream.Write(new byte[] { 0, 0, 0, 1 }, 0, 4); + memStream.Write(Encoding.GetEncoding("ASCII").GetBytes(chunkName), 0, 4); + memStream.Write(new byte[] { 0, 0, 0, 0, 0 }, 0, 5); + } + + private static void CompressStream(Stream stream) + { + stream.Position = 0; + using (var deflateStream = new DeflateStream(stream, CompressionLevel.NoCompression, true)) + { + } + stream.Position = 0; + } } } \ No newline at end of file From ef4be6a7b377c28b2c12c72ed161ba392871af1d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 12 Aug 2017 19:01:05 +1000 Subject: [PATCH 08/19] Correctly read Adam7 palette colors --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 95211c5f3..372ecdc2b 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -768,10 +768,7 @@ namespace ImageSharp.Formats case PngColorType.Palette: - byte[] newScanline = ToArrayByBitsLength( - defilteredScanline, - this.bytesPerScanline, - this.header.BitDepth); + byte[] newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); var rgba = default(Rgba32); if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) @@ -784,15 +781,7 @@ namespace ImageSharp.Formats int offset = index * 3; rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; - - if (rgba.A > 0) - { - rgba.Rgb = this.palette.GetRgb24(offset); - } - else - { - rgba = default(Rgba32); - } + rgba.Rgb = this.palette.GetRgb24(offset); color.PackFromRgba32(rgba); rowSpan[x] = color; From 5f5dda9e57a6197c0dfb434838ab67b7a8357b36 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 12 Aug 2017 19:08:58 +1000 Subject: [PATCH 09/19] Update AppVeyor key --- appveyor.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 079913311..6b7ba946e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,10 +7,6 @@ skip_branch_with_pr: true init: - ps: iex ((new-object net.webclient).DownloadString('https://gist.githubusercontent.com/PureKrome/0f79e25693d574807939/raw/8cf3160c9516ef1f4effc825c0a44acc918a0b5a/appveyor-build-info.ps')) -# temp work around - https://appveyor.statuspage.io/incidents/m2vdvw39kdk8 -hosts: - api.nuget.org: 93.184.221.200 - build_script: - cmd: build.cmd @@ -26,7 +22,7 @@ deploy: server: https://www.myget.org/F/imagesharp/api/v2/package symbol_server: https://www.myget.org/F/imagesharp/symbols/api/v2/package api_key: - secure: P2Fz82nty+itjL+kNRCsMQcqzngmVtkU0R4CZqgST7zgUaE6/1q9ekh5MKKlZLkD + secure: fz0rUrt3B1HczUC1ZehwVsrFSWX9WZGDQoueDztLte9/+yQG+BBU7UrO+coE8lUf artifact: /.*\.nupkg/ on: branch: master From 462ffd90c570e8159ed4034d5469dabe149c9557 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 12 Aug 2017 19:40:28 +1000 Subject: [PATCH 10/19] Revert key change, we have a new CI! --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 6b7ba946e..fdbe46b01 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,7 +22,7 @@ deploy: server: https://www.myget.org/F/imagesharp/api/v2/package symbol_server: https://www.myget.org/F/imagesharp/symbols/api/v2/package api_key: - secure: fz0rUrt3B1HczUC1ZehwVsrFSWX9WZGDQoueDztLte9/+yQG+BBU7UrO+coE8lUf + secure: P2Fz82nty+itjL+kNRCsMQcqzngmVtkU0R4CZqgST7zgUaE6/1q9ekh5MKKlZLkD artifact: /.*\.nupkg/ on: branch: master From b8a047d4b592bfe2badd465d167d5c293d4b243e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 12 Aug 2017 19:47:04 +1000 Subject: [PATCH 11/19] Fix #281 --- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index bb230beac..948103fed 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -157,6 +157,10 @@ namespace ImageSharp.Formats } nextFlag = stream.ReadByte(); + if (nextFlag == -1) + { + break; + } } } finally From 44a21ff077663bb95d8387034f7d7f133927b265 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 12 Aug 2017 20:00:27 +1000 Subject: [PATCH 12/19] Update readme [skip ci] --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e46b11379..70e48e52e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# ImageSharp ImageSharp +# ImageSharp ImageSharp **ImageSharp** is a new, fully featured, fully managed, cross-platform, 2D graphics API designed to allow the processing of images without the use of `System.Drawing`. @@ -9,12 +9,12 @@ Built against .Net Standard 1.1 ImageSharp can be used in device, cloud, and emb > > Pre-release downloads are available from the [MyGet package repository](https://www.myget.org/gallery/imagesharp). -[![GitHub license](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/APACHE-2.0-LICENSE.txt) -[![GitHub issues](https://img.shields.io/github/issues/JimBobSquarePants/ImageSharp.svg)](https://github.com/JimBobSquarePants/ImageSharp/issues) -[![GitHub stars](https://img.shields.io/github/stars/JimBobSquarePants/ImageSharp.svg)](https://github.com/JimBobSquarePants/ImageSharp/stargazers) -[![GitHub forks](https://img.shields.io/github/forks/JimBobSquarePants/ImageSharp.svg)](https://github.com/JimBobSquarePants/ImageSharp/network) +[![GitHub license](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://raw.githubusercontent.com/SixLabors/ImageSharp/master/APACHE-2.0-LICENSE.txt) +[![GitHub issues](https://img.shields.io/github/issues/SixLabors/ImageSharp.svg)](https://github.com/SixLabors/ImageSharp/issues) +[![GitHub stars](https://img.shields.io/github/stars/SixLabors/ImageSharp.svg)](https://github.com/SixLabors/ImageSharp/stargazers) +[![GitHub forks](https://img.shields.io/github/forks/SixLabors/ImageSharp.svg)](https://github.com/SixLabors/ImageSharp/network) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ImageSharp/General?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![Twitter](https://img.shields.io/twitter/url/https/github.com/JimBobSquarePants/ImageSharp.svg?style=social)](https://twitter.com/intent/tweet?hashtags=imagesharp,dotnet,oss&text=ImageSharp.+A+new+cross-platform+2D+graphics+API+in+C%23&url=https%3a%2f%2fgithub.com%2fJimBobSquarePants%2fImageSharp&via=james_m_south) +[![Twitter](https://img.shields.io/twitter/url/https/github.com/SixLabors/ImageSharp.svg?style=social)](https://twitter.com/intent/tweet?hashtags=imagesharp,dotnet,oss&text=ImageSharp.+A+new+cross-platform+2D+graphics+API+in+C%23&url=https%3a%2f%2fgithub.com%2fSixLabors%2fImageSharp&via=sixlabors) [![OpenCollective](https://opencollective.com/imagesharp/backers/badge.svg)](#backers) [![OpenCollective](https://opencollective.com/imagesharp/sponsors/badge.svg)](#sponsors) @@ -22,8 +22,8 @@ Built against .Net Standard 1.1 ImageSharp can be used in device, cloud, and emb | |Build Status|Code Coverage| |-------------|:----------:|:-----------:| -|**Linux/Mac**|[![Build Status](https://travis-ci.org/JimBobSquarePants/ImageSharp.svg)](https://travis-ci.org/JimBobSquarePants/ImageSharp)|[![Code coverage](https://codecov.io/gh/JimBobSquarePants/ImageSharp/branch/master/graph/badge.svg)](https://codecov.io/gh/JimBobSquarePants/ImageSharp)| -|**Windows** |[![Build Status](https://ci.appveyor.com/api/projects/status/hu6d1gdpxdw0q360/branch/master?svg=true)](https://ci.appveyor.com/project/JamesSouth/imagesharp/branch/master)|[![Code coverage](https://codecov.io/gh/JimBobSquarePants/ImageSharp/branch/master/graph/badge.svg)](https://codecov.io/gh/JimBobSquarePants/ImageSharp)| +|**Linux/Mac**|[![Build Status](https://travis-ci.org/SixLabors/ImageSharp.svg)](https://travis-ci.org/SixLabors/ImageSharp)|[![Code coverage](https://codecov.io/gh/SixLabors/ImageSharp/branch/master/graph/badge.svg)](https://codecov.io/gh/SixLabors/ImageSharp)| +|**Windows** |[![Build Status](https://ci.appveyor.com/api/projects/status/m9pn907xdah3ca39/branch/master?svg=true)](https://ci.appveyor.com/project/SixLabors/imagesharp/branch/master)|[![Code coverage](https://codecov.io/gh/SixLabors/ImageSharp/branch/master/graph/badge.svg)](https://codecov.io/gh/SixLabors/ImageSharp)| ### Installation @@ -64,7 +64,7 @@ Alternatively on Linux you can use: To clone it locally click the "Clone in Windows" button above or run the following git commands. ```bash -git clone https://github.com/JimBobSquarePants/ImageSharp +git clone https://github.com/SixLabors/ImageSharp ``` ### Features @@ -121,7 +121,7 @@ For optimized access within a loop it is recommended that the following methods 1. `image.GetRowSpan(y)` 2. `image.GetRowSpan(x, y)` -For advanced pixel format usage there are multiple [PixelFormat implementations](https://github.com/JimBobSquarePants/ImageSharp/tree/master/src/ImageSharp/PixelFormats) available allowing developers to implement their own color models in the same manner as Microsoft XNA Game Studio and MonoGame. +For advanced pixel format usage there are multiple [PixelFormat implementations](https://github.com/SixLabors/ImageSharp/tree/master/src/ImageSharp/PixelFormats) available allowing developers to implement their own color models in the same manner as Microsoft XNA Game Studio and MonoGame. All in all this should allow image processing to be much more accessible to developers which has always been my goal from the start. From 4d9b2f1d29ce48c4272dbd4086f1d3903d60d5cf Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 12 Aug 2017 21:03:46 +1000 Subject: [PATCH 13/19] Fix Appveyor link [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 70e48e52e..7113d6ba1 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Built against .Net Standard 1.1 ImageSharp can be used in device, cloud, and emb | |Build Status|Code Coverage| |-------------|:----------:|:-----------:| |**Linux/Mac**|[![Build Status](https://travis-ci.org/SixLabors/ImageSharp.svg)](https://travis-ci.org/SixLabors/ImageSharp)|[![Code coverage](https://codecov.io/gh/SixLabors/ImageSharp/branch/master/graph/badge.svg)](https://codecov.io/gh/SixLabors/ImageSharp)| -|**Windows** |[![Build Status](https://ci.appveyor.com/api/projects/status/m9pn907xdah3ca39/branch/master?svg=true)](https://ci.appveyor.com/project/SixLabors/imagesharp/branch/master)|[![Code coverage](https://codecov.io/gh/SixLabors/ImageSharp/branch/master/graph/badge.svg)](https://codecov.io/gh/SixLabors/ImageSharp)| +|**Windows** |[![Build Status](https://ci.appveyor.com/api/projects/status/m9pn907xdah3ca39/branch/master?svg=true)](https://ci.appveyor.com/project/six-labors/imagesharp/branch/master)|[![Code coverage](https://codecov.io/gh/SixLabors/ImageSharp/branch/master/graph/badge.svg)](https://codecov.io/gh/SixLabors/ImageSharp)| ### Installation From d6bf435878148439b8adb931fa6c52a79e827f58 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sat, 12 Aug 2017 13:19:44 +0200 Subject: [PATCH 14/19] Renamed variable. --- tests/ImageSharp.Tests/Image/ImageRotationTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Image/ImageRotationTests.cs b/tests/ImageSharp.Tests/Image/ImageRotationTests.cs index 44fa458fa..56cec4219 100644 --- a/tests/ImageSharp.Tests/Image/ImageRotationTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageRotationTests.cs @@ -45,9 +45,9 @@ namespace ImageSharp.Tests TestFile file = TestFile.Create(TestImages.Bmp.Car); using (Image image = Image.Load(file.FilePath)) { - Size expected = image.Bounds.Size; + Size original = image.Bounds.Size; image.Rotate(angle); - return (expected, image.Bounds.Size); + return (original, image.Bounds.Size); } } } From c06c6ab9e98b85bc497e24a24479e4385e36aff1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 12 Aug 2017 21:36:01 +1000 Subject: [PATCH 15/19] Update Travis build coverity details [skip ci] --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index af8d4ad9d..4ae163530 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ env: global: # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created # via the "travis encrypt" command using the project repo's public key - - secure: "aim+fUyx7kDQQcAYV1mX16cvyFEYsxiW3y26xjmeuKzsOf6DIUK328pE8KnO50bMWhfVPjuW7jWc43jI+nbUeIW5018aFcjoOrEK2F8JvJ0UKtEo+ONchypJSXA2TSdL0iIlufMBepsmlBsSLkCwHCJYohYcueZV0u9NVPc3n282KLL8ItRZeSFG/cL/a2yrkFnTFhq9OtkUtP4CcVE7BOtzjfftNcn4Rup73e5JkLT7L9AZS7eCYkIYV0KRlT2pOa/FuOHlfP9NP+NVtd83GXUY2FKBsmN3EmrQgGDTfwfwcJjN5dqIqzkIXmLV8IKQ3aiW2//02pIe5VrdqHQG+EVMRcdpCWyKUkMj0g4rGYkqKCtVJojKtOR93ycOGUDc6+cMMoyn3J2qFydkp278dGWeLuwtGfD25fHXorqK1aL9/bGPcwdinrBmcwnuy1IECtuTkEfAPsb6O4nArnDsTEzeQxwa/MAicmpux//TNKgkQGqzCPeHKbl4vOfyyI6kCsf8edWv8fOSPvJUGvL14+/TZ6lY8S+30fosOmwMCe7xlbtcVlBVtOsKx/XUufrP2Vuptlc8INaq6++XtgpCoMLL0SJfBFQKZRmBGavv1Ztyf0aL6Qp303HKGTyXOEq2k18iJmukB6JcnEGVsaAyteGlruQIbPgHWbxhZSoJZPw=" + - secure: "rjMvEMN9rpvIXqXqCAAKzbHyABzr7E4wPU/dYJ/mHBqlCccFpQrEXVVM1MfRFXYuWZSaIioknhLATZjT5xvIYpTNM6D57z4OTmqeRHhYm80=" before_install: - echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- @@ -34,7 +34,7 @@ before_install: addons: coverity_scan: project: - name: "JimBobSquarePants/ImageSharp" + name: "SixLabors/ImageSharp" description: "Build submitted via Travis CI" notification_email: james_south@hotmail.com build_command_prepend: "dotnet restore" From 133d8c3757df65548dc16759b46e97a80949b035 Mon Sep 17 00:00:00 2001 From: Devedse Date: Sat, 12 Aug 2017 15:31:55 +0200 Subject: [PATCH 16/19] Added tests for loading image with CRC Added tests for comparing Versioning image 1 and 2 Moved equality tests for images to seperate file --- .../Image/ImageDiscoverMimeType.cs | 2 +- .../ImageSharp.Tests/Image/ImageEqualTests.cs | 124 ++++++++++++++++++ .../ImageSharp.Tests/Image/ImageLoadTests.cs | 24 +--- .../ImageSharp.Tests/Image/ImageSaveTests.cs | 2 +- tests/ImageSharp.Tests/Image/ImageTests.cs | 2 +- tests/ImageSharp.Tests/TestImages.cs | 6 +- .../TestImages/Formats/Png/versioning-1_1.png | 3 + .../TestImages/Formats/Png/versioning-1_2.png | 3 + 8 files changed, 143 insertions(+), 23 deletions(-) create mode 100644 tests/ImageSharp.Tests/Image/ImageEqualTests.cs create mode 100644 tests/ImageSharp.Tests/TestImages/Formats/Png/versioning-1_1.png create mode 100644 tests/ImageSharp.Tests/TestImages/Formats/Png/versioning-1_2.png diff --git a/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs b/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs index 59a39c454..d34fa22e2 100644 --- a/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs +++ b/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // diff --git a/tests/ImageSharp.Tests/Image/ImageEqualTests.cs b/tests/ImageSharp.Tests/Image/ImageEqualTests.cs new file mode 100644 index 000000000..5e156f543 --- /dev/null +++ b/tests/ImageSharp.Tests/Image/ImageEqualTests.cs @@ -0,0 +1,124 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests +{ + using System; + using System.IO; + + using ImageSharp.Formats; + using ImageSharp.IO; + using ImageSharp.Tests; + using Moq; + using Xunit; + + public class ImageEqualTests + { + //private readonly Mock fileSystem; + //private Image returnImage; + //private Mock localDecoder; + //private readonly string FilePath; + //private readonly Mock localMimeTypeDetector; + //private readonly Mock localImageFormatMock; + + //public Configuration LocalConfiguration { get; private set; } + //public byte[] Marker { get; private set; } + //public MemoryStream DataStream { get; private set; } + //public byte[] DecodedData { get; private set; } + + public ImageEqualTests() + { + //this.returnImage = new Image(1, 1); + + //this.localImageFormatMock = new Mock(); + + //this.localDecoder = new Mock(); + //this.localMimeTypeDetector = new Mock(); + //this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1); + //this.localMimeTypeDetector.Setup(x => x.DetectFormat(It.IsAny>())).Returns(localImageFormatMock.Object); + + //this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny())) + + // .Callback((c, s) => + // { + // using (var ms = new MemoryStream()) + // { + // s.CopyTo(ms); + // this.DecodedData = ms.ToArray(); + // } + // }) + // .Returns(this.returnImage); + + //this.fileSystem = new Mock(); + + //this.LocalConfiguration = new Configuration() + //{ + // FileSystem = this.fileSystem.Object + //}; + //this.LocalConfiguration.AddImageFormatDetector(this.localMimeTypeDetector.Object); + //this.LocalConfiguration.SetDecoder(localImageFormatMock.Object, this.localDecoder.Object); + + //TestFormat.RegisterGloablTestFormat(); + //this.Marker = Guid.NewGuid().ToByteArray(); + //this.DataStream = TestFormat.GlobalTestFormat.CreateStream(this.Marker); + + //this.FilePath = Guid.NewGuid().ToString(); + //this.fileSystem.Setup(x => x.OpenRead(this.FilePath)).Returns(this.DataStream); + + //TestFileSystem.RegisterGloablTestFormat(); + //TestFileSystem.Global.AddFile(this.FilePath, this.DataStream); + } + + [Fact] + public void TestsThatVimImagesAreEqual() + { + var image1Provider = TestImageProvider.File(TestImages.Png.VimImage1); + var image2Provider = TestImageProvider.File(TestImages.Png.VimImage2); + + using (Image img1 = image1Provider.GetImage()) + using (Image img2 = image2Provider.GetImage()) + { + bool imagesEqual = AreImagesEqual(img1, img2); + Assert.True(imagesEqual); + } + } + + [Fact] + public void TestsThatVersioningImagesAreEqual() + { + var image1Provider = TestImageProvider.File(TestImages.Png.VersioningImage1); + var image2Provider = TestImageProvider.File(TestImages.Png.VersioningImage2); + + using (Image img1 = image1Provider.GetImage()) + using (Image img2 = image2Provider.GetImage()) + { + bool imagesEqual = AreImagesEqual(img1, img2); + //Assert.True(imagesEqual); + } + } + + private bool AreImagesEqual(Image img1, Image img2) + { + Assert.Equal(img1.Width, img2.Width); + Assert.Equal(img1.Height, img2.Height); + + for (int y = 0; y < img1.Height; y++) + { + for (int x = 0; x < img1.Width; x++) + { + Rgba32 pixel1 = img1[x, y]; + Rgba32 pixel2 = img2[x, y]; + + if (pixel1 != pixel2) + { + return false; + } + } + } + + return true; + } + } +} diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs index d821f4bc7..4573d0d9d 100644 --- a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -321,27 +321,13 @@ namespace ImageSharp.Tests } [Fact] - public void TestThatTwoImagesAreEqual() + public void LoadsImageWithoutThrowingCrcException() { - var image1Provider = TestImageProvider.File(TestImages.Png.VimImage1); - var image2Provider = TestImageProvider.File(TestImages.Png.VimImage2); + var image1Provider = TestImageProvider.File(TestImages.Png.VersioningImage1); - using (Image img1 = image1Provider.GetImage()) - using (Image img2 = image2Provider.GetImage()) + using (Image img = image1Provider.GetImage()) { - Assert.Equal(img1.Width, img2.Width); - Assert.Equal(img1.Height, img2.Height); - - for (int y = 0; y < img1.Height; y++) - { - for (int x = 0; x < img1.Width; x++) - { - Rgba32 pixel1 = img1[x, y]; - Rgba32 pixel2 = img2[x, y]; - - Assert.Equal(pixel1, pixel2); - } - } + Assert.Equal(166036, img.Pixels.Length); } } diff --git a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs index eecb98380..ad8a5cc7d 100644 --- a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index 3157c27d8..217bf37fe 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 7d552d109..46887d721 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -41,6 +41,9 @@ namespace ImageSharp.Tests public const string VimImage1 = "Png/vim16x16_1.png"; public const string VimImage2 = "Png/vim16x16_2.png"; + public const string VersioningImage1 = "Png/versioning-1_1.png"; + public const string VersioningImage2 = "Png/versioning-1_2.png"; + public static class Bad { // Odd chunk lengths @@ -53,7 +56,8 @@ namespace ImageSharp.Tests P1, Pd, Blur, Splash, Cross, Powerpoint, SplashInterlaced, Interlaced, Filter0, Filter1, Filter2, Filter3, Filter4, - FilterVar, VimImage1, VimImage2 + FilterVar, VimImage1, VimImage2, VersioningImage1, + VersioningImage2 }; } diff --git a/tests/ImageSharp.Tests/TestImages/Formats/Png/versioning-1_1.png b/tests/ImageSharp.Tests/TestImages/Formats/Png/versioning-1_1.png new file mode 100644 index 000000000..0eb37aab8 --- /dev/null +++ b/tests/ImageSharp.Tests/TestImages/Formats/Png/versioning-1_1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce623255656921d491b5c389cd46931fbd6024575b87522c55d67a496dd761f0 +size 22781 diff --git a/tests/ImageSharp.Tests/TestImages/Formats/Png/versioning-1_2.png b/tests/ImageSharp.Tests/TestImages/Formats/Png/versioning-1_2.png new file mode 100644 index 000000000..d402c7fd2 --- /dev/null +++ b/tests/ImageSharp.Tests/TestImages/Formats/Png/versioning-1_2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37bace8aaaa921b757af7d43ae0e91cbe0738942439753c401209215a1acd20d +size 8165 From 78b8c9d838b28840ffc33ae02d5a5abf086b538a Mon Sep 17 00:00:00 2001 From: Devedse Date: Sat, 12 Aug 2017 15:33:12 +0200 Subject: [PATCH 17/19] Removed commented out code --- .../ImageSharp.Tests/Image/ImageEqualTests.cs | 62 ------------------- 1 file changed, 62 deletions(-) diff --git a/tests/ImageSharp.Tests/Image/ImageEqualTests.cs b/tests/ImageSharp.Tests/Image/ImageEqualTests.cs index 5e156f543..422e61d6d 100644 --- a/tests/ImageSharp.Tests/Image/ImageEqualTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageEqualTests.cs @@ -5,72 +5,10 @@ namespace ImageSharp.Tests { - using System; - using System.IO; - - using ImageSharp.Formats; - using ImageSharp.IO; - using ImageSharp.Tests; - using Moq; using Xunit; public class ImageEqualTests { - //private readonly Mock fileSystem; - //private Image returnImage; - //private Mock localDecoder; - //private readonly string FilePath; - //private readonly Mock localMimeTypeDetector; - //private readonly Mock localImageFormatMock; - - //public Configuration LocalConfiguration { get; private set; } - //public byte[] Marker { get; private set; } - //public MemoryStream DataStream { get; private set; } - //public byte[] DecodedData { get; private set; } - - public ImageEqualTests() - { - //this.returnImage = new Image(1, 1); - - //this.localImageFormatMock = new Mock(); - - //this.localDecoder = new Mock(); - //this.localMimeTypeDetector = new Mock(); - //this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1); - //this.localMimeTypeDetector.Setup(x => x.DetectFormat(It.IsAny>())).Returns(localImageFormatMock.Object); - - //this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny())) - - // .Callback((c, s) => - // { - // using (var ms = new MemoryStream()) - // { - // s.CopyTo(ms); - // this.DecodedData = ms.ToArray(); - // } - // }) - // .Returns(this.returnImage); - - //this.fileSystem = new Mock(); - - //this.LocalConfiguration = new Configuration() - //{ - // FileSystem = this.fileSystem.Object - //}; - //this.LocalConfiguration.AddImageFormatDetector(this.localMimeTypeDetector.Object); - //this.LocalConfiguration.SetDecoder(localImageFormatMock.Object, this.localDecoder.Object); - - //TestFormat.RegisterGloablTestFormat(); - //this.Marker = Guid.NewGuid().ToByteArray(); - //this.DataStream = TestFormat.GlobalTestFormat.CreateStream(this.Marker); - - //this.FilePath = Guid.NewGuid().ToString(); - //this.fileSystem.Setup(x => x.OpenRead(this.FilePath)).Returns(this.DataStream); - - //TestFileSystem.RegisterGloablTestFormat(); - //TestFileSystem.Global.AddFile(this.FilePath, this.DataStream); - } - [Fact] public void TestsThatVimImagesAreEqual() { From acb7982a880ed53628107ec0aec32d92dcafdbf7 Mon Sep 17 00:00:00 2001 From: Devedse Date: Sat, 12 Aug 2017 17:10:35 +0200 Subject: [PATCH 18/19] Commented in the Assert.True() to make the test fail. --- tests/ImageSharp.Tests/Image/ImageEqualTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Image/ImageEqualTests.cs b/tests/ImageSharp.Tests/Image/ImageEqualTests.cs index 422e61d6d..399006012 100644 --- a/tests/ImageSharp.Tests/Image/ImageEqualTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageEqualTests.cs @@ -33,7 +33,7 @@ namespace ImageSharp.Tests using (Image img2 = image2Provider.GetImage()) { bool imagesEqual = AreImagesEqual(img1, img2); - //Assert.True(imagesEqual); + Assert.True(imagesEqual); } } From 8b9c0af3228dac0ff34d461ff280636a29fcb516 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 13 Aug 2017 19:01:06 +1000 Subject: [PATCH 19/19] Fix marker skipping bug when decoding certain images --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 102 +++++++++---------- tests/ImageSharp.Tests/FileTestBase.cs | 4 +- 2 files changed, 50 insertions(+), 56 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 372ecdc2b..d9df44a09 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -267,41 +267,35 @@ namespace ImageSharp.Formats /// The bytes to convert from. Cannot be null. /// The number of bytes per scanline /// The number of bits per value. - /// The resulting array. Is never null. + /// The resulting array. Is never null. /// is null. /// is less than or equals than zero. - private static byte[] ToArrayByBitsLength(byte[] source, int bytesPerScanline, int bits) + private static Span ToArrayByBitsLength(Span source, int bytesPerScanline, int bits) { Guard.NotNull(source, nameof(source)); Guard.MustBeGreaterThan(bits, 0, nameof(bits)); - byte[] result; - - if (bits < 8) + if (bits >= 8) { - result = new byte[bytesPerScanline * 8 / bits]; - int mask = 0xFF >> (8 - bits); - int resultOffset = 0; + return source; + } - // ReSharper disable once ForCanBeConvertedToForeach - // First byte is the marker so skip. - for (int i = 1; i < bytesPerScanline; i++) + byte[] result = new byte[bytesPerScanline * 8 / bits]; + int mask = 0xFF >> (8 - bits); + int resultOffset = 0; + + for (int i = 0; i < bytesPerScanline; i++) + { + byte b = source[i]; + for (int shift = 0; shift < 8; shift += bits) { - byte b = source[i]; - for (int shift = 0; shift < 8; shift += bits) - { - int colorIndex = (b >> (8 - bits - shift)) & mask; + int colorIndex = (b >> (8 - bits - shift)) & mask; - result[resultOffset] = (byte)colorIndex; + result[resultOffset] = (byte)colorIndex; - resultOffset++; - } + resultOffset++; } } - else - { - result = source; - } return result; } @@ -584,13 +578,15 @@ namespace ImageSharp.Formats { var color = default(TPixel); Span rowSpan = pixels.GetRowSpan(this.currentRow); + + // Trim the first marker byte from the buffer var scanlineBuffer = new Span(defilteredScanline, 1); switch (this.pngColorType) { case PngColorType.Grayscale: int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); - byte[] newScanline1 = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); + Span newScanline1 = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); for (int x = 0; x < this.header.Width; x++) { byte intensity = (byte)(newScanline1[x] * factor); @@ -604,10 +600,10 @@ namespace ImageSharp.Formats for (int x = 0; x < this.header.Width; x++) { - int offset = 1 + (x * this.bytesPerPixel); + int offset = x * this.bytesPerPixel; - byte intensity = defilteredScanline[offset]; - byte alpha = defilteredScanline[offset + this.bytesPerSample]; + byte intensity = scanlineBuffer[offset]; + byte alpha = scanlineBuffer[offset + this.bytesPerSample]; color.PackFromRgba32(new Rgba32(intensity, intensity, intensity, alpha)); rowSpan[x] = color; @@ -617,7 +613,7 @@ namespace ImageSharp.Formats case PngColorType.Palette: - this.ProcessScanlineFromPalette(defilteredScanline, rowSpan); + this.ProcessScanlineFromPalette(scanlineBuffer, rowSpan); break; @@ -682,10 +678,10 @@ namespace ImageSharp.Formats /// The type of pixel we are expanding to /// The scanline /// Thecurrent output image row - private void ProcessScanlineFromPalette(byte[] defilteredScanline, Span row) + private void ProcessScanlineFromPalette(Span defilteredScanline, Span row) where TPixel : struct, IPixel { - byte[] newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); + Span newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); byte[] pal = this.palette; var color = default(TPixel); @@ -737,15 +733,15 @@ namespace ImageSharp.Formats { var color = default(TPixel); + // Trim the first marker byte from the buffer + var scanlineBuffer = new Span(defilteredScanline, 1); + switch (this.pngColorType) { case PngColorType.Grayscale: int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); - byte[] newScanline1 = ToArrayByBitsLength( - defilteredScanline, - this.bytesPerScanline, - this.header.BitDepth); - for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o++) + Span newScanline1 = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); + for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) { byte intensity = (byte)(newScanline1[o] * factor); color.PackFromRgba32(new Rgba32(intensity, intensity, intensity)); @@ -756,10 +752,10 @@ namespace ImageSharp.Formats case PngColorType.GrayscaleWithAlpha: - for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel) + for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel) { - byte intensity = defilteredScanline[o]; - byte alpha = defilteredScanline[o + this.bytesPerSample]; + byte intensity = scanlineBuffer[o]; + byte alpha = scanlineBuffer[o + this.bytesPerSample]; color.PackFromRgba32(new Rgba32(intensity, intensity, intensity, alpha)); rowSpan[x] = color; } @@ -768,14 +764,14 @@ namespace ImageSharp.Formats case PngColorType.Palette: - byte[] newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); + Span newScanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); var rgba = default(Rgba32); if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) { // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha // channel and we should try to read it. - for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o++) + for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) { int index = newScanline[o]; int offset = index * 3; @@ -791,7 +787,7 @@ namespace ImageSharp.Formats { rgba.A = 255; - for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o++) + for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) { int index = newScanline[o]; int offset = index * 3; @@ -815,10 +811,8 @@ namespace ImageSharp.Formats using (var compressed = new Buffer(length)) { // TODO: Should we use pack from vector here instead? - this.From16BitTo8Bit(new Span(defilteredScanline, 1), compressed, length); - for (int x = pixelOffset, o = 0; - x < this.header.Width; - x += increment, o += 3) + this.From16BitTo8Bit(scanlineBuffer, compressed, length); + for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 3) { rgba.R = compressed[o]; rgba.G = compressed[o + 1]; @@ -831,11 +825,11 @@ namespace ImageSharp.Formats } else { - for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel) + for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel) { - rgba.R = defilteredScanline[o]; - rgba.G = defilteredScanline[o + this.bytesPerSample]; - rgba.B = defilteredScanline[o + (2 * this.bytesPerSample)]; + rgba.R = scanlineBuffer[o]; + rgba.G = scanlineBuffer[o + this.bytesPerSample]; + rgba.B = scanlineBuffer[o + (2 * this.bytesPerSample)]; color.PackFromRgba32(rgba); rowSpan[x] = color; @@ -852,7 +846,7 @@ namespace ImageSharp.Formats using (var compressed = new Buffer(length)) { // TODO: Should we use pack from vector here instead? - this.From16BitTo8Bit(new Span(defilteredScanline, 1), compressed, length); + this.From16BitTo8Bit(scanlineBuffer, compressed, length); for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 4) { rgba.R = compressed[o]; @@ -867,12 +861,12 @@ namespace ImageSharp.Formats } else { - for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel) + for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel) { - rgba.R = defilteredScanline[o]; - rgba.G = defilteredScanline[o + this.bytesPerSample]; - rgba.B = defilteredScanline[o + (2 * this.bytesPerSample)]; - rgba.A = defilteredScanline[o + (3 * this.bytesPerSample)]; + rgba.R = scanlineBuffer[o]; + rgba.G = scanlineBuffer[o + this.bytesPerSample]; + rgba.B = scanlineBuffer[o + (2 * this.bytesPerSample)]; + rgba.A = scanlineBuffer[o + (3 * this.bytesPerSample)]; color.PackFromRgba32(rgba); rowSpan[x] = color; diff --git a/tests/ImageSharp.Tests/FileTestBase.cs b/tests/ImageSharp.Tests/FileTestBase.cs index 51a1562f5..08ed69f3e 100644 --- a/tests/ImageSharp.Tests/FileTestBase.cs +++ b/tests/ImageSharp.Tests/FileTestBase.cs @@ -79,8 +79,8 @@ namespace ImageSharp.Tests // TestFile.Create(TestImages.Bmp.NegHeight), // Perf: Enable for local testing only TestFile.Create(TestImages.Png.Splash), // TestFile.Create(TestImages.Png.Cross), // 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.Bad.ChunkLength1), // Perf: Enable for local testing only + // TestFile.Create(TestImages.Png.Bad.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