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"
diff --git a/README.md b/README.md
index e46b11379..7113d6ba1 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-#
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).
-[](https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/APACHE-2.0-LICENSE.txt)
-[](https://github.com/JimBobSquarePants/ImageSharp/issues)
-[](https://github.com/JimBobSquarePants/ImageSharp/stargazers)
-[](https://github.com/JimBobSquarePants/ImageSharp/network)
+[](https://raw.githubusercontent.com/SixLabors/ImageSharp/master/APACHE-2.0-LICENSE.txt)
+[](https://github.com/SixLabors/ImageSharp/issues)
+[](https://github.com/SixLabors/ImageSharp/stargazers)
+[](https://github.com/SixLabors/ImageSharp/network)
[](https://gitter.im/ImageSharp/General?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-[](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)
+[](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)
[](#backers)
[](#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**|[](https://travis-ci.org/JimBobSquarePants/ImageSharp)|[](https://codecov.io/gh/JimBobSquarePants/ImageSharp)|
-|**Windows** |[](https://ci.appveyor.com/project/JamesSouth/imagesharp/branch/master)|[](https://codecov.io/gh/JimBobSquarePants/ImageSharp)|
+|**Linux/Mac**|[](https://travis-ci.org/SixLabors/ImageSharp)|[](https://codecov.io/gh/SixLabors/ImageSharp)|
+|**Windows** |[](https://ci.appveyor.com/project/six-labors/imagesharp/branch/master)|[](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.
diff --git a/appveyor.yml b/appveyor.yml
index 079913311..fdbe46b01 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
diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs
index a34544ab0..ef1e1705c 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.
@@ -186,7 +186,7 @@ namespace ImageSharp
///
public void ClearImageFormatDetectors()
{
- this.imageFormatDetectors.Clear();
+ this.imageFormatDetectors = new ConcurrentBag();
}
///
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/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
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..d9df44a09 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -267,45 +267,48 @@ 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;
}
+ 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.
///
@@ -575,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);
@@ -595,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;
@@ -608,7 +613,7 @@ namespace ImageSharp.Formats
case PngColorType.Palette:
- this.ProcessScanlineFromPalette(defilteredScanline, rowSpan);
+ this.ProcessScanlineFromPalette(scanlineBuffer, rowSpan);
break;
@@ -673,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);
@@ -688,19 +693,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 +709,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);
@@ -736,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));
@@ -755,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;
}
@@ -767,31 +764,20 @@ 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;
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;
@@ -801,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;
@@ -825,14 +811,12 @@ 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(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 + 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;
@@ -841,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;
@@ -862,13 +846,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(scanlineBuffer, 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;
@@ -877,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;
@@ -1025,9 +1009,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/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/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs
index 45d04626e..1959bb9cb 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs
@@ -80,7 +80,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/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
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
index 6d82b5374..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;
@@ -18,7 +19,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]
@@ -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
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs
index 43ca2a1b6..e065385ac 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]
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..399006012
--- /dev/null
+++ b/tests/ImageSharp.Tests/Image/ImageEqualTests.cs
@@ -0,0 +1,62 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Tests
+{
+ using Xunit;
+
+ public class ImageEqualTests
+ {
+ [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 bb64ceda3..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.
//
@@ -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,17 @@ namespace ImageSharp.Tests
Assert.Equal(Rgba32.White, px[1, 0]);
Assert.Equal(Rgba32.Black, px[1, 1]);
+ }
+ }
+
+ [Fact]
+ public void LoadsImageWithoutThrowingCrcException()
+ {
+ var image1Provider = TestImageProvider.File(TestImages.Png.VersioningImage1);
+ using (Image img = image1Provider.GetImage())
+ {
+ Assert.Equal(166036, img.Pixels.Length);
}
}
diff --git a/tests/ImageSharp.Tests/Image/ImageRotationTests.cs b/tests/ImageSharp.Tests/Image/ImageRotationTests.cs
new file mode 100644
index 000000000..56cec4219
--- /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 original = image.Bounds.Size;
+ image.Rotate(angle);
+ return (original, image.Bounds.Size);
+ }
+ }
+ }
+}
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 f35720f19..46887d721 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";
@@ -37,6 +38,12 @@ 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 const string VersioningImage1 = "Png/versioning-1_1.png";
+ public const string VersioningImage2 = "Png/versioning-1_2.png";
+
public static class Bad
{
// Odd chunk lengths
@@ -49,7 +56,8 @@ namespace ImageSharp.Tests
P1, Pd, Blur, Splash, Cross,
Powerpoint, SplashInterlaced, Interlaced,
Filter0, Filter1, Filter2, Filter3, Filter4,
- FilterVar
+ FilterVar, VimImage1, VimImage2, VersioningImage1,
+ VersioningImage2
};
}
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
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
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