diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index b702bfca9a..2941a43f54 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -8,7 +8,6 @@ namespace ImageSharp.Formats using System.Collections.Generic; using System.IO; using System.Linq; - using System.Numerics; using System.Text; /// @@ -336,7 +335,7 @@ namespace ImageSharp.Formats byte intensity = defilteredScanline[offset]; TColor color = default(TColor); - color.PackFromVector4(new Vector4(intensity, intensity, intensity, 255) / 255F); + color.PackFromBytes(intensity, intensity, intensity, 255); pixels[(row * this.header.Width) + x] = color; } @@ -352,7 +351,7 @@ namespace ImageSharp.Formats byte alpha = defilteredScanline[offset + this.bytesPerSample]; TColor color = default(TColor); - color.PackFromVector4(new Vector4(intensity, intensity, intensity, alpha) / 255F); + color.PackFromBytes(intensity, intensity, intensity, alpha); pixels[(row * this.header.Width) + x] = color; } @@ -379,7 +378,7 @@ namespace ImageSharp.Formats byte r = this.palette[pixelOffset]; byte g = this.palette[pixelOffset + 1]; byte b = this.palette[pixelOffset + 2]; - color.PackFromVector4(new Vector4(r, g, b, a) / 255F); + color.PackFromBytes(r, g, b, a); } pixels[offset] = color; @@ -398,7 +397,7 @@ namespace ImageSharp.Formats byte b = this.palette[pixelOffset + 2]; TColor color = default(TColor); - color.PackFromVector4(new Vector4(r, g, b, 255) / 255F); + color.PackFromBytes(r, g, b, 255); pixels[offset] = color; } } @@ -416,7 +415,7 @@ namespace ImageSharp.Formats byte b = defilteredScanline[offset + (2 * this.bytesPerSample)]; TColor color = default(TColor); - color.PackFromVector4(new Vector4(r, g, b, 255) / 255F); + color.PackFromBytes(r, g, b, 255); pixels[(row * this.header.Width) + x] = color; } @@ -434,7 +433,7 @@ namespace ImageSharp.Formats byte a = defilteredScanline[offset + (3 * this.bytesPerSample)]; TColor color = default(TColor); - color.PackFromVector4(new Vector4(r, g, b, a) / 255F); + color.PackFromBytes(r, g, b, a); pixels[(row * this.header.Width) + x] = color; } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 7f71906692..03f74d5a72 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -14,7 +14,7 @@ namespace ImageSharp.Formats /// /// Performs the png encoding operation. - /// TODO: Perf. There's lots of array parsing going on here. This should be unmanaged. + /// TODO: Perf. There's lots of array parsing and copying going on here. This should be unmanaged. /// internal sealed class PngEncoderCore { @@ -254,34 +254,31 @@ namespace ImageSharp.Formats // Copy the pixels across from the image. this.pixelData = new byte[this.width * this.height * this.bytesPerPixel]; int stride = this.width * this.bytesPerPixel; + byte[] bytes = new byte[4]; using (PixelAccessor pixels = image.Lock()) { - Parallel.For( - 0, - this.height, - Bootstrapper.Instance.ParallelOptions, - y => - { - for (int x = 0; x < this.width; x++) - { - // Convert the color to YCbCr and store the luminance - // Optionally store the original color alpha. - int dataOffset = (y * stride) + (x * this.bytesPerPixel); - Color source = new Color(pixels[x, y].ToVector4()); - YCbCr luminance = source; - for (int i = 0; i < this.bytesPerPixel; i++) - { - if (i == 0) - { - this.pixelData[dataOffset] = ((byte)luminance.Y).Clamp(0, 255); - } - else - { - this.pixelData[dataOffset + i] = source.A; - } - } - } - }); + for (int y = 0; y < this.height; y++) + { + for (int x = 0; x < this.width; x++) + { + // Convert the color to YCbCr and store the luminance + // Optionally store the original color alpha. + int dataOffset = (y * stride) + (x * this.bytesPerPixel); + pixels[x, y].ToBytes(bytes, 0, ComponentOrder.XYZW); + YCbCr luminance = new Color(bytes[0], bytes[1], bytes[2], bytes[3]); + for (int i = 0; i < this.bytesPerPixel; i++) + { + if (i == 0) + { + this.pixelData[dataOffset] = (byte)luminance.Y; + } + else + { + this.pixelData[dataOffset + i] = bytes[3]; + } + } + } + } } } @@ -296,10 +293,12 @@ namespace ImageSharp.Formats where TPacked : struct { // Copy the pixels across from the image. + // TODO: This could be sped up more if we add a method to PixelAccessor that does this by row directly to a byte array. this.pixelData = new byte[this.width * this.height * this.bytesPerPixel]; int stride = this.width * this.bytesPerPixel; using (PixelAccessor pixels = image.Lock()) { + int bpp = this.bytesPerPixel; Parallel.For( 0, this.height, @@ -309,15 +308,7 @@ namespace ImageSharp.Formats for (int x = 0; x < this.width; x++) { int dataOffset = (y * stride) + (x * this.bytesPerPixel); - Color source = new Color(pixels[x, y].ToVector4()); - - this.pixelData[dataOffset] = source.R; - this.pixelData[dataOffset + 1] = source.G; - this.pixelData[dataOffset + 2] = source.B; - if (this.bytesPerPixel == 4) - { - this.pixelData[dataOffset + 3] = source.A; - } + pixels[x, y].ToBytes(this.pixelData, dataOffset, bpp == 4 ? ComponentOrder.XYZW : ComponentOrder.XYZ); } }); } @@ -330,6 +321,7 @@ namespace ImageSharp.Formats /// The private byte[] EncodePixelData() { + // TODO: Use pointers List filteredScanlines = new List(); byte[] previousScanline = new byte[this.width * this.bytesPerPixel]; @@ -344,6 +336,7 @@ namespace ImageSharp.Formats previousScanline = rawScanline; } + // TODO: We should be able to use a byte array when not using interlaced encoding. List result = new List(); foreach (byte[] encodedScanline in filteredScanlines) @@ -516,6 +509,7 @@ namespace ImageSharp.Formats int colorTableLength = (int)Math.Pow(2, header.BitDepth) * 3; byte[] colorTable = new byte[colorTableLength]; + // TODO: Optimize this. Parallel.For( 0, pixelCount,