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