Browse Source

Add format tests

Former-commit-id: 05ae692a75c4b11f2e4474f84412f432f93e8753
Former-commit-id: 782629c7d712f5496c6ff4cdeea242eef0896e31
Former-commit-id: da773565a12c5de9186d546542b2b8f976903567
pull/1/head
James Jackson-South 10 years ago
parent
commit
682f5b73e3
  1. 28
      src/ImageProcessorCore/Quantizers/Options/Quantization.cs
  2. 2
      src/ImageProcessorCore/Quantizers/Palette/PaletteQuantizer.cs
  3. 65
      src/ImageProcessorCore/Quantizers/Quantize.cs
  4. 3
      src/ImageProcessorCore/Quantizers/QuantizedImage.cs
  5. 2
      src/ImageProcessorCore/Samplers/Crop.cs
  6. 2
      src/ImageProcessorCore/Samplers/EntropyCrop.cs
  7. 2
      src/ImageProcessorCore/Samplers/Pad.cs
  8. 2
      src/ImageProcessorCore/Samplers/Resize.cs
  9. 47
      tests/ImageProcessorCore.Tests/Formats/Bmp/BitmapTests.cs
  10. 199
      tests/ImageProcessorCore.Tests/Formats/GeneralFormatTests.cs
  11. 22
      tests/ImageProcessorCore.Tests/Formats/Png/PngTests.cs

28
src/ImageProcessorCore/Quantizers/Options/Quantization.cs

@ -0,0 +1,28 @@
// <copyright file="Quantization.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore
{
/// <summary>
/// Provides enumeration over how an image should be quantized.
/// </summary>
public enum Quantization
{
/// <summary>
/// An adaptive Octree quantizer. Fast with good quality.
/// </summary>
Octree,
/// <summary>
/// Xiaolin Wu's Color Quantizer which generates high quality output.
/// </summary>
Wu,
/// <summary>
/// Palette based, Uses the collection of web-safe colors by default.
/// </summary>
Palette
}
}

2
src/ImageProcessorCore/Quantizers/Palette/PaletteQuantizer.cs

@ -101,7 +101,7 @@ namespace ImageProcessorCore.Quantizers
int leastDistance = int.MaxValue;
int red = bytes[0];
int green = bytes[1];
int blue = bytes[3];
int blue = bytes[2];
// Loop through the entire palette, looking for the closest color match
for (int index = 0; index < this.colors.Length; index++)

65
src/ImageProcessorCore/Quantizers/Quantize.cs

@ -0,0 +1,65 @@
// <copyright file="Quantize.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using ImageProcessorCore.Quantizers;
namespace ImageProcessorCore
{
/// <summary>
/// Extension methods for the <see cref="Image{T,TP}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Applies quantization to the image.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="mode">The quantization mode to apply to perform the operation.</param>
/// <param name="maxColors">The maximum number of colors to return. Defaults to 256.</param>
/// <returns>The <see cref="Image{T,TP}"/>.</returns>
public static Image<T, TP> Quantize<T, TP>(this Image<T, TP> source, Quantization mode = Quantization.Octree, int maxColors = 256)
where T : IPackedVector<TP>
where TP : struct
{
IQuantizer<T, TP> quantizer;
switch (mode)
{
case Quantization.Wu:
quantizer = new WuQuantizer<T, TP>();
break;
case Quantization.Palette:
quantizer = new PaletteQuantizer<T, TP>();
break;
default:
quantizer = new OctreeQuantizer<T, TP>();
break;
}
return Quantize(source, quantizer, maxColors);
}
/// <summary>
/// Applies quantization to the image.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="quantizer">The quantizer to apply to perform the operation.</param>
/// <param name="maxColors">The maximum number of colors to return.</param>
/// <returns>The <see cref="Image{T,TP}"/>.</returns>
public static Image<T, TP> Quantize<T, TP>(this Image<T, TP> source, IQuantizer<T, TP> quantizer, int maxColors)
where T : IPackedVector<TP>
where TP : struct
{
QuantizedImage<T, TP> quantizedImage = quantizer.Quantize(source, maxColors);
source.SetPixels(source.Width, source.Height, quantizedImage.ToImage().Pixels);
return source;
}
}
}

3
src/ImageProcessorCore/Quantizers/QuantizedImage.cs

@ -90,9 +90,8 @@ namespace ImageProcessorCore.Quantizers
Bootstrapper.Instance.ParallelOptions,
i =>
{
int offset = i * 4;
T color = this.Palette[Math.Min(palletCount, this.Pixels[i])];
pixels[offset] = color;
pixels[i] = color;
});
image.SetPixels(this.Width, this.Height, pixels);

2
src/ImageProcessorCore/Samplers/Crop.cs

@ -1,7 +1,7 @@
// <copyright file="Crop.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>-------------------------------------------------------------------------------------------------------------------
// </copyright>
namespace ImageProcessorCore
{

2
src/ImageProcessorCore/Samplers/EntropyCrop.cs

@ -1,7 +1,7 @@
// <copyright file="EntropyCrop.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>-------------------------------------------------------------------------------------------------------------------
// </copyright>
namespace ImageProcessorCore
{

2
src/ImageProcessorCore/Samplers/Pad.cs

@ -1,7 +1,7 @@
// <copyright file="Pad.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>-------------------------------------------------------------------------------------------------------------------
// </copyright>
namespace ImageProcessorCore
{

2
src/ImageProcessorCore/Samplers/Resize.cs

@ -1,7 +1,7 @@
// <copyright file="Resize.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>-------------------------------------------------------------------------------------------------------------------
// </copyright>
namespace ImageProcessorCore
{

47
tests/ImageProcessorCore.Tests/Formats/Bmp/BitmapTests.cs

@ -0,0 +1,47 @@
// <copyright file="BitmapTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Tests
{
using System.IO;
using Formats;
using Xunit;
public class BitmapTests : FileTestBase
{
[Fact]
public void BitmapCanEncodeDifferentBitRates()
{
const string path = "TestOutput/Bmp";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
Image image = new Image(stream);
string encodeFilename = path + "/24-" + Path.GetFileNameWithoutExtension(file) + ".bmp";
using (FileStream output = File.OpenWrite(encodeFilename))
{
image.Save(output, new BmpEncoder { BitsPerPixel = BmpBitsPerPixel.Pixel24 });
}
encodeFilename = path + "/32-" + Path.GetFileNameWithoutExtension(file) + ".bmp";
using (FileStream output = File.OpenWrite(encodeFilename))
{
image.Save(output, new BmpEncoder { BitsPerPixel = BmpBitsPerPixel.Pixel32 });
}
}
}
}
}
}

199
tests/ImageProcessorCore.Tests/Formats/GeneralFormatTests.cs

@ -0,0 +1,199 @@
// <copyright file="GeneralFormatTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Tests
{
using System;
using System.IO;
using Xunit;
public class GeneralFormatTests : FileTestBase
{
[Fact]
public void ResolutionShouldChange()
{
const string path = "TestOutput/Resolution";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
string filename = Path.GetFileName(file);
Image image = new Image(stream);
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.VerticalResolution = 150;
image.HorizontalResolution = 150;
image.Save(output);
}
}
}
}
[Fact]
public void ImageCanEncodeToString()
{
const string path = "TestOutput/ToString";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
Image image = new Image(stream);
string filename = path + "/" + Path.GetFileNameWithoutExtension(file) + ".txt";
File.WriteAllText(filename, image.ToString());
}
}
}
[Fact]
public void DecodeThenEncodeImageFromStreamShouldSucceed()
{
const string path = "TestOutput/Encode";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
Image image = new Image(stream);
string encodeFilename = path + "/" + Path.GetFileName(file);
using (FileStream output = File.OpenWrite(encodeFilename))
{
image.Save(output);
}
}
}
}
[Fact]
public void QuantizeImageShouldPreserveMaximumColorPrecision()
{
const string path = "TestOutput/Quantize";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
Image image = new Image(stream);
// Copy the original pixels to save decoding time.
Color[] pixels = new Color[image.Width * image.Height];
Array.Copy(image.Pixels, pixels, image.Pixels.Length);
using (FileStream output = File.OpenWrite($"{path}/Octree-{Path.GetFileName(file)}"))
{
image.Quantize(Quantization.Octree)
.Save(output, image.CurrentImageFormat);
}
image.SetPixels(image.Width, image.Height, pixels);
using (FileStream output = File.OpenWrite($"{path}/Wu-{Path.GetFileName(file)}"))
{
image.Quantize(Quantization.Wu)
.Save(output, image.CurrentImageFormat);
}
image.SetPixels(image.Width, image.Height, pixels);
using (FileStream output = File.OpenWrite($"{path}/Palette-{Path.GetFileName(file)}"))
{
image.Quantize(Quantization.Palette)
.Save(output, image.CurrentImageFormat);
}
}
}
}
[Fact]
public void ImageCanConvertFormat()
{
const string path = "TestOutput/Format";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
Image image = new Image(stream);
using (FileStream output = File.OpenWrite($"{path}/{Path.GetFileNameWithoutExtension(file)}.gif"))
{
image.SaveAsGif(output);
}
using (FileStream output = File.OpenWrite($"{path}/{Path.GetFileNameWithoutExtension(file)}.bmp"))
{
image.SaveAsBmp(output);
}
using (FileStream output = File.OpenWrite($"{path}/{Path.GetFileNameWithoutExtension(file)}.jpg"))
{
image.SaveAsJpeg(output);
}
using (FileStream output = File.OpenWrite($"{path}/{Path.GetFileNameWithoutExtension(file)}.png"))
{
image.SaveAsPng(output);
}
}
}
}
[Fact]
public void ImageShouldPreservePixelByteOrderWhenSerialized()
{
const string path = "TestOutput/Serialized";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
Image image = new Image(stream);
byte[] serialized;
using (MemoryStream memoryStream = new MemoryStream())
{
image.Save(memoryStream);
memoryStream.Flush();
serialized = memoryStream.ToArray();
}
using (MemoryStream memoryStream = new MemoryStream(serialized))
{
Image image2 = new Image(memoryStream);
using (FileStream output = File.OpenWrite($"{path}/{Path.GetFileName(file)}"))
{
image2.Save(output);
}
}
}
}
}
}
}

