mirror of https://github.com/SixLabors/ImageSharp
Browse Source
Former-commit-id: 05ae692a75c4b11f2e4474f84412f432f93e8753 Former-commit-id: 782629c7d712f5496c6ff4cdeea242eef0896e31 Former-commit-id: da773565a12c5de9186d546542b2b8f976903567pull/1/head
11 changed files with 356 additions and 18 deletions
@ -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 |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -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 }); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue