From b46dac6bcedf650328f6c7d0680702278410947c Mon Sep 17 00:00:00 2001 From: Raffael Herrmann Date: Sat, 22 Jun 2024 23:50:01 +0200 Subject: [PATCH 1/7] Added benchmarks and test cases for BitmapByteQRCode --- QRCoderBenchmarks/BitmapByteQRCode.cs | 51 +++++++++++++++++++ QRCoderTests/BitmapByteQRCodeRendererTests.cs | 50 ++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 QRCoderBenchmarks/BitmapByteQRCode.cs create mode 100644 QRCoderTests/BitmapByteQRCodeRendererTests.cs diff --git a/QRCoderBenchmarks/BitmapByteQRCode.cs b/QRCoderBenchmarks/BitmapByteQRCode.cs new file mode 100644 index 00000000..4ccfdc0c --- /dev/null +++ b/QRCoderBenchmarks/BitmapByteQRCode.cs @@ -0,0 +1,51 @@ +using System.Collections.ObjectModel; +using BenchmarkDotNet.Attributes; +using QRCoder; + +namespace QRCoderBenchmarks; + +[MemoryDiagnoser] +public class BitmapByteQRCodeBenchmark +{ + private readonly Dictionary _samples; + + public BitmapByteQRCodeBenchmark() + { + var eccLvl = QRCoder.QRCodeGenerator.ECCLevel.L; + _samples = new Dictionary() + { + { "small", QRCoder.QRCodeGenerator.GenerateQrCode("ABCD", eccLvl) }, + { "medium", QRCoder.QRCodeGenerator.GenerateQrCode("https://github.com/codebude/QRCoder/blob/f89aa90081f369983a9ba114e49cc6ebf0b2a7b1/QRCoder/Framework4.0Methods/Stream4Methods.cs", eccLvl) }, + { "big", QRCoder.QRCodeGenerator.GenerateQrCode( new string('a', 2600), eccLvl) } + }; + } + + + [Benchmark] + public void RenderBitmapByteQRCodeSmall() + { + var qrCode = new BitmapByteQRCode(_samples["small"]); + _ = qrCode.GetGraphic(10); + } + + [Benchmark] + public void RenderBitmapByteQRCodeMedium() + { + var qrCode = new BitmapByteQRCode(_samples["medium"]); + _ = qrCode.GetGraphic(10); + } + + [Benchmark] + public void RenderBitmapByteQRCodeBig() + { + var qrCode = new BitmapByteQRCode(_samples["big"]); + _ = qrCode.GetGraphic(10); + } + + [Benchmark] + public void RenderBitmapByteQRCodeHuge() + { + var qrCode = new BitmapByteQRCode(_samples["big"]); + _ = qrCode.GetGraphic(50); + } +} diff --git a/QRCoderTests/BitmapByteQRCodeRendererTests.cs b/QRCoderTests/BitmapByteQRCodeRendererTests.cs new file mode 100644 index 00000000..f5ff187c --- /dev/null +++ b/QRCoderTests/BitmapByteQRCodeRendererTests.cs @@ -0,0 +1,50 @@ +using QRCoder; +using QRCoderTests.Helpers; +using QRCoderTests.Helpers.XUnitExtenstions; +using Shouldly; +using Xunit; + + +namespace QRCoderTests; + + +public class BitmapByteQRCodeRendererTests +{ + [Fact] + [Category("QRRenderer/BitmapByteQRCode")] + public void can_render_bitmapbyte_qrcode() + { + var gen = new QRCodeGenerator(); + var data = gen.CreateQrCode("This is a quick test! 123#?", QRCodeGenerator.ECCLevel.H); + var bmp = new BitmapByteQRCode(data).GetGraphic(10); + + var result = HelperFunctions.ByteArrayToHash(bmp); + result.ShouldBe("2d262d074f5c436ad93025150392dd38"); + } + + + [Fact] + [Category("QRRenderer/BitmapByteQRCode")] + public void can_render_bitmapbyte_qrcode_color_bytearray() + { + var gen = new QRCodeGenerator(); + var data = gen.CreateQrCode("This is a quick test! 123#?", QRCodeGenerator.ECCLevel.H); + var bmp = new BitmapByteQRCode(data).GetGraphic(10, new byte[] { 30, 30, 30 }, new byte[] { 255, 0, 0 }); + + var result = HelperFunctions.ByteArrayToHash(bmp); + result.ShouldBe("1184507c7eb98f9ca76afd04313c41cb"); + } + + [Fact] + [Category("QRRenderer/BitmapByteQRCode")] + public void can_render_bitmapbyte_qrcode_drawing_color() + { + var gen = new QRCodeGenerator(); + var data = gen.CreateQrCode("This is a quick test! 123#?", QRCodeGenerator.ECCLevel.H); + var bmp = new BitmapByteQRCode(data).GetGraphic(10, "#e3e3e3", "#ffffff"); + + var result = HelperFunctions.ByteArrayToHash(bmp); + result.ShouldBe("40cd208fc46aa726d6e98a2028ffd2b7"); + } + +} From 8da423796253dfeca07902bbd2b0fd173c47237e Mon Sep 17 00:00:00 2001 From: Raffael Herrmann Date: Sat, 22 Jun 2024 23:50:58 +0200 Subject: [PATCH 2/7] Re-wrote BitmapByteQRCode for better performance Removed loops where possible and set fixed size objects --- QRCoder/BitmapByteQRCode.cs | 70 ++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/QRCoder/BitmapByteQRCode.cs b/QRCoder/BitmapByteQRCode.cs index 529cc5cc..29cc82f0 100644 --- a/QRCoder/BitmapByteQRCode.cs +++ b/QRCoder/BitmapByteQRCode.cs @@ -53,13 +53,35 @@ public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgb, byte[] lightC { var sideLength = QrCodeData.ModuleMatrix.Count * pixelsPerModule; - var moduleDark = darkColorRgb.Reverse(); - var moduleLight = lightColorRgb.Reverse(); + var moduleDarkSingle = darkColorRgb.Reverse().ToArray(); + var moduleLightSingle = lightColorRgb.Reverse().ToArray(); - var bmp = new List(); + // Pre-calculate color/module bytes + var moduleDark = new byte[pixelsPerModule * 3]; + var moduleLight = new byte[pixelsPerModule * 3]; + for (int i = 0; i < pixelsPerModule; i++) + { + Array.Copy(moduleDarkSingle, 0, moduleDark, i * 3, 3); + Array.Copy(moduleLightSingle, 0, moduleLight, i * 3, 3); + } + + // Pre-calculate padding bytes + var padding = new byte[sideLength % 4]; + + // Calculate filesize (header + pixel data + padding) + var fileSize = 54 + (3 * (sideLength * sideLength)) + (sideLength * padding.Length); + + + var bmp = new List(fileSize); + + //header part 1 + bmp.AddRange(new byte[] { 0x42, 0x4D }); - //header - bmp.AddRange(new byte[] { 0x42, 0x4D, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00 }); + // filesize + bmp.AddRange(IntTo4Byte(fileSize)); + + // header part 2 + bmp.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00 }); //width bmp.AddRange(IntTo4Byte(sideLength)); @@ -70,36 +92,28 @@ public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgb, byte[] lightC bmp.AddRange(new byte[] { 0x01, 0x00, 0x18, 0x00 }); bmp.AddRange(new byte[24]); + //Group of pixels placeholder + var group = new byte[(int)(sideLength / pixelsPerModule) * moduleDark.Length]; //draw qr code for (var x = sideLength - 1; x >= 0; x -= pixelsPerModule) { - for (int pm = 0; pm < pixelsPerModule; pm++) + var i_x = (x + pixelsPerModule) / pixelsPerModule - 1; + // Pre-calculate array + for (var y = 0; y < sideLength; y += pixelsPerModule) { - for (var y = 0; y < sideLength; y += pixelsPerModule) - { - var module = - QrCodeData.ModuleMatrix[(x + pixelsPerModule) / pixelsPerModule - 1][(y + pixelsPerModule) / pixelsPerModule - 1]; - for (int i = 0; i < pixelsPerModule; i++) - { - bmp.AddRange(module ? moduleDark : moduleLight); - } - } - if (sideLength % 4 != 0) - { - for (int i = 0; i < sideLength % 4; i++) - { - bmp.Add(0x00); - } - } + var module = QrCodeData.ModuleMatrix[i_x][(y + pixelsPerModule) / pixelsPerModule - 1]; + Array.Copy(module ? moduleDark : moduleLight, 0, group, y / pixelsPerModule * moduleDark.Length, moduleDark.Length); } - } + for (int pm = 0; pm < pixelsPerModule; pm++) + { + // Draw pixels + bmp.AddRange(group); - // write filesize in header - var bmpFileSize = IntTo4Byte(bmp.Count); - for (int i = 0; i < bmpFileSize.Length; i++) - { - bmp[2 + i] = bmpFileSize[i]; + // Add padding (to make line length a multiple of 4) + bmp.AddRange(padding); + } } + return bmp.ToArray(); } From 430f89a002a37734d0c22d4736c27698e83aa308 Mon Sep 17 00:00:00 2001 From: Raffael Herrmann Date: Sat, 22 Jun 2024 23:54:43 +0200 Subject: [PATCH 3/7] Fixed formatting --- QRCoder/BitmapByteQRCode.cs | 2 +- QRCoderBenchmarks/BitmapByteQRCode.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/QRCoder/BitmapByteQRCode.cs b/QRCoder/BitmapByteQRCode.cs index 29cc82f0..78255462 100644 --- a/QRCoder/BitmapByteQRCode.cs +++ b/QRCoder/BitmapByteQRCode.cs @@ -113,7 +113,7 @@ public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgb, byte[] lightC bmp.AddRange(padding); } } - + return bmp.ToArray(); } diff --git a/QRCoderBenchmarks/BitmapByteQRCode.cs b/QRCoderBenchmarks/BitmapByteQRCode.cs index 4ccfdc0c..446d8b3a 100644 --- a/QRCoderBenchmarks/BitmapByteQRCode.cs +++ b/QRCoderBenchmarks/BitmapByteQRCode.cs @@ -1,4 +1,3 @@ -using System.Collections.ObjectModel; using BenchmarkDotNet.Attributes; using QRCoder; From 8656f709dc63189b72b873a7f6961abbbed2f0e1 Mon Sep 17 00:00:00 2001 From: Raffael Herrmann Date: Sun, 23 Jun 2024 12:41:01 +0200 Subject: [PATCH 4/7] First part of BitmapByteQRCode optimizations suggested in PR review --- QRCoder/BitmapByteQRCode.cs | 78 +++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/QRCoder/BitmapByteQRCode.cs b/QRCoder/BitmapByteQRCode.cs index 78255462..5b622133 100644 --- a/QRCoder/BitmapByteQRCode.cs +++ b/QRCoder/BitmapByteQRCode.cs @@ -12,6 +12,10 @@ namespace QRCoder; // ReSharper disable once InconsistentNaming public class BitmapByteQRCode : AbstractQRCode, IDisposable { + private static readonly byte[] _bitmapHeaderPart1 = new byte[] { 0x42, 0x4D }; + private static readonly byte[] _bitmapHeaderPart2 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00 }; + private static readonly byte[] _bitmapHeaderPartEnd = new byte[] { 0x01, 0x00, 0x18, 0x00 }; + /// /// Initializes a new instance of the class. /// Constructor without parameters to be used in COM objects connections. @@ -53,44 +57,57 @@ public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgb, byte[] lightC { var sideLength = QrCodeData.ModuleMatrix.Count * pixelsPerModule; - var moduleDarkSingle = darkColorRgb.Reverse().ToArray(); - var moduleLightSingle = lightColorRgb.Reverse().ToArray(); + //var moduleDarkSingle = darkColorRgb.Reverse().ToArray(); + //var moduleLightSingle = lightColorRgb.Reverse().ToArray(); // Pre-calculate color/module bytes - var moduleDark = new byte[pixelsPerModule * 3]; - var moduleLight = new byte[pixelsPerModule * 3]; - for (int i = 0; i < pixelsPerModule; i++) + byte[] moduleDark = new byte[pixelsPerModule * 3]; + byte[] moduleLight = new byte[pixelsPerModule * 3]; + for (int i = 0; i < pixelsPerModule * 3; i += 3) { - Array.Copy(moduleDarkSingle, 0, moduleDark, i * 3, 3); - Array.Copy(moduleLightSingle, 0, moduleLight, i * 3, 3); + moduleDark[i] = darkColorRgb[2]; + moduleDark[i + 1] = darkColorRgb[1]; + moduleDark[i + 2] = darkColorRgb[0]; + moduleLight[i] = lightColorRgb[2]; + moduleLight[i + 1] = lightColorRgb[1]; + moduleLight[i + 2] = lightColorRgb[0]; } // Pre-calculate padding bytes - var padding = new byte[sideLength % 4]; + var paddingLen = sideLength % 4; // Calculate filesize (header + pixel data + padding) - var fileSize = 54 + (3 * (sideLength * sideLength)) + (sideLength * padding.Length); - + var fileSize = 54 + (3 * (sideLength * sideLength)) + (sideLength * paddingLen); - var bmp = new List(fileSize); + // Bitmap container + byte[] bmp = new byte[fileSize]; + int ix = 0; //header part 1 - bmp.AddRange(new byte[] { 0x42, 0x4D }); + Array.Copy(_bitmapHeaderPart1, 0, bmp, ix, _bitmapHeaderPart1.Length); + ix += _bitmapHeaderPart1.Length; // filesize - bmp.AddRange(IntTo4Byte(fileSize)); + CopyIntAs4ByteToArray(fileSize, ix, ref bmp); + ix += 4; // header part 2 - bmp.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00 }); + Array.Copy(_bitmapHeaderPart2, 0, bmp, ix, _bitmapHeaderPart2.Length); + ix += _bitmapHeaderPart2.Length; //width - bmp.AddRange(IntTo4Byte(sideLength)); + CopyIntAs4ByteToArray(sideLength, ix, ref bmp); + ix += 4; //height - bmp.AddRange(IntTo4Byte(sideLength)); + CopyIntAs4ByteToArray(sideLength, ix, ref bmp); + ix += 4; //header end - bmp.AddRange(new byte[] { 0x01, 0x00, 0x18, 0x00 }); - bmp.AddRange(new byte[24]); + Array.Copy(_bitmapHeaderPartEnd, 0, bmp, ix, _bitmapHeaderPartEnd.Length); + ix += _bitmapHeaderPartEnd.Length; + + // Add header null-bytes + ix += 24; //Group of pixels placeholder var group = new byte[(int)(sideLength / pixelsPerModule) * moduleDark.Length]; @@ -107,14 +124,15 @@ public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgb, byte[] lightC for (int pm = 0; pm < pixelsPerModule; pm++) { // Draw pixels - bmp.AddRange(group); + Array.Copy(group, 0, bmp, ix, group.Length); + ix += group.Length; // Add padding (to make line length a multiple of 4) - bmp.AddRange(padding); + ix += paddingLen; } } - return bmp.ToArray(); + return bmp; } @@ -133,22 +151,22 @@ private byte[] HexColorToByteArray(string colorString) return byteColor; } + /// - /// Converts an integer to a 4-byte array. + /// Converts an integer to a 4 bytes and writes them to a byte array at given position /// /// The integer to convert. - /// Returns the integer as a 4-byte array. - private byte[] IntTo4Byte(int inp) + /// Index of destinationArray where the converted bytes are written to + /// Destination byte array that receives the bytes + private void CopyIntAs4ByteToArray(int inp, int destinationIndex, ref byte[] destinationArray) { - byte[] bytes = new byte[4]; unchecked { - bytes[3] = (byte)(inp >> 24); - bytes[2] = (byte)(inp >> 16); - bytes[1] = (byte)(inp >> 8); - bytes[0] = (byte)(inp); + destinationArray[destinationIndex + 3] = (byte)(inp >> 24); + destinationArray[destinationIndex + 2] = (byte)(inp >> 16); + destinationArray[destinationIndex + 1] = (byte)(inp >> 8); + destinationArray[destinationIndex + 0] = (byte)(inp); } - return bytes; } } From bb636ea485bd540fe7d2b55f482bf8628a52fad3 Mon Sep 17 00:00:00 2001 From: Raffael Herrmann Date: Sun, 23 Jun 2024 13:07:18 +0200 Subject: [PATCH 5/7] Second part of BitmapByteQRCode optimizations suggested in PR review --- QRCoder/BitmapByteQRCode.cs | 43 ++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/QRCoder/BitmapByteQRCode.cs b/QRCoder/BitmapByteQRCode.cs index 5b622133..ffb13215 100644 --- a/QRCoder/BitmapByteQRCode.cs +++ b/QRCoder/BitmapByteQRCode.cs @@ -57,9 +57,6 @@ public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgb, byte[] lightC { var sideLength = QrCodeData.ModuleMatrix.Count * pixelsPerModule; - //var moduleDarkSingle = darkColorRgb.Reverse().ToArray(); - //var moduleLightSingle = lightColorRgb.Reverse().ToArray(); - // Pre-calculate color/module bytes byte[] moduleDark = new byte[pixelsPerModule * 3]; byte[] moduleLight = new byte[pixelsPerModule * 3]; @@ -83,52 +80,58 @@ public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgb, byte[] lightC byte[] bmp = new byte[fileSize]; int ix = 0; - //header part 1 + // Header part 1 Array.Copy(_bitmapHeaderPart1, 0, bmp, ix, _bitmapHeaderPart1.Length); ix += _bitmapHeaderPart1.Length; - // filesize + // Filesize CopyIntAs4ByteToArray(fileSize, ix, ref bmp); ix += 4; - // header part 2 + // Header part 2 Array.Copy(_bitmapHeaderPart2, 0, bmp, ix, _bitmapHeaderPart2.Length); ix += _bitmapHeaderPart2.Length; - //width + // Width CopyIntAs4ByteToArray(sideLength, ix, ref bmp); ix += 4; - //height + // Height CopyIntAs4ByteToArray(sideLength, ix, ref bmp); ix += 4; - //header end + // Header end Array.Copy(_bitmapHeaderPartEnd, 0, bmp, ix, _bitmapHeaderPartEnd.Length); ix += _bitmapHeaderPartEnd.Length; // Add header null-bytes ix += 24; - //Group of pixels placeholder + + // Draw qr code var group = new byte[(int)(sideLength / pixelsPerModule) * moduleDark.Length]; - //draw qr code for (var x = sideLength - 1; x >= 0; x -= pixelsPerModule) { - var i_x = (x + pixelsPerModule) / pixelsPerModule - 1; - // Pre-calculate array + var modMatrixX = (x + pixelsPerModule) / pixelsPerModule - 1; + + // Write data for first pixel of pixelsPerModule + int posStartFirstPx = ix; for (var y = 0; y < sideLength; y += pixelsPerModule) { - var module = QrCodeData.ModuleMatrix[i_x][(y + pixelsPerModule) / pixelsPerModule - 1]; + var module = QrCodeData.ModuleMatrix[modMatrixX][(y + pixelsPerModule) / pixelsPerModule - 1]; Array.Copy(module ? moduleDark : moduleLight, 0, group, y / pixelsPerModule * moduleDark.Length, moduleDark.Length); + Array.Copy(module ? moduleDark : moduleLight, 0, bmp, ix, moduleDark.Length); + ix += moduleDark.Length; } - for (int pm = 0; pm < pixelsPerModule; pm++) + // Add padding (to make line length a multiple of 4) + ix += paddingLen; + int lenFirstPx = ix - posStartFirstPx; + + // Re-write (copy) first pixel (pixelsPerModule - 1) times + for (int pm = 0; pm < (pixelsPerModule - 1); pm++) { // Draw pixels - Array.Copy(group, 0, bmp, ix, group.Length); - ix += group.Length; - - // Add padding (to make line length a multiple of 4) - ix += paddingLen; + Array.Copy(bmp, posStartFirstPx, bmp, ix, lenFirstPx); + ix += lenFirstPx; } } From 9a0f73dbeca8897e6d10d1d04859477069b8901a Mon Sep 17 00:00:00 2001 From: Raffael Herrmann Date: Sun, 23 Jun 2024 13:07:55 +0200 Subject: [PATCH 6/7] Formatted via dotnet format --- QRCoder/BitmapByteQRCode.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/QRCoder/BitmapByteQRCode.cs b/QRCoder/BitmapByteQRCode.cs index ffb13215..cd15d387 100644 --- a/QRCoder/BitmapByteQRCode.cs +++ b/QRCoder/BitmapByteQRCode.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; using static QRCoder.QRCodeGenerator; namespace QRCoder; From 86c2e47561ef35b56f4be8f70d93c2ffd5ef40c9 Mon Sep 17 00:00:00 2001 From: Raffael Herrmann Date: Sun, 23 Jun 2024 21:20:46 +0200 Subject: [PATCH 7/7] Removed unused code and unnecessary ref keyword --- QRCoder/BitmapByteQRCode.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/QRCoder/BitmapByteQRCode.cs b/QRCoder/BitmapByteQRCode.cs index cd15d387..27b3b34f 100644 --- a/QRCoder/BitmapByteQRCode.cs +++ b/QRCoder/BitmapByteQRCode.cs @@ -83,7 +83,7 @@ public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgb, byte[] lightC ix += _bitmapHeaderPart1.Length; // Filesize - CopyIntAs4ByteToArray(fileSize, ix, ref bmp); + CopyIntAs4ByteToArray(fileSize, ix, bmp); ix += 4; // Header part 2 @@ -91,10 +91,10 @@ public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgb, byte[] lightC ix += _bitmapHeaderPart2.Length; // Width - CopyIntAs4ByteToArray(sideLength, ix, ref bmp); + CopyIntAs4ByteToArray(sideLength, ix, bmp); ix += 4; // Height - CopyIntAs4ByteToArray(sideLength, ix, ref bmp); + CopyIntAs4ByteToArray(sideLength, ix, bmp); ix += 4; // Header end @@ -106,7 +106,6 @@ public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgb, byte[] lightC // Draw qr code - var group = new byte[(int)(sideLength / pixelsPerModule) * moduleDark.Length]; for (var x = sideLength - 1; x >= 0; x -= pixelsPerModule) { var modMatrixX = (x + pixelsPerModule) / pixelsPerModule - 1; @@ -116,7 +115,6 @@ public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgb, byte[] lightC for (var y = 0; y < sideLength; y += pixelsPerModule) { var module = QrCodeData.ModuleMatrix[modMatrixX][(y + pixelsPerModule) / pixelsPerModule - 1]; - Array.Copy(module ? moduleDark : moduleLight, 0, group, y / pixelsPerModule * moduleDark.Length, moduleDark.Length); Array.Copy(module ? moduleDark : moduleLight, 0, bmp, ix, moduleDark.Length); ix += moduleDark.Length; } @@ -159,7 +157,7 @@ private byte[] HexColorToByteArray(string colorString) /// The integer to convert. /// Index of destinationArray where the converted bytes are written to /// Destination byte array that receives the bytes - private void CopyIntAs4ByteToArray(int inp, int destinationIndex, ref byte[] destinationArray) + private void CopyIntAs4ByteToArray(int inp, int destinationIndex, byte[] destinationArray) { unchecked {