Skip to content

Commit 6fcfe09

Browse files
brianpopowJimBobSquarePants
authored andcommitted
Feature: Bitmap RLE undefined pixel handling (#927)
* Add bitmap decoder option, how to treat skipped pixels for RLE * Refactored bitmap tests into smaller tests, instead of just one test which goes through all bitmap files * Add another adobe v3 header bitmap testcase * Using the constant from BmpConstants to Identify bitmaps * Bitmap decoder now can handle oversized palette's * Add test for invalid palette size * Renamed RleUndefinedPixelHandling to RleSkippedPixelHandling * Explicitly using SystemDrawingReferenceDecoder in some BitmapDecoder tests * Add test cases for unsupported bitmaps * Comparing RLE test images to reference decoder only on windows * Add test case for decoding winv4 fast path * Add another 8 Bit RLE test with magick reference decoder * Optimize RLE skipped pixel handling * Refactor RLE decoding to eliminate code duplication * Using MagickReferenceDecoder for the 8-Bit RLE test
1 parent b6883c1 commit 6fcfe09

24 files changed

+495
-85
lines changed

src/ImageSharp/Formats/Bmp/BmpDecoder.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@ namespace SixLabors.ImageSharp.Formats.Bmp
1414
/// <list type="bullet">
1515
/// <item>JPG</item>
1616
/// <item>PNG</item>
17-
/// <item>RLE4</item>
17+
/// <item>Some OS/2 specific subtypes like: Bitmap Array, Color Icon, Color Pointer, Icon, Pointer.</item>
1818
/// </list>
1919
/// Formats will be supported in a later releases. We advise always
2020
/// to use only 24 Bit Windows bitmaps.
2121
/// </remarks>
2222
public sealed class BmpDecoder : IImageDecoder, IBmpDecoderOptions, IImageInfoDetector
2323
{
24+
/// <summary>
25+
/// Gets or sets a value indicating how to deal with skipped pixels, which can occur during decoding run length encoded bitmaps.
26+
/// </summary>
27+
public RleSkippedPixelHandling RleSkippedPixelHandling { get; set; } = RleSkippedPixelHandling.Black;
28+
2429
/// <inheritdoc/>
2530
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
2631
where TPixel : struct, IPixel<TPixel>

src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

Lines changed: 191 additions & 49 deletions
Large diffs are not rendered by default.

src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,19 @@ internal sealed class BmpEncoderCore
5151
/// </summary>
5252
private const int ColorPaletteSize8Bit = 1024;
5353

54+
/// <summary>
55+
/// Used for allocating memory during processing operations.
56+
/// </summary>
5457
private readonly MemoryAllocator memoryAllocator;
5558

59+
/// <summary>
60+
/// The global configuration.
61+
/// </summary>
5662
private Configuration configuration;
5763

64+
/// <summary>
65+
/// The color depth, in number of bits per pixel.
66+
/// </summary>
5867
private BmpBitsPerPixel? bitsPerPixel;
5968

6069
/// <summary>

src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0.
33

44
using System;
5+
using System.Buffers.Binary;
56

67
namespace SixLabors.ImageSharp.Formats.Bmp
78
{
@@ -21,10 +22,7 @@ public IImageFormat DetectFormat(ReadOnlySpan<byte> header)
2122

2223
private bool IsSupportedFileFormat(ReadOnlySpan<byte> header)
2324
{
24-
// TODO: This should be in constants
25-
return header.Length >= this.HeaderSize
26-
&& header[0] == 0x42 // B
27-
&& header[1] == 0x4D; // M
25+
return header.Length >= this.HeaderSize && BinaryPrimitives.ReadInt16LittleEndian(header) == BmpConstants.TypeMarkers.Bitmap;
2826
}
2927
}
3028
}

src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp
88
/// </summary>
99
internal interface IBmpDecoderOptions
1010
{
11-
// added this for consistency so we can add stuff as required, no options currently available
11+
/// <summary>
12+
/// Gets the value indicating how to deal with skipped pixels, which can occur during decoding run length encoded bitmaps.
13+
/// </summary>
14+
RleSkippedPixelHandling RleSkippedPixelHandling { get; }
1215
}
1316
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) Six Labors and contributors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
namespace SixLabors.ImageSharp.Formats.Bmp
5+
{
6+
/// <summary>
7+
/// Defines possible options, how skipped pixels during decoding of run length encoded bitmaps should be treated.
8+
/// </summary>
9+
public enum RleSkippedPixelHandling : int
10+
{
11+
/// <summary>
12+
/// Undefined pixels should be black. This is the default behavior and equal to how System.Drawing handles undefined pixels.
13+
/// </summary>
14+
Black = 0,
15+
16+
/// <summary>
17+
/// Undefined pixels should be transparent.
18+
/// </summary>
19+
Transparent = 1,
20+
21+
/// <summary>
22+
/// Undefined pixels should have the first color of the palette.
23+
/// </summary>
24+
FirstColorOfPalette = 2
25+
}
26+
}

tests/ImageSharp.Tests/FileTestBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public abstract class FileTestBase
2828
/// <summary>
2929
/// A collection of all the bmp test images
3030
/// </summary>
31-
public static IEnumerable<string> AllBmpFiles = TestImages.Bmp.All;
31+
public static IEnumerable<string> AllBmpFiles = TestImages.Bmp.Benchmark;
3232

3333
/// <summary>
3434
/// A collection of all the jpeg test images

0 commit comments

Comments
 (0)