Browse Source

Merge remote-tracking branch 'origin/master' into bp/bmptests

# Conflicts:
#	tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs
pull/1678/head
Brian Popow 5 years ago
parent
commit
0099bb0018
  1. 140
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  2. 25
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  3. 8
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  4. 21
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
  5. 5
      src/ImageSharp/Formats/Tiff/Compression/Compressors/PackBitsCompressor.cs
  6. 3
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs
  7. 29
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  8. 4
      src/ImageSharp/Formats/Tiff/Writers/TiffCompositeColorWriter{TPixel}.cs
  9. 35
      src/ImageSharp/IO/ChunkedMemoryStream.cs
  10. 6
      src/ImageSharp/Image.Decode.cs
  11. 22
      tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs

140
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<byte> row = this.memoryAllocator.Allocate<byte>(arrayWidth + padding, AllocationOptions.Clean);
TPixel color = default;
Span<byte> rowSpan = row.GetSpan();
for (int y = 0; y < height; y++)
{
TPixel color = default;
Span<byte> rowSpan = row.GetSpan();
int newY = Invert(y, height, inverted);
this.stream.Read(rowSpan);
int offset = 0;
Span<TPixel> 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<TPixel> 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<byte, Bgr24>(ref colors[colorIndex]));
pixelRow[newX] = color;
}
offset++;
color.FromBgr24(Unsafe.As<byte, Bgr24>(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<byte> buffer = this.memoryAllocator.Allocate<byte>(stride);
Span<byte> 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<TPixel> pixelRow = pixels.GetRowSpan(newY);
this.stream.Read(bufferSpan);
int newY = Invert(y, height, inverted);
Span<TPixel> 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<byte> buffer = this.memoryAllocator.Allocate<byte>(stride);
Span<byte> 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<TPixel> 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<TPixel> 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;
}
}
}

25
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
/// <summary>
/// The global color table.
/// </summary>
private IManagedByteBuffer globalColorTable;
private IMemoryOwner<byte> globalColorTable;
/// <summary>
/// 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<byte> commentsBuffer = this.MemoryAllocator.Allocate<byte>(length);
Span<byte> 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<byte> localColorTable = null;
Buffer2D<byte> 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<byte>(length, AllocationOptions.Clean);
this.stream.Read(localColorTable.GetSpan());
}
indices = this.Configuration.MemoryAllocator.Allocate2D<byte>(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<byte>(globalColorTableLength, AllocationOptions.Clean);
// Read the global color table data from the stream
stream.Read(this.globalColorTable.Array, 0, globalColorTableLength);
stream.Read(this.globalColorTable.GetSpan());
}
}
}

8
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<Rgb24>();
using IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength, AllocationOptions.Clean);
using IMemoryOwner<byte> colorTable = this.memoryAllocator.Allocate<byte>(colorTableLength, AllocationOptions.Clean);
Span<byte> colorTableSpan = colorTable.GetSpan();
PixelOperations<TPixel>.Instance.ToRgb24Bytes(
this.configuration,
image.Palette.Span,
colorTable.GetSpan(),
colorTableSpan,
image.Palette.Length);
stream.Write(colorTable.Array, 0, colorTableLength);
stream.Write(colorTableSpan);
}
/// <summary>

