From 70893d22ad1f7f3ac6762efd43d34e2c221c5d8d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 22 Feb 2018 21:34:50 +0100 Subject: [PATCH] replaced some of the PixelArea usages in bmp decoder --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 25 +++++++++++++---- src/ImageSharp/Formats/Bmp/BmpEncoder.cs | 3 ++- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 27 +++++++++++++++---- src/ImageSharp/Memory/BufferExtensions.cs | 12 +++++++++ .../Memory/MemoryManagerExtensions.cs | 18 +++++++++++++ .../Formats/Bmp/BmpEncoderTests.cs | 2 -- 6 files changed, 74 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 201c041a24..0c77fc482f 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -69,7 +69,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// private BmpInfoHeader infoHeader; - private Configuration configuration; + private readonly Configuration configuration; + + private readonly MemoryManager memoryManager; /// /// Initializes a new instance of the class. @@ -79,6 +81,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp public BmpDecoderCore(Configuration configuration, IBmpDecoderOptions options) { this.configuration = configuration; + this.memoryManager = configuration.MemoryManager; } /// @@ -432,16 +435,28 @@ namespace SixLabors.ImageSharp.Formats.Bmp where TPixel : struct, IPixel { int padding = CalculatePadding(width, 3); - using (var row = new PixelArea(width, ComponentOrder.Zyx, padding)) + + using (IManagedByteBuffer row = this.memoryManager.AllocatePaddedPixelRowBuffer(width, 3, padding)) { for (int y = 0; y < height; y++) { - row.Read(this.currentStream); - + this.currentStream.Read(row); int newY = Invert(y, height, inverted); - pixels.CopyFrom(row, newY); + Span pixelSpan = pixels.GetRowSpan(newY); + PixelOperations.Instance.PackFromBgr24Bytes(row.Span, pixelSpan, width); } } + + //using (var row = new PixelArea(width, ComponentOrder.Zyx, padding)) + //{ + // for (int y = 0; y < height; y++) + // { + // row.Read(this.currentStream); + + // int newY = Invert(y, height, inverted); + // pixels.CopyFrom(row, newY); + // } + //} } /// diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs index 366afceb5f..d80e43c63b 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Bmp @@ -23,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { - var encoder = new BmpEncoderCore(this); + var encoder = new BmpEncoderCore(this, image.GetMemoryManager()); encoder.Encode(image, stream); } } diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index d34d170847..26d16cea32 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -8,6 +8,8 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Bmp { + using SixLabors.ImageSharp.Memory; + /// /// Image encoder for writing an image to a stream as a Windows bitmap. /// @@ -21,14 +23,18 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Gets or sets the number of bits per pixel. /// - private BmpBitsPerPixel bitsPerPixel; + private readonly BmpBitsPerPixel bitsPerPixel; + + private readonly MemoryManager memoryManager; /// /// Initializes a new instance of the class. /// /// The encoder options - public BmpEncoderCore(IBmpEncoderOptions options) + /// The memory manager + public BmpEncoderCore(IBmpEncoderOptions options, MemoryManager memoryManager) { + this.memoryManager = memoryManager; this.bitsPerPixel = options.BitsPerPixel; } @@ -173,14 +179,25 @@ namespace SixLabors.ImageSharp.Formats.Bmp private void Write24Bit(EndianBinaryWriter writer, PixelAccessor pixels) where TPixel : struct, IPixel { - using (PixelArea row = new PixelArea(pixels.Width, ComponentOrder.Zyx, this.padding)) + using (IManagedByteBuffer row = + this.memoryManager.AllocatePaddedPixelRowBuffer(pixels.Width, 3, this.padding)) { for (int y = pixels.Height - 1; y >= 0; y--) { - pixels.CopyTo(row, y); - writer.Write(row.Bytes, 0, row.Length); + Span pixelSpan = pixels.GetRowSpan(y); + PixelOperations.Instance.ToBgr24Bytes(pixelSpan, row.Span, pixelSpan.Length); + writer.Write(row.Array, 0, row.Length()); } } + + //using (PixelArea row = new PixelArea(pixels.Width, ComponentOrder.Zyx, this.padding)) + //{ + // for (int y = pixels.Height - 1; y >= 0; y--) + // { + // pixels.CopyTo(row, y); + // writer.Write(row.Bytes, 0, row.Length); + // } + //} } } } diff --git a/src/ImageSharp/Memory/BufferExtensions.cs b/src/ImageSharp/Memory/BufferExtensions.cs index b863dfc9aa..882b8875fc 100644 --- a/src/ImageSharp/Memory/BufferExtensions.cs +++ b/src/ImageSharp/Memory/BufferExtensions.cs @@ -6,6 +6,8 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Memory { + using System.IO; + internal static class BufferExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -53,5 +55,15 @@ namespace SixLabors.ImageSharp.Memory public static ref T DangerousGetPinnableReference(this IBuffer buffer) where T : struct => ref buffer.Span.DangerousGetPinnableReference(); + + public static void Read(this Stream stream, IManagedByteBuffer buffer) + { + stream.Read(buffer.Array, 0, buffer.Length()); + } + + public static void Write(this Stream stream, IManagedByteBuffer buffer) + { + stream.Write(buffer.Array, 0, buffer.Length()); + } } } \ No newline at end of file diff --git a/src/ImageSharp/Memory/MemoryManagerExtensions.cs b/src/ImageSharp/Memory/MemoryManagerExtensions.cs index b7fcaf4b36..3511d20390 100644 --- a/src/ImageSharp/Memory/MemoryManagerExtensions.cs +++ b/src/ImageSharp/Memory/MemoryManagerExtensions.cs @@ -51,5 +51,23 @@ public static Buffer2D AllocateClean2D(this MemoryManager memoryManager, int width, int height) where T : struct => Allocate2D(memoryManager, width, height, true); + + /// + /// Allocates padded buffers for BMP encoder/decoder. (Replacing old PixelRow/PixelArea) + /// + /// The + /// Pixel count in the row + /// The pixel size in bytes, eg. 3 for RGB + /// The padding + /// A + public static IManagedByteBuffer AllocatePaddedPixelRowBuffer( + this MemoryManager memoryManager, + int width, + int pixelSizeInBytes, + int paddingInBytes) + { + int length = (width * pixelSizeInBytes) + paddingInBytes; + return memoryManager.AllocateManagedByteBuffer(length); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs index 362df2be68..a4ed0c0fd2 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs @@ -15,8 +15,6 @@ namespace SixLabors.ImageSharp.Tests public class BmpEncoderTests : FileTestBase { - private const PixelTypes PixelTypesToTest = PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.Rgb24; - public static readonly TheoryData BitsPerPixel = new TheoryData {