@@ -453,6 +453,7 @@ private void ReadRle24<TPixel>(BufferedReadStream stream, Buffer2D<TPixel> pixel
453453 /// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param>
454454 private void UncompressRle4 ( BufferedReadStream stream , int w , Span < byte > buffer , Span < bool > undefinedPixels , Span < bool > rowsWithUndefinedPixels )
455455 {
456+ Span < byte > scratchBuffer = stackalloc byte [ 128 ] ;
456457 Span < byte > cmd = stackalloc byte [ 2 ] ;
457458 int count = 0 ;
458459
@@ -491,9 +492,9 @@ private void UncompressRle4(BufferedReadStream stream, int w, Span<byte> buffer,
491492 int max = cmd [ 1 ] ;
492493 int bytesToRead = ( int ) ( ( ( uint ) max + 1 ) / 2 ) ;
493494
494- byte [ ] run = new byte [ bytesToRead ] ;
495+ Span < byte > run = bytesToRead <= 128 ? scratchBuffer . Slice ( 0 , bytesToRead ) : new byte [ bytesToRead ] ;
495496
496- stream . Read ( run , 0 , run . Length ) ;
497+ stream . Read ( run ) ;
497498
498499 int idx = 0 ;
499500 for ( int i = 0 ; i < max ; i ++ )
@@ -559,6 +560,7 @@ private void UncompressRle4(BufferedReadStream stream, int w, Span<byte> buffer,
559560 /// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param>
560561 private void UncompressRle8 ( BufferedReadStream stream , int w , Span < byte > buffer , Span < bool > undefinedPixels , Span < bool > rowsWithUndefinedPixels )
561562 {
563+ Span < byte > scratchBuffer = stackalloc byte [ 128 ] ;
562564 Span < byte > cmd = stackalloc byte [ 2 ] ;
563565 int count = 0 ;
564566
@@ -596,13 +598,13 @@ private void UncompressRle8(BufferedReadStream stream, int w, Span<byte> buffer,
596598 // Take this number of bytes from the stream as uncompressed data.
597599 int length = cmd [ 1 ] ;
598600
599- byte [ ] run = new byte [ length ] ;
601+ Span < byte > run = length <= 128 ? scratchBuffer . Slice ( 0 , length ) : new byte [ length ] ;
600602
601- stream . Read ( run , 0 , run . Length ) ;
603+ stream . Read ( run ) ;
602604
603- run . AsSpan ( ) . CopyTo ( buffer [ count ..] ) ;
605+ run . CopyTo ( buffer [ count ..] ) ;
604606
605- count += run . Length ;
607+ count += length ;
606608
607609 // Absolute mode data is aligned to two-byte word-boundary.
608610 int padding = length & 1 ;
@@ -639,6 +641,7 @@ private void UncompressRle8(BufferedReadStream stream, int w, Span<byte> buffer,
639641 /// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param>
640642 private void UncompressRle24 ( BufferedReadStream stream , int w , Span < byte > buffer , Span < bool > undefinedPixels , Span < bool > rowsWithUndefinedPixels )
641643 {
644+ Span < byte > scratchBuffer = stackalloc byte [ 128 ] ;
642645 Span < byte > cmd = stackalloc byte [ 2 ] ;
643646 int uncompressedPixels = 0 ;
644647
@@ -675,17 +678,18 @@ private void UncompressRle24(BufferedReadStream stream, int w, Span<byte> buffer
675678 // If the second byte > 2, we are in 'absolute mode'.
676679 // Take this number of bytes from the stream as uncompressed data.
677680 int length = cmd [ 1 ] ;
681+ int length3 = length * 3 ;
678682
679- byte [ ] run = new byte [ length * 3 ] ;
683+ Span < byte > run = length3 <= 128 ? scratchBuffer . Slice ( 0 , length3 ) : new byte [ length3 ] ;
680684
681- stream . Read ( run , 0 , run . Length ) ;
685+ stream . Read ( run ) ;
682686
683- run . AsSpan ( ) . CopyTo ( buffer [ ( uncompressedPixels * 3 ) ..] ) ;
687+ run . CopyTo ( buffer [ ( uncompressedPixels * 3 ) ..] ) ;
684688
685689 uncompressedPixels += length ;
686690
687691 // Absolute mode data is aligned to two-byte word-boundary.
688- int padding = run . Length & 1 ;
692+ int padding = length3 & 1 ;
689693
690694 stream . Skip ( padding ) ;
691695
@@ -1286,18 +1290,18 @@ private void ReadInfoHeader(BufferedReadStream stream)
12861290 // color masks for each color channel follow the info header.
12871291 if ( this . infoHeader . Compression == BmpCompression . BitFields )
12881292 {
1289- byte [ ] bitfieldsBuffer = new byte [ 12 ] ;
1290- stream . Read ( bitfieldsBuffer , 0 , 12 ) ;
1291- Span < byte > data = bitfieldsBuffer . AsSpan ( ) ;
1293+ Span < byte > bitfieldsBuffer = stackalloc byte [ 12 ] ;
1294+ stream . Read ( bitfieldsBuffer ) ;
1295+ Span < byte > data = bitfieldsBuffer ;
12921296 this . infoHeader . RedMask = BinaryPrimitives . ReadInt32LittleEndian ( data [ ..4 ] ) ;
12931297 this . infoHeader . GreenMask = BinaryPrimitives . ReadInt32LittleEndian ( data . Slice ( 4 , 4 ) ) ;
12941298 this . infoHeader . BlueMask = BinaryPrimitives . ReadInt32LittleEndian ( data . Slice ( 8 , 4 ) ) ;
12951299 }
12961300 else if ( this . infoHeader . Compression == BmpCompression . BI_ALPHABITFIELDS )
12971301 {
1298- byte [ ] bitfieldsBuffer = new byte [ 16 ] ;
1299- stream . Read ( bitfieldsBuffer , 0 , 16 ) ;
1300- Span < byte > data = bitfieldsBuffer . AsSpan ( ) ;
1302+ Span < byte > bitfieldsBuffer = stackalloc byte [ 16 ] ;
1303+ stream . Read ( bitfieldsBuffer ) ;
1304+ Span < byte > data = bitfieldsBuffer ;
13011305 this . infoHeader . RedMask = BinaryPrimitives . ReadInt32LittleEndian ( data [ ..4 ] ) ;
13021306 this . infoHeader . GreenMask = BinaryPrimitives . ReadInt32LittleEndian ( data . Slice ( 4 , 4 ) ) ;
13031307 this . infoHeader . BlueMask = BinaryPrimitives . ReadInt32LittleEndian ( data . Slice ( 8 , 4 ) ) ;
@@ -1470,7 +1474,7 @@ private int ReadImageHeaders(BufferedReadStream stream, out bool inverted, out b
14701474 {
14711475 // Usually the color palette is 1024 byte (256 colors * 4), but the documentation does not mention a size limit.
14721476 // Make sure, that we will not read pass the bitmap offset (starting position of image data).
1473- if ( ( stream . Position + colorMapSizeBytes ) > this . fileHeader . Offset )
1477+ if ( stream . Position > this . fileHeader . Offset - colorMapSizeBytes )
14741478 {
14751479 BmpThrowHelper . ThrowInvalidImageContentException (
14761480 $ "Reading the color map would read beyond the bitmap offset. Either the color map size of '{ colorMapSizeBytes } ' is invalid or the bitmap offset.") ;
0 commit comments