mirror of https://github.com/SixLabors/ImageSharp
Browse Source
# Conflicts: # src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cspull/673/head
719 changed files with 54201 additions and 22016 deletions
@ -1,95 +1,99 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using System.Threading.Tasks; |
|||
using SixLabors.ImageSharp.Advanced; |
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.Memory; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Drawing |
|||
{ |
|||
/// <summary>
|
|||
/// Combines two images together by blending the pixels.
|
|||
/// </summary>
|
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using System.Threading.Tasks; |
|||
using SixLabors.ImageSharp.Advanced; |
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.ParallelUtils; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.Memory; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Drawing |
|||
{ |
|||
/// <summary>
|
|||
/// Combines two images together by blending the pixels.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixelDst">The pixel format of destination image.</typeparam>
|
|||
/// <typeparam name="TPixelSrc">The pixel format os source image.</typeparam>
|
|||
internal class DrawImageProcessor<TPixelDst, TPixelSrc> : ImageProcessor<TPixelDst> |
|||
/// <typeparam name="TPixelSrc">The pixel format of source image.</typeparam>
|
|||
internal class DrawImageProcessor<TPixelDst, TPixelSrc> : ImageProcessor<TPixelDst> |
|||
where TPixelDst : struct, IPixel<TPixelDst> |
|||
where TPixelSrc : struct, IPixel<TPixelSrc> |
|||
where TPixelSrc : struct, IPixel<TPixelSrc> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixelDst, TPixelSrc}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="image">The image to blend with the currently processing image.</param>
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixelDst, TPixelSrc}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="image">The image to blend with the currently processing image.</param>
|
|||
/// <param name="location">The location to draw the blended image.</param>
|
|||
/// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param>
|
|||
/// <param name="alphaCompositionMode">The Alpha blending mode to use when drawing the image.</param>
|
|||
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
|
|||
public DrawImageProcessor(Image<TPixelSrc> image, Point location, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, float opacity) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); |
|||
|
|||
this.Image = image; |
|||
this.Opacity = opacity; |
|||
this.Blender = PixelOperations<TPixelDst>.Instance.GetPixelBlender(colorBlendingMode, alphaCompositionMode); |
|||
this.Location = location; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the image to blend
|
|||
/// </summary>
|
|||
public Image<TPixelSrc> Image { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the opacity of the image to blend
|
|||
/// </summary>
|
|||
public float Opacity { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the pixel blender
|
|||
/// </summary>
|
|||
public PixelBlender<TPixelDst> Blender { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the location to draw the blended image
|
|||
/// </summary>
|
|||
public Point Location { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnFrameApply(ImageFrame<TPixelDst> source, Rectangle sourceRectangle, Configuration configuration) |
|||
{ |
|||
Image<TPixelSrc> targetImage = this.Image; |
|||
PixelBlender<TPixelDst> blender = this.Blender; |
|||
int locationY = this.Location.Y; |
|||
|
|||
// Align start/end positions.
|
|||
Rectangle bounds = targetImage.Bounds(); |
|||
|
|||
int minX = Math.Max(this.Location.X, sourceRectangle.X); |
|||
int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width); |
|||
int targetX = minX - this.Location.X; |
|||
|
|||
int minY = Math.Max(this.Location.Y, sourceRectangle.Y); |
|||
int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom); |
|||
|
|||
int width = maxX - minX; |
|||
|
|||
MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator; |
|||
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
|
|||
public DrawImageProcessor(Image<TPixelSrc> image, Point location, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, float opacity) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); |
|||
|
|||
this.Image = image; |
|||
this.Opacity = opacity; |
|||
this.Blender = PixelOperations<TPixelDst>.Instance.GetPixelBlender(colorBlendingMode, alphaCompositionMode); |
|||
this.Location = location; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the image to blend
|
|||
/// </summary>
|
|||
public Image<TPixelSrc> Image { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the opacity of the image to blend
|
|||
/// </summary>
|
|||
public float Opacity { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the pixel blender
|
|||
/// </summary>
|
|||
public PixelBlender<TPixelDst> Blender { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the location to draw the blended image
|
|||
/// </summary>
|
|||
public Point Location { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnFrameApply(ImageFrame<TPixelDst> source, Rectangle sourceRectangle, Configuration configuration) |
|||
{ |
|||
Image<TPixelSrc> targetImage = this.Image; |
|||
PixelBlender<TPixelDst> blender = this.Blender; |
|||
int locationY = this.Location.Y; |
|||
|
|||
// Align start/end positions.
|
|||
Rectangle bounds = targetImage.Bounds(); |
|||
|
|||
int minX = Math.Max(this.Location.X, sourceRectangle.X); |
|||
int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width); |
|||
int targetX = minX - this.Location.X; |
|||
|
|||
int minY = Math.Max(this.Location.Y, sourceRectangle.Y); |
|||
int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom); |
|||
|
|||
int width = maxX - minX; |
|||
|
|||
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); |
|||
|
|||
ParallelFor.WithConfiguration( |
|||
minY, |
|||
maxY, |
|||
configuration, |
|||
y => |
|||
{ |
|||
Span<TPixelDst> background = source.GetPixelRowSpan(y).Slice(minX, width); |
|||
Span<TPixelSrc> foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); |
|||
blender.Blend<TPixelSrc>(memoryAllocator, background, background, foreground, this.Opacity); |
|||
}); |
|||
} |
|||
} |
|||
ParallelHelper.IterateRows( |
|||
workingRect, |
|||
configuration, |
|||
rows => |
|||
{ |
|||
for (int y = rows.Min; y < rows.Max; y++) |
|||
{ |
|||
Span<TPixelDst> background = source.GetPixelRowSpan(y).Slice(minX, width); |
|||
Span<TPixelSrc> foreground = |
|||
targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); |
|||
blender.Blend<TPixelSrc>(configuration, background, background, foreground, this.Opacity); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,103 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing.Processors.Dithering; |
|||
using SixLabors.ImageSharp.Processing.Processors.Quantization; |
|||
|
|||
namespace SixLabors.ImageSharp.Advanced |
|||
{ |
|||
/// <summary>
|
|||
/// Unlike traditional Mono/.NET, code on the iPhone is statically compiled ahead of time instead of being
|
|||
/// compiled on demand by a JIT compiler. This means there are a few limitations with respect to generics,
|
|||
/// these are caused because not every possible generic instantiation can be determined up front at compile time.
|
|||
/// The Aot Compiler is designed to overcome the limitations of this compiler.
|
|||
/// </summary>
|
|||
public static class AotCompilerTools |
|||
{ |
|||
/// <summary>
|
|||
/// Seeds the compiler using the given pixel format.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
public static void Seed<TPixel>() |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
// This is we actually call all the individual methods you need to seed.
|
|||
AotCompileOctreeQuantizer<TPixel>(); |
|||
AotCompileWuQuantizer<TPixel>(); |
|||
AotCompileDithering<TPixel>(); |
|||
|
|||
// TODO: Do the discovery work to figure out what works and what doesn't.
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Seeds the compiler using the given pixel formats.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The first pixel format.</typeparam>
|
|||
/// <typeparam name="TPixel2">The second pixel format.</typeparam>
|
|||
public static void Seed<TPixel, TPixel2>() |
|||
where TPixel : struct, IPixel<TPixel> |
|||
where TPixel2 : struct, IPixel<TPixel2> |
|||
{ |
|||
Seed<TPixel>(); |
|||
Seed<TPixel2>(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Seeds the compiler using the given pixel formats.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The first pixel format.</typeparam>
|
|||
/// <typeparam name="TPixel2">The second pixel format.</typeparam>
|
|||
/// <typeparam name="TPixel3">The third pixel format.</typeparam>
|
|||
public static void Seed<TPixel, TPixel2, TPixel3>() |
|||
where TPixel : struct, IPixel<TPixel> |
|||
where TPixel2 : struct, IPixel<TPixel2> |
|||
where TPixel3 : struct, IPixel<TPixel3> |
|||
{ |
|||
Seed<TPixel, TPixel2>(); |
|||
Seed<TPixel3>(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This method doesn't actually do anything but serves an important purpose...
|
|||
/// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an excepion:
|
|||
/// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode."
|
|||
/// The reason this happens is the SaveAsGif method makes haevy use of generics, which are too confusing for the AoT
|
|||
/// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on
|
|||
/// iOS so it bombs out.
|
|||
/// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the
|
|||
/// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!!
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
private static void AotCompileOctreeQuantizer<TPixel>() |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
var test = new OctreeFrameQuantizer<TPixel>(new OctreeQuantizer(false)); |
|||
test.AotGetPalette(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This method pre-seeds the WuQuantizer in the AoT compiler for iOS.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
private static void AotCompileWuQuantizer<TPixel>() |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
var test = new WuFrameQuantizer<TPixel>(new WuQuantizer(false)); |
|||
test.QuantizeFrame(new ImageFrame<TPixel>(Configuration.Default, 1, 1)); |
|||
test.AotGetPalette(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This method pre-seeds the default dithering engine (FloydSteinbergDiffuser) in the AoT compiler for iOS.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
private static void AotCompileDithering<TPixel>() |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
var test = new FloydSteinbergDiffuser(); |
|||
TPixel pixel = default; |
|||
test.Dither<TPixel>(new ImageFrame<TPixel>(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Companding |
|||
{ |
|||
/// <summary>
|
|||
/// Implements gamma companding
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
|
|||
/// </remarks>
|
|||
public static class GammaCompanding |
|||
{ |
|||
/// <summary>
|
|||
/// Expands a companded channel to its linear equivalent with respect to the energy.
|
|||
/// </summary>
|
|||
/// <param name="channel">The channel value.</param>
|
|||
/// <param name="gamma">The gamma value.</param>
|
|||
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static float Expand(float channel, float gamma) => MathF.Pow(channel, gamma); |
|||
|
|||
/// <summary>
|
|||
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
|
|||
/// </summary>
|
|||
/// <param name="channel">The channel value.</param>
|
|||
/// <param name="gamma">The gamma value.</param>
|
|||
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static float Compress(float channel, float gamma) => MathF.Pow(channel, 1 / gamma); |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
using SixLabors.ImageSharp.ColorSpaces.Conversion; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Companding |
|||
{ |
|||
/// <summary>
|
|||
/// Implements L* companding
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// For more info see:
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
|
|||
/// </remarks>
|
|||
public static class LCompanding |
|||
{ |
|||
/// <summary>
|
|||
/// Expands a companded channel to its linear equivalent with respect to the energy.
|
|||
/// </summary>
|
|||
/// <param name="channel">The channel value.</param>
|
|||
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static float Expand(float channel) |
|||
=> channel <= 0.08 ? 100 * channel / CieConstants.Kappa : ImageMaths.Pow3((channel + 0.16F) / 1.16F); |
|||
|
|||
/// <summary>
|
|||
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
|
|||
/// </summary>
|
|||
/// <param name="channel">The channel value</param>
|
|||
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static float Compress(float channel) |
|||
=> channel <= CieConstants.Epsilon ? channel * CieConstants.Kappa / 100F : MathF.Pow(1.16F * channel, 0.3333333F) - 0.16F; |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Companding |
|||
{ |
|||
/// <summary>
|
|||
/// Implements Rec. 2020 companding function (for 12-bits).
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <see href="http://en.wikipedia.org/wiki/Rec._2020"/>
|
|||
/// For 10-bits, companding is identical to <see cref="Rec709Companding"/>
|
|||
/// </remarks>
|
|||
public static class Rec2020Companding |
|||
{ |
|||
/// <summary>
|
|||
/// Expands a companded channel to its linear equivalent with respect to the energy.
|
|||
/// </summary>
|
|||
/// <param name="channel">The channel value.</param>
|
|||
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static float Expand(float channel) |
|||
=> channel < 0.08145F ? channel / 4.5F : MathF.Pow((channel + 0.0993F) / 1.0993F, 2.222222F); |
|||
|
|||
/// <summary>
|
|||
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
|
|||
/// </summary>
|
|||
/// <param name="channel">The channel value.</param>
|
|||
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static float Compress(float channel) |
|||
=> channel < 0.0181F ? 4500F * channel : (1.0993F * channel) - 0.0993F; |
|||
} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Companding |
|||
{ |
|||
/// <summary>
|
|||
/// Implements the Rec. 709 companding function.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// http://en.wikipedia.org/wiki/Rec._709
|
|||
/// </remarks>
|
|||
public static class Rec709Companding |
|||
{ |
|||
/// <summary>
|
|||
/// Expands a companded channel to its linear equivalent with respect to the energy.
|
|||
/// </summary>
|
|||
/// <param name="channel">The channel value.</param>
|
|||
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static float Expand(float channel) |
|||
=> channel < 0.081F ? channel / 4.5F : MathF.Pow((channel + 0.099F) / 1.099F, 2.222222F); |
|||
|
|||
/// <summary>
|
|||
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
|
|||
/// </summary>
|
|||
/// <param name="channel">The channel value.</param>
|
|||
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static float Compress(float channel) |
|||
=> channel < 0.018F ? 4500F * channel : (1.099F * channel) - 0.099F; |
|||
} |
|||
} |
|||
@ -0,0 +1,89 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Companding |
|||
{ |
|||
/// <summary>
|
|||
/// Implements sRGB companding
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// For more info see:
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
|
|||
/// </remarks>
|
|||
public static class SRgbCompanding |
|||
{ |
|||
/// <summary>
|
|||
/// Expands the companded vectors to their linear equivalents with respect to the energy.
|
|||
/// </summary>
|
|||
/// <param name="vectors">The span of vectors.</param>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static void Expand(Span<Vector4> vectors) |
|||
{ |
|||
ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); |
|||
|
|||
for (int i = 0; i < vectors.Length; i++) |
|||
{ |
|||
ref Vector4 v = ref Unsafe.Add(ref baseRef, i); |
|||
v.X = Expand(v.X); |
|||
v.Y = Expand(v.Y); |
|||
v.Z = Expand(v.Z); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compresses the uncompanded vectors to their nonlinear equivalents with respect to the energy.
|
|||
/// </summary>
|
|||
/// <param name="vectors">The span of vectors.</param>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static void Compress(Span<Vector4> vectors) |
|||
{ |
|||
ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); |
|||
|
|||
for (int i = 0; i < vectors.Length; i++) |
|||
{ |
|||
ref Vector4 v = ref Unsafe.Add(ref baseRef, i); |
|||
v.X = Compress(v.X); |
|||
v.Y = Compress(v.Y); |
|||
v.Z = Compress(v.Z); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Expands a companded vector to its linear equivalent with respect to the energy.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector.</param>
|
|||
/// <returns>The <see cref="Vector4"/> representing the linear channel values.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static Vector4 Expand(Vector4 vector) => new Vector4(Expand(vector.X), Expand(vector.Y), Expand(vector.Z), vector.W); |
|||
|
|||
/// <summary>
|
|||
/// Compresses an uncompanded vector (linear) to its nonlinear equivalent.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector.</param>
|
|||
/// <returns>The <see cref="Vector4"/> representing the nonlinear channel values.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static Vector4 Compress(Vector4 vector) => new Vector4(Compress(vector.X), Compress(vector.Y), Compress(vector.Z), vector.W); |
|||
|
|||
/// <summary>
|
|||
/// Expands a companded channel to its linear equivalent with respect to the energy.
|
|||
/// </summary>
|
|||
/// <param name="channel">The channel value.</param>
|
|||
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static float Expand(float channel) => channel <= 0.04045F ? channel / 12.92F : MathF.Pow((channel + 0.055F) / 1.055F, 2.4F); |
|||
|
|||
/// <summary>
|
|||
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
|
|||
/// </summary>
|
|||
/// <param name="channel">The channel value.</param>
|
|||
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static float Compress(float channel) => channel <= 0.0031308F ? 12.92F * channel : (1.055F * MathF.Pow(channel, 0.416666666666667F)) - 0.055F; |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Numerics; |
|||
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion |
|||
{ |
|||
/// <summary>
|
|||
/// Configuration options for the <see cref="ColorSpaceConverter"/> class.
|
|||
/// </summary>
|
|||
public class ColorSpaceConverterOptions |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets the white point used for chromatic adaptation in conversions from/to XYZ color space.
|
|||
/// When <value>default</value>, no adaptation will be performed.
|
|||
/// Defaults to: <see cref="CieLuv.DefaultWhitePoint"/>.
|
|||
/// </summary>
|
|||
public CieXyz WhitePoint { get; set; } = CieLuv.DefaultWhitePoint; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the white point used *when creating* Luv/LChuv colors. (Luv/LChuv colors on the input already contain the white point information)
|
|||
/// Defaults to: <see cref="CieLuv.DefaultWhitePoint"/>.
|
|||
/// </summary>
|
|||
public CieXyz TargetLuvWhitePoint { get; set; } = CieLuv.DefaultWhitePoint; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the white point used *when creating* Lab/LChab colors. (Lab/LChab colors on the input already contain the white point information)
|
|||
/// Defaults to: <see cref="CieLab.DefaultWhitePoint"/>.
|
|||
/// </summary>
|
|||
public CieXyz TargetLabWhitePoint { get; set; } = CieLab.DefaultWhitePoint; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the white point used *when creating* HunterLab colors. (HunterLab colors on the input already contain the white point information)
|
|||
/// Defaults to: <see cref="HunterLab.DefaultWhitePoint"/>.
|
|||
/// </summary>
|
|||
public CieXyz TargetHunterLabWhitePoint { get; set; } = HunterLab.DefaultWhitePoint; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the target working space used *when creating* RGB colors. (RGB colors on the input already contain the working space information)
|
|||
/// Defaults to: <see cref="Rgb.DefaultWorkingSpace"/>.
|
|||
/// </summary>
|
|||
public RgbWorkingSpaceBase TargetRgbWorkingSpace { get; set; } = Rgb.DefaultWorkingSpace; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the chromatic adaptation method used. When <value>null</value>, no adaptation will be performed.
|
|||
/// </summary>
|
|||
public IChromaticAdaptation ChromaticAdaptation { get; set; } = new VonKriesChromaticAdaptation(); |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets transformation matrix used in conversion to and from <see cref="Lms"/>.
|
|||
/// </summary>
|
|||
public Matrix4x4 LmsAdaptationMatrix { get; set; } = CieXyzAndLmsConverter.DefaultTransformationMatrix; |
|||
} |
|||
} |
|||
@ -1,22 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion |
|||
{ |
|||
/// <summary>
|
|||
/// Converts color between two color spaces.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The input color type.</typeparam>
|
|||
/// <typeparam name="TResult">The result color type.</typeparam>
|
|||
internal interface IColorConversion<T, TResult> |
|||
where T : struct |
|||
where TResult : struct |
|||
{ |
|||
/// <summary>
|
|||
/// Performs the conversion from the input to an instance of the output type.
|
|||
/// </summary>
|
|||
/// <param name="input">The input color instance.</param>
|
|||
/// <returns>The converted result</returns>
|
|||
TResult Convert(in T input); |
|||
} |
|||
} |
|||
@ -1,49 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CmykColorSapce |
|||
{ |
|||
/// <summary>
|
|||
/// Color converter between CMYK and Rgb
|
|||
/// </summary>
|
|||
internal class CmykAndRgbConverter : IColorConversion<Cmyk, Rgb>, IColorConversion<Rgb, Cmyk> |
|||
{ |
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Rgb Convert(in Cmyk input) |
|||
{ |
|||
float r = (1F - input.C) * (1F - input.K); |
|||
float g = (1F - input.M) * (1F - input.K); |
|||
float b = (1F - input.Y) * (1F - input.K); |
|||
|
|||
return new Rgb(r, g, b); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Cmyk Convert(in Rgb input) |
|||
{ |
|||
// To CMYK
|
|||
float c = 1F - input.R; |
|||
float m = 1F - input.G; |
|||
float y = 1F - input.B; |
|||
|
|||
// To CMYK
|
|||
float k = MathF.Min(c, MathF.Min(m, y)); |
|||
|
|||
if (MathF.Abs(k - 1F) < Constants.Epsilon) |
|||
{ |
|||
return new Cmyk(0, 0, 0, 1F); |
|||
} |
|||
|
|||
c = (c - k) / (1F - k); |
|||
m = (m - k) / (1F - k); |
|||
y = (y - k) / (1F - k); |
|||
|
|||
return new Cmyk(c, m, y, k); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation |
|||
{ |
|||
/// <summary>
|
|||
/// Color converter between <see cref="Cmyk"/> and <see cref="Rgb"/>
|
|||
/// </summary>
|
|||
internal sealed class CmykAndRgbConverter |
|||
{ |
|||
/// <summary>
|
|||
/// Performs the conversion from the <see cref="Cmyk"/> input to an instance of <see cref="Rgb"/> type.
|
|||
/// </summary>
|
|||
/// <param name="input">The input color instance.</param>
|
|||
/// <returns>The converted result</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public Rgb Convert(in Cmyk input) |
|||
{ |
|||
Vector3 rgb = (Vector3.One - new Vector3(input.C, input.M, input.Y)) * (Vector3.One - new Vector3(input.K)); |
|||
return new Rgb(rgb); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="Cmyk"/> type.
|
|||
/// </summary>
|
|||
/// <param name="input">The input color instance.</param>
|
|||
/// <returns>The converted result</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public Cmyk Convert(in Rgb input) |
|||
{ |
|||
// To CMY
|
|||
Vector3 cmy = Vector3.One - input.ToVector3(); |
|||
|
|||
// To CMYK
|
|||
var k = new Vector3(MathF.Min(cmy.X, MathF.Min(cmy.Y, cmy.Z))); |
|||
|
|||
if (MathF.Abs(k.X - 1F) < Constants.Epsilon) |
|||
{ |
|||
return new Cmyk(0, 0, 0, 1F); |
|||
} |
|||
|
|||
cmy = (cmy - k) / (Vector3.One - k); |
|||
|
|||
return new Cmyk(cmy.X, cmy.Y, cmy.Z, k.X); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation |
|||
{ |
|||
/// <summary>
|
|||
/// Color converter between <see cref="HunterLab"/> and <see cref="CieXyz"/>
|
|||
/// </summary>
|
|||
internal sealed class HunterLabToCieXyzConverter : CieXyzAndHunterLabConverterBase |
|||
{ |
|||
/// <summary>
|
|||
/// Performs the conversion from the <see cref="HunterLab"/> input to an instance of <see cref="CieXyz"/> type.
|
|||
/// </summary>
|
|||
/// <param name="input">The input color instance.</param>
|
|||
/// <returns>The converted result</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public CieXyz Convert(in HunterLab input) |
|||
{ |
|||
// Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab
|
|||
float l = input.L, a = input.A, b = input.B; |
|||
float xn = input.WhitePoint.X, yn = input.WhitePoint.Y, zn = input.WhitePoint.Z; |
|||
|
|||
float ka = ComputeKa(input.WhitePoint); |
|||
float kb = ComputeKb(input.WhitePoint); |
|||
|
|||
float pow = ImageMaths.Pow2(l / 100F); |
|||
float sqrtPow = MathF.Sqrt(pow); |
|||
float y = pow * yn; |
|||
|
|||
float x = (((a / ka) * sqrtPow) + pow) * xn; |
|||
float z = (((b / kb) * sqrtPow) - pow) * (-zn); |
|||
|
|||
return new CieXyz(x, y, z); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation |
|||
{ |
|||
/// <summary>
|
|||
/// Color converter between <see cref="LinearRgb"/> and <see cref="Rgb"/>
|
|||
/// </summary>
|
|||
internal sealed class LinearRgbToRgbConverter |
|||
{ |
|||
/// <summary>
|
|||
/// Performs the conversion from the <see cref="LinearRgb"/> input to an instance of <see cref="Rgb"/> type.
|
|||
/// </summary>
|
|||
/// <param name="input">The input color instance.</param>
|
|||
/// <returns>The converted result</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public Rgb Convert(in LinearRgb input) |
|||
{ |
|||
var vector = input.ToVector3(); |
|||
vector.X = input.WorkingSpace.Compress(vector.X); |
|||
vector.Y = input.WorkingSpace.Compress(vector.Y); |
|||
vector.Z = input.WorkingSpace.Compress(vector.Z); |
|||
|
|||
return new Rgb(vector, input.WorkingSpace); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation |
|||
{ |
|||
/// <summary>
|
|||
/// Color converter between Rgb and LinearRgb
|
|||
/// </summary>
|
|||
internal class RgbToLinearRgbConverter |
|||
{ |
|||
/// <summary>
|
|||
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="LinearRgb"/> type.
|
|||
/// </summary>
|
|||
/// <param name="input">The input color instance.</param>
|
|||
/// <returns>The converted result</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public LinearRgb Convert(in Rgb input) |
|||
{ |
|||
var vector = input.ToVector3(); |
|||
vector.X = input.WorkingSpace.Expand(vector.X); |
|||
vector.Y = input.WorkingSpace.Expand(vector.Y); |
|||
vector.Z = input.WorkingSpace.Expand(vector.Z); |
|||
|
|||
return new LinearRgb(vector, input.WorkingSpace); |
|||
} |
|||
} |
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabColorSapce |
|||
{ |
|||
/// <summary>
|
|||
/// Color converter between HunterLab and CieXyz
|
|||
/// </summary>
|
|||
internal class HunterLabToCieXyzConverter : CieXyzAndHunterLabConverterBase, IColorConversion<HunterLab, CieXyz> |
|||
{ |
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public CieXyz Convert(in HunterLab input) |
|||
{ |
|||
// Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab
|
|||
float l = input.L, a = input.A, b = input.B; |
|||
float xn = input.WhitePoint.X, yn = input.WhitePoint.Y, zn = input.WhitePoint.Z; |
|||
|
|||
float ka = ComputeKa(input.WhitePoint); |
|||
float kb = ComputeKb(input.WhitePoint); |
|||
|
|||
float y = MathF.Pow(l / 100F, 2) * yn; |
|||
float x = (((a / ka) * MathF.Sqrt(y / yn)) + (y / yn)) * xn; |
|||
float z = (((b / kb) * MathF.Sqrt(y / yn)) - (y / yn)) * (-zn); |
|||
|
|||
return new CieXyz(x, y, z); |
|||
} |
|||
} |
|||
} |
|||
@ -1,46 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce |
|||
{ |
|||
/// <summary>
|
|||
/// Implements gamma companding
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
|
|||
/// </remarks>
|
|||
internal class GammaCompanding : ICompanding |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GammaCompanding"/> class.
|
|||
/// </summary>
|
|||
/// <param name="gamma">The gamma value.</param>
|
|||
public GammaCompanding(float gamma) |
|||
{ |
|||
this.Gamma = gamma; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the gamma value
|
|||
/// </summary>
|
|||
public float Gamma { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public float Expand(float channel) |
|||
{ |
|||
return MathF.Pow(channel, this.Gamma); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public float Compress(float channel) |
|||
{ |
|||
return MathF.Pow(channel, 1 / this.Gamma); |
|||
} |
|||
} |
|||
} |
|||
@ -1,35 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce |
|||
{ |
|||
/// <summary>
|
|||
/// Implements L* companding
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// For more info see:
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
|
|||
/// </remarks>
|
|||
internal class LCompanding : ICompanding |
|||
{ |
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public float Expand(float channel) |
|||
{ |
|||
return channel <= 0.08 ? 100 * channel / CieConstants.Kappa : MathF.Pow((channel + 0.16F) / 1.16F, 3); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public float Compress(float channel) |
|||
{ |
|||
return channel <= CieConstants.Epsilon |
|||
? channel * CieConstants.Kappa / 100F |
|||
: MathF.Pow(1.16F * channel, 0.3333333F) - 0.16F; |
|||
} |
|||
} |
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Numerics; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce |
|||
{ |
|||
/// <summary>
|
|||
/// Color converter between LinearRgb and Rgb
|
|||
/// </summary>
|
|||
internal class LinearRgbToRgbConverter : IColorConversion<LinearRgb, Rgb> |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public Rgb Convert(in LinearRgb input) |
|||
{ |
|||
Vector3 vector = input.Vector; |
|||
vector.X = input.WorkingSpace.Companding.Compress(vector.X); |
|||
vector.Y = input.WorkingSpace.Companding.Compress(vector.Y); |
|||
vector.Z = input.WorkingSpace.Companding.Compress(vector.Z); |
|||
|
|||
return new Rgb(vector, input.WorkingSpace); |
|||
} |
|||
} |
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce |
|||
{ |
|||
/// <summary>
|
|||
/// Implements Rec. 2020 companding function (for 12-bits).
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <see href="http://en.wikipedia.org/wiki/Rec._2020"/>
|
|||
/// For 10-bits, companding is identical to <see cref="Rec709Companding"/>
|
|||
/// </remarks>
|
|||
internal class Rec2020Companding : ICompanding |
|||
{ |
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public float Expand(float channel) |
|||
{ |
|||
return channel < 0.08145F ? channel / 4.5F : MathF.Pow((channel + 0.0993F) / 1.0993F, 2.222222F); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public float Compress(float channel) |
|||
{ |
|||
return channel < 0.0181F ? 4500F * channel : (1.0993F * channel) - 0.0993F; |
|||
} |
|||
} |
|||
} |
|||
@ -1,31 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce |
|||
{ |
|||
/// <summary>
|
|||
/// Implements the Rec. 709 companding function
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// http://en.wikipedia.org/wiki/Rec._709
|
|||
/// </remarks>
|
|||
internal class Rec709Companding : ICompanding |
|||
{ |
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public float Expand(float channel) |
|||
{ |
|||
return channel < 0.081F ? channel / 4.5F : MathF.Pow((channel + 0.099F) / 1.099F, 2.222222F); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public float Compress(float channel) |
|||
{ |
|||
return channel < 0.018F ? 4500F * channel : (1.099F * channel) - 0.099F; |
|||
} |
|||
} |
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Numerics; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce |
|||
{ |
|||
/// <summary>
|
|||
/// Color converter between Rgb and LinearRgb
|
|||
/// </summary>
|
|||
internal class RgbToLinearRgbConverter : IColorConversion<Rgb, LinearRgb> |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public LinearRgb Convert(in Rgb input) |
|||
{ |
|||
Vector3 vector = input.Vector; |
|||
vector.X = input.WorkingSpace.Companding.Expand(vector.X); |
|||
vector.Y = input.WorkingSpace.Companding.Expand(vector.Y); |
|||
vector.Z = input.WorkingSpace.Companding.Expand(vector.Z); |
|||
|
|||
return new LinearRgb(vector, input.WorkingSpace); |
|||
} |
|||
} |
|||
} |
|||
@ -1,98 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce |
|||
{ |
|||
/// <summary>
|
|||
/// Trivial implementation of <see cref="RgbWorkingSpace"/>
|
|||
/// </summary>
|
|||
internal class RgbWorkingSpace |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="RgbWorkingSpace"/> class.
|
|||
/// </summary>
|
|||
/// <param name="referenceWhite">The reference white point.</param>
|
|||
/// <param name="companding">The function pair for converting to <see cref="CieXyz"/> and back.</param>
|
|||
/// <param name="chromaticityCoordinates">The chromaticity of the rgb primaries.</param>
|
|||
public RgbWorkingSpace(CieXyz referenceWhite, ICompanding companding, RgbPrimariesChromaticityCoordinates chromaticityCoordinates) |
|||
{ |
|||
this.WhitePoint = referenceWhite; |
|||
this.Companding = companding; |
|||
this.ChromaticityCoordinates = chromaticityCoordinates; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the reference white point
|
|||
/// </summary>
|
|||
public CieXyz WhitePoint { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the function pair for converting to <see cref="CieXyz"/> and back.
|
|||
/// </summary>
|
|||
public ICompanding Companding { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the chromaticity of the rgb primaries.
|
|||
/// </summary>
|
|||
public RgbPrimariesChromaticityCoordinates ChromaticityCoordinates { get; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="RgbWorkingSpace"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="RgbWorkingSpace"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="RgbWorkingSpace"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(RgbWorkingSpace left, RgbWorkingSpace right) |
|||
{ |
|||
return Equals(left, right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="RgbWorkingSpace"/> objects for inequality
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="RgbWorkingSpace"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="RgbWorkingSpace"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(RgbWorkingSpace left, RgbWorkingSpace right) |
|||
{ |
|||
return !Equals(left, right); |
|||
} |
|||
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return obj is RgbWorkingSpace other && this.Equals(other); |
|||
} |
|||
|
|||
public bool Equals(RgbWorkingSpace other) |
|||
{ |
|||
// TODO: Object.Equals for ICompanding will be slow.
|
|||
return this.WhitePoint.Equals(other.WhitePoint) |
|||
&& this.ChromaticityCoordinates.Equals(other.ChromaticityCoordinates) |
|||
&& Equals(this.Companding, other.Companding); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() |
|||
{ |
|||
unchecked |
|||
{ |
|||
int hashCode = this.WhitePoint.GetHashCode(); |
|||
hashCode = (hashCode * 397) ^ this.ChromaticityCoordinates.GetHashCode(); |
|||
hashCode = (hashCode * 397) ^ (this.Companding?.GetHashCode() ?? 0); |
|||
return hashCode; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,33 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce |
|||
{ |
|||
/// <summary>
|
|||
/// Implements sRGB companding
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// For more info see:
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
|
|||
/// </remarks>
|
|||
internal class SRgbCompanding : ICompanding |
|||
{ |
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public float Expand(float channel) |
|||
{ |
|||
return channel <= 0.04045F ? channel / 12.92F : MathF.Pow((channel + 0.055F) / 1.055F, 2.4F); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public float Compress(float channel) |
|||
{ |
|||
return channel <= 0.0031308F ? 12.92F * channel : (1.055F * MathF.Pow(channel, 0.416666666666667F)) - 0.055F; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
using SixLabors.ImageSharp.ColorSpaces.Companding; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation |
|||
{ |
|||
/// <summary>
|
|||
/// The gamma working space.
|
|||
/// </summary>
|
|||
public class GammaWorkingSpace : RgbWorkingSpaceBase |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GammaWorkingSpace" /> class.
|
|||
/// </summary>
|
|||
/// <param name="gamma">The gamma value.</param>
|
|||
/// <param name="referenceWhite">The reference white point.</param>
|
|||
/// <param name="chromaticityCoordinates">The chromaticity of the rgb primaries.</param>
|
|||
public GammaWorkingSpace(float gamma, CieXyz referenceWhite, RgbPrimariesChromaticityCoordinates chromaticityCoordinates) |
|||
: base(referenceWhite, chromaticityCoordinates) => this.Gamma = gamma; |
|||
|
|||
/// <summary>
|
|||
/// Gets the gamma value.
|
|||
/// </summary>
|
|||
public float Gamma { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public override float Compress(float channel) => GammaCompanding.Compress(channel, this.Gamma); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public override float Expand(float channel) => GammaCompanding.Expand(channel, this.Gamma); |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
if (obj is null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (ReferenceEquals(this, obj)) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
if (obj is GammaWorkingSpace other) |
|||
{ |
|||
return this.Gamma.Equals(other.Gamma) |
|||
&& this.WhitePoint.Equals(other.WhitePoint) |
|||
&& this.ChromaticityCoordinates.Equals(other.ChromaticityCoordinates); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() |
|||
{ |
|||
int hash = base.GetHashCode(); |
|||
return HashHelpers.Combine(hash, this.Gamma.GetHashCode()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
using SixLabors.ImageSharp.ColorSpaces.Companding; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation |
|||
{ |
|||
/// <summary>
|
|||
/// L* working space.
|
|||
/// </summary>
|
|||
public sealed class LWorkingSpace : RgbWorkingSpaceBase |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="LWorkingSpace" /> class.
|
|||
/// </summary>
|
|||
/// <param name="referenceWhite">The reference white point.</param>
|
|||
/// <param name="chromaticityCoordinates">The chromaticity of the rgb primaries.</param>
|
|||
public LWorkingSpace(CieXyz referenceWhite, RgbPrimariesChromaticityCoordinates chromaticityCoordinates) |
|||
: base(referenceWhite, chromaticityCoordinates) |
|||
{ |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public override float Compress(float channel) => LCompanding.Compress(channel); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public override float Expand(float channel) => LCompanding.Expand(channel); |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
using SixLabors.ImageSharp.ColorSpaces.Companding; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation |
|||
{ |
|||
/// <summary>
|
|||
/// Rec. 2020 (ITU-R Recommendation BT.2020F) working space.
|
|||
/// </summary>
|
|||
public sealed class Rec2020WorkingSpace : RgbWorkingSpaceBase |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rec2020WorkingSpace" /> class.
|
|||
/// </summary>
|
|||
/// <param name="referenceWhite">The reference white point.</param>
|
|||
/// <param name="chromaticityCoordinates">The chromaticity of the rgb primaries.</param>
|
|||
public Rec2020WorkingSpace(CieXyz referenceWhite, RgbPrimariesChromaticityCoordinates chromaticityCoordinates) |
|||
: base(referenceWhite, chromaticityCoordinates) |
|||
{ |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public override float Compress(float channel) => Rec2020Companding.Compress(channel); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public override float Expand(float channel) => Rec2020Companding.Expand(channel); |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
using SixLabors.ImageSharp.ColorSpaces.Companding; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation |
|||
{ |
|||
/// <summary>
|
|||
/// Rec. 709 (ITU-R Recommendation BT.709) working space.
|
|||
/// </summary>
|
|||
public sealed class Rec709WorkingSpace : RgbWorkingSpaceBase |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rec709WorkingSpace" /> class.
|
|||
/// </summary>
|
|||
/// <param name="referenceWhite">The reference white point.</param>
|
|||
/// <param name="chromaticityCoordinates">The chromaticity of the rgb primaries.</param>
|
|||
public Rec709WorkingSpace(CieXyz referenceWhite, RgbPrimariesChromaticityCoordinates chromaticityCoordinates) |
|||
: base(referenceWhite, chromaticityCoordinates) |
|||
{ |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public override float Compress(float channel) => Rec709Companding.Compress(channel); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public override float Expand(float channel) => Rec709Companding.Expand(channel); |
|||
} |
|||
} |
|||
@ -0,0 +1,83 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation |
|||
{ |
|||
/// <summary>
|
|||
/// Base class for all implementations of <see cref="RgbWorkingSpaceBase"/>.
|
|||
/// </summary>
|
|||
public abstract class RgbWorkingSpaceBase |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="RgbWorkingSpaceBase"/> class.
|
|||
/// </summary>
|
|||
/// <param name="referenceWhite">The reference white point.</param>
|
|||
/// <param name="chromaticityCoordinates">The chromaticity of the rgb primaries.</param>
|
|||
protected RgbWorkingSpaceBase(CieXyz referenceWhite, RgbPrimariesChromaticityCoordinates chromaticityCoordinates) |
|||
{ |
|||
this.WhitePoint = referenceWhite; |
|||
this.ChromaticityCoordinates = chromaticityCoordinates; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the reference white point
|
|||
/// </summary>
|
|||
public CieXyz WhitePoint { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the chromaticity of the rgb primaries.
|
|||
/// </summary>
|
|||
public RgbPrimariesChromaticityCoordinates ChromaticityCoordinates { get; } |
|||
|
|||
/// <summary>
|
|||
/// Expands a companded channel to its linear equivalent with respect to the energy.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// For more info see:
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
|
|||
/// </remarks>
|
|||
/// <param name="channel">The channel value.</param>
|
|||
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
|
|||
public abstract float Expand(float channel); |
|||
|
|||
/// <summary>
|
|||
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent (depends on the RGB color system).
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// For more info see:
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
|
|||
/// </remarks>
|
|||
/// <param name="channel">The channel value.</param>
|
|||
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
|
|||
public abstract float Compress(float channel); |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
if (obj is null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (ReferenceEquals(this, obj)) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
if (obj is RgbWorkingSpaceBase other) |
|||
{ |
|||
return this.WhitePoint.Equals(other.WhitePoint) |
|||
&& this.ChromaticityCoordinates.Equals(other.ChromaticityCoordinates); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() |
|||
{ |
|||
int hash = this.WhitePoint.GetHashCode(); |
|||
return HashHelpers.Combine(hash, this.ChromaticityCoordinates.GetHashCode()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
using SixLabors.ImageSharp.ColorSpaces.Companding; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation |
|||
{ |
|||
/// <summary>
|
|||
/// The sRgb working space.
|
|||
/// </summary>
|
|||
public sealed class SRgbWorkingSpace : RgbWorkingSpaceBase |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="SRgbWorkingSpace" /> class.
|
|||
/// </summary>
|
|||
/// <param name="referenceWhite">The reference white point.</param>
|
|||
/// <param name="chromaticityCoordinates">The chromaticity of the rgb primaries.</param>
|
|||
public SRgbWorkingSpace(CieXyz referenceWhite, RgbPrimariesChromaticityCoordinates chromaticityCoordinates) |
|||
: base(referenceWhite, chromaticityCoordinates) |
|||
{ |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public override float Compress(float channel) => SRgbCompanding.Compress(channel); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public override float Expand(float channel) => SRgbCompanding.Expand(channel); |
|||
} |
|||
} |
|||
@ -1,28 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces |
|||
{ |
|||
/// <summary>
|
|||
/// Defines a generalized method that a value type or class implements to create
|
|||
/// a type-specific method for determining approximate equality of instances.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The type of objects to compare.</typeparam>
|
|||
/// <typeparam name="TPrecision">The object specifying the type to specify precision with.</typeparam>
|
|||
internal interface IAlmostEquatable<in TPixel, in TPrecision> |
|||
where TPrecision : struct, IComparable<TPrecision> |
|||
{ |
|||
/// <summary>
|
|||
/// Indicates whether the current object is equal to another object of the same type
|
|||
/// when compared to the specified precision level.
|
|||
/// </summary>
|
|||
/// <param name="other">An object to compare with this object.</param>
|
|||
/// <param name="precision">The object specifying the level of precision.</param>
|
|||
/// <returns>
|
|||
/// true if the current object is equal to the other parameter; otherwise, false.
|
|||
/// </returns>
|
|||
bool AlmostEquals(TPixel other, TPrecision precision); |
|||
} |
|||
} |
|||
@ -1,18 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Numerics; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces |
|||
{ |
|||
/// <summary>
|
|||
/// Color represented as a vector in its color space
|
|||
/// </summary>
|
|||
internal interface IColorVector |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the vector representation of the color
|
|||
/// </summary>
|
|||
Vector3 Vector { get; } |
|||
} |
|||
} |
|||
@ -1,37 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces |
|||
{ |
|||
/// <summary>
|
|||
/// Pair of companding functions for <see cref="RgbWorkingSpace"/>.
|
|||
/// Used for conversion to <see cref="CieXyz"/> and backwards.
|
|||
/// See also: <seealso cref="RgbWorkingSpace.Companding"/>
|
|||
/// </summary>
|
|||
internal interface ICompanding |
|||
{ |
|||
/// <summary>
|
|||
/// Expands a companded channel to its linear equivalent with respect to the energy.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// For more info see:
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
|
|||
/// </remarks>
|
|||
/// <param name="channel">The channel value</param>
|
|||
/// <returns>The linear channel value</returns>
|
|||
float Expand(float channel); |
|||
|
|||
/// <summary>
|
|||
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent (depends on the RGB color system).
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// For more info see:
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
|
|||
/// </remarks>
|
|||
/// <param name="channel">The channel value</param>
|
|||
/// <returns>The nonlinear channel value</returns>
|
|||
float Compress(float channel); |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue