Browse Source

ImageMagick decoder works

pull/640/head
Anton Firszov 8 years ago
parent
commit
1791e1af95
  1. 1
      tests/ImageSharp.Tests/ImageSharp.Tests.csproj
  2. 51
      tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
  3. 60
      tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceEncoder.cs
  4. 6
      tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
  5. 106
      tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs
  6. 10
      tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs

1
tests/ImageSharp.Tests/ImageSharp.Tests.csproj

@ -27,6 +27,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Magick.NET-Q16-AnyCPU" Version="7.5.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.5.0" />
<PackageReference Include="System.Drawing.Common" Version="4.5.0" />
<PackageReference Include="xunit" Version="2.3.1" />

51
tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs

@ -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;
}
}
}
}

60
tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceEncoder.cs

@ -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);
}
}
}
}

6
tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

@ -641,7 +641,8 @@ namespace SixLabors.ImageSharp.Tests
IImageEncoder encoder,
ImageComparer customComparer = null,
bool appendPixelTypeToFileName = true,
string referenceImageExtension = null)
string referenceImageExtension = null,
IImageDecoder referenceDecoder = null)
where TPixel : struct, IPixel<TPixel>
{
string actualOutputFile = provider.Utility.SaveTestOutputFile(
@ -650,7 +651,8 @@ namespace SixLabors.ImageSharp.Tests
encoder,
testOutputDetails,
appendPixelTypeToFileName);
IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile);
referenceDecoder = referenceDecoder ?? TestEnvironment.GetReferenceDecoder(actualOutputFile);
using (var actualImage = Image.Load<TPixel>(actualOutputFile, referenceDecoder))
{

106
tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs

@ -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());
}
}
}
}

10
tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceCodecTests.cs → tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs

@ -1,4 +1,6 @@
using System.IO;
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
@ -8,13 +10,13 @@ using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
using Xunit;
using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests
namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests
{
public class ReferenceCodecTests
public class SystemDrawingReferenceCodecTests
{
private ITestOutputHelper Output { get; }
public ReferenceCodecTests(ITestOutputHelper output)
public SystemDrawingReferenceCodecTests(ITestOutputHelper output)
{
this.Output = output;
}
Loading…
Cancel
Save