22
tests/ImageProcessorCore.Tests/Formats/Jpg/GeneralFormatTests.cs → tests/ImageProcessorCore.Tests/Formats/Png/PngTests.cs

@ -1,4 +1,4 @@
// <copyright file="GeneralFormatTests.cs" company="James Jackson-South">
// <copyright file="PngTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
@ -7,30 +7,30 @@ namespace ImageProcessorCore.Tests
{
using System.IO;
using Formats;
using Xunit;
public class GeneralFormatTests : FileTestBase
public class PngTests : FileTestBase
{
[Fact]
public void ResolutionShouldChange()
public void ImageCanSaveIndexedPng()
{
if (!Directory.Exists("TestOutput/Resolution"))
const string path = "TestOutput/Png";
if (!Directory.Exists(path))
{
Directory.CreateDirectory("TestOutput/Resolution");
Directory.CreateDirectory(path);
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
string filename = Path.GetFileName(file);
Image image = new Image(stream);
using (FileStream output = File.OpenWrite($"TestOutput/Resolution/{filename}"))
using (FileStream output = File.OpenWrite($"{path}/{Path.GetFileNameWithoutExtension(file)}.png"))
{
image.VerticalResolution = 150;
image.HorizontalResolution = 150;
image.Save(output);
image.Quality = 256;
image.Save(output, new PngFormat());
}
}
}
Loading…
Cancel
Save