Browse Source

Use BinaryPrimitives instead of BitConverter and scratch buffer to avoid allocations

pull/1570/head
Brian Popow 5 years ago
parent
commit
b58825345b
  1. 17
      src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
  2. 40
      src/ImageSharp/Formats/Tiff/Writers/TiffStreamWriter.cs
  3. 5
      tests/ImageSharp.Tests/Formats/Tiff/Utils/TiffWriterTests.cs

17
src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs

@ -36,6 +36,11 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
/// </summary>
private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// A scratch buffer to reduce allocations.
/// </summary>
private readonly byte[] buffer = new byte[4];
/// <summary>
/// The global configuration.
/// </summary>
@ -238,15 +243,17 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
writer.Write(ExifWriter.GetNumberOfComponents(entry));
uint length = ExifWriter.GetLength(entry);
var raw = new byte[length];
int sz = ExifWriter.WriteValue(entry, raw, 0);
DebugGuard.IsTrue(sz == raw.Length, "Incorrect number of bytes written");
if (raw.Length <= 4)
if (length <= 4)
{
writer.WritePadded(raw);
int sz = ExifWriter.WriteValue(entry, this.buffer, 0);
DebugGuard.IsTrue(sz == length, "Incorrect number of bytes written");
writer.WritePadded(this.buffer.AsSpan(0, sz));
}
else
{
var raw = new byte[length];
int sz = ExifWriter.WriteValue(entry, raw, 0);
DebugGuard.IsTrue(sz == raw.Length, "Incorrect number of bytes written");
largeDataBlocks.Add(raw);
writer.Write(dataOffset);
dataOffset += (uint)(raw.Length + (raw.Length % 2));

40
src/ImageSharp/Formats/Tiff/Writers/TiffStreamWriter.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers.Binary;
using System.IO;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Writers
@ -13,6 +14,11 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Writers
{
private static readonly byte[] PaddingBytes = new byte[4];
/// <summary>
/// A scratch buffer to reduce allocations.
/// </summary>
private readonly byte[] buffer = new byte[4];
/// <summary>
/// Initializes a new instance of the <see cref="TiffStreamWriter"/> class.
/// </summary>
@ -37,7 +43,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Writers
/// <summary>
/// Writes an empty four bytes to the stream, returning the offset to be written later.
/// </summary>
/// <returns>The offset to be written later</returns>
/// <returns>The offset to be written later.</returns>
public long PlaceMarker()
{
long offset = this.BaseStream.Position;
@ -69,8 +75,16 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Writers
/// <param name="value">The two-byte unsigned integer to write.</param>
public void Write(ushort value)
{
byte[] bytes = BitConverter.GetBytes(value);
this.BaseStream.Write(bytes, 0, 2);
if (this.IsLittleEndian)
{
BinaryPrimitives.WriteUInt16LittleEndian(this.buffer, value);
}
else
{
BinaryPrimitives.WriteUInt16BigEndian(this.buffer, value);
}
this.BaseStream.Write(this.buffer.AsSpan(0, 2));
}
/// <summary>
@ -79,21 +93,29 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Writers
/// <param name="value">The four-byte unsigned integer to write.</param>
public void Write(uint value)
{
byte[] bytes = BitConverter.GetBytes(value);
this.BaseStream.Write(bytes, 0, 4);
if (this.IsLittleEndian)
{
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, value);
}
else
{
BinaryPrimitives.WriteUInt32BigEndian(this.buffer, value);
}
this.BaseStream.Write(this.buffer.AsSpan(0, 4));
}
/// <summary>
/// Writes an array of bytes to the current stream, padded to four-bytes.
/// </summary>
/// <param name="value">The bytes to write.</param>
public void WritePadded(byte[] value)
public void WritePadded(Span<byte> value)
{
this.BaseStream.Write(value, 0, value.Length);
this.BaseStream.Write(value);
if (value.Length < 4)
if (value.Length % 4 != 0)
{
this.BaseStream.Write(PaddingBytes, 0, 4 - value.Length);
this.BaseStream.Write(PaddingBytes, 0, 4 - (value.Length % 4));
}
}

5
tests/ImageSharp.Tests/Formats/Tiff/Utils/TiffWriterTests.cs

@ -76,12 +76,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Utils
}
[Theory]
[InlineData(new byte[] { }, new byte[] { 0, 0, 0, 0 })]
[InlineData(new byte[] { }, new byte[] { })]
[InlineData(new byte[] { 2 }, new byte[] { 2, 0, 0, 0 })]
[InlineData(new byte[] { 2, 4 }, new byte[] { 2, 4, 0, 0 })]
[InlineData(new byte[] { 2, 4, 6 }, new byte[] { 2, 4, 6, 0 })]
[InlineData(new byte[] { 2, 4, 6, 8 }, new byte[] { 2, 4, 6, 8 })]
[InlineData(new byte[] { 2, 4, 6, 8, 10, 12 }, new byte[] { 2, 4, 6, 8, 10, 12 })]
[InlineData(new byte[] { 2, 4, 6, 8, 10, 12 }, new byte[] { 2, 4, 6, 8, 10, 12, 0, 0 })]
public void WritePadded_WritesByteArray(byte[] bytes, byte[] expectedResult)
{
using var stream = new MemoryStream();

Loading…
Cancel
Save