Skip to content

Commit

Permalink
Add color profile tests
Browse files Browse the repository at this point in the history
  • Loading branch information
brianpopow committed May 7, 2022
1 parent 106f6c0 commit 5388489
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 9 deletions.
13 changes: 7 additions & 6 deletions src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
this.WriteBitmapFileHeader(stream, infoHeaderSize, colorPaletteSize, iccProfileSize, infoHeader, buffer);
this.WriteBitmapInfoHeader(stream, infoHeader, buffer, infoHeaderSize);
this.WriteImage(stream, image.Frames.RootFrame);
this.WriteColorProfile(stream, metadata, buffer);
this.WriteColorProfile(stream, iccProfileData, buffer);

stream.Flush();
}
Expand Down Expand Up @@ -246,14 +246,15 @@ private BmpInfoHeader CreateBmpInfoHeader(int width, int height, int infoHeaderS
/// Writes the color profile to the stream.
/// </summary>
/// <param name="stream">The stream to write to.</param>
/// <param name="metadata">The metadata.</param>
/// <param name="iccProfileData">The color profile data.</param>
/// <param name="buffer">The buffer.</param>
private void WriteColorProfile(Stream stream, ImageMetadata metadata, Span<byte> buffer)
private void WriteColorProfile(Stream stream, byte[] iccProfileData, Span<byte> buffer)
{
if (metadata.IccProfile != null)
if (iccProfileData != null)
{
int streamPositionAfterImageData = (int)stream.Position;
stream.Write(metadata.IccProfile.ToByteArray());
// The offset, in bytes, from the beginning of the BITMAPV5HEADER structure to the start of the profile data.
int streamPositionAfterImageData = (int)stream.Position - BmpFileHeader.Size;
stream.Write(iccProfileData);
BinaryPrimitives.WriteInt32LittleEndian(buffer, streamPositionAfterImageData);
stream.Position = BmpFileHeader.Size + 112;
stream.Write(buffer.Slice(0, 4));
Expand Down
4 changes: 2 additions & 2 deletions tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ public class BmpDecoderTests

public static readonly string[] BitfieldsBmpFiles = BitFields;

private static BmpDecoder BmpDecoder => new BmpDecoder();
private static BmpDecoder BmpDecoder => new();

public static readonly TheoryData<string, int, int, PixelResolutionUnit> RatioFiles =
new TheoryData<string, int, int, PixelResolutionUnit>
new()
{
{ Car, 3780, 3780, PixelResolutionUnit.PixelsPerMeter },
{ V5Header, 3780, 3780, PixelResolutionUnit.PixelsPerMeter },
Expand Down
27 changes: 27 additions & 0 deletions tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,33 @@ public void Encode_8BitColor_WithOctreeQuantizer<TPixel>(TestImageProvider<TPixe
public void Encode_PreservesAlpha<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
where TPixel : unmanaged, IPixel<TPixel> => TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true);

[Theory]
[WithFile(IccProfile, PixelTypes.Rgba32)]
public void Encode_PreservesColorProfile<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> input = provider.GetImage(new BmpDecoder()))
{
ImageSharp.Metadata.Profiles.Icc.IccProfile expectedProfile = input.Metadata.IccProfile;
byte[] expectedProfileBytes = expectedProfile.ToByteArray();

using (var memStream = new MemoryStream())
{
input.Save(memStream, new BmpEncoder());

memStream.Position = 0;
using (var output = Image.Load<Rgba32>(memStream))
{
ImageSharp.Metadata.Profiles.Icc.IccProfile actualProfile = output.Metadata.IccProfile;
byte[] actualProfileBytes = actualProfile.ToByteArray();

Assert.NotNull(actualProfile);
Assert.Equal(expectedProfileBytes, actualProfileBytes);
}
}
}
}

[Theory]
[WithFile(Car, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel32)]
[WithFile(V5Header, PixelTypes.Rgba32, BmpBitsPerPixel.Pixel32)]
Expand Down
16 changes: 15 additions & 1 deletion tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

using System.IO;
using SixLabors.ImageSharp.Formats.Bmp;

using SixLabors.ImageSharp.PixelFormats;
using Xunit;
using static SixLabors.ImageSharp.Tests.TestImages.Bmp;

Expand Down Expand Up @@ -47,5 +47,19 @@ public void Identify_DetectsCorrectBitmapInfoHeaderType(string imagePath, BmpInf
Assert.Equal(expectedInfoHeaderType, bitmapMetadata.InfoHeaderType);
}
}

[Theory]
[WithFile(IccProfile, PixelTypes.Rgba32)]
public void Decoder_CanReadColorProfile<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(new BmpDecoder()))
{
ImageSharp.Metadata.ImageMetadata metaData = image.Metadata;
Assert.NotNull(metaData);
Assert.NotNull(metaData.IccProfile);
Assert.Equal(16, metaData.IccProfile.Entries.Length);
}
}
}
}
1 change: 1 addition & 0 deletions tests/ImageSharp.Tests/TestImages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ public static class Bmp
public const string Rgb24jpeg = "Bmp/rgb24jpeg.bmp";
public const string Rgb24png = "Bmp/rgb24png.bmp";
public const string Rgba32v4 = "Bmp/rgba32v4.bmp";
public const string IccProfile = "Bmp/BMP_v5_with_ICC_2.bmp";

// Bitmap images with compression type BITFIELDS.
public const string Rgb32bfdef = "Bmp/rgb32bfdef.bmp";
Expand Down
3 changes: 3 additions & 0 deletions tests/Images/Input/Bmp/BMP_v5_with_ICC_2.bmp
Git LFS file not shown

0 comments on commit 5388489

Please sign in to comment.