21
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<byte> palette = this.memoryAllocator.Allocate<byte>(colorMapSizeInBytes, AllocationOptions.Clean))
{
this.currentStream.Read(palette.Array, this.fileHeader.CMapStart, colorMapSizeInBytes);
Span<byte> 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
/// <param name="palette">The color palette.</param>
/// <param name="colorMapPixelSizeInBytes">Color map size of one entry in bytes.</param>
/// <param name="origin">The image origin.</param>
private void ReadPaletted<TPixel>(int width, int height, Buffer2D<TPixel> pixels, byte[] palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
private void ReadPaletted<TPixel>(int width, int height, Buffer2D<TPixel> pixels, Span<byte> palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel>
{
TPixel color = default;
@ -304,7 +305,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <param name="palette">The color palette.</param>
/// <param name="colorMapPixelSizeInBytes">Color map size of one entry in bytes.</param>
/// <param name="origin">The image origin.</param>
private void ReadPalettedRle<TPixel>(int width, int height, Buffer2D<TPixel> pixels, byte[] palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
private void ReadPalettedRle<TPixel>(int width, int height, Buffer2D<TPixel> pixels, Span<byte> palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel>
{
int bytesPerPixel = 1;
@ -704,7 +705,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadPalettedBgra16Pixel<TPixel>(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
private void ReadPalettedBgra16Pixel<TPixel>(Span<byte> palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
where TPixel : unmanaged, IPixel<TPixel>
{
int colorIndex = this.currentStream.ReadByte();
@ -713,7 +714,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadPalettedBgra16Pixel<TPixel>(byte[] palette, int index, int colorMapPixelSizeInBytes, ref TPixel color)
private void ReadPalettedBgra16Pixel<TPixel>(Span<byte> palette, int index, int colorMapPixelSizeInBytes, ref TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
Bgra5551 bgra = default;
@ -729,7 +730,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadPalettedBgr24Pixel<TPixel>(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
private void ReadPalettedBgr24Pixel<TPixel>(Span<byte> palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
where TPixel : unmanaged, IPixel<TPixel>
{
int colorIndex = this.currentStream.ReadByte();
@ -738,7 +739,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadPalettedBgra32Pixel<TPixel>(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
private void ReadPalettedBgra32Pixel<TPixel>(Span<byte> palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
where TPixel : unmanaged, IPixel<TPixel>
{
int colorIndex = this.currentStream.ReadByte();

5
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<byte> 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<byte>(this.BytesPerRow + additionalBytes);
}
/// <inheritdoc/>

3
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
/// <param name="top">The y-coordinate of the top of the image block.</param>
/// <param name="width">The width of the image block.</param>
/// <param name="height">The height of the image block.</param>
public void Decode(IManagedByteBuffer[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
public void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);

29
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<TPixel> pixels = frame.PixelBuffer;
var stripBuffers = new IManagedByteBuffer[stripsPerPixel];
var stripBuffers = new IMemoryOwner<byte>[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<byte>(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<byte> 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<byte> stripBuffer = this.memoryAllocator.Allocate<byte>(uncompressedStripSize, AllocationOptions.Clean);
System.Span<byte> stripBufferSpan = stripBuffer.GetSpan();
Buffer2D<TPixel> 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<TPixel> colorDecoder = TiffColorDecoderFactory<TPixel>.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);
}
}

4
src/ImageSharp/Formats/Tiff/Writers/TiffCompositeColorWriter{TPixel}.cs

@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
internal abstract class TiffCompositeColorWriter<TPixel> : TiffBaseColorWriter<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private IManagedByteBuffer rowBuffer;
private IMemoryOwner<byte> rowBuffer;
protected TiffCompositeColorWriter(ImageFrame<TPixel> 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<byte>(this.BytesPerRow * height);
}
this.rowBuffer.Clear();

35
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<byte> chunkBuffer = this.readChunk.Buffer.GetSpan();
IMemoryOwner<byte> 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<byte> 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++];
}
/// <inheritdoc/>
@ -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<byte> 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;
}
/// <summary>
@ -473,7 +474,7 @@ namespace SixLabors.ImageSharp.IO
this.readOffset = 0;
}
byte[] chunkBuffer = this.readChunk.Buffer.Array;
IMemoryOwner<byte> 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<byte> buffer = this.allocator.Allocate<byte>(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<byte> Buffer { get; set; }
public MemoryChunk Next { get; set; }

6
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<byte> buffer = config.MemoryAllocator.Allocate<byte>(headerSize, AllocationOptions.Clean))
{
Span<byte> 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);

22
tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs

@ -179,14 +179,32 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp
public void Encode_4Bit_WithV3Header_Works<TPixel>(
TestImageProvider<TPixel> provider,
BmpBitsPerPixel bitsPerPixel)
where TPixel : unmanaged, IPixel<TPixel> => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: false);
where TPixel : unmanaged, IPixel<TPixel>
{
// 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);
}
[Theory]
[WithFile(Bit4, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel4)]
public void Encode_4Bit_WithV4Header_Works<TPixel>(
TestImageProvider<TPixel> provider,
BmpBitsPerPixel bitsPerPixel)
where TPixel : unmanaged, IPixel<TPixel> => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true);
where TPixel : unmanaged, IPixel<TPixel>
{
// 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);
}
[Theory]
[WithFile(Bit1, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel1)]

Loading…
Cancel
Save