diff --git a/src/UglyToad.PdfPig/Images/Png/Crc32.cs b/src/UglyToad.PdfPig/Images/Png/Crc32.cs index e75e2e7c..04055beb 100644 --- a/src/UglyToad.PdfPig/Images/Png/Crc32.cs +++ b/src/UglyToad.PdfPig/Images/Png/Crc32.cs @@ -1,12 +1,11 @@ namespace UglyToad.PdfPig.Images.Png { using System; - using System.Collections.Generic; /// /// 32-bit Cyclic Redundancy Code used by the PNG for checking the data is intact. /// - internal static class Crc32 + internal class Crc32 { private const uint Polynomial = 0xEDB88320; @@ -49,21 +48,6 @@ return crc32 ^ uint.MaxValue; } - /// - /// Calculate the CRC32 for data. - /// - public static uint Calculate(List data) - { - var crc32 = uint.MaxValue; - for (var i = 0; i < data.Count; i++) - { - var index = (crc32 ^ data[i]) & 0xFF; - crc32 = (crc32 >> 8) ^ Lookup[index]; - } - - return crc32 ^ uint.MaxValue; - } - /// /// Calculate the combined CRC32 for data. /// @@ -84,5 +68,30 @@ return crc32 ^ uint.MaxValue; } + + + private uint state = uint.MaxValue; + + /// + /// Calculate the CRC32 for data. + /// + public void Append(ReadOnlySpan data) + { + for (var i = 0; i < data.Length; i++) + { + var index = (state ^ data[i]) & 0xFF; + state = (state >> 8) ^ Lookup[index]; + } + } + + public uint GetCurrentHashAsUInt32() + { + return state ^ uint.MaxValue; + } + + public void Reset() + { + state = uint.MaxValue; + } } } diff --git a/src/UglyToad.PdfPig/Images/Png/PngStreamWriteHelper.cs b/src/UglyToad.PdfPig/Images/Png/PngStreamWriteHelper.cs index f09c52a1..68cb9479 100644 --- a/src/UglyToad.PdfPig/Images/Png/PngStreamWriteHelper.cs +++ b/src/UglyToad.PdfPig/Images/Png/PngStreamWriteHelper.cs @@ -1,14 +1,13 @@ namespace UglyToad.PdfPig.Images.Png { using System; - using System.Collections.Generic; + using System.Buffers.Binary; using System.IO; - using System.Linq; - internal class PngStreamWriteHelper : Stream + internal sealed class PngStreamWriteHelper : Stream { private readonly Stream inner; - private readonly List written = new List(); + private readonly Crc32 crc = new(); public override bool CanRead => inner.CanRead; @@ -33,7 +32,7 @@ public void WriteChunkHeader(ReadOnlySpan header) { - written.Clear(); + crc.Reset(); Write(header); } @@ -50,28 +49,33 @@ public override void Write(byte[] buffer, int offset, int count) { - written.AddRange(buffer.Skip(offset).Take(count)); + crc.Append(buffer.AsSpan(offset, count)); inner.Write(buffer, offset, count); } #if NET8_0_OR_GREATER public override void Write(ReadOnlySpan buffer) { - written.AddRange(buffer); + crc.Append(buffer); inner.Write(buffer); } #else public void Write(ReadOnlySpan buffer) { - written.AddRange(buffer.ToArray()); + crc.Append(buffer); inner.Write(buffer); } #endif public void WriteCrc() { - var result = (int)Crc32.Calculate(written); - StreamHelper.WriteBigEndianInt32(inner, result); + Span buffer = stackalloc byte[4]; + + var result = crc.GetCurrentHashAsUInt32(); + + BinaryPrimitives.WriteUInt32BigEndian(buffer, result); + + inner.Write(buffer); } } } \ No newline at end of file