mirror of https://github.com/SixLabors/ImageSharp
6 changed files with 228 additions and 6 deletions
@ -0,0 +1,51 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.IO; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
using ImageMagick; |
||||
|
|
||||
|
using SixLabors.ImageSharp.Advanced; |
||||
|
using SixLabors.ImageSharp.Formats; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs |
||||
|
{ |
||||
|
public class MagickReferenceDecoder : IImageDecoder |
||||
|
{ |
||||
|
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream) |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
using (var magickImage = new MagickImage(stream)) |
||||
|
{ |
||||
|
var result = new Image<TPixel>(configuration, magickImage.Width, magickImage.Height); |
||||
|
Span<TPixel> resultPixels = result.GetPixelSpan(); |
||||
|
|
||||
|
using (IPixelCollection pixels = magickImage.GetPixelsUnsafe()) |
||||
|
{ |
||||
|
if (magickImage.Depth == 8) |
||||
|
{ |
||||
|
byte[] data = pixels.ToByteArray("RGBA"); |
||||
|
|
||||
|
PixelOperations<TPixel>.Instance.PackFromRgba32Bytes(data, resultPixels, resultPixels.Length); |
||||
|
} |
||||
|
else if (magickImage.Depth == 16) |
||||
|
{ |
||||
|
ushort[] data = pixels.ToShortArray("RGBA"); |
||||
|
Span<byte> bytes = MemoryMarshal.Cast<ushort, byte>(data.AsSpan()); |
||||
|
|
||||
|
PixelOperations<TPixel>.Instance.PackFromRgba64Bytes(bytes, resultPixels, resultPixels.Length); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,60 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.IO; |
||||
|
|
||||
|
using SixLabors.ImageSharp.Formats; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
using ImageMagick; |
||||
|
|
||||
|
using SixLabors.ImageSharp.Advanced; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs |
||||
|
{ |
||||
|
public class MagickReferenceEncoder : IImageEncoder |
||||
|
{ |
||||
|
public MagickReferenceEncoder(MagickFormat format) |
||||
|
{ |
||||
|
this.Format = format; |
||||
|
} |
||||
|
|
||||
|
public MagickFormat Format { get; } |
||||
|
|
||||
|
public void Encode<TPixel>(Image<TPixel> image, Stream stream) |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
var black = MagickColor.FromRgba(0, 0, 0, 255); |
||||
|
using (var magickImage = new MagickImage(black, image.Width, image.Height)) |
||||
|
{ |
||||
|
bool isDeep = Unsafe.SizeOf<TPixel>() > 32; |
||||
|
|
||||
|
magickImage.Depth = isDeep ? 16 : 8; |
||||
|
|
||||
|
Span<TPixel> allPixels = image.GetPixelSpan(); |
||||
|
|
||||
|
using (IPixelCollection magickPixels = magickImage.GetPixelsUnsafe()) |
||||
|
{ |
||||
|
if (isDeep) |
||||
|
{ |
||||
|
ushort[] data = new ushort[allPixels.Length * 4]; |
||||
|
Span<Rgba64> dataSpan = MemoryMarshal.Cast<ushort, Rgba64>(data); |
||||
|
PixelOperations<TPixel>.Instance.ToRgba64(allPixels, dataSpan, allPixels.Length); |
||||
|
magickPixels.SetPixels(data); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
byte[] data = new byte[allPixels.Length * 4]; |
||||
|
PixelOperations<TPixel>.Instance.ToRgba32Bytes(allPixels, data, allPixels.Length); |
||||
|
magickPixels.SetPixels(data); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
magickImage.Write(stream, this.Format); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,106 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using ImageMagick; |
||||
|
using Xunit; |
||||
|
// ReSharper disable InconsistentNaming
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests |
||||
|
{ |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; |
||||
|
using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; |
||||
|
|
||||
|
using Xunit.Abstractions; |
||||
|
|
||||
|
public class MagickReferenceCodecTests |
||||
|
{ |
||||
|
public MagickReferenceCodecTests(ITestOutputHelper output) |
||||
|
{ |
||||
|
this.Output = output; |
||||
|
} |
||||
|
|
||||
|
private ITestOutputHelper Output { get; } |
||||
|
|
||||
|
public const PixelTypes PixelTypesToTest32 = PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.Rgb24; |
||||
|
|
||||
|
public const PixelTypes PixelTypesToTest64 = |
||||
|
PixelTypes.Rgba32 | PixelTypes.Rgb24 | PixelTypes.Rgba64 | PixelTypes.Rgb48; |
||||
|
|
||||
|
public const PixelTypes PixelTypesToTest48 = |
||||
|
PixelTypes.Rgba32 | PixelTypes.Rgba64 | PixelTypes.Rgb48; |
||||
|
|
||||
|
[Theory] |
||||
|
[WithBlankImages(1, 1, PixelTypesToTest32, TestImages.Png.Splash)] |
||||
|
[WithBlankImages(1, 1, PixelTypesToTest32, TestImages.Png.Indexed)] |
||||
|
public void MagickDecode_8BitDepthImage_IsEquivalentTo_SystemDrawingResult<TPixel>(TestImageProvider<TPixel> dummyProvider, string testImage) |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
string path = TestFile.GetInputFileFullPath(testImage); |
||||
|
|
||||
|
var magickDecoder = new MagickReferenceDecoder(); |
||||
|
var sdDecoder = new SystemDrawingReferenceDecoder(); |
||||
|
|
||||
|
ImageComparer comparer = ImageComparer.Exact; |
||||
|
|
||||
|
using (var mImage = Image.Load<TPixel>(path, magickDecoder)) |
||||
|
using (var sdImage = Image.Load<TPixel>(path, sdDecoder)) |
||||
|
{ |
||||
|
ImageSimilarityReport<TPixel, TPixel> report = comparer.CompareImagesOrFrames(mImage, sdImage); |
||||
|
|
||||
|
mImage.DebugSave(dummyProvider); |
||||
|
|
||||
|
if (TestEnvironment.IsWindows) |
||||
|
{ |
||||
|
Assert.True(report.IsEmpty); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[WithBlankImages(1, 1, PixelTypesToTest64, TestImages.Png.Rgba64Bpp)] |
||||
|
[WithBlankImages(1, 1, PixelTypesToTest48, TestImages.Png.Rgb48Bpp)] |
||||
|
[WithBlankImages(1, 1, PixelTypesToTest48, TestImages.Png.Rgb48BppInterlaced)] |
||||
|
[WithBlankImages(1, 1, PixelTypesToTest48, TestImages.Png.Rgb48BppTrans)] |
||||
|
public void MagickDecode_16BitDepthImage_IsApproximatelyEquivalentTo_SystemDrawingResult<TPixel>(TestImageProvider<TPixel> dummyProvider, string testImage) |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
string path = TestFile.GetInputFileFullPath(testImage); |
||||
|
|
||||
|
var magickDecoder = new MagickReferenceDecoder(); |
||||
|
var sdDecoder = new SystemDrawingReferenceDecoder(); |
||||
|
|
||||
|
// 1020 == 4 * 255 (Equivalent to manhattan distance of 1+1+1+1=4 in Rgba32 space)
|
||||
|
var comparer = ImageComparer.TolerantPercentage(1, 1020); |
||||
|
|
||||
|
using (var mImage = Image.Load<TPixel>(path, magickDecoder)) |
||||
|
using (var sdImage = Image.Load<TPixel>(path, sdDecoder)) |
||||
|
{ |
||||
|
ImageSimilarityReport<TPixel, TPixel> report = comparer.CompareImagesOrFrames(mImage, sdImage); |
||||
|
|
||||
|
mImage.DebugSave(dummyProvider); |
||||
|
|
||||
|
if (TestEnvironment.IsWindows) |
||||
|
{ |
||||
|
Assert.True(report.IsEmpty); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[WithTestPatternImages(100, 100, PixelTypesToTest32, MagickFormat.Png)] |
||||
|
[WithTestPatternImages(100, 100, PixelTypesToTest32, MagickFormat.Jpg)] |
||||
|
public void MagickEncode_8BitDepthImage<TPixel>(TestImageProvider<TPixel> provider, MagickFormat format) |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
string extension = format.ToString().ToLower(); |
||||
|
|
||||
|
var encoder = new MagickReferenceEncoder(format); |
||||
|
|
||||
|
using (Image<TPixel> image = provider.GetImage()) |
||||
|
{ |
||||
|
image.VerifyEncoder(provider, extension, $"{format}", encoder, referenceDecoder: new SystemDrawingReferenceDecoder()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue