diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 3c6e05a8b..54ac9dfd8 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -103,36 +103,42 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.ReadImageHeaders(stream, out bool inverted, out byte[] palette); var image = new Image(this.configuration, this.infoHeader.Width, this.infoHeader.Height); - using (PixelAccessor pixels = image.Lock()) + + Buffer2D pixels = image.Frames.RootFrame.PixelBuffer; + + switch (this.infoHeader.Compression) { - switch (this.infoHeader.Compression) - { - case BmpCompression.RGB: - if (this.infoHeader.BitsPerPixel == 32) - { - this.ReadRgb32(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); - } - else if (this.infoHeader.BitsPerPixel == 24) - { - this.ReadRgb24(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); - } - else if (this.infoHeader.BitsPerPixel == 16) - { - this.ReadRgb16(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); - } - else if (this.infoHeader.BitsPerPixel <= 8) - { - this.ReadRgbPalette(pixels, palette, this.infoHeader.Width, this.infoHeader.Height, this.infoHeader.BitsPerPixel, inverted); - } + case BmpCompression.RGB: + if (this.infoHeader.BitsPerPixel == 32) + { + this.ReadRgb32(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); + } + else if (this.infoHeader.BitsPerPixel == 24) + { + this.ReadRgb24(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); + } + else if (this.infoHeader.BitsPerPixel == 16) + { + this.ReadRgb16(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); + } + else if (this.infoHeader.BitsPerPixel <= 8) + { + this.ReadRgbPalette( + pixels, + palette, + this.infoHeader.Width, + this.infoHeader.Height, + this.infoHeader.BitsPerPixel, + inverted); + } - break; - case BmpCompression.RLE8: - this.ReadRle8(pixels, palette, this.infoHeader.Width, this.infoHeader.Height, inverted); + break; + case BmpCompression.RLE8: + this.ReadRle8(pixels, palette, this.infoHeader.Width, this.infoHeader.Height, inverted); - break; - default: - throw new NotSupportedException("Does not support this kind of bitmap files."); - } + break; + default: + throw new NotSupportedException("Does not support this kind of bitmap files."); } return image; @@ -207,7 +213,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// The width of the bitmap. /// The height of the bitmap. /// Whether the bitmap is inverted. - private void ReadRle8(PixelAccessor pixels, byte[] colors, int width, int height, bool inverted) + private void ReadRle8(Buffer2D pixels, byte[] colors, int width, int height, bool inverted) where TPixel : struct, IPixel { var color = default(TPixel); @@ -319,7 +325,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// The height of the bitmap. /// The number of bits per pixel. /// Whether the bitmap is inverted. - private void ReadRgbPalette(PixelAccessor pixels, byte[] colors, int width, int height, int bits, bool inverted) + private void ReadRgbPalette(Buffer2D pixels, byte[] colors, int width, int height, int bits, bool inverted) where TPixel : struct, IPixel { // Pixels per byte (bits per pixel) @@ -381,7 +387,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// The width of the bitmap. /// The height of the bitmap. /// Whether the bitmap is inverted. - private void ReadRgb16(PixelAccessor pixels, int width, int height, bool inverted) + private void ReadRgb16(Buffer2D pixels, int width, int height, bool inverted) where TPixel : struct, IPixel { int padding = CalculatePadding(width, 2); @@ -422,7 +428,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// The width of the bitmap. /// The height of the bitmap. /// Whether the bitmap is inverted. - private void ReadRgb24(PixelAccessor pixels, int width, int height, bool inverted) + private void ReadRgb24(Buffer2D pixels, int width, int height, bool inverted) where TPixel : struct, IPixel { int padding = CalculatePadding(width, 3); @@ -447,7 +453,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// The width of the bitmap. /// The height of the bitmap. /// Whether the bitmap is inverted. - private void ReadRgb32(PixelAccessor pixels, int width, int height, bool inverted) + private void ReadRgb32(Buffer2D pixels, int width, int height, bool inverted) where TPixel : struct, IPixel { int padding = CalculatePadding(width, 4); @@ -574,6 +580,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.stream.Read(palette, 0, colorMapSize); } + // TODO: ReSharper tells this expression is always true, looks like he's pretty right about it: if (this.infoHeader.Width > int.MaxValue || this.infoHeader.Height > int.MaxValue) { throw new ArgumentOutOfRangeException( diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index d8bf90c7c..80ca2b225 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -92,18 +92,16 @@ namespace SixLabors.ImageSharp.Formats.Bmp private void WriteImage(Stream stream, ImageFrame image) where TPixel : struct, IPixel { - using (PixelAccessor pixels = image.Lock()) + Buffer2D pixels = image.PixelBuffer; + switch (this.bitsPerPixel) { - switch (this.bitsPerPixel) - { - case BmpBitsPerPixel.Pixel32: - this.Write32Bit(stream, pixels); - break; + case BmpBitsPerPixel.Pixel32: + this.Write32Bit(stream, pixels); + break; - case BmpBitsPerPixel.Pixel24: - this.Write24Bit(stream, pixels); - break; - } + case BmpBitsPerPixel.Pixel24: + this.Write24Bit(stream, pixels); + break; } } @@ -118,7 +116,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// The pixel format. /// The to write to. /// The containing pixel data. - private void Write32Bit(Stream stream, PixelAccessor pixels) + private void Write32Bit(Stream stream, Buffer2D pixels) where TPixel : struct, IPixel { using (IManagedByteBuffer row = this.AllocateRow(pixels.Width, 4)) @@ -138,7 +136,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// The pixel format. /// The to write to. /// The containing pixel data. - private void Write24Bit(Stream stream, PixelAccessor pixels) + private void Write24Bit(Stream stream, Buffer2D pixels) where TPixel : struct, IPixel { using (IManagedByteBuffer row = this.AllocateRow(pixels.Width, 3)) diff --git a/src/ImageSharp/Processing/Convolution/Processors/EdgeDetectorCompassProcessor.cs b/src/ImageSharp/Processing/Convolution/Processors/EdgeDetectorCompassProcessor.cs index bcedd7a3c..b78145089 100644 --- a/src/ImageSharp/Processing/Convolution/Processors/EdgeDetectorCompassProcessor.cs +++ b/src/ImageSharp/Processing/Convolution/Processors/EdgeDetectorCompassProcessor.cs @@ -3,11 +3,14 @@ using System; using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Threading.Tasks; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Processing.Filters.Processors; using SixLabors.ImageSharp.Processing.Processors; +using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Convolution.Processors @@ -128,27 +131,35 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors { new ConvolutionProcessor(kernels[i]).Apply(pass, sourceRectangle, configuration); - using (PixelAccessor passPixels = pass.Lock()) - using (PixelAccessor targetPixels = source.Lock()) - { - Parallel.For( - minY, - maxY, - configuration.ParallelOptions, - y => + Buffer2D passPixels = pass.PixelBuffer; + Buffer2D targetPixels = source.PixelBuffer; + + Parallel.For( + minY, + maxY, + configuration.ParallelOptions, + y => { int offsetY = y - shiftY; + + ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(passPixels.GetRowSpan(offsetY)); + ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(targetPixels.GetRowSpan(offsetY)); + for (int x = minX; x < maxX; x++) { int offsetX = x - shiftX; // Grab the max components of the two pixels - TPixel packed = default(TPixel); - packed.PackFromVector4(Vector4.Max(passPixels[offsetX, offsetY].ToVector4(), targetPixels[offsetX, offsetY].ToVector4())); - targetPixels[offsetX, offsetY] = packed; + ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, offsetX); + ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, offsetX); + + var pixelValue = Vector4.Max( + currentPassPixel.ToVector4(), + currentTargetPixel.ToVector4()); + + currentTargetPixel.PackFromVector4(pixelValue); } }); - } } } }