mirror of https://github.com/SixLabors/ImageSharp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
281 lines
14 KiB
281 lines
14 KiB
// Copyright (c) Six Labors.
|
|
// Licensed under the Apache License, Version 2.0.
|
|
|
|
using System.IO;
|
|
|
|
using SixLabors.ImageSharp.Formats;
|
|
using SixLabors.ImageSharp.Formats.Bmp;
|
|
using SixLabors.ImageSharp.Metadata;
|
|
using SixLabors.ImageSharp.PixelFormats;
|
|
using SixLabors.ImageSharp.Processing;
|
|
using SixLabors.ImageSharp.Processing.Processors.Quantization;
|
|
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
|
|
|
|
using Xunit;
|
|
using Xunit.Abstractions;
|
|
|
|
// ReSharper disable InconsistentNaming
|
|
namespace SixLabors.ImageSharp.Tests.Formats.Bmp
|
|
{
|
|
using static TestImages.Bmp;
|
|
|
|
public class BmpEncoderTests
|
|
{
|
|
public static readonly TheoryData<BmpBitsPerPixel> BitsPerPixel =
|
|
new TheoryData<BmpBitsPerPixel>
|
|
{
|
|
BmpBitsPerPixel.Pixel24,
|
|
BmpBitsPerPixel.Pixel32
|
|
};
|
|
|
|
public static readonly TheoryData<string, int, int, PixelResolutionUnit> RatioFiles =
|
|
new TheoryData<string, int, int, PixelResolutionUnit>
|
|
{
|
|
{ Car, 3780, 3780, PixelResolutionUnit.PixelsPerMeter },
|
|
{ V5Header, 3780, 3780, PixelResolutionUnit.PixelsPerMeter },
|
|
{ RLE8, 2835, 2835, PixelResolutionUnit.PixelsPerMeter }
|
|
};
|
|
|
|
public static readonly TheoryData<string, BmpBitsPerPixel> BmpBitsPerPixelFiles =
|
|
new TheoryData<string, BmpBitsPerPixel>
|
|
{
|
|
{ Car, BmpBitsPerPixel.Pixel24 },
|
|
{ Bit32Rgb, BmpBitsPerPixel.Pixel32 }
|
|
};
|
|
|
|
public BmpEncoderTests(ITestOutputHelper output) => this.Output = output;
|
|
|
|
private ITestOutputHelper Output { get; }
|
|
|
|
[Theory]
|
|
[MemberData(nameof(RatioFiles))]
|
|
public void Encode_PreserveRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit)
|
|
{
|
|
var options = new BmpEncoder();
|
|
|
|
var testFile = TestFile.Create(imagePath);
|
|
using (Image<Rgba32> input = testFile.CreateRgba32Image())
|
|
{
|
|
using (var memStream = new MemoryStream())
|
|
{
|
|
input.Save(memStream, options);
|
|
|
|
memStream.Position = 0;
|
|
using (var output = Image.Load<Rgba32>(memStream))
|
|
{
|
|
ImageMetadata meta = output.Metadata;
|
|
Assert.Equal(xResolution, meta.HorizontalResolution);
|
|
Assert.Equal(yResolution, meta.VerticalResolution);
|
|
Assert.Equal(resolutionUnit, meta.ResolutionUnits);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[MemberData(nameof(BmpBitsPerPixelFiles))]
|
|
public void Encode_PreserveBitsPerPixel(string imagePath, BmpBitsPerPixel bmpBitsPerPixel)
|
|
{
|
|
var options = new BmpEncoder();
|
|
|
|
var testFile = TestFile.Create(imagePath);
|
|
using (Image<Rgba32> input = testFile.CreateRgba32Image())
|
|
{
|
|
using (var memStream = new MemoryStream())
|
|
{
|
|
input.Save(memStream, options);
|
|
|
|
memStream.Position = 0;
|
|
using (var output = Image.Load<Rgba32>(memStream))
|
|
{
|
|
BmpMetadata meta = output.Metadata.GetBmpMetadata();
|
|
|
|
Assert.Equal(bmpBitsPerPixel, meta.BitsPerPixel);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[WithTestPatternImages(nameof(BitsPerPixel), 24, 24, PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.Rgb24)]
|
|
public void Encode_IsNotBoundToSinglePixelType<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
|
|
where TPixel : unmanaged, IPixel<TPixel> => TestBmpEncoderCore(provider, bitsPerPixel);
|
|
|
|
[Theory]
|
|
[WithTestPatternImages(nameof(BitsPerPixel), 48, 24, PixelTypes.Rgba32)]
|
|
[WithTestPatternImages(nameof(BitsPerPixel), 47, 8, PixelTypes.Rgba32)]
|
|
[WithTestPatternImages(nameof(BitsPerPixel), 49, 7, PixelTypes.Rgba32)]
|
|
[WithSolidFilledImages(nameof(BitsPerPixel), 1, 1, 255, 100, 50, 255, PixelTypes.Rgba32)]
|
|
[WithTestPatternImages(nameof(BitsPerPixel), 7, 5, PixelTypes.Rgba32)]
|
|
public void Encode_WorksWithDifferentSizes<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
|
|
where TPixel : unmanaged, IPixel<TPixel> => TestBmpEncoderCore(provider, bitsPerPixel);
|
|
|
|
[Theory]
|
|
[WithFile(Bit32Rgb, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)]
|
|
[WithFile(Bit32Rgba, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)]
|
|
[WithFile(WinBmpv4, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)]
|
|
[WithFile(WinBmpv5, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)]
|
|
public void Encode_32Bit_WithV3Header_Works<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
|
|
|
|
// If supportTransparency is false, a v3 bitmap header will be written.
|
|
where TPixel : unmanaged, IPixel<TPixel> => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: false);
|
|
|
|
[Theory]
|
|
[WithFile(Bit32Rgb, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)]
|
|
[WithFile(Bit32Rgba, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)]
|
|
[WithFile(WinBmpv4, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)]
|
|
[WithFile(WinBmpv5, PixelTypes.Rgba32 | PixelTypes.Rgb24, BmpBitsPerPixel.Pixel32)]
|
|
public void Encode_32Bit_WithV4Header_Works<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
|
|
where TPixel : unmanaged, IPixel<TPixel> => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true);
|
|
|
|
[Theory]
|
|
[WithFile(WinBmpv3, PixelTypes.Rgb24, BmpBitsPerPixel.Pixel24)] // WinBmpv3 is a 24 bits per pixel image.
|
|
[WithFile(F, PixelTypes.Rgb24, BmpBitsPerPixel.Pixel24)]
|
|
public void Encode_24Bit_WithV3Header_Works<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
|
|
where TPixel : unmanaged, IPixel<TPixel> => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: false);
|
|
|
|
[Theory]
|
|
[WithFile(WinBmpv3, PixelTypes.Rgb24, BmpBitsPerPixel.Pixel24)]
|
|
[WithFile(F, PixelTypes.Rgb24, BmpBitsPerPixel.Pixel24)]
|
|
public void Encode_24Bit_WithV4Header_Works<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
|
|
where TPixel : unmanaged, IPixel<TPixel> => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true);
|
|
|
|
[Theory]
|
|
[WithFile(Rgb16, PixelTypes.Bgra5551, BmpBitsPerPixel.Pixel16)]
|
|
[WithFile(Bit16, PixelTypes.Bgra5551, BmpBitsPerPixel.Pixel16)]
|
|
public void Encode_16Bit_WithV3Header_Works<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
|
|
where TPixel : unmanaged, IPixel<TPixel> => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: false);
|
|
|
|
[Theory]
|
|
[WithFile(Rgb16, PixelTypes.Bgra5551, BmpBitsPerPixel.Pixel16)]
|
|
[WithFile(Bit16, PixelTypes.Bgra5551, BmpBitsPerPixel.Pixel16)]
|
|
public void Encode_16Bit_WithV4Header_Works<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
|
|
where TPixel : unmanaged, IPixel<TPixel> => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true);
|
|
|
|
[ActiveIssue("https://github.com/SixLabors/ImageSharp/issues/1380", TestPlatforms.Linux)]
|
|
[Theory]
|
|
[WithFile(WinBmpv5, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel8)]
|
|
[WithFile(Bit8Palette4, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel8)]
|
|
public void Encode_8Bit_WithV3Header_Works<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
|
|
where TPixel : unmanaged, IPixel<TPixel> => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: false);
|
|
|
|
[ActiveIssue("https://github.com/SixLabors/ImageSharp/issues/1380", TestPlatforms.Linux)]
|
|
[Theory]
|
|
[WithFile(WinBmpv5, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel8)]
|
|
[WithFile(Bit8Palette4, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel8)]
|
|
public void Encode_8Bit_WithV4Header_Works<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
|
|
where TPixel : unmanaged, IPixel<TPixel> => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true);
|
|
|
|
[ActiveIssue("https://github.com/SixLabors/ImageSharp/issues/1380", TestPlatforms.Linux)]
|
|
[Theory]
|
|
[WithFile(Bit8Gs, PixelTypes.L8, BmpBitsPerPixel.Pixel8)]
|
|
public void Encode_8BitGray_WithV3Header_Works<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
|
|
where TPixel : unmanaged, IPixel<TPixel> =>
|
|
TestBmpEncoderCore(
|
|
provider,
|
|
bitsPerPixel,
|
|
supportTransparency: false);
|
|
|
|
[ActiveIssue("https://github.com/SixLabors/ImageSharp/issues/1380", TestPlatforms.Linux)]
|
|
[Theory]
|
|
[WithFile(Bit8Gs, PixelTypes.L8, BmpBitsPerPixel.Pixel8)]
|
|
public void Encode_8BitGray_WithV4Header_Works<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
|
|
where TPixel : unmanaged, IPixel<TPixel> =>
|
|
TestBmpEncoderCore(
|
|
provider,
|
|
bitsPerPixel,
|
|
supportTransparency: true);
|
|
|
|
[ActiveIssue("https://github.com/SixLabors/ImageSharp/issues/1380", TestPlatforms.Linux)]
|
|
[Theory]
|
|
[WithFile(Bit32Rgb, PixelTypes.Rgba32)]
|
|
public void Encode_8BitColor_WithWuQuantizer<TPixel>(TestImageProvider<TPixel> provider)
|
|
where TPixel : unmanaged, IPixel<TPixel>
|
|
{
|
|
if (!TestEnvironment.Is64BitProcess)
|
|
{
|
|
return;
|
|
}
|
|
|
|
using (Image<TPixel> image = provider.GetImage())
|
|
{
|
|
var encoder = new BmpEncoder
|
|
{
|
|
BitsPerPixel = BmpBitsPerPixel.Pixel8,
|
|
Quantizer = new WuQuantizer()
|
|
};
|
|
string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "bmp", encoder, appendPixelTypeToFileName: false);
|
|
IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile);
|
|
using (var referenceImage = Image.Load<TPixel>(actualOutputFile, referenceDecoder))
|
|
{
|
|
referenceImage.CompareToReferenceOutput(ImageComparer.TolerantPercentage(0.01f), provider, extension: "bmp", appendPixelTypeToFileName: false);
|
|
}
|
|
}
|
|
}
|
|
|
|
[ActiveIssue("https://github.com/SixLabors/ImageSharp/issues/1380", TestPlatforms.Linux)]
|
|
[Theory]
|
|
[WithFile(Bit32Rgb, PixelTypes.Rgba32)]
|
|
public void Encode_8BitColor_WithOctreeQuantizer<TPixel>(TestImageProvider<TPixel> provider)
|
|
where TPixel : unmanaged, IPixel<TPixel>
|
|
{
|
|
if (!TestEnvironment.Is64BitProcess)
|
|
{
|
|
return;
|
|
}
|
|
|
|
using (Image<TPixel> image = provider.GetImage())
|
|
{
|
|
var encoder = new BmpEncoder
|
|
{
|
|
BitsPerPixel = BmpBitsPerPixel.Pixel8,
|
|
Quantizer = new OctreeQuantizer()
|
|
};
|
|
string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "bmp", encoder, appendPixelTypeToFileName: false);
|
|
IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile);
|
|
using (var referenceImage = Image.Load<TPixel>(actualOutputFile, referenceDecoder))
|
|
{
|
|
referenceImage.CompareToReferenceOutput(ImageComparer.TolerantPercentage(0.01f), provider, extension: "bmp", appendPixelTypeToFileName: false);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[WithFile(TestImages.Png.GrayAlpha2BitInterlaced, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel32)]
|
|
[WithFile(Bit32Rgba, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel32)]
|
|
public void Encode_PreservesAlpha<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
|
|
where TPixel : unmanaged, IPixel<TPixel> => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true);
|
|
|
|
[Theory]
|
|
[WithFile(Car, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel32)]
|
|
[WithFile(V5Header, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel32)]
|
|
public void Encode_WorksWithDiscontiguousBuffers<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
|
|
where TPixel : unmanaged, IPixel<TPixel>
|
|
{
|
|
provider.LimitAllocatorBufferCapacity().InBytesSqrt(100);
|
|
TestBmpEncoderCore(provider, bitsPerPixel);
|
|
}
|
|
|
|
private static void TestBmpEncoderCore<TPixel>(
|
|
TestImageProvider<TPixel> provider,
|
|
BmpBitsPerPixel bitsPerPixel,
|
|
bool supportTransparency = true,
|
|
ImageComparer customComparer = null)
|
|
where TPixel : unmanaged, IPixel<TPixel>
|
|
{
|
|
using (Image<TPixel> image = provider.GetImage())
|
|
{
|
|
// There is no alpha in bmp with less then 32 bits per pixels, so the reference image will be made opaque.
|
|
if (bitsPerPixel != BmpBitsPerPixel.Pixel32)
|
|
{
|
|
image.Mutate(c => c.MakeOpaque());
|
|
}
|
|
|
|
var encoder = new BmpEncoder { BitsPerPixel = bitsPerPixel, SupportTransparency = supportTransparency };
|
|
|
|
// Does DebugSave & load reference CompareToReferenceInput():
|
|
image.VerifyEncoder(provider, "bmp", bitsPerPixel, encoder, customComparer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|