mirror of https://github.com/SixLabors/ImageSharp
13 changed files with 487 additions and 7 deletions
@ -0,0 +1,32 @@ |
|||||
|
// <copyright file="Atkinson.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Dithering |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Applies error diffusion based dithering using the Atkinson image dithering algorithm.
|
||||
|
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>
|
||||
|
/// </summary>
|
||||
|
public class Atkinson : ErrorDiffusion |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The diffusion matrix
|
||||
|
/// </summary>
|
||||
|
private static readonly byte[,] AtkinsonMatrix = |
||||
|
{ |
||||
|
{ 0, 0, 1, 1 }, |
||||
|
{ 1, 1, 1, 0 }, |
||||
|
{ 0, 1, 0, 0 } |
||||
|
}; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="Atkinson"/> class.
|
||||
|
/// </summary>
|
||||
|
public Atkinson() |
||||
|
: base(AtkinsonMatrix, 8) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
// <copyright file="Burks.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Dithering |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Applies error diffusion based dithering using the Burks image dithering algorithm.
|
||||
|
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>
|
||||
|
/// </summary>
|
||||
|
public class Burks : ErrorDiffusion |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The diffusion matrix
|
||||
|
/// </summary>
|
||||
|
private static readonly byte[,] BurksMatrix = |
||||
|
{ |
||||
|
{ 0, 0, 0, 8, 4 }, |
||||
|
{ 2, 4, 8, 4, 2 } |
||||
|
}; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="Burks"/> class.
|
||||
|
/// </summary>
|
||||
|
public Burks() |
||||
|
: base(BurksMatrix, 32) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,107 @@ |
|||||
|
// <copyright file="ErrorDiffusion.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Dithering |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The base class for performing effor diffusion based dithering.
|
||||
|
/// </summary>
|
||||
|
public abstract class ErrorDiffusion : IErrorDiffusion |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The vector to perform division.
|
||||
|
/// </summary>
|
||||
|
private readonly Vector4 divisorVector; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The matrix width
|
||||
|
/// </summary>
|
||||
|
private readonly byte matrixHeight; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The matrix height
|
||||
|
/// </summary>
|
||||
|
private readonly byte matrixWidth; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The offset at which to start the dithering operation.
|
||||
|
/// </summary>
|
||||
|
private readonly int startingOffset; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="ErrorDiffusion"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="matrix">The dithering matrix.</param>
|
||||
|
/// <param name="divisor">The divisor.</param>
|
||||
|
protected ErrorDiffusion(byte[,] matrix, byte divisor) |
||||
|
{ |
||||
|
Guard.NotNull(matrix, nameof(matrix)); |
||||
|
Guard.MustBeGreaterThan(divisor, 0, nameof(divisor)); |
||||
|
|
||||
|
this.Matrix = matrix; |
||||
|
this.matrixWidth = (byte)(matrix.GetUpperBound(1) + 1); |
||||
|
this.matrixHeight = (byte)(matrix.GetUpperBound(0) + 1); |
||||
|
this.divisorVector = new Vector4(divisor); |
||||
|
|
||||
|
this.startingOffset = 0; |
||||
|
for (int i = 0; i < this.matrixWidth; i++) |
||||
|
{ |
||||
|
if (matrix[0, i] != 0) |
||||
|
{ |
||||
|
this.startingOffset = (byte)(i - 1); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public byte[,] Matrix { get; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
public void Dither<TColor>(PixelAccessor<TColor> pixels, TColor source, TColor transformed, int x, int y, int width, int height) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor> |
||||
|
{ |
||||
|
// Assign the transformed pixel to the array.
|
||||
|
pixels[x, y] = transformed; |
||||
|
|
||||
|
// Calculate the error
|
||||
|
Vector4 error = source.ToVector4() - transformed.ToVector4(); |
||||
|
|
||||
|
// Loop through and distribute the error amongst neighbouring pixels.
|
||||
|
for (int row = 0; row < this.matrixHeight; row++) |
||||
|
{ |
||||
|
int matrixY = y + row; |
||||
|
|
||||
|
for (int col = 0; col < this.matrixWidth; col++) |
||||
|
{ |
||||
|
int matrixX = x + (col - this.startingOffset); |
||||
|
|
||||
|
if (matrixX > 0 && matrixX < width && matrixY > 0 && matrixY < height) |
||||
|
{ |
||||
|
byte coefficient = this.Matrix[row, col]; |
||||
|
if (coefficient == 0) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
Vector4 coefficientVector = new Vector4(this.Matrix[row, col]); |
||||
|
Vector4 offsetColor = pixels[matrixX, matrixY].ToVector4(); |
||||
|
Vector4 result = ((error * coefficientVector) / this.divisorVector) + offsetColor; |
||||
|
result.W = offsetColor.W; |
||||
|
|
||||
|
TColor packed = default(TColor); |
||||
|
packed.PackFromVector4(result); |
||||
|
pixels[matrixX, matrixY] = packed; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
// <copyright file="FloydSteinberg.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Dithering |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Applies error diffusion based dithering using the Floyd–Steinberg image dithering algorithm.
|
||||
|
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>
|
||||
|
/// </summary>
|
||||
|
public class FloydSteinberg : ErrorDiffusion |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The diffusion matrix
|
||||
|
/// </summary>
|
||||
|
private static readonly byte[,] FloydSteinbergMatrix = |
||||
|
{ |
||||
|
{ 0, 0, 7 }, |
||||
|
{ 3, 5, 1 } |
||||
|
}; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="FloydSteinberg"/> class.
|
||||
|
/// </summary>
|
||||
|
public FloydSteinberg() |
||||
|
: base(FloydSteinbergMatrix, 16) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
// <copyright file="IErrorDiffusion.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Dithering |
||||
|
{ |
||||
|
using System; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Encapsulates properties and methods required to perfom diffused error dithering on an image.
|
||||
|
/// </summary>
|
||||
|
public interface IErrorDiffusion |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets the dithering matrix
|
||||
|
/// </summary>
|
||||
|
byte[,] Matrix { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Transforms the image applying the dither matrix. This method alters the input pixels array
|
||||
|
/// </summary>
|
||||
|
/// <param name="pixels">The pixel accessor </param>
|
||||
|
/// <param name="source">The source pixel</param>
|
||||
|
/// <param name="transformed">The transformed pixel</param>
|
||||
|
/// <param name="x">The column index.</param>
|
||||
|
/// <param name="y">The row index.</param>
|
||||
|
/// <param name="width">The image width.</param>
|
||||
|
/// <param name="height">The image height.</param>
|
||||
|
/// <typeparam name="TColor">The pixel format.</typeparam>
|
||||
|
void Dither<TColor>(PixelAccessor<TColor> pixels, TColor source, TColor transformed, int x, int y, int width, int height) |
||||
|
where TColor : struct, IPackedPixel, IEquatable<TColor>; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
// <copyright file="JarvisJudiceNinke.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Dithering |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Applies error diffusion based dithering using the JarvisJudiceNinke image dithering algorithm.
|
||||
|
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>
|
||||
|
/// </summary>
|
||||
|
public class JarvisJudiceNinke : ErrorDiffusion |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The diffusion matrix
|
||||
|
/// </summary>
|
||||
|
private static readonly byte[,] JarvisJudiceNinkeMatrix = |
||||
|
{ |
||||
|
{ 0, 0, 0, 7, 5 }, |
||||
|
{ 3, 5, 7, 5, 3 }, |
||||
|
{ 1, 3, 5, 3, 1 } |
||||
|
}; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="JarvisJudiceNinke"/> class.
|
||||
|
/// </summary>
|
||||
|
public JarvisJudiceNinke() |
||||
|
: base(JarvisJudiceNinkeMatrix, 48) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
// <copyright file="Sierra2.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Dithering |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Applies error diffusion based dithering using the Sierra2 image dithering algorithm.
|
||||
|
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>
|
||||
|
/// </summary>
|
||||
|
public class Sierra2 : ErrorDiffusion |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The diffusion matrix
|
||||
|
/// </summary>
|
||||
|
private static readonly byte[,] Sierra2Matrix = |
||||
|
{ |
||||
|
{ 0, 0, 0, 4, 3 }, |
||||
|
{ 1, 2, 3, 2, 1 } |
||||
|
}; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="Sierra2"/> class.
|
||||
|
/// </summary>
|
||||
|
public Sierra2() |
||||
|
: base(Sierra2Matrix, 16) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
// <copyright file="Sierra3.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Dithering |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Applies error diffusion based dithering using the Sierra3 image dithering algorithm.
|
||||
|
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>
|
||||
|
/// </summary>
|
||||
|
public class Sierra3 : ErrorDiffusion |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The diffusion matrix
|
||||
|
/// </summary>
|
||||
|
private static readonly byte[,] Sierra3Matrix = |
||||
|
{ |
||||
|
{ 0, 0, 0, 5, 3 }, |
||||
|
{ 2, 4, 5, 4, 2 }, |
||||
|
{ 0, 2, 3, 2, 0 } |
||||
|
}; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="Sierra3"/> class.
|
||||
|
/// </summary>
|
||||
|
public Sierra3() |
||||
|
: base(Sierra3Matrix, 32) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
// <copyright file="SierraLite.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Dithering |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Applies error diffusion based dithering using the SierraLite image dithering algorithm.
|
||||
|
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>
|
||||
|
/// </summary>
|
||||
|
public class SierraLite : ErrorDiffusion |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The diffusion matrix
|
||||
|
/// </summary>
|
||||
|
private static readonly byte[,] SierraLiteMatrix = |
||||
|
{ |
||||
|
{ 0, 0, 2 }, |
||||
|
{ 1, 1, 0 } |
||||
|
}; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="SierraLite"/> class.
|
||||
|
/// </summary>
|
||||
|
public SierraLite() |
||||
|
: base(SierraLiteMatrix, 4) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
// <copyright file="Stucki.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Dithering |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Applies error diffusion based dithering using the Stucki image dithering algorithm.
|
||||
|
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>
|
||||
|
/// </summary>
|
||||
|
public class Stucki : ErrorDiffusion |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The diffusion matrix
|
||||
|
/// </summary>
|
||||
|
private static readonly byte[,] StuckiMatrix = |
||||
|
{ |
||||
|
{ 0, 0, 0, 8, 4 }, |
||||
|
{ 2, 4, 8, 4, 2 }, |
||||
|
{ 1, 2, 4, 2, 1 } |
||||
|
}; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="Stucki"/> class.
|
||||
|
/// </summary>
|
||||
|
public Stucki() |
||||
|
: base(StuckiMatrix, 4) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue