From 27025f200ff65fc4e7928beea369accb2f3c93ca Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 22 Jun 2021 09:24:57 +1000 Subject: [PATCH 1/6] Removed IManagedByteBuffer from BmpDecoder --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 140 +++++++++--------- .../Formats/Bmp/BmpEncoderTests.cs | 16 +- 2 files changed, 83 insertions(+), 73 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 03124781a8..8919befcb2 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -817,31 +817,29 @@ namespace SixLabors.ImageSharp.Formats.Bmp padding = 4 - padding; } - using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(arrayWidth + padding, AllocationOptions.Clean)) + using IMemoryOwner row = this.memoryAllocator.Allocate(arrayWidth + padding, AllocationOptions.Clean); + TPixel color = default; + Span rowSpan = row.GetSpan(); + + for (int y = 0; y < height; y++) { - TPixel color = default; - Span rowSpan = row.GetSpan(); + int newY = Invert(y, height, inverted); + this.stream.Read(rowSpan); + int offset = 0; + Span pixelRow = pixels.GetRowSpan(newY); - for (int y = 0; y < height; y++) + for (int x = 0; x < arrayWidth; x++) { - int newY = Invert(y, height, inverted); - this.stream.Read(row.Array, 0, row.Length()); - int offset = 0; - Span pixelRow = pixels.GetRowSpan(newY); - - for (int x = 0; x < arrayWidth; x++) + int colOffset = x * ppb; + for (int shift = 0, newX = colOffset; shift < ppb && newX < width; shift++, newX++) { - int colOffset = x * ppb; - for (int shift = 0, newX = colOffset; shift < ppb && newX < width; shift++, newX++) - { - int colorIndex = ((rowSpan[offset] >> (8 - bitsPerPixel - (shift * bitsPerPixel))) & mask) * bytesPerColorMapEntry; + int colorIndex = ((rowSpan[offset] >> (8 - bitsPerPixel - (shift * bitsPerPixel))) & mask) * bytesPerColorMapEntry; - color.FromBgr24(Unsafe.As(ref colors[colorIndex])); - pixelRow[newX] = color; - } - - offset++; + color.FromBgr24(Unsafe.As(ref colors[colorIndex])); + pixelRow[newX] = color; } + + offset++; } } } @@ -873,29 +871,29 @@ namespace SixLabors.ImageSharp.Formats.Bmp int greenMaskBits = CountBits((uint)greenMask); int blueMaskBits = CountBits((uint)blueMask); - using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride)) + using IMemoryOwner buffer = this.memoryAllocator.Allocate(stride); + Span bufferSpan = buffer.GetSpan(); + + for (int y = 0; y < height; y++) { - for (int y = 0; y < height; y++) - { - this.stream.Read(buffer.Array, 0, stride); - int newY = Invert(y, height, inverted); - Span pixelRow = pixels.GetRowSpan(newY); + this.stream.Read(bufferSpan); + int newY = Invert(y, height, inverted); + Span pixelRow = pixels.GetRowSpan(newY); - int offset = 0; - for (int x = 0; x < width; x++) - { - short temp = BitConverter.ToInt16(buffer.Array, offset); + int offset = 0; + for (int x = 0; x < width; x++) + { + short temp = BinaryPrimitives.ReadInt16LittleEndian(bufferSpan.Slice(offset)); - // Rescale values, so the values range from 0 to 255. - int r = (redMaskBits == 5) ? GetBytesFrom5BitValue((temp & redMask) >> rightShiftRedMask) : GetBytesFrom6BitValue((temp & redMask) >> rightShiftRedMask); - int g = (greenMaskBits == 5) ? GetBytesFrom5BitValue((temp & greenMask) >> rightShiftGreenMask) : GetBytesFrom6BitValue((temp & greenMask) >> rightShiftGreenMask); - int b = (blueMaskBits == 5) ? GetBytesFrom5BitValue((temp & blueMask) >> rightShiftBlueMask) : GetBytesFrom6BitValue((temp & blueMask) >> rightShiftBlueMask); - var rgb = new Rgb24((byte)r, (byte)g, (byte)b); + // Rescale values, so the values range from 0 to 255. + int r = (redMaskBits == 5) ? GetBytesFrom5BitValue((temp & redMask) >> rightShiftRedMask) : GetBytesFrom6BitValue((temp & redMask) >> rightShiftRedMask); + int g = (greenMaskBits == 5) ? GetBytesFrom5BitValue((temp & greenMask) >> rightShiftGreenMask) : GetBytesFrom6BitValue((temp & greenMask) >> rightShiftGreenMask); + int b = (blueMaskBits == 5) ? GetBytesFrom5BitValue((temp & blueMask) >> rightShiftBlueMask) : GetBytesFrom6BitValue((temp & blueMask) >> rightShiftBlueMask); + var rgb = new Rgb24((byte)r, (byte)g, (byte)b); - color.FromRgb24(rgb); - pixelRow[x] = color; - offset += 2; - } + color.FromRgb24(rgb); + pixelRow[x] = color; + offset += 2; } } } @@ -1104,44 +1102,44 @@ namespace SixLabors.ImageSharp.Formats.Bmp bool unusualBitMask = bitsRedMask > 8 || bitsGreenMask > 8 || bitsBlueMask > 8 || invMaxValueAlpha > 8; - using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride)) + using IMemoryOwner buffer = this.memoryAllocator.Allocate(stride); + Span bufferSpan = buffer.GetSpan(); + + for (int y = 0; y < height; y++) { - for (int y = 0; y < height; y++) + this.stream.Read(bufferSpan); + int newY = Invert(y, height, inverted); + Span pixelRow = pixels.GetRowSpan(newY); + + int offset = 0; + for (int x = 0; x < width; x++) { - this.stream.Read(buffer.Array, 0, stride); - int newY = Invert(y, height, inverted); - Span pixelRow = pixels.GetRowSpan(newY); + uint temp = BinaryPrimitives.ReadUInt32LittleEndian(bufferSpan.Slice(offset)); - int offset = 0; - for (int x = 0; x < width; x++) + if (unusualBitMask) { - uint temp = BitConverter.ToUInt32(buffer.Array, offset); - - if (unusualBitMask) - { - uint r = (uint)(temp & redMask) >> rightShiftRedMask; - uint g = (uint)(temp & greenMask) >> rightShiftGreenMask; - uint b = (uint)(temp & blueMask) >> rightShiftBlueMask; - float alpha = alphaMask != 0 ? invMaxValueAlpha * ((uint)(temp & alphaMask) >> rightShiftAlphaMask) : 1.0f; - var vector4 = new Vector4( - r * invMaxValueRed, - g * invMaxValueGreen, - b * invMaxValueBlue, - alpha); - color.FromVector4(vector4); - } - else - { - byte r = (byte)((temp & redMask) >> rightShiftRedMask); - byte g = (byte)((temp & greenMask) >> rightShiftGreenMask); - byte b = (byte)((temp & blueMask) >> rightShiftBlueMask); - byte a = alphaMask != 0 ? (byte)((temp & alphaMask) >> rightShiftAlphaMask) : (byte)255; - color.FromRgba32(new Rgba32(r, g, b, a)); - } - - pixelRow[x] = color; - offset += 4; + uint r = (uint)(temp & redMask) >> rightShiftRedMask; + uint g = (uint)(temp & greenMask) >> rightShiftGreenMask; + uint b = (uint)(temp & blueMask) >> rightShiftBlueMask; + float alpha = alphaMask != 0 ? invMaxValueAlpha * ((uint)(temp & alphaMask) >> rightShiftAlphaMask) : 1.0f; + var vector4 = new Vector4( + r * invMaxValueRed, + g * invMaxValueGreen, + b * invMaxValueBlue, + alpha); + color.FromVector4(vector4); } + else + { + byte r = (byte)((temp & redMask) >> rightShiftRedMask); + byte g = (byte)((temp & greenMask) >> rightShiftGreenMask); + byte b = (byte)((temp & blueMask) >> rightShiftBlueMask); + byte a = alphaMask != 0 ? (byte)((temp & alphaMask) >> rightShiftAlphaMask) : (byte)255; + color.FromRgba32(new Rgba32(r, g, b, a)); + } + + pixelRow[x] = color; + offset += 4; } } } diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs index 70079ee6e5..864299522e 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs @@ -184,7 +184,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp // The Magick Reference Decoder can not decode 4-Bit bitmaps, so only execute this on windows. if (TestEnvironment.IsWindows) { - TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: false); + // Oddly the difference only happens locally but we'll not test for that. + // I suspect the issue is with the reference codec. + ImageComparer comparer = TestEnvironment.IsFramework + ? ImageComparer.TolerantPercentage(0.0161F) + : ImageComparer.Exact; + + TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: false, customComparer: comparer); } } @@ -198,7 +204,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp // The Magick Reference Decoder can not decode 4-Bit bitmaps, so only execute this on windows. if (TestEnvironment.IsWindows) { - TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true); + // Oddly the difference only happens locally but we'll not test for that. + // I suspect the issue is with the reference codec. + ImageComparer comparer = TestEnvironment.IsFramework + ? ImageComparer.TolerantPercentage(0.0161F) + : ImageComparer.Exact; + + TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true, customComparer: comparer); } } From 9c96f023fcc59bcdb5e3ea64e9d8f04f8e3ba4f2 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 22 Jun 2021 11:23:19 +1000 Subject: [PATCH 2/6] Remove from Gif --- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 25 ++++++++++---------- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 8 ++++--- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index fb3d989d4b..e59dad6826 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -33,7 +34,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// The global color table. /// - private IManagedByteBuffer globalColorTable; + private IMemoryOwner globalColorTable; /// /// The area to restore. @@ -323,12 +324,12 @@ namespace SixLabors.ImageSharp.Formats.Gif continue; } - using (IManagedByteBuffer commentsBuffer = this.MemoryAllocator.AllocateManagedByteBuffer(length)) - { - this.stream.Read(commentsBuffer.Array, 0, length); - string commentPart = GifConstants.Encoding.GetString(commentsBuffer.Array, 0, length); - stringBuilder.Append(commentPart); - } + using IMemoryOwner commentsBuffer = this.MemoryAllocator.Allocate(length); + Span commentsSpan = commentsBuffer.GetSpan(); + + this.stream.Read(commentsSpan); + string commentPart = GifConstants.Encoding.GetString(commentsSpan); + stringBuilder.Append(commentPart); } if (stringBuilder.Length > 0) @@ -348,7 +349,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { this.ReadImageDescriptor(); - IManagedByteBuffer localColorTable = null; + IMemoryOwner localColorTable = null; Buffer2D indices = null; try { @@ -356,8 +357,8 @@ namespace SixLabors.ImageSharp.Formats.Gif if (this.imageDescriptor.LocalColorTableFlag) { int length = this.imageDescriptor.LocalColorTableSize * 3; - localColorTable = this.Configuration.MemoryAllocator.AllocateManagedByteBuffer(length, AllocationOptions.Clean); - this.stream.Read(localColorTable.Array, 0, length); + localColorTable = this.Configuration.MemoryAllocator.Allocate(length, AllocationOptions.Clean); + this.stream.Read(localColorTable.GetSpan()); } indices = this.Configuration.MemoryAllocator.Allocate2D(this.imageDescriptor.Width, this.imageDescriptor.Height, AllocationOptions.Clean); @@ -622,10 +623,10 @@ namespace SixLabors.ImageSharp.Formats.Gif int globalColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize * 3; this.gifMetadata.GlobalColorTableLength = globalColorTableLength; - this.globalColorTable = this.MemoryAllocator.AllocateManagedByteBuffer(globalColorTableLength, AllocationOptions.Clean); + this.globalColorTable = this.MemoryAllocator.Allocate(globalColorTableLength, AllocationOptions.Clean); // Read the global color table data from the stream - stream.Read(this.globalColorTable.Array, 0, globalColorTableLength); + stream.Read(this.globalColorTable.GetSpan()); } } } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 4c881ec3f2..05ea14e9ce 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -470,14 +470,16 @@ namespace SixLabors.ImageSharp.Formats.Gif // The maximum number of colors for the bit depth int colorTableLength = ColorNumerics.GetColorCountForBitDepth(this.bitDepth) * Unsafe.SizeOf(); - using IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength, AllocationOptions.Clean); + using IMemoryOwner colorTable = this.memoryAllocator.Allocate(colorTableLength, AllocationOptions.Clean); + Span colorTableSpan = colorTable.GetSpan(); + PixelOperations.Instance.ToRgb24Bytes( this.configuration, image.Palette.Span, - colorTable.GetSpan(), + colorTableSpan, image.Palette.Length); - stream.Write(colorTable.Array, 0, colorTableLength); + stream.Write(colorTableSpan); } /// From 3ca1a1847441c3f3bd8ea7c499c1bdaeb2841f7f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 22 Jun 2021 12:12:03 +1000 Subject: [PATCH 3/6] Update TgaDecoderCore.cs --- src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 21 ++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index f717c22304..8f97861400 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -114,9 +114,10 @@ namespace SixLabors.ImageSharp.Formats.Tga int colorMapPixelSizeInBytes = this.fileHeader.CMapDepth / 8; int colorMapSizeInBytes = this.fileHeader.CMapLength * colorMapPixelSizeInBytes; - using (IManagedByteBuffer palette = this.memoryAllocator.AllocateManagedByteBuffer(colorMapSizeInBytes, AllocationOptions.Clean)) + using (IMemoryOwner palette = this.memoryAllocator.Allocate(colorMapSizeInBytes, AllocationOptions.Clean)) { - this.currentStream.Read(palette.Array, this.fileHeader.CMapStart, colorMapSizeInBytes); + Span paletteSpan = palette.GetSpan(); + this.currentStream.Read(paletteSpan, this.fileHeader.CMapStart, colorMapSizeInBytes); if (this.fileHeader.ImageType == TgaImageType.RleColorMapped) { @@ -124,7 +125,7 @@ namespace SixLabors.ImageSharp.Formats.Tga this.fileHeader.Width, this.fileHeader.Height, pixels, - palette.Array, + paletteSpan, colorMapPixelSizeInBytes, origin); } @@ -134,7 +135,7 @@ namespace SixLabors.ImageSharp.Formats.Tga this.fileHeader.Width, this.fileHeader.Height, pixels, - palette.Array, + paletteSpan, colorMapPixelSizeInBytes, origin); } @@ -224,7 +225,7 @@ namespace SixLabors.ImageSharp.Formats.Tga /// The color palette. /// Color map size of one entry in bytes. /// The image origin. - private void ReadPaletted(int width, int height, Buffer2D pixels, byte[] palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin) + private void ReadPaletted(int width, int height, Buffer2D pixels, Span palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { TPixel color = default; @@ -304,7 +305,7 @@ namespace SixLabors.ImageSharp.Formats.Tga /// The color palette. /// Color map size of one entry in bytes. /// The image origin. - private void ReadPalettedRle(int width, int height, Buffer2D pixels, byte[] palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin) + private void ReadPalettedRle(int width, int height, Buffer2D pixels, Span palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { int bytesPerPixel = 1; @@ -704,7 +705,7 @@ namespace SixLabors.ImageSharp.Formats.Tga } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ReadPalettedBgra16Pixel(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) + private void ReadPalettedBgra16Pixel(Span palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) where TPixel : unmanaged, IPixel { int colorIndex = this.currentStream.ReadByte(); @@ -713,7 +714,7 @@ namespace SixLabors.ImageSharp.Formats.Tga } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ReadPalettedBgra16Pixel(byte[] palette, int index, int colorMapPixelSizeInBytes, ref TPixel color) + private void ReadPalettedBgra16Pixel(Span palette, int index, int colorMapPixelSizeInBytes, ref TPixel color) where TPixel : unmanaged, IPixel { Bgra5551 bgra = default; @@ -729,7 +730,7 @@ namespace SixLabors.ImageSharp.Formats.Tga } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ReadPalettedBgr24Pixel(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) + private void ReadPalettedBgr24Pixel(Span palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) where TPixel : unmanaged, IPixel { int colorIndex = this.currentStream.ReadByte(); @@ -738,7 +739,7 @@ namespace SixLabors.ImageSharp.Formats.Tga } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ReadPalettedBgra32Pixel(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) + private void ReadPalettedBgra32Pixel(Span palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) where TPixel : unmanaged, IPixel { int colorIndex = this.currentStream.ReadByte(); From 7e6b3f289267ceb6ba48c33b3d711c973cb5cadf Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 22 Jun 2021 15:17:32 +1000 Subject: [PATCH 4/6] Tiff --- .../Compressors/PackBitsCompressor.cs | 5 ++-- .../RgbPlanarTiffColor{TPixel}.cs | 3 +- .../Formats/Tiff/TiffDecoderCore.cs | 29 +++++++++++++------ .../TiffCompositeColorWriter{TPixel}.cs | 4 +-- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Compression/Compressors/PackBitsCompressor.cs b/src/ImageSharp/Formats/Tiff/Compression/Compressors/PackBitsCompressor.cs index 5a23831878..d06aeb1042 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Compressors/PackBitsCompressor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Compressors/PackBitsCompressor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.IO; using SixLabors.ImageSharp.Formats.Tiff.Constants; using SixLabors.ImageSharp.Memory; @@ -10,7 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors { internal sealed class PackBitsCompressor : TiffBaseCompressor { - private IManagedByteBuffer pixelData; + private IMemoryOwner pixelData; public PackBitsCompressor(Stream output, MemoryAllocator allocator, int width, int bitsPerPixel) : base(output, allocator, width, bitsPerPixel) @@ -24,7 +25,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors public override void Initialize(int rowsPerStrip) { int additionalBytes = ((this.BytesPerRow + 126) / 127) + 1; - this.pixelData = this.Allocator.AllocateManagedByteBuffer(this.BytesPerRow + additionalBytes); + this.pixelData = this.Allocator.Allocate(this.BytesPerRow + additionalBytes); } /// diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs index 8dda0cf38f..3400bd65d8 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. +using System.Buffers; using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; @@ -46,7 +47,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation /// The y-coordinate of the top of the image block. /// The width of the image block. /// The height of the image block. - public void Decode(IManagedByteBuffer[] data, Buffer2D pixels, int left, int top, int width, int height) + public void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { var color = default(TPixel); diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 5ce696118d..3d5bfc7374 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. +using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -247,14 +248,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff Buffer2D pixels = frame.PixelBuffer; - var stripBuffers = new IManagedByteBuffer[stripsPerPixel]; + var stripBuffers = new IMemoryOwner[stripsPerPixel]; try { for (int stripIndex = 0; stripIndex < stripBuffers.Length; stripIndex++) { int uncompressedStripSize = this.CalculateStripBufferSize(frame.Width, rowsPerStrip, stripIndex); - stripBuffers[stripIndex] = this.memoryAllocator.AllocateManagedByteBuffer(uncompressedStripSize); + stripBuffers[stripIndex] = this.memoryAllocator.Allocate(uncompressedStripSize); } using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, frame.Width, bitsPerPixel, this.Predictor, this.FaxCompressionOptions); @@ -277,7 +278,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff } finally { - foreach (IManagedByteBuffer buf in stripBuffers) + foreach (IMemoryOwner buf in stripBuffers) { buf?.Dispose(); } @@ -296,17 +297,27 @@ namespace SixLabors.ImageSharp.Formats.Tiff int uncompressedStripSize = this.CalculateStripBufferSize(frame.Width, rowsPerStrip); int bitsPerPixel = this.BitsPerPixel; - using IManagedByteBuffer stripBuffer = this.memoryAllocator.AllocateManagedByteBuffer(uncompressedStripSize, AllocationOptions.Clean); - + using IMemoryOwner stripBuffer = this.memoryAllocator.Allocate(uncompressedStripSize, AllocationOptions.Clean); + System.Span stripBufferSpan = stripBuffer.GetSpan(); Buffer2D pixels = frame.PixelBuffer; - using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, frame.Width, bitsPerPixel, this.Predictor, this.FaxCompressionOptions); + using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create( + this.CompressionType, + this.memoryAllocator, + this.PhotometricInterpretation, + frame.Width, + bitsPerPixel, + this.Predictor, + this.FaxCompressionOptions); TiffBaseColorDecoder colorDecoder = TiffColorDecoderFactory.Create(this.ColorType, this.BitsPerSample, this.ColorMap); for (int stripIndex = 0; stripIndex < stripOffsets.Length; stripIndex++) { - int stripHeight = stripIndex < stripOffsets.Length - 1 || frame.Height % rowsPerStrip == 0 ? rowsPerStrip : frame.Height % rowsPerStrip; + int stripHeight = stripIndex < stripOffsets.Length - 1 || frame.Height % rowsPerStrip == 0 + ? rowsPerStrip + : frame.Height % rowsPerStrip; + int top = rowsPerStrip * stripIndex; if (top + stripHeight > frame.Height) { @@ -314,9 +325,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff break; } - decompressor.Decompress(this.inputStream, (uint)stripOffsets[stripIndex], (uint)stripByteCounts[stripIndex], stripBuffer.GetSpan()); + decompressor.Decompress(this.inputStream, (uint)stripOffsets[stripIndex], (uint)stripByteCounts[stripIndex], stripBufferSpan); - colorDecoder.Decode(stripBuffer.GetSpan(), pixels, 0, top, frame.Width, stripHeight); + colorDecoder.Decode(stripBufferSpan, pixels, 0, top, frame.Width, stripHeight); } } diff --git a/src/ImageSharp/Formats/Tiff/Writers/TiffCompositeColorWriter{TPixel}.cs b/src/ImageSharp/Formats/Tiff/Writers/TiffCompositeColorWriter{TPixel}.cs index 43cb666b6a..88c5f33ddd 100644 --- a/src/ImageSharp/Formats/Tiff/Writers/TiffCompositeColorWriter{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/Writers/TiffCompositeColorWriter{TPixel}.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers internal abstract class TiffCompositeColorWriter : TiffBaseColorWriter where TPixel : unmanaged, IPixel { - private IManagedByteBuffer rowBuffer; + private IMemoryOwner rowBuffer; protected TiffCompositeColorWriter(ImageFrame image, MemoryAllocator memoryAllocator, Configuration configuration, TiffEncoderEntriesCollector entriesCollector) : base(image, memoryAllocator, configuration, entriesCollector) @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers { if (this.rowBuffer == null) { - this.rowBuffer = this.MemoryAllocator.AllocateManagedByteBuffer(this.BytesPerRow * height); + this.rowBuffer = this.MemoryAllocator.Allocate(this.BytesPerRow * height); } this.rowBuffer.Clear(); From 9a42c871a12994a6f94f5ff82150edb8bb3a595c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 22 Jun 2021 15:17:39 +1000 Subject: [PATCH 5/6] Update Image.Decode.cs --- src/ImageSharp/Image.Decode.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index da23fb47dd..9d5ceeacfb 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.IO; using System.Linq; using System.Threading; @@ -57,8 +58,9 @@ namespace SixLabors.ImageSharp return null; } - using (IManagedByteBuffer buffer = config.MemoryAllocator.AllocateManagedByteBuffer(headerSize, AllocationOptions.Clean)) + using (IMemoryOwner buffer = config.MemoryAllocator.Allocate(headerSize, AllocationOptions.Clean)) { + Span bufferSpan = buffer.GetSpan(); long startPosition = stream.Position; // Read doesn't always guarantee the full returned length so read a byte @@ -67,7 +69,7 @@ namespace SixLabors.ImageSharp int i; do { - i = stream.Read(buffer.Array, n, headerSize - n); + i = stream.Read(bufferSpan, n, headerSize - n); n += i; } while (n < headerSize && i > 0); From 52fbad6aeafc0c265c92e7a329574bd89bf01405 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 22 Jun 2021 19:39:46 +1000 Subject: [PATCH 6/6] Update ChunkedMemoryStream.cs --- src/ImageSharp/IO/ChunkedMemoryStream.cs | 35 ++++++++++++------------ 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/ImageSharp/IO/ChunkedMemoryStream.cs b/src/ImageSharp/IO/ChunkedMemoryStream.cs index c5fc6b9395..b9220c56ab 100644 --- a/src/ImageSharp/IO/ChunkedMemoryStream.cs +++ b/src/ImageSharp/IO/ChunkedMemoryStream.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.IO; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; @@ -239,8 +240,8 @@ namespace SixLabors.ImageSharp.IO Guard.MustBeGreaterThanOrEqualTo(offset, 0, nameof(offset)); Guard.MustBeGreaterThanOrEqualTo(count, 0, nameof(count)); - const string BufferMessage = "Offset subtracted from the buffer length is less than count."; - Guard.IsFalse(buffer.Length - offset < count, nameof(buffer), BufferMessage); + const string bufferMessage = "Offset subtracted from the buffer length is less than count."; + Guard.IsFalse(buffer.Length - offset < count, nameof(buffer), bufferMessage); return this.ReadImpl(buffer.AsSpan().Slice(offset, count)); } @@ -266,7 +267,7 @@ namespace SixLabors.ImageSharp.IO this.readOffset = 0; } - Span chunkBuffer = this.readChunk.Buffer.GetSpan(); + IMemoryOwner chunkBuffer = this.readChunk.Buffer; int chunkSize = this.readChunk.Length; if (this.readChunk.Next is null) { @@ -288,7 +289,7 @@ namespace SixLabors.ImageSharp.IO this.readChunk = this.readChunk.Next; this.readOffset = 0; - chunkBuffer = this.readChunk.Buffer.GetSpan(); + chunkBuffer = this.readChunk.Buffer; chunkSize = this.readChunk.Length; if (this.readChunk.Next is null) { @@ -324,7 +325,7 @@ namespace SixLabors.ImageSharp.IO this.readOffset = 0; } - byte[] chunkBuffer = this.readChunk.Buffer.Array; + IMemoryOwner chunkBuffer = this.readChunk.Buffer; int chunkSize = this.readChunk.Length; if (this.readChunk.Next is null) { @@ -341,10 +342,10 @@ namespace SixLabors.ImageSharp.IO this.readChunk = this.readChunk.Next; this.readOffset = 0; - chunkBuffer = this.readChunk.Buffer.Array; + chunkBuffer = this.readChunk.Buffer; } - return chunkBuffer[this.readOffset++]; + return chunkBuffer.GetSpan()[this.readOffset++]; } /// @@ -355,8 +356,8 @@ namespace SixLabors.ImageSharp.IO Guard.MustBeGreaterThanOrEqualTo(offset, 0, nameof(offset)); Guard.MustBeGreaterThanOrEqualTo(count, 0, nameof(count)); - const string BufferMessage = "Offset subtracted from the buffer length is less than count."; - Guard.IsFalse(buffer.Length - offset < count, nameof(buffer), BufferMessage); + const string bufferMessage = "Offset subtracted from the buffer length is less than count."; + Guard.IsFalse(buffer.Length - offset < count, nameof(buffer), bufferMessage); this.WriteImpl(buffer.AsSpan().Slice(offset, count)); } @@ -415,7 +416,7 @@ namespace SixLabors.ImageSharp.IO this.writeOffset = 0; } - byte[] chunkBuffer = this.writeChunk.Buffer.Array; + IMemoryOwner chunkBuffer = this.writeChunk.Buffer; int chunkSize = this.writeChunk.Length; if (this.writeOffset == chunkSize) @@ -424,10 +425,10 @@ namespace SixLabors.ImageSharp.IO this.writeChunk.Next = this.AllocateMemoryChunk(); this.writeChunk = this.writeChunk.Next; this.writeOffset = 0; - chunkBuffer = this.writeChunk.Buffer.Array; + chunkBuffer = this.writeChunk.Buffer; } - chunkBuffer[this.writeOffset++] = value; + chunkBuffer.GetSpan()[this.writeOffset++] = value; } /// @@ -473,7 +474,7 @@ namespace SixLabors.ImageSharp.IO this.readOffset = 0; } - byte[] chunkBuffer = this.readChunk.Buffer.Array; + IMemoryOwner chunkBuffer = this.readChunk.Buffer; int chunkSize = this.readChunk.Length; if (this.readChunk.Next is null) { @@ -495,7 +496,7 @@ namespace SixLabors.ImageSharp.IO this.readChunk = this.readChunk.Next; this.readOffset = 0; - chunkBuffer = this.readChunk.Buffer.Array; + chunkBuffer = this.readChunk.Buffer; chunkSize = this.readChunk.Length; if (this.readChunk.Next is null) { @@ -504,7 +505,7 @@ namespace SixLabors.ImageSharp.IO } int writeCount = chunkSize - this.readOffset; - stream.Write(chunkBuffer, this.readOffset, writeCount); + stream.Write(chunkBuffer.GetSpan(), this.readOffset, writeCount); this.readOffset = chunkSize; } } @@ -529,7 +530,7 @@ namespace SixLabors.ImageSharp.IO [MethodImpl(MethodImplOptions.AggressiveInlining)] private MemoryChunk AllocateMemoryChunk() { - IManagedByteBuffer buffer = this.allocator.AllocateManagedByteBuffer(this.chunkLength); + IMemoryOwner buffer = this.allocator.Allocate(this.chunkLength); return new MemoryChunk { Buffer = buffer, @@ -551,7 +552,7 @@ namespace SixLabors.ImageSharp.IO { private bool isDisposed; - public IManagedByteBuffer Buffer { get; set; } + public IMemoryOwner Buffer { get; set; } public MemoryChunk Next { get; set; }