diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 66c8b6c08..42a350c15 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -55,9 +55,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.padding = bytesPerLine - (image.Width * (int)this.bitsPerPixel); // Do not use IDisposable pattern here as we want to preserve the stream. - EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); + var writer = new LittleEndianBinaryWriter(stream); - BmpInfoHeader infoHeader = new BmpInfoHeader + var infoHeader = new BmpInfoHeader { HeaderSize = BmpInfoHeader.BitmapInfoHeaderSize, Height = image.Height, @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp ClrImportant = 0 }; - BmpFileHeader fileHeader = new BmpFileHeader + var fileHeader = new BmpFileHeader { Type = 19778, // BM Offset = 54, @@ -87,12 +87,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// Writes the bitmap header data to the binary stream. /// /// - /// The containing the stream to write to. + /// The containing the stream to write to. /// /// /// The containing the header data. /// - private static void WriteHeader(EndianBinaryWriter writer, BmpFileHeader fileHeader) + private static void WriteHeader(LittleEndianBinaryWriter writer, BmpFileHeader fileHeader) { writer.Write(fileHeader.Type); writer.Write(fileHeader.FileSize); @@ -104,12 +104,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// Writes the bitmap information to the binary stream. /// /// - /// The containing the stream to write to. + /// The containing the stream to write to. /// /// /// The containing the detailed information about the image. /// - private void WriteInfo(EndianBinaryWriter writer, BmpInfoHeader infoHeader) + private void WriteInfo(LittleEndianBinaryWriter writer, BmpInfoHeader infoHeader) { writer.Write(infoHeader.HeaderSize); writer.Write(infoHeader.Width); @@ -128,11 +128,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// Writes the pixel data to the binary stream. /// /// The pixel format. - /// The containing the stream to write to. + /// The containing the stream to write to. /// /// The containing pixel data. /// - private void WriteImage(EndianBinaryWriter writer, ImageFrame image) + private void WriteImage(LittleEndianBinaryWriter writer, ImageFrame image) where TPixel : struct, IPixel { using (PixelAccessor pixels = image.Lock()) @@ -159,9 +159,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// Writes the 32bit color palette to the stream. /// /// The pixel format. - /// The containing the stream to write to. + /// The containing the stream to write to. /// The containing pixel data. - private void Write32Bit(EndianBinaryWriter writer, PixelAccessor pixels) + private void Write32Bit(LittleEndianBinaryWriter writer, PixelAccessor pixels) where TPixel : struct, IPixel { using (IManagedByteBuffer row = this.AllocateRow(pixels.Width, 4)) @@ -179,9 +179,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// Writes the 24bit color palette to the stream. /// /// The pixel format. - /// The containing the stream to write to. + /// The containing the stream to write to. /// The containing pixel data. - private void Write24Bit(EndianBinaryWriter writer, PixelAccessor pixels) + private void Write24Bit(LittleEndianBinaryWriter writer, PixelAccessor pixels) where TPixel : struct, IPixel { using (IManagedByteBuffer row = this.AllocateRow(pixels.Width, 3)) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 7550d0669..5472b3fd4 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Formats.Gif Guard.NotNull(stream, nameof(stream)); // Do not use IDisposable pattern here as we want to preserve the stream. - var writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); + var writer = new LittleEndianBinaryWriter(stream); this.hasFrames = image.Frames.Count > 1; @@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Writes the file header signature and version to the stream. /// /// The writer to write to the stream with. - private void WriteHeader(EndianBinaryWriter writer) + private void WriteHeader(LittleEndianBinaryWriter writer) { writer.Write(GifConstants.MagicNumber, 0, GifConstants.MagicNumber.Length); } @@ -167,7 +167,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The image to encode. /// The writer to write to the stream with. /// The transparency index to set the default background index to. - private void WriteLogicalScreenDescriptor(Image image, EndianBinaryWriter writer, int transparencyIndex) + private void WriteLogicalScreenDescriptor(Image image, LittleEndianBinaryWriter writer, int transparencyIndex) where TPixel : struct, IPixel { var descriptor = new GifLogicalScreenDescriptor @@ -202,7 +202,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The writer to write to the stream with. /// The animated image repeat count. /// The number of image frames. - private void WriteApplicationExtension(EndianBinaryWriter writer, ushort repeatCount, int frames) + private void WriteApplicationExtension(LittleEndianBinaryWriter writer, ushort repeatCount, int frames) { // Application Extension Header if (repeatCount != 1 && frames > 0) @@ -231,7 +231,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The pixel format. /// The to be encoded. /// The stream to write to. - private void WriteComments(Image image, EndianBinaryWriter writer) + private void WriteComments(Image image, LittleEndianBinaryWriter writer) where TPixel : struct, IPixel { if (this.ignoreMetadata) @@ -264,7 +264,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The metadata of the image or frame. /// The stream to write to. /// The index of the color in the color palette to make transparent. - private void WriteGraphicalControlExtension(ImageFrameMetaData metaData, EndianBinaryWriter writer, int transparencyIndex) + private void WriteGraphicalControlExtension(ImageFrameMetaData metaData, LittleEndianBinaryWriter writer, int transparencyIndex) { var extension = new GifGraphicsControlExtension { @@ -299,7 +299,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The pixel format. /// The to be encoded. /// The stream to write to. - private void WriteImageDescriptor(ImageFrame image, EndianBinaryWriter writer) + private void WriteImageDescriptor(ImageFrame image, LittleEndianBinaryWriter writer) where TPixel : struct, IPixel { writer.Write(GifConstants.ImageDescriptorLabel); // 2c @@ -325,7 +325,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The pixel format. /// The to encode. /// The writer to write to the stream with. - private void WriteColorTable(QuantizedFrame image, EndianBinaryWriter writer) + private void WriteColorTable(QuantizedFrame image, LittleEndianBinaryWriter writer) where TPixel : struct, IPixel { // Grab the palette and write it to the stream. @@ -357,7 +357,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The pixel format. /// The containing indexed pixels. /// The stream to write to. - private void WriteImageData(QuantizedFrame image, EndianBinaryWriter writer) + private void WriteImageData(QuantizedFrame image, LittleEndianBinaryWriter writer) where TPixel : struct, IPixel { using (var encoder = new LzwEncoder(this.memoryManager, image.Pixels, (byte)this.bitDepth)) diff --git a/src/ImageSharp/IO/BigEndianBinaryWriter.cs b/src/ImageSharp/IO/BigEndianBinaryWriter.cs new file mode 100644 index 000000000..a3de65557 --- /dev/null +++ b/src/ImageSharp/IO/BigEndianBinaryWriter.cs @@ -0,0 +1,87 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers.Binary; +using System.IO; + +namespace SixLabors.ImageSharp.IO +{ + /// + /// A BigEndian variant of + /// + internal sealed class BigEndianBinaryWriter : EndianBinaryWriter + { + /// + /// Initializes a new instance of the class + /// + /// Stream to write data to + public BigEndianBinaryWriter(Stream stream) + : base(stream) + { + } + + /// + public override Endianness Endianness => Endianness.BigEndian; + + /// + public override void Write(short value) + { + BinaryPrimitives.WriteInt16BigEndian(this.buffer, value); + + this.WriteInternal(this.buffer, 2); + } + + /// + public override void Write(int value) + { + BinaryPrimitives.WriteInt32BigEndian(this.buffer, value); + + this.WriteInternal(this.buffer, 4); + } + + /// + public override void Write(long value) + { + BinaryPrimitives.WriteInt64BigEndian(this.buffer, value); + + this.WriteInternal(this.buffer, 8); + } + + /// + public override void Write(ushort value) + { + BinaryPrimitives.WriteUInt16BigEndian(this.buffer, value); + + this.WriteInternal(this.buffer, 2); + } + + /// + public override void Write(uint value) + { + BinaryPrimitives.WriteUInt32BigEndian(this.buffer, value); + + this.WriteInternal(this.buffer, 4); + } + + /// + public override void Write(ulong value) + { + BinaryPrimitives.WriteUInt64BigEndian(this.buffer, value); + + this.WriteInternal(this.buffer, 8); + } + + /// + public override unsafe void Write(float value) + { + this.Write(*((int*)&value)); + } + + /// + public override unsafe void Write(double value) + { + this.Write(*((long*)&value)); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/IO/EndianBinaryWriter.cs b/src/ImageSharp/IO/EndianBinaryWriter.cs index 9c42f0b69..1366764de 100644 --- a/src/ImageSharp/IO/EndianBinaryWriter.cs +++ b/src/ImageSharp/IO/EndianBinaryWriter.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers.Binary; using System.IO; namespace SixLabors.ImageSharp.IO @@ -10,17 +9,12 @@ namespace SixLabors.ImageSharp.IO /// /// Equivalent of , but with either endianness /// - internal class EndianBinaryWriter : IDisposable + internal abstract class EndianBinaryWriter : IDisposable { /// /// Buffer used for temporary storage during conversion from primitives /// - private readonly byte[] buffer = new byte[16]; - - /// - /// The endianness used to write the data - /// - private readonly Endianness endianness; + protected readonly byte[] buffer = new byte[16]; /// /// Whether or not this writer has been disposed yet. @@ -29,17 +23,14 @@ namespace SixLabors.ImageSharp.IO /// /// Initializes a new instance of the class - /// with the given bit converter, writing to the given stream, using the given encoding. /// - /// Endianness to use when writing data /// Stream to write data to - public EndianBinaryWriter(Endianness endianness, Stream stream) + public EndianBinaryWriter(Stream stream) { Guard.NotNull(stream, nameof(stream)); Guard.IsTrue(stream.CanWrite, nameof(stream), "Stream isn't writable"); this.BaseStream = stream; - this.endianness = endianness; } /// @@ -47,6 +38,11 @@ namespace SixLabors.ImageSharp.IO /// public Stream BaseStream { get; } + /// + /// Gets the endianness of the BinaryWriter + /// + public abstract Endianness Endianness { get; } + /// /// Closes the writer, including the underlying stream. /// @@ -91,134 +87,56 @@ namespace SixLabors.ImageSharp.IO /// for this writer. 2 bytes are written. /// /// The value to write - public void Write(short value) - { - if (this.endianness == Endianness.BigEndian) - { - BinaryPrimitives.WriteInt16BigEndian(this.buffer, value); - } - else - { - BinaryPrimitives.WriteInt16LittleEndian(this.buffer, value); - } - - this.WriteInternal(this.buffer, 2); - } + public abstract void Write(short value); /// /// Writes a 32-bit signed integer to the stream, using the bit converter /// for this writer. 4 bytes are written. /// /// The value to write - public void Write(int value) - { - if (this.endianness == Endianness.BigEndian) - { - BinaryPrimitives.WriteInt32BigEndian(this.buffer, value); - } - else - { - BinaryPrimitives.WriteInt32LittleEndian(this.buffer, value); - } - - this.WriteInternal(this.buffer, 4); - } + public abstract void Write(int value); /// /// Writes a 64-bit signed integer to the stream, using the bit converter /// for this writer. 8 bytes are written. /// /// The value to write - public void Write(long value) - { - if (this.endianness == Endianness.BigEndian) - { - BinaryPrimitives.WriteInt64BigEndian(this.buffer, value); - } - else - { - BinaryPrimitives.WriteInt64LittleEndian(this.buffer, value); - } - - this.WriteInternal(this.buffer, 8); - } + public abstract void Write(long value); /// /// Writes a 16-bit unsigned integer to the stream, using the bit converter /// for this writer. 2 bytes are written. /// /// The value to write - public void Write(ushort value) - { - if (this.endianness == Endianness.BigEndian) - { - BinaryPrimitives.WriteUInt16BigEndian(this.buffer, value); - } - else - { - BinaryPrimitives.WriteUInt16LittleEndian(this.buffer, value); - } - - this.WriteInternal(this.buffer, 2); - } + public abstract void Write(ushort value); /// /// Writes a 32-bit unsigned integer to the stream, using the bit converter /// for this writer. 4 bytes are written. /// /// The value to write - public void Write(uint value) - { - if (this.endianness == Endianness.BigEndian) - { - BinaryPrimitives.WriteUInt32BigEndian(this.buffer, value); - } - else - { - BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, value); - } - - this.WriteInternal(this.buffer, 4); - } + public abstract void Write(uint value); /// /// Writes a 64-bit unsigned integer to the stream, using the bit converter /// for this writer. 8 bytes are written. /// /// The value to write - public void Write(ulong value) - { - if (this.endianness == Endianness.BigEndian) - { - BinaryPrimitives.WriteUInt64BigEndian(this.buffer, value); - } - else - { - BinaryPrimitives.WriteUInt64LittleEndian(this.buffer, value); - } - - this.WriteInternal(this.buffer, 8); - } + public abstract void Write(ulong value); /// /// Writes a single-precision floating-point value to the stream, using the bit converter /// for this writer. 4 bytes are written. /// /// The value to write - public unsafe void Write(float value) - { - this.Write(*((int*)&value)); - } + public abstract void Write(float value); /// /// Writes a double-precision floating-point value to the stream, using the bit converter /// for this writer. 8 bytes are written. /// /// The value to write - public unsafe void Write(double value) - { - this.Write(*((long*)&value)); - } + public abstract void Write(double value); /// /// Writes a signed byte to the stream. @@ -284,7 +202,7 @@ namespace SixLabors.ImageSharp.IO { if (this.disposed) { - throw new ObjectDisposedException(nameof(EndianBinaryWriter)); + throw new ObjectDisposedException(nameof(BigEndianBinaryWriter)); } } @@ -294,10 +212,22 @@ namespace SixLabors.ImageSharp.IO /// /// The array of bytes to write from /// The number of bytes to write - private void WriteInternal(byte[] bytes, int length) + protected void WriteInternal(byte[] bytes, int length) { this.CheckDisposed(); this.BaseStream.Write(bytes, 0, length); } + + public static EndianBinaryWriter Create(Endianness endianness, Stream stream) + { + if (endianness == Endianness.BigEndian) + { + return new BigEndianBinaryWriter(stream); + } + else + { + return new LittleEndianBinaryWriter(stream); + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/IO/LittleEndianBinaryWriter.cs b/src/ImageSharp/IO/LittleEndianBinaryWriter.cs new file mode 100644 index 000000000..7be137fb0 --- /dev/null +++ b/src/ImageSharp/IO/LittleEndianBinaryWriter.cs @@ -0,0 +1,87 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers.Binary; +using System.IO; + +namespace SixLabors.ImageSharp.IO +{ + /// + /// A Little Endian variant of + /// + internal sealed class LittleEndianBinaryWriter : EndianBinaryWriter + { + /// + /// Initializes a new instance of the class + /// + /// Stream to write data to + public LittleEndianBinaryWriter(Stream stream) + : base(stream) + { + } + + /// + public override Endianness Endianness => Endianness.LittleEndian; + + /// + public override void Write(short value) + { + BinaryPrimitives.WriteInt16LittleEndian(this.buffer, value); + + this.WriteInternal(this.buffer, 2); + } + + /// + public override void Write(int value) + { + BinaryPrimitives.WriteInt32LittleEndian(this.buffer, value); + + this.WriteInternal(this.buffer, 4); + } + + /// + public override void Write(long value) + { + BinaryPrimitives.WriteInt64LittleEndian(this.buffer, value); + + this.WriteInternal(this.buffer, 8); + } + + /// + public override void Write(ushort value) + { + BinaryPrimitives.WriteUInt16LittleEndian(this.buffer, value); + + this.WriteInternal(this.buffer, 2); + } + + /// + public override void Write(uint value) + { + BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, value); + + this.WriteInternal(this.buffer, 4); + } + + /// + public override void Write(ulong value) + { + BinaryPrimitives.WriteUInt64LittleEndian(this.buffer, value); + + this.WriteInternal(this.buffer, 8); + } + + /// + public override unsafe void Write(float value) + { + this.Write(*((int*)&value)); + } + + /// + public override unsafe void Write(double value) + { + this.Write(*((long*)&value)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/IO/EndianBinaryReaderWriterTests.cs b/tests/ImageSharp.Tests/IO/EndianBinaryReaderWriterTests.cs index 6e22b1689..2712baafa 100644 --- a/tests/ImageSharp.Tests/IO/EndianBinaryReaderWriterTests.cs +++ b/tests/ImageSharp.Tests/IO/EndianBinaryReaderWriterTests.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Tests.IO { var stream = new MemoryStream(); - using (var writer = new EndianBinaryWriter(endianness, stream)) + using (var writer = EndianBinaryWriter.Create(endianness, stream)) { writer.Write((float)Math.PI); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.IO { var stream = new MemoryStream(); - using (var writer = new EndianBinaryWriter(endianness, stream)) + using (var writer = EndianBinaryWriter.Create(endianness, stream)) { writer.Write(Math.PI); @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Tests.IO { var stream = new MemoryStream(); - var writer = new EndianBinaryWriter(endianness, stream); + var writer = EndianBinaryWriter.Create(endianness, stream); writer.Write(true); // Bool writer.Write((byte)1); // Byte