From 3182f935dc84b4ebfce2b506ab0d5eb83ca8aa5a Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sun, 5 Feb 2023 15:25:49 +0100 Subject: [PATCH] Remove nullable disable from Formats.BMP * Removed nullable disable * refactored stream usage. It is now always passed as a parameter and not stored a a instance variable --- src/ImageSharp/Color/Color.cs | 3 +- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 179 ++++++++++-------- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 5 +- .../PaletteDitherProcessor{TPixel}.cs | 2 +- .../Processors/Quantization/IQuantizer.cs | 4 +- .../Quantization/OctreeQuantizer.cs | 4 +- .../Quantization/OctreeQuantizer{TPixel}.cs | 2 +- .../Quantization/PaletteQuantizer.cs | 6 +- .../Quantization/PaletteQuantizer{TPixel}.cs | 2 +- .../Processors/Quantization/WuQuantizer.cs | 4 +- .../Quantization/WuQuantizer{TPixel}.cs | 2 +- 11 files changed, 112 insertions(+), 101 deletions(-) diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs index 99a271bcf..590a3ed31 100644 --- a/src/ImageSharp/Color/Color.cs +++ b/src/ImageSharp/Color/Color.cs @@ -286,12 +286,11 @@ public readonly partial struct Color : IEquatable /// Bulk converts a span of to a span of a specified type. /// /// The pixel type to convert to. - /// The configuration. /// The source color span. /// The destination pixel span. [MethodImpl(InliningOptions.ShortMethod)] #pragma warning disable RCS1163 // Unused parameter. - public static void ToPixel(Configuration configuration, ReadOnlySpan source, Span destination) + public static void ToPixel(ReadOnlySpan source, Span destination) #pragma warning restore RCS1163 // Unused parameter. where TPixel : unmanaged, IPixel { diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index fd0497d9a..cb1c7a251 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -1,9 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using System.Buffers; using System.Buffers.Binary; +using System.Diagnostics.CodeAnalysis; using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Common.Helpers; @@ -58,20 +58,15 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// private const int RleDelta = 0x02; - /// - /// The stream to decode from. - /// - private BufferedReadStream stream; - /// /// The metadata. /// - private ImageMetadata metadata; + private ImageMetadata? metadata; /// /// The bitmap specific metadata. /// - private BmpMetadata bmpMetadata; + private BmpMetadata? bmpMetadata; /// /// The file header containing general information. @@ -126,7 +121,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { - Image image = null; + Image? image = null; try { int bytesPerColorMapEntry = this.ReadImageHeaders(stream, out bool inverted, out byte[] palette); @@ -142,24 +137,25 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals { if (this.bmpMetadata.InfoHeaderType == BmpInfoHeaderType.WinVersion3) { - this.ReadRgb32Slow(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); + this.ReadRgb32Slow(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); } else { - this.ReadRgb32Fast(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); + this.ReadRgb32Fast(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); } } else if (this.infoHeader.BitsPerPixel == 24) { - this.ReadRgb24(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); + this.ReadRgb24(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); } else if (this.infoHeader.BitsPerPixel == 16) { - this.ReadRgb16(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); + this.ReadRgb16(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); } else if (this.infoHeader.BitsPerPixel <= 8) { this.ReadRgbPalette( + stream, pixels, palette, this.infoHeader.Width, @@ -172,19 +168,19 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals break; case BmpCompression.RLE24: - this.ReadRle24(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); + this.ReadRle24(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); break; case BmpCompression.RLE8: case BmpCompression.RLE4: - this.ReadRle(this.infoHeader.Compression, pixels, palette, this.infoHeader.Width, this.infoHeader.Height, inverted); + this.ReadRle(stream, this.infoHeader.Compression, pixels, palette, this.infoHeader.Width, this.infoHeader.Height, inverted); break; case BmpCompression.BitFields: case BmpCompression.BI_ALPHABITFIELDS: - this.ReadBitFields(pixels, inverted); + this.ReadBitFields(stream, pixels, inverted); break; @@ -250,14 +246,16 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// which will be used to determine which bits belong to that channel. /// /// The pixel format. + /// The containing image data. /// The output pixel buffer containing the decoded image. /// Whether the bitmap is inverted. - private void ReadBitFields(Buffer2D pixels, bool inverted) + private void ReadBitFields(BufferedReadStream stream, Buffer2D pixels, bool inverted) where TPixel : unmanaged, IPixel { if (this.infoHeader.BitsPerPixel == 16) { this.ReadRgb16( + stream, pixels, this.infoHeader.Width, this.infoHeader.Height, @@ -269,6 +267,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals else { this.ReadRgb32BitFields( + stream, pixels, this.infoHeader.Width, this.infoHeader.Height, @@ -282,17 +281,17 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// /// Looks up color values and builds the image from de-compressed RLE8 or RLE4 data. - /// Compressed RLE8 stream is uncompressed by - /// Compressed RLE4 stream is uncompressed by + /// Compressed RLE4 stream is uncompressed by /// /// The pixel format. + /// The containing image data. /// The compression type. Either RLE4 or RLE8. /// The to assign the palette to. /// The containing the colors. /// The width of the bitmap. /// The height of the bitmap. /// Whether the bitmap is inverted. - private void ReadRle(BmpCompression compression, Buffer2D pixels, byte[] colors, int width, int height, bool inverted) + private void ReadRle(BufferedReadStream stream, BmpCompression compression, Buffer2D pixels, byte[] colors, int width, int height, bool inverted) where TPixel : unmanaged, IPixel { TPixel color = default; @@ -305,11 +304,11 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals Span bufferSpan = buffer.Memory.Span; if (compression is BmpCompression.RLE8) { - this.UncompressRle8(width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); + this.UncompressRle8(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); } else { - this.UncompressRle4(width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); + this.UncompressRle4(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); } for (int y = 0; y < height; y++) @@ -368,11 +367,12 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// Looks up color values and builds the image from de-compressed RLE24. /// /// The pixel format. + /// The containing image data. /// The to assign the palette to. /// The width of the bitmap. /// The height of the bitmap. /// Whether the bitmap is inverted. - private void ReadRle24(Buffer2D pixels, int width, int height, bool inverted) + private void ReadRle24(BufferedReadStream stream, Buffer2D pixels, int width, int height, bool inverted) where TPixel : unmanaged, IPixel { TPixel color = default; @@ -384,7 +384,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals Span undefinedPixelsSpan = undefinedPixels.Memory.Span; Span bufferSpan = buffer.GetSpan(); - this.UncompressRle24(width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); + this.UncompressRle24(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); for (int y = 0; y < height; y++) { int newY = Invert(y, height, inverted); @@ -446,18 +446,19 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals ///
If first byte is 0, the second byte may have special meaning. ///
Otherwise, the first byte is the length of the run and second byte contains two color indexes. /// + /// The containing image data. /// The width of the bitmap. /// Buffer for uncompressed data. /// Keeps track over skipped and therefore undefined pixels. /// Keeps track of rows, which have undefined pixels. - private void UncompressRle4(int w, Span buffer, Span undefinedPixels, Span rowsWithUndefinedPixels) + private void UncompressRle4(BufferedReadStream stream, int w, Span buffer, Span undefinedPixels, Span rowsWithUndefinedPixels) { Span cmd = stackalloc byte[2]; int count = 0; while (count < buffer.Length) { - if (this.stream.Read(cmd, 0, cmd.Length) != 2) + if (stream.Read(cmd, 0, cmd.Length) != 2) { BmpThrowHelper.ThrowInvalidImageContentException("Failed to read 2 bytes from the stream while uncompressing RLE4 bitmap."); } @@ -478,8 +479,8 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals break; case RleDelta: - int dx = this.stream.ReadByte(); - int dy = this.stream.ReadByte(); + int dx = stream.ReadByte(); + int dy = stream.ReadByte(); count += RleSkipDelta(count, w, dx, dy, undefinedPixels, rowsWithUndefinedPixels); break; @@ -492,7 +493,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals byte[] run = new byte[bytesToRead]; - this.stream.Read(run, 0, run.Length); + stream.Read(run, 0, run.Length); int idx = 0; for (int i = 0; i < max; i++) @@ -512,7 +513,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals // Absolute mode data is aligned to two-byte word-boundary. int padding = bytesToRead & 1; - this.stream.Skip(padding); + stream.Skip(padding); break; } @@ -551,18 +552,19 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals ///
If first byte is 0, the second byte may have special meaning. ///
Otherwise, the first byte is the length of the run and second byte is the color for the run. /// + /// The containing image data. /// The width of the bitmap. /// Buffer for uncompressed data. /// Keeps track of skipped and therefore undefined pixels. /// Keeps track of rows, which have undefined pixels. - private void UncompressRle8(int w, Span buffer, Span undefinedPixels, Span rowsWithUndefinedPixels) + private void UncompressRle8(BufferedReadStream stream, int w, Span buffer, Span undefinedPixels, Span rowsWithUndefinedPixels) { Span cmd = stackalloc byte[2]; int count = 0; while (count < buffer.Length) { - if (this.stream.Read(cmd, 0, cmd.Length) != 2) + if (stream.Read(cmd, 0, cmd.Length) != 2) { BmpThrowHelper.ThrowInvalidImageContentException("Failed to read 2 bytes from stream while uncompressing RLE8 bitmap."); } @@ -583,8 +585,8 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals break; case RleDelta: - int dx = this.stream.ReadByte(); - int dy = this.stream.ReadByte(); + int dx = stream.ReadByte(); + int dy = stream.ReadByte(); count += RleSkipDelta(count, w, dx, dy, undefinedPixels, rowsWithUndefinedPixels); break; @@ -596,7 +598,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals byte[] run = new byte[length]; - this.stream.Read(run, 0, run.Length); + stream.Read(run, 0, run.Length); run.AsSpan().CopyTo(buffer[count..]); @@ -605,7 +607,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals // Absolute mode data is aligned to two-byte word-boundary. int padding = length & 1; - this.stream.Skip(padding); + stream.Skip(padding); break; } @@ -630,18 +632,19 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals ///
If first byte is 0, the second byte may have special meaning. ///
Otherwise, the first byte is the length of the run and following three bytes are the color for the run. /// + /// The containing image data. /// The width of the bitmap. /// Buffer for uncompressed data. /// Keeps track of skipped and therefore undefined pixels. /// Keeps track of rows, which have undefined pixels. - private void UncompressRle24(int w, Span buffer, Span undefinedPixels, Span rowsWithUndefinedPixels) + private void UncompressRle24(BufferedReadStream stream, int w, Span buffer, Span undefinedPixels, Span rowsWithUndefinedPixels) { Span cmd = stackalloc byte[2]; int uncompressedPixels = 0; while (uncompressedPixels < buffer.Length) { - if (this.stream.Read(cmd, 0, cmd.Length) != 2) + if (stream.Read(cmd, 0, cmd.Length) != 2) { BmpThrowHelper.ThrowInvalidImageContentException("Failed to read 2 bytes from stream while uncompressing RLE24 bitmap."); } @@ -662,8 +665,8 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals break; case RleDelta: - int dx = this.stream.ReadByte(); - int dy = this.stream.ReadByte(); + int dx = stream.ReadByte(); + int dy = stream.ReadByte(); uncompressedPixels += RleSkipDelta(uncompressedPixels, w, dx, dy, undefinedPixels, rowsWithUndefinedPixels); break; @@ -675,7 +678,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals byte[] run = new byte[length * 3]; - this.stream.Read(run, 0, run.Length); + stream.Read(run, 0, run.Length); run.AsSpan().CopyTo(buffer[(uncompressedPixels * 3)..]); @@ -684,7 +687,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals // Absolute mode data is aligned to two-byte word-boundary. int padding = run.Length & 1; - this.stream.Skip(padding); + stream.Skip(padding); break; } @@ -693,8 +696,8 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals { int max = uncompressedPixels + cmd[0]; byte blueIdx = cmd[1]; - byte greenIdx = (byte)this.stream.ReadByte(); - byte redIdx = (byte)this.stream.ReadByte(); + byte greenIdx = (byte)stream.ReadByte(); + byte redIdx = (byte)stream.ReadByte(); int bufferIdx = uncompressedPixels * 3; for (; uncompressedPixels < max; uncompressedPixels++) @@ -800,6 +803,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// Reads the color palette from the stream. /// /// The pixel format. + /// The containing image data. /// The to assign the palette to. /// The containing the colors. /// The width of the bitmap. @@ -808,7 +812,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// Usually 4 bytes, but in case of Windows 2.x bitmaps or OS/2 1.x bitmaps /// the bytes per color palette entry's can be 3 bytes instead of 4. /// Whether the bitmap is inverted. - private void ReadRgbPalette(Buffer2D pixels, byte[] colors, int width, int height, int bitsPerPixel, int bytesPerColorMapEntry, bool inverted) + private void ReadRgbPalette(BufferedReadStream stream, Buffer2D pixels, byte[] colors, int width, int height, int bitsPerPixel, int bytesPerColorMapEntry, bool inverted) where TPixel : unmanaged, IPixel { // Pixels per byte (bits per pixel). @@ -833,7 +837,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals for (int y = 0; y < height; y++) { int newY = Invert(y, height, inverted); - if (this.stream.Read(rowSpan) == 0) + if (stream.Read(rowSpan) == 0) { BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!"); } @@ -861,6 +865,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// Reads the 16 bit color palette from the stream. /// /// The pixel format. + /// The containing image data. /// The to assign the palette to. /// The width of the bitmap. /// The height of the bitmap. @@ -868,7 +873,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// The bitmask for the red channel. /// The bitmask for the green channel. /// The bitmask for the blue channel. - private void ReadRgb16(Buffer2D pixels, int width, int height, bool inverted, int redMask = DefaultRgb16RMask, int greenMask = DefaultRgb16GMask, int blueMask = DefaultRgb16BMask) + private void ReadRgb16(BufferedReadStream stream, Buffer2D pixels, int width, int height, bool inverted, int redMask = DefaultRgb16RMask, int greenMask = DefaultRgb16GMask, int blueMask = DefaultRgb16BMask) where TPixel : unmanaged, IPixel { int padding = CalculatePadding(width, 2); @@ -889,7 +894,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals for (int y = 0; y < height; y++) { - if (this.stream.Read(bufferSpan) == 0) + if (stream.Read(bufferSpan) == 0) { BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!"); } @@ -935,11 +940,12 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// Reads the 24 bit color palette from the stream. /// /// The pixel format. + /// The containing image data. /// The to assign the palette to. /// The width of the bitmap. /// The height of the bitmap. /// Whether the bitmap is inverted. - private void ReadRgb24(Buffer2D pixels, int width, int height, bool inverted) + private void ReadRgb24(BufferedReadStream stream, Buffer2D pixels, int width, int height, bool inverted) where TPixel : unmanaged, IPixel { int padding = CalculatePadding(width, 3); @@ -948,7 +954,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals for (int y = 0; y < height; y++) { - if (this.stream.Read(rowSpan) == 0) + if (stream.Read(rowSpan) == 0) { BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!"); } @@ -967,11 +973,12 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// Reads the 32 bit color palette from the stream. /// /// The pixel format. + /// The containing image data. /// The to assign the palette to. /// The width of the bitmap. /// The height of the bitmap. /// Whether the bitmap is inverted. - private void ReadRgb32Fast(Buffer2D pixels, int width, int height, bool inverted) + private void ReadRgb32Fast(BufferedReadStream stream, Buffer2D pixels, int width, int height, bool inverted) where TPixel : unmanaged, IPixel { int padding = CalculatePadding(width, 4); @@ -980,7 +987,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals for (int y = 0; y < height; y++) { - if (this.stream.Read(rowSpan) == 0) + if (stream.Read(rowSpan) == 0) { BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!"); } @@ -1000,11 +1007,12 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// This is a special case only used for 32bpp WinBMPv3 files, which could be in either BGR0 or BGRA format. /// /// The pixel format. + /// The containing image data. /// The to assign the palette to. /// The width of the bitmap. /// The height of the bitmap. /// Whether the bitmap is inverted. - private void ReadRgb32Slow(Buffer2D pixels, int width, int height, bool inverted) + private void ReadRgb32Slow(BufferedReadStream stream, Buffer2D pixels, int width, int height, bool inverted) where TPixel : unmanaged, IPixel { int padding = CalculatePadding(width, 4); @@ -1012,7 +1020,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals using IMemoryOwner bgraRow = this.memoryAllocator.Allocate(width); Span rowSpan = row.GetSpan(); Span bgraRowSpan = bgraRow.GetSpan(); - long currentPosition = this.stream.Position; + long currentPosition = stream.Position; bool hasAlpha = false; // Loop though the rows checking each pixel. We start by assuming it's @@ -1020,7 +1028,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals // actually a BGRA image, and change tactics accordingly. for (int y = 0; y < height; y++) { - if (this.stream.Read(rowSpan) == 0) + if (stream.Read(rowSpan) == 0) { BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!"); } @@ -1049,14 +1057,14 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals } // Reset our stream for a second pass. - this.stream.Position = currentPosition; + stream.Position = currentPosition; // Process the pixels in bulk taking the raw alpha component value. if (hasAlpha) { for (int y = 0; y < height; y++) { - if (this.stream.Read(rowSpan) == 0) + if (stream.Read(rowSpan) == 0) { BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!"); } @@ -1077,7 +1085,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals // Slow path. We need to set each alpha component value to fully opaque. for (int y = 0; y < height; y++) { - if (this.stream.Read(rowSpan) == 0) + if (stream.Read(rowSpan) == 0) { BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!"); } @@ -1105,6 +1113,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// Decode an 32 Bit Bitmap containing a bitmask for each color channel. /// /// The pixel format. + /// The containing image data. /// The output pixel buffer containing the decoded image. /// The width of the image. /// The height of the image. @@ -1113,7 +1122,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// The bitmask for the green channel. /// The bitmask for the blue channel. /// The bitmask for the alpha channel. - private void ReadRgb32BitFields(Buffer2D pixels, int width, int height, bool inverted, int redMask, int greenMask, int blueMask, int alphaMask) + private void ReadRgb32BitFields(BufferedReadStream stream, Buffer2D pixels, int width, int height, bool inverted, int redMask, int greenMask, int blueMask, int alphaMask) where TPixel : unmanaged, IPixel { TPixel color = default; @@ -1142,7 +1151,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals for (int y = 0; y < height; y++) { - if (this.stream.Read(bufferSpan) == 0) + if (stream.Read(bufferSpan) == 0) { BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!"); } @@ -1228,10 +1237,13 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// /// Reads the from the stream. /// - private void ReadInfoHeader() + /// The containing image data. + [MemberNotNull(nameof(metadata))] + [MemberNotNull(nameof(bmpMetadata))] + private void ReadInfoHeader(BufferedReadStream stream) { Span buffer = stackalloc byte[BmpInfoHeader.MaxHeaderSize]; - long infoHeaderStart = this.stream.Position; + long infoHeaderStart = stream.Position; // Resolution is stored in PPM. this.metadata = new ImageMetadata @@ -1240,7 +1252,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals }; // Read the header size. - this.stream.Read(buffer, 0, BmpInfoHeader.HeaderSizeSize); + stream.Read(buffer, 0, BmpInfoHeader.HeaderSizeSize); int headerSize = BinaryPrimitives.ReadInt32LittleEndian(buffer); if (headerSize is < BmpInfoHeader.CoreSize or > BmpInfoHeader.MaxHeaderSize) @@ -1249,7 +1261,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals } // Read the rest of the header. - this.stream.Read(buffer, BmpInfoHeader.HeaderSizeSize, headerSize - BmpInfoHeader.HeaderSizeSize); + stream.Read(buffer, BmpInfoHeader.HeaderSizeSize, headerSize - BmpInfoHeader.HeaderSizeSize); BmpInfoHeaderType infoHeaderType = BmpInfoHeaderType.WinVersion2; if (headerSize == BmpInfoHeader.CoreSize) @@ -1275,7 +1287,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals if (this.infoHeader.Compression == BmpCompression.BitFields) { byte[] bitfieldsBuffer = new byte[12]; - this.stream.Read(bitfieldsBuffer, 0, 12); + stream.Read(bitfieldsBuffer, 0, 12); Span data = bitfieldsBuffer.AsSpan(); this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data[..4]); this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)); @@ -1284,7 +1296,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals else if (this.infoHeader.Compression == BmpCompression.BI_ALPHABITFIELDS) { byte[] bitfieldsBuffer = new byte[16]; - this.stream.Read(bitfieldsBuffer, 0, 16); + stream.Read(bitfieldsBuffer, 0, 16); Span data = bitfieldsBuffer.AsSpan(); this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data[..4]); this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)); @@ -1324,12 +1336,12 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals if (this.infoHeader.ProfileData != 0 && this.infoHeader.ProfileSize != 0) { // Read color profile. - long streamPosition = this.stream.Position; + long streamPosition = stream.Position; byte[] iccProfileData = new byte[this.infoHeader.ProfileSize]; - this.stream.Position = infoHeaderStart + this.infoHeader.ProfileData; - this.stream.Read(iccProfileData); + stream.Position = infoHeaderStart + this.infoHeader.ProfileData; + stream.Read(iccProfileData); this.metadata.IccProfile = new IccProfile(iccProfileData); - this.stream.Position = streamPosition; + stream.Position = streamPosition; } } else @@ -1358,10 +1370,11 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// /// Reads the from the stream. /// - private void ReadFileHeader() + /// The containing image data. + private void ReadFileHeader(BufferedReadStream stream) { Span buffer = stackalloc byte[BmpFileHeader.Size]; - this.stream.Read(buffer, 0, BmpFileHeader.Size); + stream.Read(buffer, 0, BmpFileHeader.Size); short fileTypeMarker = BinaryPrimitives.ReadInt16LittleEndian(buffer); switch (fileTypeMarker) @@ -1375,7 +1388,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals // Because we only decode the first bitmap in the array, the array header will be ignored. // The bitmap file header of the first image follows the array header. - this.stream.Read(buffer, 0, BmpFileHeader.Size); + stream.Read(buffer, 0, BmpFileHeader.Size); this.fileHeader = BmpFileHeader.Parse(buffer); if (this.fileHeader.Type != BmpConstants.TypeMarkers.Bitmap) { @@ -1398,12 +1411,12 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals /// The color palette. /// Bytes per color palette entry. Usually 4 bytes, but in case of Windows 2.x bitmaps or OS/2 1.x bitmaps /// the bytes per color palette entry's can be 3 bytes instead of 4. + [MemberNotNull(nameof(metadata))] + [MemberNotNull(nameof(bmpMetadata))] private int ReadImageHeaders(BufferedReadStream stream, out bool inverted, out byte[] palette) { - this.stream = stream; - - this.ReadFileHeader(); - this.ReadInfoHeader(); + this.ReadFileHeader(stream); + this.ReadInfoHeader(stream); // see http://www.drdobbs.com/architecture-and-design/the-bmp-file-format-part-1/184409517 // If the height is negative, then this is a Windows bitmap whose origin @@ -1451,13 +1464,13 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals colorMapSizeBytes = this.infoHeader.ClrUsed * bytesPerColorMapEntry; } - palette = null; + palette = Array.Empty(); if (colorMapSizeBytes > 0) { // Usually the color palette is 1024 byte (256 colors * 4), but the documentation does not mention a size limit. // Make sure, that we will not read pass the bitmap offset (starting position of image data). - if ((this.stream.Position + colorMapSizeBytes) > this.fileHeader.Offset) + if ((stream.Position + colorMapSizeBytes) > this.fileHeader.Offset) { BmpThrowHelper.ThrowInvalidImageContentException( $"Reading the color map would read beyond the bitmap offset. Either the color map size of '{colorMapSizeBytes}' is invalid or the bitmap offset."); @@ -1465,21 +1478,21 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals palette = new byte[colorMapSizeBytes]; - if (this.stream.Read(palette, 0, colorMapSizeBytes) == 0) + if (stream.Read(palette, 0, colorMapSizeBytes) == 0) { BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for the palette!"); } } - int skipAmount = this.fileHeader.Offset - (int)this.stream.Position; - if ((skipAmount + (int)this.stream.Position) > this.stream.Length) + int skipAmount = this.fileHeader.Offset - (int)stream.Position; + if ((skipAmount + (int)stream.Position) > stream.Length) { BmpThrowHelper.ThrowInvalidImageContentException("Invalid file header offset found. Offset is greater than the stream length."); } if (skipAmount > 0) { - this.stream.Skip(skipAmount); + stream.Skip(skipAmount); } return bytesPerColorMapEntry; diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 9f1e85639..0f432fbda 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using System.Buffers; using System.Buffers.Binary; @@ -72,7 +71,7 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals /// /// The global configuration. /// - private Configuration configuration; + private Configuration? configuration; /// /// The color depth, in number of bits per pixel. @@ -142,7 +141,7 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals _ => 0 }; - byte[] iccProfileData = null; + byte[] iccProfileData = Array.Empty(); int iccProfileSize = 0; if (metadata.IccProfile != null) { diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs index abf283e6c..982cc7d46 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs @@ -35,7 +35,7 @@ internal sealed class PaletteDitherProcessor : ImageProcessor ReadOnlySpan sourcePalette = definition.Palette.Span; this.paletteOwner = this.Configuration.MemoryAllocator.Allocate(sourcePalette.Length); - Color.ToPixel(this.Configuration, sourcePalette, this.paletteOwner.Memory.Span); + Color.ToPixel(sourcePalette, this.paletteOwner.Memory.Span); this.ditherProcessor = new DitherProcessor( this.Configuration, diff --git a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs index 9d5b60604..f46cea2e0 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs @@ -21,7 +21,7 @@ public interface IQuantizer /// The to configure internal operations. /// The pixel format. /// The . - IQuantizer CreatePixelSpecificQuantizer(Configuration configuration) + IQuantizer CreatePixelSpecificQuantizer(Configuration? configuration) where TPixel : unmanaged, IPixel; /// @@ -31,6 +31,6 @@ public interface IQuantizer /// The to configure internal operations. /// The options to create the quantizer with. /// The . - IQuantizer CreatePixelSpecificQuantizer(Configuration configuration, QuantizerOptions options) + IQuantizer CreatePixelSpecificQuantizer(Configuration? configuration, QuantizerOptions options) where TPixel : unmanaged, IPixel; } diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs index 0a1032bf0..0d2450e22 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs @@ -34,12 +34,12 @@ public class OctreeQuantizer : IQuantizer public QuantizerOptions Options { get; } /// - public IQuantizer CreatePixelSpecificQuantizer(Configuration configuration) + public IQuantizer CreatePixelSpecificQuantizer(Configuration? configuration) where TPixel : unmanaged, IPixel => this.CreatePixelSpecificQuantizer(configuration, this.Options); /// - public IQuantizer CreatePixelSpecificQuantizer(Configuration configuration, QuantizerOptions options) + public IQuantizer CreatePixelSpecificQuantizer(Configuration? configuration, QuantizerOptions options) where TPixel : unmanaged, IPixel => new OctreeQuantizer(configuration, options); } diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs index d66a38d80..37ebc39ba 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs @@ -38,7 +38,7 @@ public struct OctreeQuantizer : IQuantizer /// The configuration which allows altering default behaviour or extending the library. /// The quantizer options defining quantization rules. [MethodImpl(InliningOptions.ShortMethod)] - public OctreeQuantizer(Configuration configuration, QuantizerOptions options) + public OctreeQuantizer(Configuration? configuration, QuantizerOptions options) { Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(options, nameof(options)); diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index f3ed39c95..c5617fe86 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -39,19 +39,19 @@ public class PaletteQuantizer : IQuantizer public QuantizerOptions Options { get; } /// - public IQuantizer CreatePixelSpecificQuantizer(Configuration configuration) + public IQuantizer CreatePixelSpecificQuantizer(Configuration? configuration) where TPixel : unmanaged, IPixel => this.CreatePixelSpecificQuantizer(configuration, this.Options); /// - public IQuantizer CreatePixelSpecificQuantizer(Configuration configuration, QuantizerOptions options) + public IQuantizer CreatePixelSpecificQuantizer(Configuration? configuration, QuantizerOptions options) where TPixel : unmanaged, IPixel { Guard.NotNull(options, nameof(options)); // Always use the palette length over options since the palette cannot be reduced. TPixel[] palette = new TPixel[this.colorPalette.Length]; - Color.ToPixel(configuration, this.colorPalette.Span, palette.AsSpan()); + Color.ToPixel(this.colorPalette.Span, palette.AsSpan()); return new PaletteQuantizer(configuration, options, palette); } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs index ea7413aab..182bed238 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -29,7 +29,7 @@ internal struct PaletteQuantizer : IQuantizer /// The quantizer options defining quantization rules. /// The palette to use. [MethodImpl(InliningOptions.ShortMethod)] - public PaletteQuantizer(Configuration configuration, QuantizerOptions options, ReadOnlyMemory palette) + public PaletteQuantizer(Configuration? configuration, QuantizerOptions options, ReadOnlyMemory palette) { Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(options, nameof(options)); diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs index 86d798d96..dff915540 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs @@ -33,12 +33,12 @@ public class WuQuantizer : IQuantizer public QuantizerOptions Options { get; } /// - public IQuantizer CreatePixelSpecificQuantizer(Configuration configuration) + public IQuantizer CreatePixelSpecificQuantizer(Configuration? configuration) where TPixel : unmanaged, IPixel => this.CreatePixelSpecificQuantizer(configuration, this.Options); /// - public IQuantizer CreatePixelSpecificQuantizer(Configuration configuration, QuantizerOptions options) + public IQuantizer CreatePixelSpecificQuantizer(Configuration? configuration, QuantizerOptions options) where TPixel : unmanaged, IPixel => new WuQuantizer(configuration, options); } diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs index 0119558bf..c04dbe191 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs @@ -85,7 +85,7 @@ internal struct WuQuantizer : IQuantizer /// The configuration which allows altering default behaviour or extending the library. /// The quantizer options defining quantization rules. [MethodImpl(InliningOptions.ShortMethod)] - public WuQuantizer(Configuration configuration, QuantizerOptions options) + public WuQuantizer(Configuration? configuration, QuantizerOptions options) { Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(options, nameof(options));