diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index fd8972fbbc..dc76c27b82 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -503,7 +503,7 @@ namespace ImageSharp.Formats
throw new ImageFormatException("Unknown filter type.");
}
- this.ProcessDefilteredScanline(scanline, y, pixels, Adam7FirstColumn[pass], Adam7ColumnIncrement[pass]);
+ this.ProcessInterlacedDefilteredScanline(scanline, y, pixels, Adam7FirstColumn[pass], Adam7ColumnIncrement[pass]);
Swap(ref scanline, ref previousScanline);
}
@@ -526,20 +526,17 @@ namespace ImageSharp.Formats
/// The de-filtered scanline
/// The current image row.
/// The image pixels
- /// The column start index. Always 0 for none interlaced images.
- /// The column increment. Always 1 for none interlaced images.
- private void ProcessDefilteredScanline(byte[] defilteredScanline, int row, PixelAccessor pixels, int startIndex = 0, int increment = 1)
+ private void ProcessDefilteredScanline(byte[] defilteredScanline, int row, PixelAccessor pixels)
where TColor : struct, IPackedPixel
where TPacked : struct
{
TColor color = default(TColor);
-
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 = startIndex; x < this.header.Width; x += increment)
+ for (int x = 0; x < this.header.Width; x++)
{
byte intensity = (byte)(newScanline1[x] * factor);
color.PackFromBytes(intensity, intensity, intensity, 255);
@@ -550,7 +547,7 @@ namespace ImageSharp.Formats
case PngColorType.GrayscaleWithAlpha:
- for (int x = startIndex; x < this.header.Width; x += increment)
+ for (int x = 0; x < this.header.Width; x++)
{
int offset = 1 + (x * this.bytesPerPixel);
@@ -571,7 +568,7 @@ namespace ImageSharp.Formats
{
// 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 = startIndex; x < this.header.Width; x += increment)
+ for (int x = 0; x < this.header.Width; x++)
{
int index = newScanline[x];
int pixelOffset = index * 3;
@@ -595,7 +592,7 @@ namespace ImageSharp.Formats
}
else
{
- for (int x = startIndex; x < this.header.Width; x += increment)
+ for (int x = 0; x < this.header.Width; x++)
{
int index = newScanline[x];
int pixelOffset = index * 3;
@@ -613,7 +610,7 @@ namespace ImageSharp.Formats
case PngColorType.Rgb:
- for (int x = startIndex; x < this.header.Width; x += increment)
+ for (int x = 0; x < this.header.Width; x++)
{
int offset = 1 + (x * this.bytesPerPixel);
@@ -629,7 +626,7 @@ namespace ImageSharp.Formats
case PngColorType.RgbWithAlpha:
- for (int x = startIndex; x < this.header.Width; x += increment)
+ for (int x = 0; x < this.header.Width; x++)
{
int offset = 1 + (x * this.bytesPerPixel);
@@ -646,6 +643,129 @@ namespace ImageSharp.Formats
}
}
+ ///
+ /// Processes the interlaced de-filtered scanline filling the image pixel data
+ ///
+ /// The pixel format.
+ /// The packed format. uint, long, float.
+ /// The de-filtered scanline
+ /// The current image row.
+ /// The image pixels
+ /// The column start index. Always 0 for none interlaced images.
+ /// The column increment. Always 1 for none interlaced images.
+ private void ProcessInterlacedDefilteredScanline(byte[] defilteredScanline, int row, PixelAccessor pixels, int pixelOffset = 0, int increment = 1)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ TColor color = default(TColor);
+
+ 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; x < this.header.Width; x += increment)
+ {
+ byte intensity = (byte)(newScanline1[x - pixelOffset] * factor);
+ color.PackFromBytes(intensity, intensity, intensity, 255);
+ pixels[x, row] = color;
+ }
+
+ break;
+
+ case PngColorType.GrayscaleWithAlpha:
+
+ for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel)
+ {
+ byte intensity = defilteredScanline[o];
+ byte alpha = defilteredScanline[o + this.bytesPerSample];
+
+ color.PackFromBytes(intensity, intensity, intensity, alpha);
+ pixels[x, row] = color;
+ }
+
+ break;
+
+ case PngColorType.Palette:
+
+ byte[] newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth);
+
+ 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; x < this.header.Width; x += increment)
+ {
+ int index = newScanline[x - pixelOffset];
+ int offset = index * 3;
+
+ byte a = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255;
+
+ if (a > 0)
+ {
+ byte r = this.palette[offset];
+ byte g = this.palette[offset + 1];
+ byte b = this.palette[offset + 2];
+ color.PackFromBytes(r, g, b, a);
+ }
+ else
+ {
+ color.PackFromBytes(0, 0, 0, 0);
+ }
+
+ pixels[x, row] = color;
+ }
+ }
+ else
+ {
+ for (int x = pixelOffset; x < this.header.Width; x += increment)
+ {
+ int index = newScanline[x - pixelOffset];
+ int offset = index * 3;
+
+ byte r = this.palette[offset];
+ byte g = this.palette[offset + 1];
+ byte b = this.palette[offset + 2];
+
+ color.PackFromBytes(r, g, b, 255);
+ pixels[x, row] = color;
+ }
+ }
+
+ break;
+
+ case PngColorType.Rgb:
+
+ for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel)
+ {
+ byte r = defilteredScanline[o];
+ byte g = defilteredScanline[o + this.bytesPerSample];
+ byte b = defilteredScanline[o + (2 * this.bytesPerSample)];
+
+ color.PackFromBytes(r, g, b, 255);
+ pixels[x, row] = color;
+ }
+
+ break;
+
+ case PngColorType.RgbWithAlpha:
+
+ for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel)
+ {
+ byte r = defilteredScanline[o];
+ byte g = defilteredScanline[o + this.bytesPerSample];
+ byte b = defilteredScanline[o + (2 * this.bytesPerSample)];
+ byte a = defilteredScanline[o + (3 * this.bytesPerSample)];
+
+ color.PackFromBytes(r, g, b, a);
+ pixels[x, row] = color;
+ }
+
+ break;
+ }
+ }
+
+
///
/// Reads a text chunk containing image properties from the data.
///
@@ -838,6 +958,11 @@ namespace ImageSharp.Formats
chunk.Length = BitConverter.ToInt32(this.chunkLengthBuffer, 0);
}
+ ///
+ /// Returns the correct number of columns for each interlaced pass.
+ ///
+ /// Th current pass index
+ /// The
private int ComputeColumnsAdam7(int pass)
{
int width = this.header.Width;
diff --git a/tests/ImageSharp.Tests/FileTestBase.cs b/tests/ImageSharp.Tests/FileTestBase.cs
index c2d0916bc2..e8034ebfd1 100644
--- a/tests/ImageSharp.Tests/FileTestBase.cs
+++ b/tests/ImageSharp.Tests/FileTestBase.cs
@@ -31,7 +31,7 @@ namespace ImageSharp.Tests
// new TestFile(TestImages.Bmp.Neg_height), // Perf: Enable for local testing only
// new TestFile(TestImages.Png.Blur), // Perf: Enable for local testing only
// new TestFile(TestImages.Png.Indexed), // Perf: Enable for local testing only
- new TestFile(TestImages.Png.Splash),
+ //new TestFile(TestImages.Png.Splash),
new TestFile(TestImages.Png.SplashInterlace),
// new TestFile(TestImages.Png.Filter0), // Perf: Enable for local testing only
// new TestFile(TestImages.Png.Filter1), // Perf: Enable for local testing only
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index 23632e2332..a8117df685 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -18,9 +18,9 @@ namespace ImageSharp.Tests
public static string Pd => folder + "pd.png";
public static string Blur => folder + "blur.png";
public static string Indexed => folder + "indexed.png";
- public static string Splash => folder + "splash-interlaced.png";
+ public static string Splash => folder + "splash.png";
- public static string SplashInterlace => folder + "splash.png";
+ public static string SplashInterlace => folder + "splash-interlaced.png";
// filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html
public static string Filter0 => folder + "filter0.png";
public static string Filter1 => folder + "filter1.png";
diff --git a/tests/ImageSharp.Tests/TestImages/Formats/Png/interlaced.png b/tests/ImageSharp.Tests/TestImages/Formats/Png/interlaced.png
new file mode 100644
index 0000000000..d4b75523dd
--- /dev/null
+++ b/tests/ImageSharp.Tests/TestImages/Formats/Png/interlaced.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7e1c92b1a57b762f736e14d480eb016b551ce0dc67aa588b246d838d00c0fc3f
+size 17372