mirror of https://github.com/SixLabors/ImageSharp
348 changed files with 0 additions and 40420 deletions
@ -1,34 +0,0 @@ |
|||||
|
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00 |
|
||||
# Visual Studio 14 |
|
||||
VisualStudioVersion = 14.0.25420.1 |
|
||||
MinimumVisualStudioVersion = 10.0.40219.1 |
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp46", "src\ImageSharp46\ImageSharp46.csproj", "{FBA0B5F6-09C2-4317-8EF6-6ADB9B20E6B1}" |
|
||||
EndProject |
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Tests46", "tests\ImageSharp.Tests46\ImageSharp.Tests46.csproj", "{635E0A15-3893-4763-A7F6-FCCFF85BCCA4}" |
|
||||
EndProject |
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleBenchmark", "tests\ConsoleBenchmark\ConsoleBenchmark.csproj", "{8783E3A1-79F1-4E37-AA79-F06C48BED5E7}" |
|
||||
EndProject |
|
||||
Global |
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
|
||||
Debug|Any CPU = Debug|Any CPU |
|
||||
Release|Any CPU = Release|Any CPU |
|
||||
EndGlobalSection |
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
|
||||
{FBA0B5F6-09C2-4317-8EF6-6ADB9B20E6B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
|
||||
{FBA0B5F6-09C2-4317-8EF6-6ADB9B20E6B1}.Debug|Any CPU.Build.0 = Debug|Any CPU |
|
||||
{FBA0B5F6-09C2-4317-8EF6-6ADB9B20E6B1}.Release|Any CPU.ActiveCfg = Release|Any CPU |
|
||||
{FBA0B5F6-09C2-4317-8EF6-6ADB9B20E6B1}.Release|Any CPU.Build.0 = Release|Any CPU |
|
||||
{635E0A15-3893-4763-A7F6-FCCFF85BCCA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
|
||||
{635E0A15-3893-4763-A7F6-FCCFF85BCCA4}.Debug|Any CPU.Build.0 = Debug|Any CPU |
|
||||
{635E0A15-3893-4763-A7F6-FCCFF85BCCA4}.Release|Any CPU.ActiveCfg = Release|Any CPU |
|
||||
{635E0A15-3893-4763-A7F6-FCCFF85BCCA4}.Release|Any CPU.Build.0 = Release|Any CPU |
|
||||
{8783E3A1-79F1-4E37-AA79-F06C48BED5E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
|
||||
{8783E3A1-79F1-4E37-AA79-F06C48BED5E7}.Debug|Any CPU.Build.0 = Debug|Any CPU |
|
||||
{8783E3A1-79F1-4E37-AA79-F06C48BED5E7}.Release|Any CPU.ActiveCfg = Release|Any CPU |
|
||||
{8783E3A1-79F1-4E37-AA79-F06C48BED5E7}.Release|Any CPU.Build.0 = Release|Any CPU |
|
||||
EndGlobalSection |
|
||||
GlobalSection(SolutionProperties) = preSolution |
|
||||
HideSolutionNode = FALSE |
|
||||
EndGlobalSection |
|
||||
EndGlobal |
|
||||
@ -1,69 +0,0 @@ |
|||||
// <copyright file="Bootstrapper.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Collections.ObjectModel; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
using Formats; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Provides initialization code which allows extending the library.
|
|
||||
/// </summary>
|
|
||||
public class Bootstrapper |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// A new instance Initializes a new instance of the <see cref="Bootstrapper"/> class.
|
|
||||
/// with lazy initialization.
|
|
||||
/// </summary>
|
|
||||
private static readonly Lazy<Bootstrapper> Lazy = new Lazy<Bootstrapper>(() => new Bootstrapper()); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The default list of supported <see cref="IImageFormat"/>
|
|
||||
/// </summary>
|
|
||||
private readonly List<IImageFormat> imageFormats; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Prevents a default instance of the <see cref="Bootstrapper"/> class from being created.
|
|
||||
/// </summary>
|
|
||||
private Bootstrapper() |
|
||||
{ |
|
||||
this.imageFormats = new List<IImageFormat> |
|
||||
{ |
|
||||
new BmpFormat(), |
|
||||
new JpegFormat(), |
|
||||
new PngFormat(), |
|
||||
new GifFormat() |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the current bootstrapper instance.
|
|
||||
/// </summary>
|
|
||||
public static Bootstrapper Instance => Lazy.Value; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the collection of supported <see cref="IImageFormat"/>
|
|
||||
/// </summary>
|
|
||||
public IReadOnlyCollection<IImageFormat> ImageFormats => new ReadOnlyCollection<IImageFormat>(this.imageFormats); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the global parallel options for processing tasks in parallel.
|
|
||||
/// </summary>
|
|
||||
public ParallelOptions ParallelOptions { get; set; } = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Adds a new <see cref="IImageFormat"/> to the collection of supported image formats.
|
|
||||
/// </summary>
|
|
||||
/// <param name="format">The new format to add.</param>
|
|
||||
public void AddImageFormat(IImageFormat format) |
|
||||
{ |
|
||||
this.imageFormats.Add(format); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,408 +0,0 @@ |
|||||
// <copyright file="Color.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Globalization; |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Packed vector type containing four 8-bit unsigned normalized values ranging from 0 to 255.
|
|
||||
/// The color components are stored in red, green, blue, and alpha order.
|
|
||||
/// </summary>
|
|
||||
/// <remarks>
|
|
||||
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|
||||
/// as it avoids the need to create new values for modification operations.
|
|
||||
/// </remarks>
|
|
||||
public partial struct Color : IPackedPixel<uint>, IEquatable<Color> |
|
||||
{ |
|
||||
private const int RedShift = 0; |
|
||||
private const int GreenShift = 8; |
|
||||
private const int BlueShift = 16; |
|
||||
private const int AlphaShift = 24; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The maximum byte value.
|
|
||||
/// </summary>
|
|
||||
private static readonly Vector4 MaxBytes = new Vector4(255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The half vector value.
|
|
||||
/// </summary>
|
|
||||
private static readonly Vector4 Half = new Vector4(0.5f); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The packed value.
|
|
||||
/// </summary>
|
|
||||
private uint packedValue; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="Color"/> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="r">The red component.</param>
|
|
||||
/// <param name="g">The green component.</param>
|
|
||||
/// <param name="b">The blue component.</param>
|
|
||||
/// <param name="a">The alpha component.</param>
|
|
||||
public Color(byte r, byte g, byte b, byte a = 255) |
|
||||
{ |
|
||||
this.packedValue = Pack(r, g, b, a); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="Color"/> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="hex">
|
|
||||
/// The hexadecimal representation of the combined color components arranged
|
|
||||
/// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax.
|
|
||||
/// </param>
|
|
||||
public Color(string hex) |
|
||||
{ |
|
||||
Guard.NotNullOrEmpty(hex, nameof(hex)); |
|
||||
|
|
||||
hex = ToRgbaHex(hex); |
|
||||
|
|
||||
if (hex == null || !uint.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out this.packedValue)) |
|
||||
{ |
|
||||
throw new ArgumentException("Hexadecimal string is not in the correct format.", nameof(hex)); |
|
||||
} |
|
||||
|
|
||||
// Order parsed from hex string will be backwards, so reverse it.
|
|
||||
this.packedValue = Pack(this.A, this.B, this.G, this.R); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="Color"/> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="r">The red component.</param>
|
|
||||
/// <param name="g">The green component.</param>
|
|
||||
/// <param name="b">The blue component.</param>
|
|
||||
/// <param name="a">The alpha component.</param>
|
|
||||
public Color(float r, float g, float b, float a = 1) |
|
||||
{ |
|
||||
this.packedValue = Pack(r, g, b, a); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="Color"/> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="vector">
|
|
||||
/// The vector containing the components for the packed vector.
|
|
||||
/// </param>
|
|
||||
public Color(Vector3 vector) |
|
||||
{ |
|
||||
this.packedValue = Pack(ref vector); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="Color"/> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="vector">
|
|
||||
/// The vector containing the components for the packed vector.
|
|
||||
/// </param>
|
|
||||
public Color(Vector4 vector) |
|
||||
{ |
|
||||
this.packedValue = Pack(ref vector); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the red component.
|
|
||||
/// </summary>
|
|
||||
public byte R |
|
||||
{ |
|
||||
get |
|
||||
{ |
|
||||
return (byte)(this.packedValue >> RedShift); |
|
||||
} |
|
||||
|
|
||||
set |
|
||||
{ |
|
||||
this.packedValue = this.packedValue & 0xFFFFFF00 | (uint)value << RedShift; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the green component.
|
|
||||
/// </summary>
|
|
||||
public byte G |
|
||||
{ |
|
||||
get |
|
||||
{ |
|
||||
return (byte)(this.packedValue >> GreenShift); |
|
||||
} |
|
||||
|
|
||||
set |
|
||||
{ |
|
||||
this.packedValue = this.packedValue & 0xFFFF00FF | (uint)value << GreenShift; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the blue component.
|
|
||||
/// </summary>
|
|
||||
public byte B |
|
||||
{ |
|
||||
get |
|
||||
{ |
|
||||
return (byte)(this.packedValue >> BlueShift); |
|
||||
} |
|
||||
|
|
||||
set |
|
||||
{ |
|
||||
this.packedValue = this.packedValue & 0xFF00FFFF | (uint)value << BlueShift; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the alpha component.
|
|
||||
/// </summary>
|
|
||||
public byte A |
|
||||
{ |
|
||||
get |
|
||||
{ |
|
||||
return (byte)(this.packedValue >> AlphaShift); |
|
||||
} |
|
||||
|
|
||||
set |
|
||||
{ |
|
||||
this.packedValue = this.packedValue & 0x00FFFFFF | (uint)value << AlphaShift; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public uint PackedValue |
|
||||
{ |
|
||||
get |
|
||||
{ |
|
||||
return this.packedValue; |
|
||||
} |
|
||||
|
|
||||
set |
|
||||
{ |
|
||||
this.packedValue = value; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="Color"/> objects for equality.
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">
|
|
||||
/// The <see cref="Color"/> on the left side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <param name="right">
|
|
||||
/// The <see cref="Color"/> on the right side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|
||||
/// </returns>
|
|
||||
public static bool operator ==(Color left, Color right) |
|
||||
{ |
|
||||
return left.packedValue == right.packedValue; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="Color"/> objects for equality.
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">The <see cref="Color"/> on the left side of the operand.</param>
|
|
||||
/// <param name="right">The <see cref="Color"/> on the right side of the operand.</param>
|
|
||||
/// <returns>
|
|
||||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|
||||
/// </returns>
|
|
||||
public static bool operator !=(Color left, Color right) |
|
||||
{ |
|
||||
return left.packedValue != right.packedValue; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Creates a new instance of the <see cref="Color"/> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="hex">
|
|
||||
/// The hexadecimal representation of the combined color components arranged
|
|
||||
/// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="Color"/>.
|
|
||||
/// </returns>
|
|
||||
public static Color FromHex(string hex) |
|
||||
{ |
|
||||
return new Color(hex); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|
||||
{ |
|
||||
this.packedValue = Pack(x, y, z, w); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the value of this instance to a hexadecimal string.
|
|
||||
/// </summary>
|
|
||||
/// <returns>A hexadecimal string representation of the value.</returns>
|
|
||||
public string ToHex() |
|
||||
{ |
|
||||
uint hexOrder = Pack(this.A, this.B, this.G, this.R); |
|
||||
return hexOrder.ToString("X8"); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|
||||
{ |
|
||||
switch (componentOrder) |
|
||||
{ |
|
||||
case ComponentOrder.ZYX: |
|
||||
bytes[startIndex] = this.B; |
|
||||
bytes[startIndex + 1] = this.G; |
|
||||
bytes[startIndex + 2] = this.R; |
|
||||
break; |
|
||||
case ComponentOrder.ZYXW: |
|
||||
bytes[startIndex] = this.B; |
|
||||
bytes[startIndex + 1] = this.G; |
|
||||
bytes[startIndex + 2] = this.R; |
|
||||
bytes[startIndex + 3] = this.A; |
|
||||
break; |
|
||||
case ComponentOrder.XYZ: |
|
||||
bytes[startIndex] = this.R; |
|
||||
bytes[startIndex + 1] = this.G; |
|
||||
bytes[startIndex + 2] = this.B; |
|
||||
break; |
|
||||
case ComponentOrder.XYZW: |
|
||||
bytes[startIndex] = this.R; |
|
||||
bytes[startIndex + 1] = this.G; |
|
||||
bytes[startIndex + 2] = this.B; |
|
||||
bytes[startIndex + 3] = this.A; |
|
||||
break; |
|
||||
default: |
|
||||
throw new NotSupportedException(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public void PackFromVector4(Vector4 vector) |
|
||||
{ |
|
||||
this.packedValue = Pack(ref vector); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public Vector4 ToVector4() |
|
||||
{ |
|
||||
return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Equals(object obj) |
|
||||
{ |
|
||||
return (obj is Color) && this.Equals((Color)obj); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool Equals(Color other) |
|
||||
{ |
|
||||
return this.packedValue == other.packedValue; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets a string representation of the packed vector.
|
|
||||
/// </summary>
|
|
||||
/// <returns>A string representation of the packed vector.</returns>
|
|
||||
public override string ToString() |
|
||||
{ |
|
||||
return this.ToVector4().ToString(); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override int GetHashCode() |
|
||||
{ |
|
||||
return this.packedValue.GetHashCode(); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Packs a <see cref="Vector4"/> into a uint.
|
|
||||
/// </summary>
|
|
||||
/// <param name="vector">The vector containing the values to pack.</param>
|
|
||||
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
|
|
||||
private static uint Pack(ref Vector4 vector) |
|
||||
{ |
|
||||
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); |
|
||||
vector *= MaxBytes; |
|
||||
vector += Half; |
|
||||
return (uint)(((byte)vector.X << RedShift) |
|
||||
| ((byte)vector.Y << GreenShift) |
|
||||
| ((byte)vector.Z << BlueShift) |
|
||||
| (byte)vector.W << AlphaShift); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Packs a <see cref="Vector3"/> into a uint.
|
|
||||
/// </summary>
|
|
||||
/// <param name="vector">The vector containing the values to pack.</param>
|
|
||||
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
|
|
||||
private static uint Pack(ref Vector3 vector) |
|
||||
{ |
|
||||
Vector4 value = new Vector4(vector, 1); |
|
||||
return Pack(ref value); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Packs the four floats into a <see cref="uint"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="x">The x-component</param>
|
|
||||
/// <param name="y">The y-component</param>
|
|
||||
/// <param name="z">The z-component</param>
|
|
||||
/// <param name="w">The w-component</param>
|
|
||||
/// <returns>The <see cref="uint"/></returns>
|
|
||||
private static uint Pack(float x, float y, float z, float w) |
|
||||
{ |
|
||||
Vector4 value = new Vector4(x, y, z, w); |
|
||||
return Pack(ref value); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Packs the four floats into a <see cref="uint"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="x">The x-component</param>
|
|
||||
/// <param name="y">The y-component</param>
|
|
||||
/// <param name="z">The z-component</param>
|
|
||||
/// <param name="w">The w-component</param>
|
|
||||
/// <returns>The <see cref="uint"/></returns>
|
|
||||
private static uint Pack(byte x, byte y, byte z, byte w) |
|
||||
{ |
|
||||
return (uint)(x << RedShift | y << GreenShift | z << BlueShift | w << AlphaShift); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the specified hex value to an rrggbbaa hex value.
|
|
||||
/// </summary>
|
|
||||
/// <param name="hex">The hex value to convert.</param>
|
|
||||
/// <returns>
|
|
||||
/// A rrggbbaa hex value.
|
|
||||
/// </returns>
|
|
||||
private static string ToRgbaHex(string hex) |
|
||||
{ |
|
||||
hex = hex.StartsWith("#") ? hex.Substring(1) : hex; |
|
||||
|
|
||||
if (hex.Length == 8) |
|
||||
{ |
|
||||
return hex; |
|
||||
} |
|
||||
|
|
||||
if (hex.Length == 6) |
|
||||
{ |
|
||||
return hex + "FF"; |
|
||||
} |
|
||||
|
|
||||
if (hex.Length < 3 || hex.Length > 4) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
string red = char.ToString(hex[0]); |
|
||||
string green = char.ToString(hex[1]); |
|
||||
string blue = char.ToString(hex[2]); |
|
||||
string alpha = hex.Length == 3 ? "F" : char.ToString(hex[3]); |
|
||||
|
|
||||
return red + red + green + green + blue + blue + alpha + alpha; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,179 +0,0 @@ |
|||||
// <copyright file="ColorConstants.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Provides useful color definitions.
|
|
||||
/// </summary>
|
|
||||
public static class ColorConstants |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Provides a lazy, one time method of returning the colors.
|
|
||||
/// </summary>
|
|
||||
private static readonly Lazy<Color[]> SafeColors = new Lazy<Color[]>(GetWebSafeColors); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets a collection of named, web safe, colors as defined in the CSS Color Module Level 4.
|
|
||||
/// </summary>
|
|
||||
public static Color[] WebSafeColors => SafeColors.Value; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns an array of web safe colors.
|
|
||||
/// </summary>
|
|
||||
/// <returns></returns>
|
|
||||
private static Color[] GetWebSafeColors() |
|
||||
{ |
|
||||
return new List<Color> |
|
||||
{ |
|
||||
Color.AliceBlue, |
|
||||
Color.AntiqueWhite, |
|
||||
Color.Aqua, |
|
||||
Color.Aquamarine, |
|
||||
Color.Azure, |
|
||||
Color.Beige, |
|
||||
Color.Bisque, |
|
||||
Color.Black, |
|
||||
Color.BlanchedAlmond, |
|
||||
Color.Blue, |
|
||||
Color.BlueViolet, |
|
||||
Color.Brown, |
|
||||
Color.BurlyWood, |
|
||||
Color.CadetBlue, |
|
||||
Color.Chartreuse, |
|
||||
Color.Chocolate, |
|
||||
Color.Coral, |
|
||||
Color.CornflowerBlue, |
|
||||
Color.Cornsilk, |
|
||||
Color.Crimson, |
|
||||
Color.Cyan, |
|
||||
Color.DarkBlue, |
|
||||
Color.DarkCyan, |
|
||||
Color.DarkGoldenrod, |
|
||||
Color.DarkGray, |
|
||||
Color.DarkGreen, |
|
||||
Color.DarkKhaki, |
|
||||
Color.DarkMagenta, |
|
||||
Color.DarkOliveGreen, |
|
||||
Color.DarkOrange, |
|
||||
Color.DarkOrchid, |
|
||||
Color.DarkRed, |
|
||||
Color.DarkSalmon, |
|
||||
Color.DarkSeaGreen, |
|
||||
Color.DarkSlateBlue, |
|
||||
Color.DarkSlateGray, |
|
||||
Color.DarkTurquoise, |
|
||||
Color.DarkViolet, |
|
||||
Color.DeepPink, |
|
||||
Color.DeepSkyBlue, |
|
||||
Color.DimGray, |
|
||||
Color.DodgerBlue, |
|
||||
Color.Firebrick, |
|
||||
Color.FloralWhite, |
|
||||
Color.ForestGreen, |
|
||||
Color.Fuchsia, |
|
||||
Color.Gainsboro, |
|
||||
Color.GhostWhite, |
|
||||
Color.Gold, |
|
||||
Color.Goldenrod, |
|
||||
Color.Gray, |
|
||||
Color.Green, |
|
||||
Color.GreenYellow, |
|
||||
Color.Honeydew, |
|
||||
Color.HotPink, |
|
||||
Color.IndianRed, |
|
||||
Color.Indigo, |
|
||||
Color.Ivory, |
|
||||
Color.Khaki, |
|
||||
Color.Lavender, |
|
||||
Color.LavenderBlush, |
|
||||
Color.LawnGreen, |
|
||||
Color.LemonChiffon, |
|
||||
Color.LightBlue, |
|
||||
Color.LightCoral, |
|
||||
Color.LightCyan, |
|
||||
Color.LightGoldenrodYellow, |
|
||||
Color.LightGray, |
|
||||
Color.LightGreen, |
|
||||
Color.LightPink, |
|
||||
Color.LightSalmon, |
|
||||
Color.LightSeaGreen, |
|
||||
Color.LightSkyBlue, |
|
||||
Color.LightSlateGray, |
|
||||
Color.LightSteelBlue, |
|
||||
Color.LightYellow, |
|
||||
Color.Lime, |
|
||||
Color.LimeGreen, |
|
||||
Color.Linen, |
|
||||
Color.Magenta, |
|
||||
Color.Maroon, |
|
||||
Color.MediumAquamarine, |
|
||||
Color.MediumBlue, |
|
||||
Color.MediumOrchid, |
|
||||
Color.MediumPurple, |
|
||||
Color.MediumSeaGreen, |
|
||||
Color.MediumSlateBlue, |
|
||||
Color.MediumSpringGreen, |
|
||||
Color.MediumTurquoise, |
|
||||
Color.MediumVioletRed, |
|
||||
Color.MidnightBlue, |
|
||||
Color.MintCream, |
|
||||
Color.MistyRose, |
|
||||
Color.Moccasin, |
|
||||
Color.NavajoWhite, |
|
||||
Color.Navy, |
|
||||
Color.OldLace, |
|
||||
Color.Olive, |
|
||||
Color.OliveDrab, |
|
||||
Color.Orange, |
|
||||
Color.OrangeRed, |
|
||||
Color.Orchid, |
|
||||
Color.PaleGoldenrod, |
|
||||
Color.PaleGreen, |
|
||||
Color.PaleTurquoise, |
|
||||
Color.PaleVioletRed, |
|
||||
Color.PapayaWhip, |
|
||||
Color.PeachPuff, |
|
||||
Color.Peru, |
|
||||
Color.Pink, |
|
||||
Color.Plum, |
|
||||
Color.PowderBlue, |
|
||||
Color.Purple, |
|
||||
Color.RebeccaPurple, |
|
||||
Color.Red, |
|
||||
Color.RosyBrown, |
|
||||
Color.RoyalBlue, |
|
||||
Color.SaddleBrown, |
|
||||
Color.Salmon, |
|
||||
Color.SandyBrown, |
|
||||
Color.SeaGreen, |
|
||||
Color.SeaShell, |
|
||||
Color.Sienna, |
|
||||
Color.Silver, |
|
||||
Color.SkyBlue, |
|
||||
Color.SlateBlue, |
|
||||
Color.SlateGray, |
|
||||
Color.Snow, |
|
||||
Color.SpringGreen, |
|
||||
Color.SteelBlue, |
|
||||
Color.Tan, |
|
||||
Color.Teal, |
|
||||
Color.Thistle, |
|
||||
Color.Tomato, |
|
||||
Color.Transparent, |
|
||||
Color.Turquoise, |
|
||||
Color.Violet, |
|
||||
Color.Wheat, |
|
||||
Color.White, |
|
||||
Color.WhiteSmoke, |
|
||||
Color.Yellow, |
|
||||
Color.YellowGreen |
|
||||
}.ToArray(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,728 +0,0 @@ |
|||||
// <copyright file="ColorDefinitions.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Packed vector type containing four 8-bit unsigned normalized values ranging from 0 to 255.
|
|
||||
/// The color components are stored in red, green, blue, and alpha order.
|
|
||||
/// </summary>
|
|
||||
/// <remarks>
|
|
||||
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|
||||
/// as it avoids the need to create new values for modification operations.
|
|
||||
/// </remarks>
|
|
||||
public partial struct Color |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F0F8FF.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color AliceBlue = new Color(240, 248, 255, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FAEBD7.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color AntiqueWhite = new Color(250, 235, 215, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00FFFF.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Aqua = new Color(0, 255, 255, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #7FFFD4.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Aquamarine = new Color(127, 255, 212, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F0FFFF.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Azure = new Color(240, 255, 255, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F5F5DC.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Beige = new Color(245, 245, 220, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFE4C4.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Bisque = new Color(255, 228, 196, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #000000.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Black = new Color(0, 0, 0, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFEBCD.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color BlanchedAlmond = new Color(255, 235, 205, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #0000FF.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Blue = new Color(0, 0, 255, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #8A2BE2.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color BlueViolet = new Color(138, 43, 226, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #A52A2A.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Brown = new Color(165, 42, 42, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #DEB887.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color BurlyWood = new Color(222, 184, 135, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #5F9EA0.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color CadetBlue = new Color(95, 158, 160, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #7FFF00.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Chartreuse = new Color(127, 255, 0, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #D2691E.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Chocolate = new Color(210, 105, 30, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF7F50.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Coral = new Color(255, 127, 80, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #6495ED.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color CornflowerBlue = new Color(100, 149, 237, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFF8DC.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Cornsilk = new Color(255, 248, 220, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #DC143C.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Crimson = new Color(220, 20, 60, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00FFFF.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Cyan = new Color(0, 255, 255, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00008B.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkBlue = new Color(0, 0, 139, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #008B8B.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkCyan = new Color(0, 139, 139, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #B8860B.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkGoldenrod = new Color(184, 134, 11, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #A9A9A9.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkGray = new Color(169, 169, 169, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #006400.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkGreen = new Color(0, 100, 0, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #BDB76B.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkKhaki = new Color(189, 183, 107, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #8B008B.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkMagenta = new Color(139, 0, 139, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #556B2F.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkOliveGreen = new Color(85, 107, 47, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF8C00.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkOrange = new Color(255, 140, 0, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #9932CC.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkOrchid = new Color(153, 50, 204, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #8B0000.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkRed = new Color(139, 0, 0, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #E9967A.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkSalmon = new Color(233, 150, 122, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #8FBC8B.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkSeaGreen = new Color(143, 188, 139, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #483D8B.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkSlateBlue = new Color(72, 61, 139, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #2F4F4F.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkSlateGray = new Color(47, 79, 79, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00CED1.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkTurquoise = new Color(0, 206, 209, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #9400D3.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DarkViolet = new Color(148, 0, 211, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF1493.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DeepPink = new Color(255, 20, 147, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00BFFF.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DeepSkyBlue = new Color(0, 191, 255, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #696969.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DimGray = new Color(105, 105, 105, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #1E90FF.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color DodgerBlue = new Color(30, 144, 255, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #B22222.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Firebrick = new Color(178, 34, 34, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFAF0.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color FloralWhite = new Color(255, 250, 240, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #228B22.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color ForestGreen = new Color(34, 139, 34, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF00FF.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Fuchsia = new Color(255, 0, 255, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #DCDCDC.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Gainsboro = new Color(220, 220, 220, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F8F8FF.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color GhostWhite = new Color(248, 248, 255, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFD700.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Gold = new Color(255, 215, 0, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #DAA520.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Goldenrod = new Color(218, 165, 32, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #808080.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Gray = new Color(128, 128, 128, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #008000.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Green = new Color(0, 128, 0, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #ADFF2F.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color GreenYellow = new Color(173, 255, 47, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F0FFF0.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Honeydew = new Color(240, 255, 240, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF69B4.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color HotPink = new Color(255, 105, 180, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #CD5C5C.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color IndianRed = new Color(205, 92, 92, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #4B0082.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Indigo = new Color(75, 0, 130, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFFF0.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Ivory = new Color(255, 255, 240, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F0E68C.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Khaki = new Color(240, 230, 140, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #E6E6FA.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Lavender = new Color(230, 230, 250, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFF0F5.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LavenderBlush = new Color(255, 240, 245, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #7CFC00.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LawnGreen = new Color(124, 252, 0, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFACD.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LemonChiffon = new Color(255, 250, 205, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #ADD8E6.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LightBlue = new Color(173, 216, 230, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F08080.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LightCoral = new Color(240, 128, 128, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #E0FFFF.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LightCyan = new Color(224, 255, 255, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FAFAD2.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LightGoldenrodYellow = new Color(250, 250, 210, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #D3D3D3.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LightGray = new Color(211, 211, 211, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #90EE90.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LightGreen = new Color(144, 238, 144, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFB6C1.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LightPink = new Color(255, 182, 193, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFA07A.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LightSalmon = new Color(255, 160, 122, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #20B2AA.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LightSeaGreen = new Color(32, 178, 170, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #87CEFA.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LightSkyBlue = new Color(135, 206, 250, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #778899.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LightSlateGray = new Color(119, 136, 153, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #B0C4DE.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LightSteelBlue = new Color(176, 196, 222, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFFE0.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LightYellow = new Color(255, 255, 224, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00FF00.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Lime = new Color(0, 255, 0, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #32CD32.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color LimeGreen = new Color(50, 205, 50, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FAF0E6.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Linen = new Color(250, 240, 230, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF00FF.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Magenta = new Color(255, 0, 255, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #800000.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Maroon = new Color(128, 0, 0, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #66CDAA.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color MediumAquamarine = new Color(102, 205, 170, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #0000CD.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color MediumBlue = new Color(0, 0, 205, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #BA55D3.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color MediumOrchid = new Color(186, 85, 211, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #9370DB.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color MediumPurple = new Color(147, 112, 219, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #3CB371.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color MediumSeaGreen = new Color(60, 179, 113, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #7B68EE.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color MediumSlateBlue = new Color(123, 104, 238, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00FA9A.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color MediumSpringGreen = new Color(0, 250, 154, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #48D1CC.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color MediumTurquoise = new Color(72, 209, 204, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #C71585.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color MediumVioletRed = new Color(199, 21, 133, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #191970.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color MidnightBlue = new Color(25, 25, 112, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F5FFFA.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color MintCream = new Color(245, 255, 250, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFE4E1.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color MistyRose = new Color(255, 228, 225, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFE4B5.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Moccasin = new Color(255, 228, 181, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFDEAD.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color NavajoWhite = new Color(255, 222, 173, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #000080.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Navy = new Color(0, 0, 128, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FDF5E6.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color OldLace = new Color(253, 245, 230, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #808000.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Olive = new Color(128, 128, 0, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #6B8E23.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color OliveDrab = new Color(107, 142, 35, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFA500.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Orange = new Color(255, 165, 0, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF4500.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color OrangeRed = new Color(255, 69, 0, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #DA70D6.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Orchid = new Color(218, 112, 214, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #EEE8AA.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color PaleGoldenrod = new Color(238, 232, 170, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #98FB98.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color PaleGreen = new Color(152, 251, 152, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #AFEEEE.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color PaleTurquoise = new Color(175, 238, 238, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #DB7093.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color PaleVioletRed = new Color(219, 112, 147, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFEFD5.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color PapayaWhip = new Color(255, 239, 213, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFDAB9.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color PeachPuff = new Color(255, 218, 185, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #CD853F.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Peru = new Color(205, 133, 63, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFC0CB.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Pink = new Color(255, 192, 203, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #DDA0DD.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Plum = new Color(221, 160, 221, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #B0E0E6.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color PowderBlue = new Color(176, 224, 230, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #800080.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Purple = new Color(128, 0, 128, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #0.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color RebeccaPurple = new Color(102, 51, 153, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF0000.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Red = new Color(255, 0, 0, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #BC8F8F.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color RosyBrown = new Color(188, 143, 143, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #4169E1.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color RoyalBlue = new Color(65, 105, 225, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #8B4513.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color SaddleBrown = new Color(139, 69, 19, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FA8072.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Salmon = new Color(250, 128, 114, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F4A460.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color SandyBrown = new Color(244, 164, 96, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #2E8B57.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color SeaGreen = new Color(46, 139, 87, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFF5EE.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color SeaShell = new Color(255, 245, 238, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #A0522D.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Sienna = new Color(160, 82, 45, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #C0C0C0.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Silver = new Color(192, 192, 192, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #87CEEB.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color SkyBlue = new Color(135, 206, 235, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #6A5ACD.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color SlateBlue = new Color(106, 90, 205, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #708090.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color SlateGray = new Color(112, 128, 144, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFAFA.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Snow = new Color(255, 250, 250, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00FF7F.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color SpringGreen = new Color(0, 255, 127, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #4682B4.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color SteelBlue = new Color(70, 130, 180, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #D2B48C.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Tan = new Color(210, 180, 140, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #008080.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Teal = new Color(0, 128, 128, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #D8BFD8.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Thistle = new Color(216, 191, 216, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF6347.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Tomato = new Color(255, 99, 71, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFFFF.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Transparent = new Color(255, 255, 255, 0); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #40E0D0.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Turquoise = new Color(64, 224, 208, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #EE82EE.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Violet = new Color(238, 130, 238, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F5DEB3.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Wheat = new Color(245, 222, 179, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFFFF.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color White = new Color(255, 255, 255, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F5F5F5.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color WhiteSmoke = new Color(245, 245, 245, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFF00.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color Yellow = new Color(255, 255, 0, 255); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #9ACD32.
|
|
||||
/// </summary>
|
|
||||
public static readonly Color YellowGreen = new Color(154, 205, 50, 255); |
|
||||
} |
|
||||
} |
|
||||
@ -1,74 +0,0 @@ |
|||||
// <copyright file="ColorTransforms.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Packed vector type containing four 8-bit unsigned normalized values ranging from 0 to 255.
|
|
||||
/// The color components are stored in red, green, blue, and alpha order.
|
|
||||
/// </summary>
|
|
||||
/// <remarks>
|
|
||||
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|
||||
/// as it avoids the need to create new values for modification operations.
|
|
||||
/// </remarks>
|
|
||||
public partial struct Color |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Blends two colors by multiplication.
|
|
||||
/// <remarks>
|
|
||||
/// The source color is multiplied by the destination color and replaces the destination.
|
|
||||
/// The resultant color is always at least as dark as either the source or destination color.
|
|
||||
/// Multiplying any color with black results in black. Multiplying any color with white preserves the
|
|
||||
/// original color.
|
|
||||
/// </remarks>
|
|
||||
/// </summary>
|
|
||||
/// <param name="source">The source color.</param>
|
|
||||
/// <param name="destination">The destination color.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="Color"/>.
|
|
||||
/// </returns>
|
|
||||
public static Color Multiply(Color source, Color destination) |
|
||||
{ |
|
||||
if (destination == Color.Black) |
|
||||
{ |
|
||||
return Color.Black; |
|
||||
} |
|
||||
|
|
||||
if (destination == Color.White) |
|
||||
{ |
|
||||
return source; |
|
||||
} |
|
||||
|
|
||||
// TODO: This will use less memory than using Vector4
|
|
||||
// but we should test speed vs memory to see which is best balance.
|
|
||||
byte r = (byte)(source.R * destination.R).Clamp(0, 255); |
|
||||
byte g = (byte)(source.G * destination.G).Clamp(0, 255); |
|
||||
byte b = (byte)(source.B * destination.B).Clamp(0, 255); |
|
||||
byte a = (byte)(source.A * destination.A).Clamp(0, 255); |
|
||||
|
|
||||
return new Color(r, g, b, a); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Linearly interpolates from one color to another based on the given weighting.
|
|
||||
/// </summary>
|
|
||||
/// <param name="from">The first color value.</param>
|
|
||||
/// <param name="to">The second color value.</param>
|
|
||||
/// <param name="amount">
|
|
||||
/// A value between 0 and 1 indicating the weight of the second source vector.
|
|
||||
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="Color"/>
|
|
||||
/// </returns>
|
|
||||
public static Color Lerp(Color from, Color to, float amount) |
|
||||
{ |
|
||||
return new Color(Vector4.Lerp(from.ToVector4(), to.ToVector4(), amount)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,292 +0,0 @@ |
|||||
// <copyright file="ColorspaceTransforms.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Packed vector type containing four 8-bit unsigned normalized values ranging from 0 to 255.
|
|
||||
/// The color components are stored in red, green, blue, and alpha order.
|
|
||||
/// </summary>
|
|
||||
/// <remarks>
|
|
||||
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|
||||
/// as it avoids the need to create new values for modification operations.
|
|
||||
/// </remarks>
|
|
||||
public partial struct Color |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The epsilon for comparing floating point numbers.
|
|
||||
/// </summary>
|
|
||||
private const float Epsilon = 0.001F; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|
||||
/// <see cref="Bgra32"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">The instance of <see cref="Color"/> to convert.</param>
|
|
||||
/// <returns>
|
|
||||
/// An instance of <see cref="Bgra32"/>.
|
|
||||
/// </returns>
|
|
||||
public static implicit operator Color(Bgra32 color) |
|
||||
{ |
|
||||
return new Color(color.R, color.G, color.B, color.A); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Allows the implicit conversion of an instance of <see cref="Cmyk"/> to a
|
|
||||
/// <see cref="Color"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cmykColor">The instance of <see cref="Cmyk"/> to convert.</param>
|
|
||||
/// <returns>
|
|
||||
/// An instance of <see cref="Color"/>.
|
|
||||
/// </returns>
|
|
||||
public static implicit operator Color(Cmyk cmykColor) |
|
||||
{ |
|
||||
float r = (1 - cmykColor.C) * (1 - cmykColor.K); |
|
||||
float g = (1 - cmykColor.M) * (1 - cmykColor.K); |
|
||||
float b = (1 - cmykColor.Y) * (1 - cmykColor.K); |
|
||||
return new Color(r, g, b, 1); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Allows the implicit conversion of an instance of <see cref="YCbCr"/> to a
|
|
||||
/// <see cref="Color"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">The instance of <see cref="YCbCr"/> to convert.</param>
|
|
||||
/// <returns>
|
|
||||
/// An instance of <see cref="Color"/>.
|
|
||||
/// </returns>
|
|
||||
public static implicit operator Color(YCbCr color) |
|
||||
{ |
|
||||
byte y = color.Y; |
|
||||
int cb = color.Cb - 128; |
|
||||
int cr = color.Cr - 128; |
|
||||
|
|
||||
byte r = (byte)(y + (1.402F * cr)).Clamp(0, 255); |
|
||||
byte g = (byte)(y - (0.34414F * cb) - (0.71414F * cr)).Clamp(0, 255); |
|
||||
byte b = (byte)(y + (1.772F * cb)).Clamp(0, 255); |
|
||||
|
|
||||
return new Color(r, g, b); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Allows the implicit conversion of an instance of <see cref="CieXyz"/> to a
|
|
||||
/// <see cref="Color"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">The instance of <see cref="CieXyz"/> to convert.</param>
|
|
||||
/// <returns>
|
|
||||
/// An instance of <see cref="Color"/>.
|
|
||||
/// </returns>
|
|
||||
public static implicit operator Color(CieXyz color) |
|
||||
{ |
|
||||
float x = color.X / 100F; |
|
||||
float y = color.Y / 100F; |
|
||||
float z = color.Z / 100F; |
|
||||
|
|
||||
// Then XYZ to RGB (multiplication by 100 was done above already)
|
|
||||
float r = (x * 3.2406F) + (y * -1.5372F) + (z * -0.4986F); |
|
||||
float g = (x * -0.9689F) + (y * 1.8758F) + (z * 0.0415F); |
|
||||
float b = (x * 0.0557F) + (y * -0.2040F) + (z * 1.0570F); |
|
||||
|
|
||||
Vector4 vector = new Vector4(r, g, b, 1).Compress(); |
|
||||
return new Color(vector); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Allows the implicit conversion of an instance of <see cref="Hsv"/> to a
|
|
||||
/// <see cref="Color"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">The instance of <see cref="Hsv"/> to convert.</param>
|
|
||||
/// <returns>
|
|
||||
/// An instance of <see cref="Color"/>.
|
|
||||
/// </returns>
|
|
||||
public static implicit operator Color(Hsv color) |
|
||||
{ |
|
||||
float s = color.S; |
|
||||
float v = color.V; |
|
||||
|
|
||||
if (Math.Abs(s) < Epsilon) |
|
||||
{ |
|
||||
return new Color(v, v, v, 1); |
|
||||
} |
|
||||
|
|
||||
float h = (Math.Abs(color.H - 360) < Epsilon) ? 0 : color.H / 60; |
|
||||
int i = (int)Math.Truncate(h); |
|
||||
float f = h - i; |
|
||||
|
|
||||
float p = v * (1.0F - s); |
|
||||
float q = v * (1.0F - (s * f)); |
|
||||
float t = v * (1.0F - (s * (1.0F - f))); |
|
||||
|
|
||||
float r, g, b; |
|
||||
switch (i) |
|
||||
{ |
|
||||
case 0: |
|
||||
r = v; |
|
||||
g = t; |
|
||||
b = p; |
|
||||
break; |
|
||||
|
|
||||
case 1: |
|
||||
r = q; |
|
||||
g = v; |
|
||||
b = p; |
|
||||
break; |
|
||||
|
|
||||
case 2: |
|
||||
r = p; |
|
||||
g = v; |
|
||||
b = t; |
|
||||
break; |
|
||||
|
|
||||
case 3: |
|
||||
r = p; |
|
||||
g = q; |
|
||||
b = v; |
|
||||
break; |
|
||||
|
|
||||
case 4: |
|
||||
r = t; |
|
||||
g = p; |
|
||||
b = v; |
|
||||
break; |
|
||||
|
|
||||
default: |
|
||||
r = v; |
|
||||
g = p; |
|
||||
b = q; |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
return new Color(r, g, b, 1); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Allows the implicit conversion of an instance of <see cref="Hsl"/> to a
|
|
||||
/// <see cref="Color"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">The instance of <see cref="Hsl"/> to convert.</param>
|
|
||||
/// <returns>
|
|
||||
/// An instance of <see cref="Color"/>.
|
|
||||
/// </returns>
|
|
||||
public static implicit operator Color(Hsl color) |
|
||||
{ |
|
||||
float rangedH = color.H / 360F; |
|
||||
float r = 0; |
|
||||
float g = 0; |
|
||||
float b = 0; |
|
||||
float s = color.S; |
|
||||
float l = color.L; |
|
||||
|
|
||||
if (Math.Abs(l) > Epsilon) |
|
||||
{ |
|
||||
if (Math.Abs(s) < Epsilon) |
|
||||
{ |
|
||||
r = g = b = l; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
float temp2 = (l < 0.5f) ? l * (1f + s) : l + s - (l * s); |
|
||||
float temp1 = (2f * l) - temp2; |
|
||||
|
|
||||
r = GetColorComponent(temp1, temp2, rangedH + 0.3333333F); |
|
||||
g = GetColorComponent(temp1, temp2, rangedH); |
|
||||
b = GetColorComponent(temp1, temp2, rangedH - 0.3333333F); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return new Color(r, g, b, 1); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Allows the implicit conversion of an instance of <see cref="CieLab"/> to a
|
|
||||
/// <see cref="Color"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cieLabColor">The instance of <see cref="CieLab"/> to convert.</param>
|
|
||||
/// <returns>
|
|
||||
/// An instance of <see cref="Color"/>.
|
|
||||
/// </returns>
|
|
||||
public static implicit operator Color(CieLab cieLabColor) |
|
||||
{ |
|
||||
// First convert back to XYZ...
|
|
||||
float y = (cieLabColor.L + 16F) / 116F; |
|
||||
float x = (cieLabColor.A / 500F) + y; |
|
||||
float z = y - (cieLabColor.B / 200F); |
|
||||
|
|
||||
float x3 = x * x * x; |
|
||||
float y3 = y * y * y; |
|
||||
float z3 = z * z * z; |
|
||||
|
|
||||
x = x3 > 0.008856F ? x3 : (x - 0.137931F) / 7.787F; |
|
||||
y = (cieLabColor.L > 7.999625F) ? y3 : (cieLabColor.L / 903.3F); |
|
||||
z = (z3 > 0.008856F) ? z3 : (z - 0.137931F) / 7.787F; |
|
||||
|
|
||||
x *= 0.95047F; |
|
||||
z *= 1.08883F; |
|
||||
|
|
||||
// Then XYZ to RGB (multiplication by 100 was done above already)
|
|
||||
float r = (x * 3.2406F) + (y * -1.5372F) + (z * -0.4986F); |
|
||||
float g = (x * -0.9689F) + (y * 1.8758F) + (z * 0.0415F); |
|
||||
float b = (x * 0.0557F) + (y * -0.2040F) + (z * 1.0570F); |
|
||||
|
|
||||
return new Color(new Vector4(r, g, b, 1F).Compress()); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the color component from the given values.
|
|
||||
/// </summary>
|
|
||||
/// <param name="first">The first value.</param>
|
|
||||
/// <param name="second">The second value.</param>
|
|
||||
/// <param name="third">The third value.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="float"/>.
|
|
||||
/// </returns>
|
|
||||
private static float GetColorComponent(float first, float second, float third) |
|
||||
{ |
|
||||
third = MoveIntoRange(third); |
|
||||
if (third < 0.1666667F) |
|
||||
{ |
|
||||
return first + ((second - first) * 6.0f * third); |
|
||||
} |
|
||||
|
|
||||
if (third < 0.5) |
|
||||
{ |
|
||||
return second; |
|
||||
} |
|
||||
|
|
||||
if (third < 0.6666667F) |
|
||||
{ |
|
||||
return first + ((second - first) * (0.6666667F - third) * 6.0f); |
|
||||
} |
|
||||
|
|
||||
return first; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Moves the specific value within the acceptable range for
|
|
||||
/// conversion.
|
|
||||
/// <remarks>Used for converting <see cref="Hsl"/> colors to this type.</remarks>
|
|
||||
/// </summary>
|
|
||||
/// <param name="value">The value to shift.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="float"/>.
|
|
||||
/// </returns>
|
|
||||
private static float MoveIntoRange(float value) |
|
||||
{ |
|
||||
if (value < 0.0) |
|
||||
{ |
|
||||
value += 1.0f; |
|
||||
} |
|
||||
else if (value > 1.0) |
|
||||
{ |
|
||||
value -= 1.0f; |
|
||||
} |
|
||||
|
|
||||
return value; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,167 +0,0 @@ |
|||||
// <copyright file="Bgra32.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.ComponentModel; |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents an BGRA (blue, green, red, alpha) color.
|
|
||||
/// </summary>
|
|
||||
public struct Bgra32 : IEquatable<Bgra32> |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Represents a 32 bit <see cref="Bgra32"/> that has B, G, R, and A values set to zero.
|
|
||||
/// </summary>
|
|
||||
public static readonly Bgra32 Empty = default(Bgra32); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The backing vector for SIMD support.
|
|
||||
/// </summary>
|
|
||||
private Vector4 backingVector; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="Bgra32"/> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="b">The blue component of this <see cref="Bgra32"/>.</param>
|
|
||||
/// <param name="g">The green component of this <see cref="Bgra32"/>.</param>
|
|
||||
/// <param name="r">The red component of this <see cref="Bgra32"/>.</param>
|
|
||||
/// <param name="a">The alpha component of this <see cref="Bgra32"/>.</param>
|
|
||||
public Bgra32(byte b, byte g, byte r, byte a = 255) |
|
||||
: this() |
|
||||
{ |
|
||||
this.backingVector = Vector4.Clamp(new Vector4(b, g, r, a), Vector4.Zero, new Vector4(255)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the blue component of the color
|
|
||||
/// </summary>
|
|
||||
public byte B => (byte)this.backingVector.X; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the green component of the color
|
|
||||
/// </summary>
|
|
||||
public byte G => (byte)this.backingVector.Y; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the red component of the color
|
|
||||
/// </summary>
|
|
||||
public byte R => (byte)this.backingVector.Z; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the alpha component of the color
|
|
||||
/// </summary>
|
|
||||
public byte A => (byte)this.backingVector.W; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the <see cref="Bgra32"/> integer representation of the color.
|
|
||||
/// </summary>
|
|
||||
public int Bgra => (this.R << 16) | (this.G << 8) | (this.B << 0) | (this.A << 24); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets a value indicating whether this <see cref="Bgra32"/> is empty.
|
|
||||
/// </summary>
|
|
||||
[EditorBrowsable(EditorBrowsableState.Never)] |
|
||||
public bool IsEmpty => this.Equals(Empty); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|
||||
/// <see cref="Bgra32"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">
|
|
||||
/// The instance of <see cref="Color"/> to convert.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// An instance of <see cref="Bgra32"/>.
|
|
||||
/// </returns>
|
|
||||
public static implicit operator Bgra32(Color color) |
|
||||
{ |
|
||||
return new Bgra32(color.B, color.G, color.R, color.A); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="Bgra32"/> objects for equality.
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">
|
|
||||
/// The <see cref="Bgra32"/> on the left side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <param name="right">
|
|
||||
/// The <see cref="Bgra32"/> 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 ==(Bgra32 left, Bgra32 right) |
|
||||
{ |
|
||||
return left.Equals(right); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="Bgra32"/> objects for inequality.
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">
|
|
||||
/// The <see cref="Bgra32"/> on the left side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <param name="right">
|
|
||||
/// The <see cref="Bgra32"/> 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 !=(Bgra32 left, Bgra32 right) |
|
||||
{ |
|
||||
return !left.Equals(right); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Equals(object obj) |
|
||||
{ |
|
||||
if (obj is Bgra32) |
|
||||
{ |
|
||||
Bgra32 color = (Bgra32)obj; |
|
||||
|
|
||||
return this.backingVector == color.backingVector; |
|
||||
} |
|
||||
|
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override int GetHashCode() |
|
||||
{ |
|
||||
return GetHashCode(this); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override string ToString() |
|
||||
{ |
|
||||
if (this.IsEmpty) |
|
||||
{ |
|
||||
return "Bgra32 [ Empty ]"; |
|
||||
} |
|
||||
|
|
||||
return $"Bgra32 [ B={this.B}, G={this.G}, R={this.R}, A={this.A} ]"; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool Equals(Bgra32 other) |
|
||||
{ |
|
||||
return this.backingVector.Equals(other.backingVector); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns the hash code for this instance.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">
|
|
||||
/// The instance of <see cref="Bgra32"/> to return the hash code for.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// A 32-bit signed integer that is the hash code for this instance.
|
|
||||
/// </returns>
|
|
||||
private static int GetHashCode(Bgra32 color) => color.backingVector.GetHashCode(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,192 +0,0 @@ |
|||||
// <copyright file="CieLab.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.ComponentModel; |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents an CIE LAB 1976 color.
|
|
||||
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space"/>
|
|
||||
/// </summary>
|
|
||||
public struct CieLab : IEquatable<CieLab>, IAlmostEquatable<CieLab, float> |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="CieLab"/> that has L, A, B values set to zero.
|
|
||||
/// </summary>
|
|
||||
public static readonly CieLab Empty = default(CieLab); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The epsilon for comparing floating point numbers.
|
|
||||
/// </summary>
|
|
||||
private const float Epsilon = 0.001f; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The backing vector for SIMD support.
|
|
||||
/// </summary>
|
|
||||
private Vector3 backingVector; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="CieLab"/> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="l">The lightness dimension.</param>
|
|
||||
/// <param name="a">The a (green - magenta) component.</param>
|
|
||||
/// <param name="b">The b (blue - yellow) component.</param>
|
|
||||
public CieLab(float l, float a, float b) |
|
||||
: this() |
|
||||
{ |
|
||||
this.backingVector = Vector3.Clamp(new Vector3(l, a, b), new Vector3(0, -100, -100), new Vector3(100)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the lightness dimension.
|
|
||||
/// <remarks>A value ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
|
|
||||
/// </summary>
|
|
||||
public float L => this.backingVector.X; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the a color component.
|
|
||||
/// <remarks>Negative is green, positive magenta.</remarks>
|
|
||||
/// </summary>
|
|
||||
public float A => this.backingVector.Y; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the b color component.
|
|
||||
/// <remarks>Negative is blue, positive is yellow</remarks>
|
|
||||
/// </summary>
|
|
||||
public float B => this.backingVector.Z; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets a value indicating whether this <see cref="CieLab"/> is empty.
|
|
||||
/// </summary>
|
|
||||
[EditorBrowsable(EditorBrowsableState.Never)] |
|
||||
public bool IsEmpty => this.Equals(Empty); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|
||||
/// <see cref="CieLab"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">
|
|
||||
/// The instance of <see cref="Color"/> to convert.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// An instance of <see cref="CieLab"/>.
|
|
||||
/// </returns>
|
|
||||
public static implicit operator CieLab(Color color) |
|
||||
{ |
|
||||
// First convert to CIE XYZ
|
|
||||
Vector4 vector = color.ToVector4().Expand(); |
|
||||
float x = (vector.X * 0.4124F) + (vector.Y * 0.3576F) + (vector.Z * 0.1805F); |
|
||||
float y = (vector.X * 0.2126F) + (vector.Y * 0.7152F) + (vector.Z * 0.0722F); |
|
||||
float z = (vector.X * 0.0193F) + (vector.Y * 0.1192F) + (vector.Z * 0.9505F); |
|
||||
|
|
||||
// Now to LAB
|
|
||||
x /= 0.95047F; |
|
||||
//y /= 1F;
|
|
||||
z /= 1.08883F; |
|
||||
|
|
||||
x = x > 0.008856F ? (float)Math.Pow(x, 0.3333333F) : ((903.3F * x) + 16F) / 116F; |
|
||||
y = y > 0.008856F ? (float)Math.Pow(y, 0.3333333F) : ((903.3F * y) + 16F) / 116F; |
|
||||
z = z > 0.008856F ? (float)Math.Pow(z, 0.3333333F) : ((903.3F * z) + 16F) / 116F; |
|
||||
|
|
||||
float l = Math.Max(0, (116F * y) - 16F); |
|
||||
float a = 500F * (x - y); |
|
||||
float b = 200F * (y - z); |
|
||||
|
|
||||
return new CieLab(l, a, b); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="CieLab"/> objects for equality.
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">
|
|
||||
/// The <see cref="CieLab"/> on the left side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <param name="right">
|
|
||||
/// The <see cref="CieLab"/> 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 ==(CieLab left, CieLab right) |
|
||||
{ |
|
||||
return left.Equals(right); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="CieLab"/> objects for inequality
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">
|
|
||||
/// The <see cref="CieLab"/> on the left side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <param name="right">
|
|
||||
/// The <see cref="CieLab"/> 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 !=(CieLab left, CieLab right) |
|
||||
{ |
|
||||
return !left.Equals(right); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override int GetHashCode() |
|
||||
{ |
|
||||
return GetHashCode(this); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override string ToString() |
|
||||
{ |
|
||||
if (this.IsEmpty) |
|
||||
{ |
|
||||
return "CieLab [Empty]"; |
|
||||
} |
|
||||
|
|
||||
return $"CieLab [ L={this.L:#0.##}, A={this.A:#0.##}, B={this.B:#0.##}]"; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Equals(object obj) |
|
||||
{ |
|
||||
if (obj is CieLab) |
|
||||
{ |
|
||||
return this.Equals((CieLab)obj); |
|
||||
} |
|
||||
|
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool Equals(CieLab other) |
|
||||
{ |
|
||||
return this.AlmostEquals(other, Epsilon); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool AlmostEquals(CieLab other, float precision) |
|
||||
{ |
|
||||
Vector3 result = Vector3.Abs(this.backingVector - other.backingVector); |
|
||||
|
|
||||
return result.X < precision |
|
||||
&& result.Y < precision |
|
||||
&& result.Z < precision; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns the hash code for this instance.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">
|
|
||||
/// The instance of <see cref="CieLab"/> to return the hash code for.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// A 32-bit signed integer that is the hash code for this instance.
|
|
||||
/// </returns>
|
|
||||
private static int GetHashCode(CieLab color) => color.backingVector.GetHashCode(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,184 +0,0 @@ |
|||||
// <copyright file="CieXyz.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.ComponentModel; |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents an CIE 1931 color
|
|
||||
/// <see href="https://en.wikipedia.org/wiki/CIE_1931_color_space"/>
|
|
||||
/// </summary>
|
|
||||
public struct CieXyz : IEquatable<CieXyz>, IAlmostEquatable<CieXyz, float> |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="CieXyz"/> that has Y, Cb, and Cr values set to zero.
|
|
||||
/// </summary>
|
|
||||
public static readonly CieXyz Empty = default(CieXyz); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The epsilon for comparing floating point numbers.
|
|
||||
/// </summary>
|
|
||||
private const float Epsilon = 0.001f; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The backing vector for SIMD support.
|
|
||||
/// </summary>
|
|
||||
private Vector3 backingVector; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="CieXyz"/> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="y">The y luminance component.</param>
|
|
||||
/// <param name="x">X is a mix (a linear combination) of cone response curves chosen to be nonnegative</param>
|
|
||||
/// <param name="z">Z is quasi-equal to blue stimulation, or the S cone of the human eye.</param>
|
|
||||
public CieXyz(float x, float y, float z) |
|
||||
: this() |
|
||||
{ |
|
||||
// Not clamping as documentation about this space seems to indicate "usual" ranges
|
|
||||
this.backingVector = new Vector3(x, y, z); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the Y luminance component.
|
|
||||
/// <remarks>A value ranging between 380 and 780.</remarks>
|
|
||||
/// </summary>
|
|
||||
public float X => this.backingVector.X; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the Cb chroma component.
|
|
||||
/// <remarks>A value ranging between 380 and 780.</remarks>
|
|
||||
/// </summary>
|
|
||||
public float Y => this.backingVector.Y; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the Cr chroma component.
|
|
||||
/// <remarks>A value ranging between 380 and 780.</remarks>
|
|
||||
/// </summary>
|
|
||||
public float Z => this.backingVector.Z; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets a value indicating whether this <see cref="CieXyz"/> is empty.
|
|
||||
/// </summary>
|
|
||||
[EditorBrowsable(EditorBrowsableState.Never)] |
|
||||
public bool IsEmpty => this.Equals(Empty); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|
||||
/// <see cref="CieXyz"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">
|
|
||||
/// The instance of <see cref="Color"/> to convert.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// An instance of <see cref="CieXyz"/>.
|
|
||||
/// </returns>
|
|
||||
public static implicit operator CieXyz(Color color) |
|
||||
{ |
|
||||
Vector4 vector = color.ToVector4().Expand(); |
|
||||
|
|
||||
float x = (vector.X * 0.4124F) + (vector.Y * 0.3576F) + (vector.Z * 0.1805F); |
|
||||
float y = (vector.X * 0.2126F) + (vector.Y * 0.7152F) + (vector.Z * 0.0722F); |
|
||||
float z = (vector.X * 0.0193F) + (vector.Y * 0.1192F) + (vector.Z * 0.9505F); |
|
||||
|
|
||||
x *= 100F; |
|
||||
y *= 100F; |
|
||||
z *= 100F; |
|
||||
|
|
||||
return new CieXyz(x, y, z); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="CieXyz"/> objects for equality.
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">
|
|
||||
/// The <see cref="CieXyz"/> on the left side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <param name="right">
|
|
||||
/// The <see cref="CieXyz"/> 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 ==(CieXyz left, CieXyz right) |
|
||||
{ |
|
||||
return left.Equals(right); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="CieXyz"/> objects for inequality.
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">
|
|
||||
/// The <see cref="CieXyz"/> on the left side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <param name="right">
|
|
||||
/// The <see cref="CieXyz"/> 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 !=(CieXyz left, CieXyz right) |
|
||||
{ |
|
||||
return !left.Equals(right); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override int GetHashCode() |
|
||||
{ |
|
||||
return GetHashCode(this); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override string ToString() |
|
||||
{ |
|
||||
if (this.IsEmpty) |
|
||||
{ |
|
||||
return "CieXyz [ Empty ]"; |
|
||||
} |
|
||||
|
|
||||
return $"CieXyz [ X={this.X:#0.##}, Y={this.Y:#0.##}, Z={this.Z:#0.##} ]"; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Equals(object obj) |
|
||||
{ |
|
||||
if (obj is CieXyz) |
|
||||
{ |
|
||||
return this.Equals((CieXyz)obj); |
|
||||
} |
|
||||
|
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool Equals(CieXyz other) |
|
||||
{ |
|
||||
return this.AlmostEquals(other, Epsilon); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool AlmostEquals(CieXyz other, float precision) |
|
||||
{ |
|
||||
Vector3 result = Vector3.Abs(this.backingVector - other.backingVector); |
|
||||
|
|
||||
return result.X < precision |
|
||||
&& result.Y < precision |
|
||||
&& result.Z < precision; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns the hash code for this instance.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">
|
|
||||
/// The instance of <see cref="Hsv"/> to return the hash code for.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// A 32-bit signed integer that is the hash code for this instance.
|
|
||||
/// </returns>
|
|
||||
private static int GetHashCode(CieXyz color) => color.backingVector.GetHashCode(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,195 +0,0 @@ |
|||||
// <copyright file="Cmyk.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.ComponentModel; |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents an CMYK (cyan, magenta, yellow, keyline) color.
|
|
||||
/// </summary>
|
|
||||
public struct Cmyk : IEquatable<Cmyk>, IAlmostEquatable<Cmyk, float> |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Cmyk"/> that has C, M, Y, and K values set to zero.
|
|
||||
/// </summary>
|
|
||||
public static readonly Cmyk Empty = default(Cmyk); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The epsilon for comparing floating point numbers.
|
|
||||
/// </summary>
|
|
||||
private const float Epsilon = 0.001f; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The backing vector for SIMD support.
|
|
||||
/// </summary>
|
|
||||
private Vector4 backingVector; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="Cmyk"/> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="c">The cyan component.</param>
|
|
||||
/// <param name="m">The magenta component.</param>
|
|
||||
/// <param name="y">The yellow component.</param>
|
|
||||
/// <param name="k">The keyline black component.</param>
|
|
||||
public Cmyk(float c, float m, float y, float k) |
|
||||
: this() |
|
||||
{ |
|
||||
this.backingVector = Vector4.Clamp(new Vector4(c, m, y, k), Vector4.Zero, Vector4.One); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the cyan color component.
|
|
||||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|
||||
/// </summary>
|
|
||||
public float C => this.backingVector.X; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the magenta color component.
|
|
||||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|
||||
/// </summary>
|
|
||||
public float M => this.backingVector.Y; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the yellow color component.
|
|
||||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|
||||
/// </summary>
|
|
||||
public float Y => this.backingVector.Z; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the keyline black color component.
|
|
||||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|
||||
/// </summary>
|
|
||||
public float K => this.backingVector.W; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets a value indicating whether this <see cref="Cmyk"/> is empty.
|
|
||||
/// </summary>
|
|
||||
[EditorBrowsable(EditorBrowsableState.Never)] |
|
||||
public bool IsEmpty => this.Equals(Empty); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|
||||
/// <see cref="Cmyk"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">
|
|
||||
/// The instance of <see cref="Bgra32"/> to convert.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// An instance of <see cref="Cmyk"/>.
|
|
||||
/// </returns>
|
|
||||
public static implicit operator Cmyk(Color color) |
|
||||
{ |
|
||||
float c = 1f - (color.R / 255F); |
|
||||
float m = 1f - (color.G / 255F); |
|
||||
float y = 1f - (color.B / 255F); |
|
||||
|
|
||||
float k = Math.Min(c, Math.Min(m, y)); |
|
||||
|
|
||||
if (Math.Abs(k - 1.0f) <= Epsilon) |
|
||||
{ |
|
||||
return new Cmyk(0, 0, 0, 1); |
|
||||
} |
|
||||
|
|
||||
c = (c - k) / (1 - k); |
|
||||
m = (m - k) / (1 - k); |
|
||||
y = (y - k) / (1 - k); |
|
||||
|
|
||||
return new Cmyk(c, m, y, k); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="Cmyk"/> objects for equality.
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">
|
|
||||
/// The <see cref="Cmyk"/> on the left side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <param name="right">
|
|
||||
/// The <see cref="Cmyk"/> 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 ==(Cmyk left, Cmyk right) |
|
||||
{ |
|
||||
return left.Equals(right); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="Cmyk"/> objects for inequality
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">
|
|
||||
/// The <see cref="Cmyk"/> on the left side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <param name="right">
|
|
||||
/// The <see cref="Cmyk"/> 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 !=(Cmyk left, Cmyk right) |
|
||||
{ |
|
||||
return !left.Equals(right); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override int GetHashCode() |
|
||||
{ |
|
||||
return GetHashCode(this); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override string ToString() |
|
||||
{ |
|
||||
if (this.IsEmpty) |
|
||||
{ |
|
||||
return "Cmyk [Empty]"; |
|
||||
} |
|
||||
|
|
||||
return $"Cmyk [ C={this.C:#0.##}, M={this.M:#0.##}, Y={this.Y:#0.##}, K={this.K:#0.##}]"; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Equals(object obj) |
|
||||
{ |
|
||||
if (obj is Cmyk) |
|
||||
{ |
|
||||
return this.Equals((Cmyk)obj); |
|
||||
} |
|
||||
|
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool Equals(Cmyk other) |
|
||||
{ |
|
||||
return this.AlmostEquals(other, Epsilon); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool AlmostEquals(Cmyk other, float precision) |
|
||||
{ |
|
||||
Vector4 result = Vector4.Abs(this.backingVector - other.backingVector); |
|
||||
|
|
||||
return result.X < precision |
|
||||
&& result.Y < precision |
|
||||
&& result.Z < precision |
|
||||
&& result.W < precision; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns the hash code for this instance.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">
|
|
||||
/// The instance of <see cref="Cmyk"/> to return the hash code for.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// A 32-bit signed integer that is the hash code for this instance.
|
|
||||
/// </returns>
|
|
||||
private static int GetHashCode(Cmyk color) => color.backingVector.GetHashCode(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,213 +0,0 @@ |
|||||
// <copyright file="Hsl.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.ComponentModel; |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a Hsl (hue, saturation, lightness) color.
|
|
||||
/// </summary>
|
|
||||
public struct Hsl : IEquatable<Hsl>, IAlmostEquatable<Hsl, float> |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Hsl"/> that has H, S, and L values set to zero.
|
|
||||
/// </summary>
|
|
||||
public static readonly Hsl Empty = default(Hsl); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The epsilon for comparing floating point numbers.
|
|
||||
/// </summary>
|
|
||||
private const float Epsilon = 0.001F; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The backing vector for SIMD support.
|
|
||||
/// </summary>
|
|
||||
private Vector3 backingVector; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="Hsl"/> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="h">The h hue component.</param>
|
|
||||
/// <param name="s">The s saturation component.</param>
|
|
||||
/// <param name="l">The l value (lightness) component.</param>
|
|
||||
public Hsl(float h, float s, float l) |
|
||||
{ |
|
||||
this.backingVector = Vector3.Clamp(new Vector3(h, s, l), Vector3.Zero, new Vector3(360, 1, 1)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the hue component.
|
|
||||
/// <remarks>A value ranging between 0 and 360.</remarks>
|
|
||||
/// </summary>
|
|
||||
public float H => this.backingVector.X; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the saturation component.
|
|
||||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|
||||
/// </summary>
|
|
||||
public float S => this.backingVector.Y; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the lightness component.
|
|
||||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|
||||
/// </summary>
|
|
||||
public float L => this.backingVector.Z; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets a value indicating whether this <see cref="Hsl"/> is empty.
|
|
||||
/// </summary>
|
|
||||
[EditorBrowsable(EditorBrowsableState.Never)] |
|
||||
public bool IsEmpty => this.Equals(Empty); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|
||||
/// <see cref="Hsl"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">The instance of <see cref="Color"/> to convert.</param>
|
|
||||
/// <returns>
|
|
||||
/// An instance of <see cref="Hsl"/>.
|
|
||||
/// </returns>
|
|
||||
public static implicit operator Hsl(Color color) |
|
||||
{ |
|
||||
float r = color.R / 255F; |
|
||||
float g = color.G / 255F; |
|
||||
float b = color.B / 255F; |
|
||||
|
|
||||
float max = Math.Max(r, Math.Max(g, b)); |
|
||||
float min = Math.Min(r, Math.Min(g, b)); |
|
||||
float chroma = max - min; |
|
||||
float h = 0; |
|
||||
float s = 0; |
|
||||
float l = (max + min) / 2; |
|
||||
|
|
||||
if (Math.Abs(chroma) < Epsilon) |
|
||||
{ |
|
||||
return new Hsl(0, s, l); |
|
||||
} |
|
||||
|
|
||||
if (Math.Abs(r - max) < Epsilon) |
|
||||
{ |
|
||||
h = (g - b) / chroma; |
|
||||
} |
|
||||
else if (Math.Abs(g - max) < Epsilon) |
|
||||
{ |
|
||||
h = 2 + ((b - r) / chroma); |
|
||||
} |
|
||||
else if (Math.Abs(b - max) < Epsilon) |
|
||||
{ |
|
||||
h = 4 + ((r - g) / chroma); |
|
||||
} |
|
||||
|
|
||||
h *= 60; |
|
||||
if (h < 0.0) |
|
||||
{ |
|
||||
h += 360; |
|
||||
} |
|
||||
|
|
||||
if (l <= .5f) |
|
||||
{ |
|
||||
s = chroma / (max + min); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
s = chroma / (2 - chroma); |
|
||||
} |
|
||||
|
|
||||
return new Hsl(h, s, l); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="Hsl"/> objects for equality.
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">
|
|
||||
/// The <see cref="Hsl"/> on the left side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <param name="right">
|
|
||||
/// The <see cref="Hsl"/> 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 ==(Hsl left, Hsl right) |
|
||||
{ |
|
||||
return left.Equals(right); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="Hsl"/> objects for inequality.
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">
|
|
||||
/// The <see cref="Hsl"/> on the left side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <param name="right">
|
|
||||
/// The <see cref="Hsl"/> 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 !=(Hsl left, Hsl right) |
|
||||
{ |
|
||||
return !left.Equals(right); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override int GetHashCode() |
|
||||
{ |
|
||||
return GetHashCode(this); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override string ToString() |
|
||||
{ |
|
||||
if (this.IsEmpty) |
|
||||
{ |
|
||||
return "Hsl [ Empty ]"; |
|
||||
} |
|
||||
|
|
||||
return $"Hsl [ H={this.H:#0.##}, S={this.S:#0.##}, L={this.L:#0.##} ]"; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Equals(object obj) |
|
||||
{ |
|
||||
if (obj is Hsl) |
|
||||
{ |
|
||||
return this.Equals((Hsl)obj); |
|
||||
} |
|
||||
|
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool Equals(Hsl other) |
|
||||
{ |
|
||||
return this.AlmostEquals(other, Epsilon); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool AlmostEquals(Hsl other, float precision) |
|
||||
{ |
|
||||
Vector3 result = Vector3.Abs(this.backingVector - other.backingVector); |
|
||||
|
|
||||
return result.X < precision |
|
||||
&& result.Y < precision |
|
||||
&& result.Z < precision; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns the hash code for this instance.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">
|
|
||||
/// The instance of <see cref="Hsl"/> to return the hash code for.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// A 32-bit signed integer that is the hash code for this instance.
|
|
||||
/// </returns>
|
|
||||
private static int GetHashCode(Hsl color) => color.backingVector.GetHashCode(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,206 +0,0 @@ |
|||||
// <copyright file="Hsv.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.ComponentModel; |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents a HSV (hue, saturation, value) color. Also known as HSB (hue, saturation, brightness).
|
|
||||
/// </summary>
|
|
||||
public struct Hsv : IEquatable<Hsv>, IAlmostEquatable<Hsv, float> |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="Hsv"/> that has H, S, and V values set to zero.
|
|
||||
/// </summary>
|
|
||||
public static readonly Hsv Empty = default(Hsv); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The epsilon for comparing floating point numbers.
|
|
||||
/// </summary>
|
|
||||
private const float Epsilon = 0.001F; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The backing vector for SIMD support.
|
|
||||
/// </summary>
|
|
||||
private Vector3 backingVector; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="Hsv"/> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="h">The h hue component.</param>
|
|
||||
/// <param name="s">The s saturation component.</param>
|
|
||||
/// <param name="v">The v value (brightness) component.</param>
|
|
||||
public Hsv(float h, float s, float v) |
|
||||
{ |
|
||||
this.backingVector = Vector3.Clamp(new Vector3(h, s, v), Vector3.Zero, new Vector3(360, 1, 1)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the hue component.
|
|
||||
/// <remarks>A value ranging between 0 and 360.</remarks>
|
|
||||
/// </summary>
|
|
||||
public float H => this.backingVector.X; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the saturation component.
|
|
||||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|
||||
/// </summary>
|
|
||||
public float S => this.backingVector.Y; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the value (brightness) component.
|
|
||||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|
||||
/// </summary>
|
|
||||
public float V => this.backingVector.Z; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets a value indicating whether this <see cref="Hsv"/> is empty.
|
|
||||
/// </summary>
|
|
||||
[EditorBrowsable(EditorBrowsableState.Never)] |
|
||||
public bool IsEmpty => this.Equals(Empty); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|
||||
/// <see cref="Hsv"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">The instance of <see cref="Color"/> to convert.</param>
|
|
||||
/// <returns>
|
|
||||
/// An instance of <see cref="Hsv"/>.
|
|
||||
/// </returns>
|
|
||||
public static implicit operator Hsv(Color color) |
|
||||
{ |
|
||||
float r = color.R / 255F; |
|
||||
float g = color.G / 255F; |
|
||||
float b = color.B / 255F; |
|
||||
|
|
||||
float max = Math.Max(r, Math.Max(g, b)); |
|
||||
float min = Math.Min(r, Math.Min(g, b)); |
|
||||
float chroma = max - min; |
|
||||
float h = 0; |
|
||||
float s = 0; |
|
||||
float v = max; |
|
||||
|
|
||||
if (Math.Abs(chroma) < Epsilon) |
|
||||
{ |
|
||||
return new Hsv(0, s, v); |
|
||||
} |
|
||||
|
|
||||
if (Math.Abs(r - max) < Epsilon) |
|
||||
{ |
|
||||
h = (g - b) / chroma; |
|
||||
} |
|
||||
else if (Math.Abs(g - max) < Epsilon) |
|
||||
{ |
|
||||
h = 2 + ((b - r) / chroma); |
|
||||
} |
|
||||
else if (Math.Abs(b - max) < Epsilon) |
|
||||
{ |
|
||||
h = 4 + ((r - g) / chroma); |
|
||||
} |
|
||||
|
|
||||
h *= 60; |
|
||||
if (h < 0.0) |
|
||||
{ |
|
||||
h += 360; |
|
||||
} |
|
||||
|
|
||||
s = chroma / v; |
|
||||
|
|
||||
return new Hsv(h, s, v); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="Hsv"/> objects for equality.
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">
|
|
||||
/// The <see cref="Hsv"/> on the left side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <param name="right">
|
|
||||
/// The <see cref="Hsv"/> 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 ==(Hsv left, Hsv right) |
|
||||
{ |
|
||||
return left.Equals(right); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="Hsv"/> objects for inequality.
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">
|
|
||||
/// The <see cref="Hsv"/> on the left side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <param name="right">
|
|
||||
/// The <see cref="Hsv"/> 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 !=(Hsv left, Hsv right) |
|
||||
{ |
|
||||
return !left.Equals(right); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override int GetHashCode() |
|
||||
{ |
|
||||
return GetHashCode(this); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override string ToString() |
|
||||
{ |
|
||||
if (this.IsEmpty) |
|
||||
{ |
|
||||
return "Hsv [ Empty ]"; |
|
||||
} |
|
||||
|
|
||||
return $"Hsv [ H={this.H:#0.##}, S={this.S:#0.##}, V={this.V:#0.##} ]"; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Equals(object obj) |
|
||||
{ |
|
||||
if (obj is Hsv) |
|
||||
{ |
|
||||
return this.Equals((Hsv)obj); |
|
||||
} |
|
||||
|
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool Equals(Hsv other) |
|
||||
{ |
|
||||
return this.AlmostEquals(other, Epsilon); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool AlmostEquals(Hsv other, float precision) |
|
||||
{ |
|
||||
Vector3 result = Vector3.Abs(this.backingVector - other.backingVector); |
|
||||
|
|
||||
return result.X < precision |
|
||||
&& result.Y < precision |
|
||||
&& result.Z < precision; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns the hash code for this instance.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">
|
|
||||
/// The instance of <see cref="Hsv"/> to return the hash code for.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// A 32-bit signed integer that is the hash code for this instance.
|
|
||||
/// </returns>
|
|
||||
private static int GetHashCode(Hsv color) => color.backingVector.GetHashCode(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,30 +0,0 @@ |
|||||
// <copyright file="IAlmostEquatable.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
|
|
||||
/// <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="TColor">The type of objects to compare.</typeparam>
|
|
||||
/// <typeparam name="TPrecision">The object specifying the type to specify precision with.</typeparam>
|
|
||||
public interface IAlmostEquatable<in TColor, 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(TColor other, TPrecision precision); |
|
||||
} |
|
||||
} |
|
||||
@ -1,157 +0,0 @@ |
|||||
// <copyright file="YCbCr.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.ComponentModel; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents an YCbCr (luminance, blue chroma, red chroma) color conforming to the full range standard used in digital imaging systems.
|
|
||||
/// <see href="http://en.wikipedia.org/wiki/YCbCr"/>
|
|
||||
/// </summary>
|
|
||||
public struct YCbCr : IEquatable<YCbCr> |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Represents a <see cref="YCbCr"/> that has Y, Cb, and Cr values set to zero.
|
|
||||
/// </summary>
|
|
||||
public static readonly YCbCr Empty = default(YCbCr); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="YCbCr"/> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="y">The y luminance component.</param>
|
|
||||
/// <param name="cb">The cb chroma component.</param>
|
|
||||
/// <param name="cr">The cr chroma component.</param>
|
|
||||
public YCbCr(byte y, byte cb, byte cr) |
|
||||
: this() |
|
||||
{ |
|
||||
this.Y = y; |
|
||||
this.Cb = cb; |
|
||||
this.Cr = cr; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the Y luminance component.
|
|
||||
/// <remarks>A value ranging between 0 and 255.</remarks>
|
|
||||
/// </summary>
|
|
||||
public byte Y { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the Cb chroma component.
|
|
||||
/// <remarks>A value ranging between 0 and 255.</remarks>
|
|
||||
/// </summary>
|
|
||||
public byte Cb { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the Cr chroma component.
|
|
||||
/// <remarks>A value ranging between 0 and 255.</remarks>
|
|
||||
/// </summary>
|
|
||||
public byte Cr { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets a value indicating whether this <see cref="YCbCr"/> is empty.
|
|
||||
/// </summary>
|
|
||||
[EditorBrowsable(EditorBrowsableState.Never)] |
|
||||
public bool IsEmpty => this.Equals(Empty); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|
||||
/// <see cref="YCbCr"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">
|
|
||||
/// The instance of <see cref="Color"/> to convert.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// An instance of <see cref="YCbCr"/>.
|
|
||||
/// </returns>
|
|
||||
public static implicit operator YCbCr(Color color) |
|
||||
{ |
|
||||
byte r = color.R; |
|
||||
byte g = color.G; |
|
||||
byte b = color.B; |
|
||||
|
|
||||
byte y = (byte)((0.299F * r) + (0.587F * g) + (0.114F * b)); |
|
||||
byte cb = (byte)(128 + ((-0.168736F * r) - (0.331264F * g) + (0.5F * b))); |
|
||||
byte cr = (byte)(128 + ((0.5F * r) - (0.418688F * g) - (0.081312F * b))); |
|
||||
|
|
||||
return new YCbCr(y, cb, cr); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="YCbCr"/> objects for equality.
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">
|
|
||||
/// The <see cref="YCbCr"/> on the left side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <param name="right">
|
|
||||
/// The <see cref="YCbCr"/> 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 ==(YCbCr left, YCbCr right) |
|
||||
{ |
|
||||
return left.Equals(right); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compares two <see cref="YCbCr"/> objects for inequality.
|
|
||||
/// </summary>
|
|
||||
/// <param name="left">
|
|
||||
/// The <see cref="YCbCr"/> on the left side of the operand.
|
|
||||
/// </param>
|
|
||||
/// <param name="right">
|
|
||||
/// The <see cref="YCbCr"/> 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 !=(YCbCr left, YCbCr right) |
|
||||
{ |
|
||||
return !left.Equals(right); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override int GetHashCode() |
|
||||
{ |
|
||||
unchecked |
|
||||
{ |
|
||||
int hashCode = this.Y.GetHashCode(); |
|
||||
hashCode = (hashCode * 397) ^ this.Cb.GetHashCode(); |
|
||||
hashCode = (hashCode * 397) ^ this.Cr.GetHashCode(); |
|
||||
return hashCode; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override string ToString() |
|
||||
{ |
|
||||
if (this.IsEmpty) |
|
||||
{ |
|
||||
return "YCbCr [ Empty ]"; |
|
||||
} |
|
||||
|
|
||||
return $"YCbCr [ Y={this.Y}, Cb={this.Cb}, Cr={this.Cr} ]"; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Equals(object obj) |
|
||||
{ |
|
||||
if (obj is YCbCr) |
|
||||
{ |
|
||||
return this.Equals((YCbCr)obj); |
|
||||
} |
|
||||
|
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool Equals(YCbCr other) |
|
||||
{ |
|
||||
return this.Y == other.Y && this.Cb == other.Cb && this.Cr == other.Cr; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,33 +0,0 @@ |
|||||
// <copyright file="ComponentOrder.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Enumerates the various component orders.
|
|
||||
/// </summary>
|
|
||||
public enum ComponentOrder |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Z-> Y-> X order. Equivalent to B-> G-> R in <see cref="Color"/>
|
|
||||
/// </summary>
|
|
||||
ZYX, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Z-> Y-> X-> W order. Equivalent to B-> G-> R-> A in <see cref="Color"/>
|
|
||||
/// </summary>
|
|
||||
ZYXW, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// X-> Y-> Z order. Equivalent to R-> G-> B in <see cref="Color"/>
|
|
||||
/// </summary>
|
|
||||
XYZ, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// X-> Y-> Z-> W order. Equivalent to R-> G-> B-> A in <see cref="Color"/>
|
|
||||
/// </summary>
|
|
||||
XYZW, |
|
||||
} |
|
||||
} |
|
||||
@ -1,31 +0,0 @@ |
|||||
// <copyright file="IPackedBytes.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// An interface that converts packed vector types to and from <see cref="T:byte[]"/> values,
|
|
||||
/// allowing multiple encodings to be manipulated in a generic manner.
|
|
||||
/// </summary>
|
|
||||
public interface IPackedBytes |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets the packed representation from the gives bytes.
|
|
||||
/// </summary>
|
|
||||
/// <param name="x">The x-component.</param>
|
|
||||
/// <param name="y">The y-component.</param>
|
|
||||
/// <param name="z">The z-component.</param>
|
|
||||
/// <param name="w">The w-component.</param>
|
|
||||
void PackFromBytes(byte x, byte y, byte z, byte w); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the packed representation into the gives bytes.
|
|
||||
/// </summary>
|
|
||||
/// <param name="bytes">The bytes to set the color in.</param>
|
|
||||
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
|
|
||||
/// <param name="componentOrder">The order of the components.</param>
|
|
||||
void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder); |
|
||||
} |
|
||||
} |
|
||||
@ -1,16 +0,0 @@ |
|||||
// <copyright file="IPackedPixel.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// An interface that represents a packed pixel type.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public interface IPackedPixel<TPacked> : IPackedVector<TPacked>, IPackedBytes |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
@ -1,42 +0,0 @@ |
|||||
// <copyright file="IPackedVector.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// An interface that converts packed vector types to and from <see cref="Vector4"/> values,
|
|
||||
/// allowing multiple encodings to be manipulated in a generic manner.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public interface IPackedVector<TPacked> : IPackedVector |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets or sets the packed representation of the value.
|
|
||||
/// </summary>
|
|
||||
TPacked PackedValue { get; set; } |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// An interface that converts packed vector types to and from <see cref="Vector4"/> values.
|
|
||||
/// </summary>
|
|
||||
public interface IPackedVector |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Sets the packed representation from a <see cref="Vector4"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="vector">The vector to create the packed representation from.</param>
|
|
||||
void PackFromVector4(Vector4 vector); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Expands the packed representation into a <see cref="Vector4"/>.
|
|
||||
/// The vector components are typically expanded in least to greatest significance order.
|
|
||||
/// </summary>
|
|
||||
/// <returns>The <see cref="Vector4"/>.</returns>
|
|
||||
Vector4 ToVector4(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,33 +0,0 @@ |
|||||
// <copyright file="RgbaComponent.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Enumerates the RGBA (red, green, blue, alpha) color components.
|
|
||||
/// </summary>
|
|
||||
public enum RgbaComponent |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The red component.
|
|
||||
/// </summary>
|
|
||||
R = 0, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The green component.
|
|
||||
/// </summary>
|
|
||||
G = 1, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The blue component.
|
|
||||
/// </summary>
|
|
||||
B = 2, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The alpha component.
|
|
||||
/// </summary>
|
|
||||
A = 3 |
|
||||
} |
|
||||
} |
|
||||
@ -1,45 +0,0 @@ |
|||||
// <copyright file="ImageFormatException.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The exception that is thrown when the library tries to load
|
|
||||
/// an image, which has an invalid format.
|
|
||||
/// </summary>
|
|
||||
public class ImageFormatException : Exception |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="ImageFormatException"/> class.
|
|
||||
/// </summary>
|
|
||||
public ImageFormatException() |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="ImageFormatException"/> class with the name of the
|
|
||||
/// parameter that causes this exception.
|
|
||||
/// </summary>
|
|
||||
/// <param name="errorMessage">The error message that explains the reason for this exception.</param>
|
|
||||
public ImageFormatException(string errorMessage) |
|
||||
: base(errorMessage) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="ImageFormatException"/> class with a specified
|
|
||||
/// error message and the exception that is the cause of this exception.
|
|
||||
/// </summary>
|
|
||||
/// <param name="errorMessage">The error message that explains the reason for this exception.</param>
|
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic)
|
|
||||
/// if no inner exception is specified.</param>
|
|
||||
public ImageFormatException(string errorMessage, Exception innerException) |
|
||||
: base(errorMessage, innerException) |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,44 +0,0 @@ |
|||||
// <copyright file="ImageProcessingException.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The exception that is thrown when an error occurs when applying a process to an image.
|
|
||||
/// </summary>
|
|
||||
public class ImageProcessingException : Exception |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="ImageProcessingException"/> class.
|
|
||||
/// </summary>
|
|
||||
public ImageProcessingException() |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="ImageProcessingException"/> class with the name of the
|
|
||||
/// parameter that causes this exception.
|
|
||||
/// </summary>
|
|
||||
/// <param name="errorMessage">The error message that explains the reason for this exception.</param>
|
|
||||
public ImageProcessingException(string errorMessage) |
|
||||
: base(errorMessage) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="ImageProcessingException"/> class with a specified
|
|
||||
/// error message and the exception that is the cause of this exception.
|
|
||||
/// </summary>
|
|
||||
/// <param name="errorMessage">The error message that explains the reason for this exception.</param>
|
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic)
|
|
||||
/// if no inner exception is specified.</param>
|
|
||||
public ImageProcessingException(string errorMessage, Exception innerException) |
|
||||
: base(errorMessage, innerException) |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,91 +0,0 @@ |
|||||
// <copyright file="ByteExtensions.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="byte"/> struct.
|
|
||||
/// </summary>
|
|
||||
internal static class ByteExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Converts a byte array to a new array where each value in the original array is represented
|
|
||||
/// by a the specified number of bits.
|
|
||||
/// </summary>
|
|
||||
/// <param name="source">The bytes to convert from. Cannot be null.</param>
|
|
||||
/// <param name="bits">The number of bits per value.</param>
|
|
||||
/// <returns>The resulting <see cref="T:byte[]"/> array. Is never null.</returns>
|
|
||||
/// <exception cref="System.ArgumentNullException"><paramref name="source"/> is null.</exception>
|
|
||||
/// <exception cref="System.ArgumentException"><paramref name="bits"/> is less than or equals than zero.</exception>
|
|
||||
public static byte[] ToArrayByBitsLength(this byte[] source, int bits) |
|
||||
{ |
|
||||
Guard.NotNull(source, nameof(source)); |
|
||||
Guard.MustBeGreaterThan(bits, 0, "bits"); |
|
||||
|
|
||||
byte[] result; |
|
||||
|
|
||||
if (bits < 8) |
|
||||
{ |
|
||||
result = new byte[source.Length * 8 / bits]; |
|
||||
int mask = 0xFF >> (8 - bits); |
|
||||
int resultOffset = 0; |
|
||||
|
|
||||
// ReSharper disable once ForCanBeConvertedToForeach
|
|
||||
for (int i = 0; i < source.Length; i++) |
|
||||
{ |
|
||||
byte b = source[i]; |
|
||||
for (int shift = 0; shift < 8; shift += bits) |
|
||||
{ |
|
||||
int colorIndex = (b >> (8 - bits - shift)) & mask; |
|
||||
|
|
||||
result[resultOffset] = (byte)colorIndex; |
|
||||
|
|
||||
resultOffset++; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
result = source; |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Optimized <see cref="T:byte[]"/> reversal algorithm.
|
|
||||
/// </summary>
|
|
||||
/// <param name="source">The byte array.</param>
|
|
||||
public static void ReverseBytes(this byte[] source) |
|
||||
{ |
|
||||
ReverseBytes(source, 0, source.Length); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Optimized <see cref="T:byte[]"/> reversal algorithm.
|
|
||||
/// </summary>
|
|
||||
/// <param name="source">The byte array.</param>
|
|
||||
/// <param name="index">The index.</param>
|
|
||||
/// <param name="length">The length.</param>
|
|
||||
/// <exception cref="System.ArgumentNullException"><paramref name="source"/> is null.</exception>
|
|
||||
public static void ReverseBytes(this byte[] source, int index, int length) |
|
||||
{ |
|
||||
Guard.NotNull(source, nameof(source)); |
|
||||
|
|
||||
int i = index; |
|
||||
int j = index + length - 1; |
|
||||
while (i < j) |
|
||||
{ |
|
||||
byte temp = source[i]; |
|
||||
source[i] = source[j]; |
|
||||
source[j] = temp; |
|
||||
i++; |
|
||||
j--; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,173 +0,0 @@ |
|||||
// <copyright file="ComparableExtensions.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
using System.Runtime.CompilerServices; |
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for classes that implement <see cref="IComparable{T}"/>.
|
|
||||
/// </summary>
|
|
||||
internal static class ComparableExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Restricts a <see cref="byte"/> to be within a specified range.
|
|
||||
/// </summary>
|
|
||||
/// <param name="value">The The value to clamp.</param>
|
|
||||
/// <param name="min">The minimum value. If value is less than min, min will be returned.</param>
|
|
||||
/// <param name="max">The maximum value. If value is greater than max, max will be returned.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="byte"/> representing the clamped value.
|
|
||||
/// </returns>
|
|
||||
public static byte Clamp(this byte value, byte min, byte max) |
|
||||
{ |
|
||||
// Order is important here as someone might set min to higher than max.
|
|
||||
if (value > max) |
|
||||
{ |
|
||||
return max; |
|
||||
} |
|
||||
|
|
||||
if (value < min) |
|
||||
{ |
|
||||
return min; |
|
||||
} |
|
||||
|
|
||||
return value; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Restricts a <see cref="uint"/> to be within a specified range.
|
|
||||
/// </summary>
|
|
||||
/// <param name="value">The The value to clamp.</param>
|
|
||||
/// <param name="min">The minimum value. If value is less than min, min will be returned.</param>
|
|
||||
/// <param name="max">The maximum value. If value is greater than max, max will be returned.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="int"/> representing the clamped value.
|
|
||||
/// </returns>
|
|
||||
public static uint Clamp(this uint value, uint min, uint max) |
|
||||
{ |
|
||||
if (value > max) |
|
||||
{ |
|
||||
return max; |
|
||||
} |
|
||||
|
|
||||
if (value < min) |
|
||||
{ |
|
||||
return min; |
|
||||
} |
|
||||
|
|
||||
return value; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Restricts a <see cref="int"/> to be within a specified range.
|
|
||||
/// </summary>
|
|
||||
/// <param name="value">The The value to clamp.</param>
|
|
||||
/// <param name="min">The minimum value. If value is less than min, min will be returned.</param>
|
|
||||
/// <param name="max">The maximum value. If value is greater than max, max will be returned.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="int"/> representing the clamped value.
|
|
||||
/// </returns>
|
|
||||
public static int Clamp(this int value, int min, int max) |
|
||||
{ |
|
||||
if (value > max) |
|
||||
{ |
|
||||
return max; |
|
||||
} |
|
||||
|
|
||||
if (value < min) |
|
||||
{ |
|
||||
return min; |
|
||||
} |
|
||||
|
|
||||
return value; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Restricts a <see cref="float"/> to be within a specified range.
|
|
||||
/// </summary>
|
|
||||
/// <param name="value">The The value to clamp.</param>
|
|
||||
/// <param name="min">The minimum value. If value is less than min, min will be returned.</param>
|
|
||||
/// <param name="max">The maximum value. If value is greater than max, max will be returned.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="float"/> representing the clamped value.
|
|
||||
/// </returns>
|
|
||||
///
|
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
public static float Clamp(this float value, float min, float max) |
|
||||
{ |
|
||||
if (value > max) |
|
||||
{ |
|
||||
return max; |
|
||||
} |
|
||||
|
|
||||
if (value < min) |
|
||||
{ |
|
||||
return min; |
|
||||
} |
|
||||
|
|
||||
return value; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Restricts a <see cref="double"/> to be within a specified range.
|
|
||||
/// </summary>
|
|
||||
/// <param name="value">The The value to clamp.</param>
|
|
||||
/// <param name="min">The minimum value. If value is less than min, min will be returned.</param>
|
|
||||
/// <param name="max">The maximum value. If value is greater than max, max will be returned.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="double"/> representing the clamped value.
|
|
||||
/// </returns>
|
|
||||
public static double Clamp(this double value, double min, double max) |
|
||||
{ |
|
||||
if (value > max) |
|
||||
{ |
|
||||
return max; |
|
||||
} |
|
||||
|
|
||||
if (value < min) |
|
||||
{ |
|
||||
return min; |
|
||||
} |
|
||||
|
|
||||
return value; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts an <see cref="int"/> to a <see cref="byte"/> first restricting the value between the
|
|
||||
/// minimum and maximum allowable ranges.
|
|
||||
/// </summary>
|
|
||||
/// <param name="value">The <see cref="int"/> this method extends.</param>
|
|
||||
/// <returns>The <see cref="byte"/></returns>
|
|
||||
public static byte ToByte(this int value) |
|
||||
{ |
|
||||
return (byte)value.Clamp(0, 255); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts an <see cref="float"/> to a <see cref="byte"/> first restricting the value between the
|
|
||||
/// minimum and maximum allowable ranges.
|
|
||||
/// </summary>
|
|
||||
/// <param name="value">The <see cref="float"/> this method extends.</param>
|
|
||||
/// <returns>The <see cref="byte"/></returns>
|
|
||||
public static byte ToByte(this float value) |
|
||||
{ |
|
||||
return (byte)value.Clamp(0, 255); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts an <see cref="double"/> to a <see cref="byte"/> first restricting the value between the
|
|
||||
/// minimum and maximum allowable ranges.
|
|
||||
/// </summary>
|
|
||||
/// <param name="value">The <see cref="double"/> this method extends.</param>
|
|
||||
/// <returns>The <see cref="byte"/></returns>
|
|
||||
public static byte ToByte(this double value) |
|
||||
{ |
|
||||
return (byte)value.Clamp(0, 255); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,88 +0,0 @@ |
|||||
// <copyright file="EnumerableExtensions.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Encapsulates a series of time saving extension methods to the <see cref="T:System.Collections.IEnumerable"/> interface.
|
|
||||
/// </summary>
|
|
||||
public static class EnumerableExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Generates a sequence of integral numbers within a specified range.
|
|
||||
/// </summary>
|
|
||||
/// <param name="fromInclusive">
|
|
||||
/// The start index, inclusive.
|
|
||||
/// </param>
|
|
||||
/// <param name="toExclusive">
|
|
||||
/// The end index, exclusive.
|
|
||||
/// </param>
|
|
||||
/// <param name="step">
|
|
||||
/// The incremental step.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="IEnumerable{Int32}"/> that contains a range of sequential integral numbers.
|
|
||||
/// </returns>
|
|
||||
public static IEnumerable<int> SteppedRange(int fromInclusive, int toExclusive, int step) |
|
||||
{ |
|
||||
// Borrowed from Enumerable.Range
|
|
||||
long num = (fromInclusive + toExclusive) - 1L; |
|
||||
if ((toExclusive < 0) || (num > 0x7fffffffL)) |
|
||||
{ |
|
||||
throw new ArgumentOutOfRangeException(nameof(toExclusive)); |
|
||||
} |
|
||||
|
|
||||
return RangeIterator(fromInclusive, i => i < toExclusive, step); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Generates a sequence of integral numbers within a specified range.
|
|
||||
/// </summary>
|
|
||||
/// <param name="fromInclusive">
|
|
||||
/// The start index, inclusive.
|
|
||||
/// </param>
|
|
||||
/// <param name="toDelegate">
|
|
||||
/// A method that has one parameter and returns a <see cref="bool"/> calculating the end index
|
|
||||
/// </param>
|
|
||||
/// <param name="step">
|
|
||||
/// The incremental step.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="IEnumerable{Int32}"/> that contains a range of sequential integral numbers.
|
|
||||
/// </returns>
|
|
||||
public static IEnumerable<int> SteppedRange(int fromInclusive, Func<int, bool> toDelegate, int step) |
|
||||
{ |
|
||||
return RangeIterator(fromInclusive, toDelegate, step); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Generates a sequence of integral numbers within a specified range.
|
|
||||
/// </summary>
|
|
||||
/// <param name="fromInclusive">
|
|
||||
/// The start index, inclusive.
|
|
||||
/// </param>
|
|
||||
/// <param name="toDelegate">
|
|
||||
/// A method that has one parameter and returns a <see cref="bool"/> calculating the end index
|
|
||||
/// </param>
|
|
||||
/// <param name="step">
|
|
||||
/// The incremental step.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="IEnumerable{Int32}"/> that contains a range of sequential integral numbers.
|
|
||||
/// </returns>
|
|
||||
private static IEnumerable<int> RangeIterator(int fromInclusive, Func<int, bool> toDelegate, int step) |
|
||||
{ |
|
||||
int i = fromInclusive; |
|
||||
while (toDelegate(i)) |
|
||||
{ |
|
||||
yield return i; |
|
||||
i += step; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,30 +0,0 @@ |
|||||
// <copyright file="StreamExtensions.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System.IO; |
|
||||
|
|
||||
internal static class StreamExtensions |
|
||||
{ |
|
||||
public static void Skip(this Stream stream, int count) |
|
||||
{ |
|
||||
if (count < 1) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
if (stream.CanSeek) |
|
||||
{ |
|
||||
stream.Position += count; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
byte[] foo = new byte[count]; |
|
||||
stream.Read(foo, 0, count); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,83 +0,0 @@ |
|||||
// <copyright file="Vector4Extensions.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Numerics; |
|
||||
using System.Runtime.CompilerServices; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Vector4"/> struct.
|
|
||||
/// </summary>
|
|
||||
public static class Vector4Extensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Compresses a linear color signal to its sRGB equivalent.
|
|
||||
/// <see href="http://www.4p8.com/eric.brasseur/gamma.html#formulas"/>
|
|
||||
/// <see href="http://entropymine.com/imageworsener/srgbformula/"/>
|
|
||||
/// </summary>
|
|
||||
/// <param name="linear">The <see cref="Vector4"/> whose signal to compress.</param>
|
|
||||
/// <returns>The <see cref="Vector4"/>.</returns>
|
|
||||
public static Vector4 Compress(this Vector4 linear) |
|
||||
{ |
|
||||
// TODO: Is there a faster way to do this?
|
|
||||
return new Vector4(Compress(linear.X), Compress(linear.Y), Compress(linear.Z), linear.W); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Expands an sRGB color signal to its linear equivalent.
|
|
||||
/// <see href="http://www.4p8.com/eric.brasseur/gamma.html#formulas"/>
|
|
||||
/// <see href="http://entropymine.com/imageworsener/srgbformula/"/>
|
|
||||
/// </summary>
|
|
||||
/// <param name="gamma">The <see cref="Color"/> whose signal to expand.</param>
|
|
||||
/// <returns>The <see cref="Vector4"/>.</returns>
|
|
||||
public static Vector4 Expand(this Vector4 gamma) |
|
||||
{ |
|
||||
// TODO: Is there a faster way to do this?
|
|
||||
return new Vector4(Expand(gamma.X), Expand(gamma.Y), Expand(gamma.Z), gamma.W); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the compressed sRGB value from an linear signal.
|
|
||||
/// <see href="http://www.4p8.com/eric.brasseur/gamma.html#formulas"/>
|
|
||||
/// <see href="http://entropymine.com/imageworsener/srgbformula/"/>
|
|
||||
/// </summary>
|
|
||||
/// <param name="signal">The signal value to compress.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="float"/>.
|
|
||||
/// </returns>
|
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
private static float Compress(float signal) |
|
||||
{ |
|
||||
if (signal <= 0.0031308F) |
|
||||
{ |
|
||||
return signal * 12.92F; |
|
||||
} |
|
||||
|
|
||||
return (1.055F * (float)Math.Pow(signal, 0.41666666F)) - 0.055F; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the expanded linear value from an sRGB signal.
|
|
||||
/// <see href="http://www.4p8.com/eric.brasseur/gamma.html#formulas"/>
|
|
||||
/// <see href="http://entropymine.com/imageworsener/srgbformula/"/>
|
|
||||
/// </summary>
|
|
||||
/// <param name="signal">The signal value to expand.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="float"/>.
|
|
||||
/// </returns>
|
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
private static float Expand(float signal) |
|
||||
{ |
|
||||
if (signal <= 0.04045F) |
|
||||
{ |
|
||||
return signal / 12.92F; |
|
||||
} |
|
||||
|
|
||||
return (float)Math.Pow((signal + 0.055F) / 1.055F, 2.4F); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,205 +0,0 @@ |
|||||
// <copyright file="Guard.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Diagnostics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Provides methods to protect against invalid parameters.
|
|
||||
/// </summary>
|
|
||||
[DebuggerStepThrough] |
|
||||
internal static class Guard |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Verifies, that the method parameter with specified object value is not null
|
|
||||
/// and throws an exception if it is found to be so.
|
|
||||
/// </summary>
|
|
||||
/// <param name="target">The target object, which cannot be null.</param>
|
|
||||
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
|
|
||||
/// <param name="message">The error message, if any to add to the exception.</param>
|
|
||||
/// <exception cref="ArgumentNullException"><paramref name="target"/> is null</exception>
|
|
||||
public static void NotNull(object target, string parameterName, string message = "") |
|
||||
{ |
|
||||
if (target == null) |
|
||||
{ |
|
||||
if (!string.IsNullOrWhiteSpace(message)) |
|
||||
{ |
|
||||
throw new ArgumentNullException(parameterName, message); |
|
||||
} |
|
||||
|
|
||||
throw new ArgumentNullException(parameterName); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Verifies, that the string method parameter with specified object value and message
|
|
||||
/// is not null, not empty and does not contain only blanks and throws an exception
|
|
||||
/// if the object is null.
|
|
||||
/// </summary>
|
|
||||
/// <param name="target">The target string, which should be checked against being null or empty.</param>
|
|
||||
/// <param name="parameterName">Name of the parameter.</param>
|
|
||||
/// <exception cref="ArgumentNullException"><paramref name="target"/> is null.</exception>
|
|
||||
/// <exception cref="ArgumentException"><paramref name="target"/> is empty or contains only blanks.</exception>
|
|
||||
public static void NotNullOrEmpty(string target, string parameterName) |
|
||||
{ |
|
||||
if (target == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(parameterName); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrWhiteSpace(target)) |
|
||||
{ |
|
||||
throw new ArgumentException("Value cannot be null or empty and cannot contain only blanks.", parameterName); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Verifies that the specified value is less than a maximum value
|
|
||||
/// and throws an exception if it is not.
|
|
||||
/// </summary>
|
|
||||
/// <param name="value">The target value, which should be validated.</param>
|
|
||||
/// <param name="max">The maximum value.</param>
|
|
||||
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
|
|
||||
/// <typeparam name="TValue">The type of the value.</typeparam>
|
|
||||
/// <exception cref="ArgumentException">
|
|
||||
/// <paramref name="value"/> is greater than the maximum value.
|
|
||||
/// </exception>
|
|
||||
public static void MustBeLessThan<TValue>(TValue value, TValue max, string parameterName) |
|
||||
where TValue : IComparable<TValue> |
|
||||
{ |
|
||||
if (value.CompareTo(max) >= 0) |
|
||||
{ |
|
||||
throw new ArgumentOutOfRangeException(parameterName, $"Value must be less than {max}."); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Verifies that the specified value is less than or equal to a maximum value
|
|
||||
/// and throws an exception if it is not.
|
|
||||
/// </summary>
|
|
||||
/// <param name="value">The target value, which should be validated.</param>
|
|
||||
/// <param name="max">The maximum value.</param>
|
|
||||
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
|
|
||||
/// <typeparam name="TValue">The type of the value.</typeparam>
|
|
||||
/// <exception cref="ArgumentException">
|
|
||||
/// <paramref name="value"/> is greater than the maximum value.
|
|
||||
/// </exception>
|
|
||||
public static void MustBeLessThanOrEqualTo<TValue>(TValue value, TValue max, string parameterName) |
|
||||
where TValue : IComparable<TValue> |
|
||||
{ |
|
||||
if (value.CompareTo(max) > 0) |
|
||||
{ |
|
||||
throw new ArgumentOutOfRangeException(parameterName, $"Value must be less than or equal to {max}."); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Verifies that the specified value is greater than a minimum value
|
|
||||
/// and throws an exception if it is not.
|
|
||||
/// </summary>
|
|
||||
/// <param name="value">The target value, which should be validated.</param>
|
|
||||
/// <param name="min">The minimum value.</param>
|
|
||||
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
|
|
||||
/// <typeparam name="TValue">The type of the value.</typeparam>
|
|
||||
/// <exception cref="ArgumentException">
|
|
||||
/// <paramref name="value"/> is less than the minimum value.
|
|
||||
/// </exception>
|
|
||||
public static void MustBeGreaterThan<TValue>(TValue value, TValue min, string parameterName) |
|
||||
where TValue : IComparable<TValue> |
|
||||
{ |
|
||||
if (value.CompareTo(min) <= 0) |
|
||||
{ |
|
||||
throw new ArgumentOutOfRangeException( |
|
||||
parameterName, |
|
||||
$"Value must be greater than {min}."); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Verifies that the specified value is greater than or equal to a minimum value
|
|
||||
/// and throws an exception if it is not.
|
|
||||
/// </summary>
|
|
||||
/// <param name="value">The target value, which should be validated.</param>
|
|
||||
/// <param name="min">The minimum value.</param>
|
|
||||
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
|
|
||||
/// <typeparam name="TValue">The type of the value.</typeparam>
|
|
||||
/// <exception cref="ArgumentException">
|
|
||||
/// <paramref name="value"/> is less than the minimum value.
|
|
||||
/// </exception>
|
|
||||
public static void MustBeGreaterThanOrEqualTo<TValue>(TValue value, TValue min, string parameterName) |
|
||||
where TValue : IComparable<TValue> |
|
||||
{ |
|
||||
if (value.CompareTo(min) < 0) |
|
||||
{ |
|
||||
throw new ArgumentOutOfRangeException(parameterName, $"Value must be greater than or equal to {min}."); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Verifies that the specified value is greater than or equal to a minimum value and less than
|
|
||||
/// or equal to a maximum value and throws an exception if it is not.
|
|
||||
/// </summary>
|
|
||||
/// <param name="value">The target value, which should be validated.</param>
|
|
||||
/// <param name="min">The minimum value.</param>
|
|
||||
/// <param name="max">The maximum value.</param>
|
|
||||
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
|
|
||||
/// <typeparam name="TValue">The type of the value.</typeparam>
|
|
||||
/// <exception cref="ArgumentException">
|
|
||||
/// <paramref name="value"/> is less than the minimum value of greater than the maximum value.
|
|
||||
/// </exception>
|
|
||||
public static void MustBeBetweenOrEqualTo<TValue>(TValue value, TValue min, TValue max, string parameterName) |
|
||||
where TValue : IComparable<TValue> |
|
||||
{ |
|
||||
if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0) |
|
||||
{ |
|
||||
throw new ArgumentOutOfRangeException(parameterName, $"Value must be greater than or equal to {min} and less than or equal to {max}."); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Verifies, that the method parameter with specified target value is true
|
|
||||
/// and throws an exception if it is found to be so.
|
|
||||
/// </summary>
|
|
||||
/// <param name="target">
|
|
||||
/// The target value, which cannot be false.
|
|
||||
/// </param>
|
|
||||
/// <param name="parameterName">
|
|
||||
/// The name of the parameter that is to be checked.
|
|
||||
/// </param>
|
|
||||
/// <param name="message">
|
|
||||
/// The error message, if any to add to the exception.
|
|
||||
/// </param>
|
|
||||
/// <exception cref="ArgumentException">
|
|
||||
/// <paramref name="target"/> is false
|
|
||||
/// </exception>
|
|
||||
public static void IsTrue(bool target, string parameterName, string message) |
|
||||
{ |
|
||||
if (!target) |
|
||||
{ |
|
||||
throw new ArgumentException(message, parameterName); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Verifies, that the method parameter with specified target value is false
|
|
||||
/// and throws an exception if it is found to be so.
|
|
||||
/// </summary>
|
|
||||
/// <param name="target">The target value, which cannot be true.</param>
|
|
||||
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
|
|
||||
/// <param name="message">The error message, if any to add to the exception.</param>
|
|
||||
/// <exception cref="ArgumentException">
|
|
||||
/// <paramref name="target"/> is true
|
|
||||
/// </exception>
|
|
||||
public static void IsFalse(bool target, string parameterName, string message) |
|
||||
{ |
|
||||
if (target) |
|
||||
{ |
|
||||
throw new ArgumentException(message, parameterName); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,293 +0,0 @@ |
|||||
// <copyright file="ImageMaths.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Linq; |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Provides common mathematical methods.
|
|
||||
/// </summary>
|
|
||||
internal static class ImageMaths |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Returns how many bits are required to store the specified number of colors.
|
|
||||
/// Performs a Log2() on the value.
|
|
||||
/// </summary>
|
|
||||
/// <param name="colors">The number of colors.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="int"/>
|
|
||||
/// </returns>
|
|
||||
public static int GetBitsNeededForColorDepth(int colors) |
|
||||
{ |
|
||||
return (int)Math.Ceiling(Math.Log(colors, 2)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Implementation of 1D Gaussian G(x) function
|
|
||||
/// </summary>
|
|
||||
/// <param name="x">The x provided to G(x).</param>
|
|
||||
/// <param name="sigma">The spread of the blur.</param>
|
|
||||
/// <returns>The Gaussian G(x)</returns>
|
|
||||
public static float Gaussian(float x, float sigma) |
|
||||
{ |
|
||||
const float Numerator = 1.0f; |
|
||||
float denominator = (float)(Math.Sqrt(2 * Math.PI) * sigma); |
|
||||
|
|
||||
float exponentNumerator = -x * x; |
|
||||
float exponentDenominator = (float)(2 * Math.Pow(sigma, 2)); |
|
||||
|
|
||||
float left = Numerator / denominator; |
|
||||
float right = (float)Math.Exp(exponentNumerator / exponentDenominator); |
|
||||
|
|
||||
return left * right; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns the result of a B-C filter against the given value.
|
|
||||
/// <see href="http://www.imagemagick.org/Usage/filter/#cubic_bc"/>
|
|
||||
/// </summary>
|
|
||||
/// <param name="x">The value to process.</param>
|
|
||||
/// <param name="b">The B-Spline curve variable.</param>
|
|
||||
/// <param name="c">The Cardinal curve variable.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="float"/>.
|
|
||||
/// </returns>
|
|
||||
public static float GetBcValue(float x, float b, float c) |
|
||||
{ |
|
||||
float temp; |
|
||||
|
|
||||
if (x < 0F) |
|
||||
{ |
|
||||
x = -x; |
|
||||
} |
|
||||
|
|
||||
temp = x * x; |
|
||||
if (x < 1F) |
|
||||
{ |
|
||||
x = ((12 - (9 * b) - (6 * c)) * (x * temp)) + ((-18 + (12 * b) + (6 * c)) * temp) + (6 - (2 * b)); |
|
||||
return x / 6F; |
|
||||
} |
|
||||
|
|
||||
if (x < 2F) |
|
||||
{ |
|
||||
x = ((-b - (6 * c)) * (x * temp)) + (((6 * b) + (30 * c)) * temp) + (((-12 * b) - (48 * c)) * x) + ((8 * b) + (24 * c)); |
|
||||
return x / 6F; |
|
||||
} |
|
||||
|
|
||||
return 0F; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the result of a sine cardinal function for the given value.
|
|
||||
/// </summary>
|
|
||||
/// <param name="x">The value to calculate the result for.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="float"/>.
|
|
||||
/// </returns>
|
|
||||
public static float SinC(float x) |
|
||||
{ |
|
||||
const float Epsilon = .00001F; |
|
||||
|
|
||||
if (Math.Abs(x) > Epsilon) |
|
||||
{ |
|
||||
x *= (float)Math.PI; |
|
||||
return Clean((float)Math.Sin(x) / x); |
|
||||
} |
|
||||
|
|
||||
return 1.0f; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns the given degrees converted to radians.
|
|
||||
/// </summary>
|
|
||||
/// <param name="degrees">The angle in degrees.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="float"/> representing the degree as radians.
|
|
||||
/// </returns>
|
|
||||
public static float DegreesToRadians(float degrees) |
|
||||
{ |
|
||||
return degrees * (float)(Math.PI / 180); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the bounding <see cref="Rectangle"/> from the given points.
|
|
||||
/// </summary>
|
|
||||
/// <param name="topLeft">
|
|
||||
/// The <see cref="Point"/> designating the top left position.
|
|
||||
/// </param>
|
|
||||
/// <param name="bottomRight">
|
|
||||
/// The <see cref="Point"/> designating the bottom right position.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// The bounding <see cref="Rectangle"/>.
|
|
||||
/// </returns>
|
|
||||
public static Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight) |
|
||||
{ |
|
||||
return new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the bounding <see cref="Rectangle"/> from the given matrix.
|
|
||||
/// </summary>
|
|
||||
/// <param name="rectangle">The source rectangle.</param>
|
|
||||
/// <param name="matrix">The transformation matrix.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="Rectangle"/>.
|
|
||||
/// </returns>
|
|
||||
public static Rectangle GetBoundingRectangle(Rectangle rectangle, Matrix3x2 matrix) |
|
||||
{ |
|
||||
Vector2 leftTop = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Top), matrix); |
|
||||
Vector2 rightTop = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Top), matrix); |
|
||||
Vector2 leftBottom = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Bottom), matrix); |
|
||||
Vector2 rightBottom = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Bottom), matrix); |
|
||||
|
|
||||
Vector2[] allCorners = { leftTop, rightTop, leftBottom, rightBottom }; |
|
||||
float extentX = allCorners.Select(v => v.X).Max() - allCorners.Select(v => v.X).Min(); |
|
||||
float extentY = allCorners.Select(v => v.Y).Max() - allCorners.Select(v => v.Y).Min(); |
|
||||
return new Rectangle(0, 0, (int)extentX, (int)extentY); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Finds the bounding rectangle based on the first instance of any color component other
|
|
||||
/// than the given one.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="bitmap">The <see cref="Image"/> to search within.</param>
|
|
||||
/// <param name="componentValue">The color component value to remove.</param>
|
|
||||
/// <param name="channel">The <see cref="RgbaComponent"/> channel to test against.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="Rectangle"/>.
|
|
||||
/// </returns>
|
|
||||
public static Rectangle GetFilteredBoundingRectangle<TColor, TPacked>(ImageBase<TColor, TPacked> bitmap, float componentValue, RgbaComponent channel = RgbaComponent.B) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
const float Epsilon = .00001f; |
|
||||
int width = bitmap.Width; |
|
||||
int height = bitmap.Height; |
|
||||
Point topLeft = default(Point); |
|
||||
Point bottomRight = default(Point); |
|
||||
|
|
||||
Func<PixelAccessor<TColor, TPacked>, int, int, float, bool> delegateFunc; |
|
||||
|
|
||||
// Determine which channel to check against
|
|
||||
switch (channel) |
|
||||
{ |
|
||||
case RgbaComponent.R: |
|
||||
delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().X - b) > Epsilon; |
|
||||
break; |
|
||||
|
|
||||
case RgbaComponent.G: |
|
||||
delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().Y - b) > Epsilon; |
|
||||
break; |
|
||||
|
|
||||
case RgbaComponent.B: |
|
||||
delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().Z - b) > Epsilon; |
|
||||
break; |
|
||||
|
|
||||
default: |
|
||||
delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().W - b) > Epsilon; |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
Func<PixelAccessor<TColor, TPacked>, int> getMinY = pixels => |
|
||||
{ |
|
||||
for (int y = 0; y < height; y++) |
|
||||
{ |
|
||||
for (int x = 0; x < width; x++) |
|
||||
{ |
|
||||
if (delegateFunc(pixels, x, y, componentValue)) |
|
||||
{ |
|
||||
return y; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return 0; |
|
||||
}; |
|
||||
|
|
||||
Func<PixelAccessor<TColor, TPacked>, int> getMaxY = pixels => |
|
||||
{ |
|
||||
for (int y = height - 1; y > -1; y--) |
|
||||
{ |
|
||||
for (int x = 0; x < width; x++) |
|
||||
{ |
|
||||
if (delegateFunc(pixels, x, y, componentValue)) |
|
||||
{ |
|
||||
return y; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return height; |
|
||||
}; |
|
||||
|
|
||||
Func<PixelAccessor<TColor, TPacked>, int> getMinX = pixels => |
|
||||
{ |
|
||||
for (int x = 0; x < width; x++) |
|
||||
{ |
|
||||
for (int y = 0; y < height; y++) |
|
||||
{ |
|
||||
if (delegateFunc(pixels, x, y, componentValue)) |
|
||||
{ |
|
||||
return x; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return 0; |
|
||||
}; |
|
||||
|
|
||||
Func<PixelAccessor<TColor, TPacked>, int> getMaxX = pixels => |
|
||||
{ |
|
||||
for (int x = width - 1; x > -1; x--) |
|
||||
{ |
|
||||
for (int y = 0; y < height; y++) |
|
||||
{ |
|
||||
if (delegateFunc(pixels, x, y, componentValue)) |
|
||||
{ |
|
||||
return x; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return height; |
|
||||
}; |
|
||||
|
|
||||
using (PixelAccessor<TColor, TPacked> bitmapPixels = bitmap.Lock()) |
|
||||
{ |
|
||||
topLeft.Y = getMinY(bitmapPixels); |
|
||||
topLeft.X = getMinX(bitmapPixels); |
|
||||
bottomRight.Y = (getMaxY(bitmapPixels) + 1).Clamp(0, height); |
|
||||
bottomRight.X = (getMaxX(bitmapPixels) + 1).Clamp(0, width); |
|
||||
} |
|
||||
|
|
||||
return GetBoundingRectangle(topLeft, bottomRight); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Ensures that any passed double is correctly rounded to zero
|
|
||||
/// </summary>
|
|
||||
/// <param name="x">The value to clean.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="float"/>
|
|
||||
/// </returns>.
|
|
||||
private static float Clean(float x) |
|
||||
{ |
|
||||
const float Epsilon = .00001F; |
|
||||
|
|
||||
if (Math.Abs(x) < Epsilon) |
|
||||
{ |
|
||||
return 0F; |
|
||||
} |
|
||||
|
|
||||
return x; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,48 +0,0 @@ |
|||||
// <copyright file="Alpha.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Alters the alpha component of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="percent">The new opacity of the image. Must be between 0 and 100.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Alpha<TColor, TPacked>(this Image<TColor, TPacked> source, int percent) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Alpha(source, percent, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Alters the alpha component of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="percent">The new opacity of the image. Must be between 0 and 100.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Alpha<TColor, TPacked>(this Image<TColor, TPacked> source, int percent, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return source.Process(rectangle, new AlphaProcessor<TColor, TPacked>(percent)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,30 +0,0 @@ |
|||||
// <copyright file="BackgroundColor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Replaces the background color of image with the given one.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="color">The color to set as the background.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> BackgroundColor<TColor, TPacked>(this Image<TColor, TPacked> source, TColor color) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return source.Process(source.Bounds, new BackgroundColorProcessor<TColor, TPacked>(color)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,48 +0,0 @@ |
|||||
// <copyright file="BinaryThreshold.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Applies binerization to the image splitting the pixels at the given threshold.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="threshold">The threshold to apply binerization of the image. Must be between 0 and 1.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> BinaryThreshold<TColor, TPacked>(this Image<TColor, TPacked> source, float threshold) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return BinaryThreshold(source, threshold, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Applies binerization to the image splitting the pixels at the given threshold.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="threshold">The threshold to apply binerization of the image. Must be between 0 and 1.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> BinaryThreshold<TColor, TPacked>(this Image<TColor, TPacked> source, float threshold, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return source.Process(rectangle, new BinaryThresholdProcessor<TColor, TPacked>(threshold)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,46 +0,0 @@ |
|||||
// <copyright file="BlackWhite.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Applies black and white toning to the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> BlackWhite<TColor, TPacked>(this Image<TColor, TPacked> source) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return BlackWhite(source, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Applies black and white toning to the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> BlackWhite<TColor, TPacked>(this Image<TColor, TPacked> source, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return source.Process(rectangle, new BlackWhiteProcessor<TColor, TPacked>()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,50 +0,0 @@ |
|||||
// <copyright file="Blend.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Combines the given image together with the current one by blending their pixels.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="image">The image to blend with the currently processing image.</param>
|
|
||||
/// <param name="percent">The opacity of the image image to blend. Must be between 0 and 100.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Blend<TColor, TPacked>(this Image<TColor, TPacked> source, ImageBase<TColor, TPacked> image, int percent = 50) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Blend(source, image, percent, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Combines the given image together with the current one by blending their pixels.
|
|
||||
/// </summary>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="image">The image to blend with the currently processing image.</param>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="percent">The opacity of the image image to blend. Must be between 0 and 100.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Blend<TColor, TPacked>(this Image<TColor, TPacked> source, ImageBase<TColor, TPacked> image, int percent, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return source.Process(rectangle, new BlendProcessor<TColor, TPacked>(image, percent)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,48 +0,0 @@ |
|||||
// <copyright file="Brightness.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Alters the brightness component of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="amount">The new brightness of the image. Must be between -100 and 100.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Brightness<TColor, TPacked>(this Image<TColor, TPacked> source, int amount) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Brightness(source, amount, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Alters the brightness component of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="amount">The new brightness of the image. Must be between -100 and 100.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Brightness<TColor, TPacked>(this Image<TColor, TPacked> source, int amount, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return source.Process(rectangle, new BrightnessProcessor<TColor, TPacked>(amount)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,85 +0,0 @@ |
|||||
// <copyright file="ColorBlindness.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Applies the given colorblindness simulator to the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="colorBlindness">The type of color blindness simulator to apply.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> ColorBlindness<TColor, TPacked>(this Image<TColor, TPacked> source, ColorBlindness colorBlindness) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return ColorBlindness(source, colorBlindness, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Applies the given colorblindness simulator to the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="colorBlindness">The type of color blindness simulator to apply.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> ColorBlindness<TColor, TPacked>(this Image<TColor, TPacked> source, ColorBlindness colorBlindness, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
IImageFilter<TColor, TPacked> processor; |
|
||||
|
|
||||
switch (colorBlindness) |
|
||||
{ |
|
||||
case ImageSharp.ColorBlindness.Achromatomaly: |
|
||||
processor = new AchromatomalyProcessor<TColor, TPacked>(); |
|
||||
break; |
|
||||
|
|
||||
case ImageSharp.ColorBlindness.Achromatopsia: |
|
||||
processor = new AchromatopsiaProcessor<TColor, TPacked>(); |
|
||||
break; |
|
||||
|
|
||||
case ImageSharp.ColorBlindness.Deuteranomaly: |
|
||||
processor = new DeuteranomalyProcessor<TColor, TPacked>(); |
|
||||
break; |
|
||||
|
|
||||
case ImageSharp.ColorBlindness.Deuteranopia: |
|
||||
processor = new DeuteranopiaProcessor<TColor, TPacked>(); |
|
||||
break; |
|
||||
|
|
||||
case ImageSharp.ColorBlindness.Protanomaly: |
|
||||
processor = new ProtanomalyProcessor<TColor, TPacked>(); |
|
||||
break; |
|
||||
|
|
||||
case ImageSharp.ColorBlindness.Protanopia: |
|
||||
processor = new ProtanopiaProcessor<TColor, TPacked>(); |
|
||||
break; |
|
||||
|
|
||||
case ImageSharp.ColorBlindness.Tritanomaly: |
|
||||
processor = new TritanomalyProcessor<TColor, TPacked>(); |
|
||||
break; |
|
||||
|
|
||||
default: |
|
||||
processor = new TritanopiaProcessor<TColor, TPacked>(); |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
return source.Process(rectangle, processor); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,48 +0,0 @@ |
|||||
// <copyright file="Contrast.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Alters the contrast component of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="amount">The new contrast of the image. Must be between -100 and 100.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Contrast<TColor, TPacked>(this Image<TColor, TPacked> source, int amount) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Contrast(source, amount, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Alters the contrast component of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="amount">The new contrast of the image. Must be between -100 and 100.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Contrast<TColor, TPacked>(this Image<TColor, TPacked> source, int amount, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return source.Process(rectangle, new ContrastProcessor<TColor, TPacked>(amount)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,102 +0,0 @@ |
|||||
// <copyright file="Glow.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Applies a radial glow effect to an image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Glow<TColor, TPacked>(this Image<TColor, TPacked> source) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Glow(source, default(TColor), source.Bounds.Width * .5F, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Applies a radial glow effect to an image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="color">The color to set as the glow.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Glow<TColor, TPacked>(this Image<TColor, TPacked> source, TColor color) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Glow(source, color, source.Bounds.Width * .5F, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Applies a radial glow effect to an image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="radius">The the radius.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Glow<TColor, TPacked>(this Image<TColor, TPacked> source, float radius) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Glow(source, default(TColor), radius, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Applies a radial glow effect to an image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Glow<TColor, TPacked>(this Image<TColor, TPacked> source, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Glow(source, default(TColor), 0, rectangle); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Applies a radial glow effect to an image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="color">The color to set as the glow.</param>
|
|
||||
/// <param name="radius">The the radius.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Glow<TColor, TPacked>(this Image<TColor, TPacked> source, TColor color, float radius, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
GlowProcessor<TColor, TPacked> processor = new GlowProcessor<TColor, TPacked> { Radius = radius, }; |
|
||||
|
|
||||
if (!color.Equals(default(TColor))) |
|
||||
{ |
|
||||
processor.GlowColor = color; |
|
||||
} |
|
||||
|
|
||||
return source.Process(rectangle, processor); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,52 +0,0 @@ |
|||||
// <copyright file="Grayscale.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Applies Grayscale toning to the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="mode">The formula to apply to perform the operation.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Grayscale<TColor, TPacked>(this Image<TColor, TPacked> source, GrayscaleMode mode = GrayscaleMode.Bt709) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Grayscale(source, source.Bounds, mode); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Applies Grayscale toning to the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <param name="mode">The formula to apply to perform the operation.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Grayscale<TColor, TPacked>(this Image<TColor, TPacked> source, Rectangle rectangle, GrayscaleMode mode = GrayscaleMode.Bt709) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
IImageFilter<TColor, TPacked> processor = mode == GrayscaleMode.Bt709 |
|
||||
? (IImageFilter<TColor, TPacked>)new GrayscaleBt709Processor<TColor, TPacked>() |
|
||||
: new GrayscaleBt601Processor<TColor, TPacked>(); |
|
||||
|
|
||||
return source.Process(rectangle, processor); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,48 +0,0 @@ |
|||||
// <copyright file="Hue.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Alters the hue component of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="degrees">The angle in degrees to adjust the image.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Hue<TColor, TPacked>(this Image<TColor, TPacked> source, float degrees) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Hue(source, degrees, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Alters the hue component of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="degrees">The angle in degrees to adjust the image.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Hue<TColor, TPacked>(this Image<TColor, TPacked> source, float degrees, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return source.Process(rectangle, new HueProcessor<TColor, TPacked>(degrees)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,46 +0,0 @@ |
|||||
// <copyright file="Invert.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Inverts the colors of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <returns>The <see cref="Image"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Invert<TColor, TPacked>(this Image<TColor, TPacked> source) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Invert(source, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Inverts the colors of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Invert<TColor, TPacked>(this Image<TColor, TPacked> source, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return source.Process(rectangle, new InvertProcessor<TColor, TPacked>()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,46 +0,0 @@ |
|||||
// <copyright file="Kodachrome.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Alters the colors of the image recreating an old Kodachrome camera effect.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Kodachrome<TColor, TPacked>(this Image<TColor, TPacked> source) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Kodachrome(source, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Alters the colors of the image recreating an old Kodachrome camera effect.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Kodachrome<TColor, TPacked>(this Image<TColor, TPacked> source, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return source.Process(rectangle, new KodachromeProcessor<TColor, TPacked>()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,46 +0,0 @@ |
|||||
// <copyright file="Lomograph.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Alters the colors of the image recreating an old Lomograph camera effect.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Lomograph<TColor, TPacked>(this Image<TColor, TPacked> source) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Lomograph(source, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Alters the colors of the image recreating an old Lomograph camera effect.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Lomograph<TColor, TPacked>(this Image<TColor, TPacked> source, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return source.Process(rectangle, new LomographProcessor<TColor, TPacked>()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,53 +0,0 @@ |
|||||
// <copyright file="ColorBlindness.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Enumerates the various types of defined color blindness filters.
|
|
||||
/// </summary>
|
|
||||
public enum ColorBlindness |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Partial color desensitivity.
|
|
||||
/// </summary>
|
|
||||
Achromatomaly, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Complete color desensitivity (Monochrome)
|
|
||||
/// </summary>
|
|
||||
Achromatopsia, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Green weak
|
|
||||
/// </summary>
|
|
||||
Deuteranomaly, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Green blind
|
|
||||
/// </summary>
|
|
||||
Deuteranopia, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Red weak
|
|
||||
/// </summary>
|
|
||||
Protanomaly, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Red blind
|
|
||||
/// </summary>
|
|
||||
Protanopia, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Blue weak
|
|
||||
/// </summary>
|
|
||||
Tritanomaly, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Blue blind
|
|
||||
/// </summary>
|
|
||||
Tritanopia |
|
||||
} |
|
||||
} |
|
||||
@ -1,63 +0,0 @@ |
|||||
// <copyright file="EdgeDetection.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Enumerates the various types of defined edge detection filters.
|
|
||||
/// </summary>
|
|
||||
public enum EdgeDetection |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The Kayyali operator filter.
|
|
||||
/// </summary>
|
|
||||
Kayyali, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The Kirsch operator filter.
|
|
||||
/// </summary>
|
|
||||
Kirsch, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The Lapacian3X3 operator filter.
|
|
||||
/// </summary>
|
|
||||
Lapacian3X3, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The Lapacian5X5 operator filter.
|
|
||||
/// </summary>
|
|
||||
Lapacian5X5, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The LaplacianOfGaussian operator filter.
|
|
||||
/// </summary>
|
|
||||
LaplacianOfGaussian, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The Prewitt operator filter.
|
|
||||
/// </summary>
|
|
||||
Prewitt, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The RobertsCross operator filter.
|
|
||||
/// </summary>
|
|
||||
RobertsCross, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The Robinson operator filter.
|
|
||||
/// </summary>
|
|
||||
Robinson, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The Scharr operator filter.
|
|
||||
/// </summary>
|
|
||||
Scharr, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The Sobel operator filter.
|
|
||||
/// </summary>
|
|
||||
Sobel |
|
||||
} |
|
||||
} |
|
||||
@ -1,23 +0,0 @@ |
|||||
// <copyright file="GrayscaleMode.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Enumerates the various types of defined Grayscale filters.
|
|
||||
/// </summary>
|
|
||||
public enum GrayscaleMode |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// ITU-R Recommendation BT.709
|
|
||||
/// </summary>
|
|
||||
Bt709, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// ITU-R Recommendation BT.601
|
|
||||
/// </summary>
|
|
||||
Bt601 |
|
||||
} |
|
||||
} |
|
||||
@ -1,46 +0,0 @@ |
|||||
// <copyright file="Polaroid.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Alters the colors of the image recreating an old Polaroid camera effect.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Polaroid<TColor, TPacked>(this Image<TColor, TPacked> source) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Polaroid(source, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Alters the colors of the image recreating an old Polaroid camera effect.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Polaroid<TColor, TPacked>(this Image<TColor, TPacked> source, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return source.Process(rectangle, new PolaroidProcessor<TColor, TPacked>()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,85 +0,0 @@ |
|||||
// <copyright file="AlphaProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Numerics; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// An <see cref="IImageFilter{TColor, TPacked}"/> to change the alpha component of an <see cref="Image{TColor, TPacked}"/>.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class AlphaProcessor<TColor, TPacked> : ImageFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="AlphaProcessor{TColor, TPacked}"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="percent">The percentage to adjust the opacity of the image. Must be between 0 and 100.</param>
|
|
||||
/// <exception cref="System.ArgumentException">
|
|
||||
/// <paramref name="percent"/> is less than 0 or is greater than 100.
|
|
||||
/// </exception>
|
|
||||
public AlphaProcessor(int percent) |
|
||||
{ |
|
||||
Guard.MustBeBetweenOrEqualTo(percent, 0, 100, nameof(percent)); |
|
||||
this.Value = percent; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the alpha value.
|
|
||||
/// </summary>
|
|
||||
public int Value { get; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
protected override void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY) |
|
||||
{ |
|
||||
float alpha = this.Value / 100F; |
|
||||
int startX = sourceRectangle.X; |
|
||||
int endX = sourceRectangle.Right; |
|
||||
|
|
||||
// Align start/end positions.
|
|
||||
int minX = Math.Max(0, startX); |
|
||||
int maxX = Math.Min(source.Width, endX); |
|
||||
int minY = Math.Max(0, startY); |
|
||||
int maxY = Math.Min(source.Height, endY); |
|
||||
|
|
||||
// Reset offset if necessary.
|
|
||||
if (minX > 0) |
|
||||
{ |
|
||||
startX = 0; |
|
||||
} |
|
||||
|
|
||||
if (minY > 0) |
|
||||
{ |
|
||||
startY = 0; |
|
||||
} |
|
||||
|
|
||||
Vector4 alphaVector = new Vector4(1, 1, 1, alpha); |
|
||||
|
|
||||
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock()) |
|
||||
{ |
|
||||
Parallel.For( |
|
||||
minY, |
|
||||
maxY, |
|
||||
this.ParallelOptions, |
|
||||
y => |
|
||||
{ |
|
||||
int offsetY = y - startY; |
|
||||
for (int x = minX; x < maxX; x++) |
|
||||
{ |
|
||||
int offsetX = x - startX; |
|
||||
TColor packed = default(TColor); |
|
||||
packed.PackFromVector4(sourcePixels[offsetX, offsetY].ToVector4() * alphaVector); |
|
||||
sourcePixels[offsetX, offsetY] = packed; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,98 +0,0 @@ |
|||||
// <copyright file="BackgroundColorProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Numerics; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the background color of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class BackgroundColorProcessor<TColor, TPacked> : ImageFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The epsilon for comparing floating point numbers.
|
|
||||
/// </summary>
|
|
||||
private const float Epsilon = 0.001f; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="BackgroundColorProcessor{TColor, TPacked}"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">The <typeparamref name="TColor"/> to set the background color to.</param>
|
|
||||
public BackgroundColorProcessor(TColor color) |
|
||||
{ |
|
||||
this.Value = color; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the background color value.
|
|
||||
/// </summary>
|
|
||||
public TColor Value { get; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
protected override void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY) |
|
||||
{ |
|
||||
int startX = sourceRectangle.X; |
|
||||
int endX = sourceRectangle.Right; |
|
||||
|
|
||||
// Align start/end positions.
|
|
||||
int minX = Math.Max(0, startX); |
|
||||
int maxX = Math.Min(source.Width, endX); |
|
||||
int minY = Math.Max(0, startY); |
|
||||
int maxY = Math.Min(source.Height, endY); |
|
||||
|
|
||||
// Reset offset if necessary.
|
|
||||
if (minX > 0) |
|
||||
{ |
|
||||
startX = 0; |
|
||||
} |
|
||||
|
|
||||
if (minY > 0) |
|
||||
{ |
|
||||
startY = 0; |
|
||||
} |
|
||||
|
|
||||
Vector4 backgroundColor = this.Value.ToVector4(); |
|
||||
|
|
||||
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock()) |
|
||||
{ |
|
||||
Parallel.For( |
|
||||
minY, |
|
||||
maxY, |
|
||||
this.ParallelOptions, |
|
||||
y => |
|
||||
{ |
|
||||
int offsetY = y - startY; |
|
||||
for (int x = minX; x < maxX; x++) |
|
||||
{ |
|
||||
int offsetX = x - startX; |
|
||||
Vector4 color = sourcePixels[offsetX, offsetY].ToVector4(); |
|
||||
float a = color.W; |
|
||||
|
|
||||
if (a < 1 && a > 0) |
|
||||
{ |
|
||||
color = Vector4.Lerp(color, backgroundColor, .5F); |
|
||||
} |
|
||||
|
|
||||
if (Math.Abs(a) < Epsilon) |
|
||||
{ |
|
||||
color = backgroundColor; |
|
||||
} |
|
||||
|
|
||||
TColor packed = default(TColor); |
|
||||
packed.PackFromVector4(color); |
|
||||
sourcePixels[offsetX, offsetY] = packed; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,111 +0,0 @@ |
|||||
// <copyright file="BinaryThresholdProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// An <see cref="IImageFilter{TColor,TPacked}"/> to perform binary threshold filtering against an
|
|
||||
/// <see cref="Image"/>. The image will be converted to grayscale before thresholding occurs.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class BinaryThresholdProcessor<TColor, TPacked> : ImageFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="BinaryThresholdProcessor{TColor, TPacked}"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param>
|
|
||||
/// <exception cref="System.ArgumentException">
|
|
||||
/// <paramref name="threshold"/> is less than 0 or is greater than 1.
|
|
||||
/// </exception>
|
|
||||
public BinaryThresholdProcessor(float threshold) |
|
||||
{ |
|
||||
// TODO: Check limit.
|
|
||||
Guard.MustBeBetweenOrEqualTo(threshold, 0, 1, nameof(threshold)); |
|
||||
this.Value = threshold; |
|
||||
|
|
||||
TColor upper = default(TColor); |
|
||||
upper.PackFromVector4(Color.White.ToVector4()); |
|
||||
this.UpperColor = upper; |
|
||||
|
|
||||
TColor lower = default(TColor); |
|
||||
lower.PackFromVector4(Color.Black.ToVector4()); |
|
||||
this.LowerColor = lower; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the threshold value.
|
|
||||
/// </summary>
|
|
||||
public float Value { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the color to use for pixels that are above the threshold.
|
|
||||
/// </summary>
|
|
||||
public TColor UpperColor { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the color to use for pixels that fall below the threshold.
|
|
||||
/// </summary>
|
|
||||
public TColor LowerColor { get; set; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
protected override void OnApply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle) |
|
||||
{ |
|
||||
new GrayscaleBt709Processor<TColor, TPacked>().Apply(source, sourceRectangle); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
protected override void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY) |
|
||||
{ |
|
||||
float threshold = this.Value; |
|
||||
TColor upper = this.UpperColor; |
|
||||
TColor lower = this.LowerColor; |
|
||||
int startX = sourceRectangle.X; |
|
||||
int endX = sourceRectangle.Right; |
|
||||
|
|
||||
// Align start/end positions.
|
|
||||
int minX = Math.Max(0, startX); |
|
||||
int maxX = Math.Min(source.Width, endX); |
|
||||
int minY = Math.Max(0, startY); |
|
||||
int maxY = Math.Min(source.Height, endY); |
|
||||
|
|
||||
// Reset offset if necessary.
|
|
||||
if (minX > 0) |
|
||||
{ |
|
||||
startX = 0; |
|
||||
} |
|
||||
|
|
||||
if (minY > 0) |
|
||||
{ |
|
||||
startY = 0; |
|
||||
} |
|
||||
|
|
||||
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock()) |
|
||||
{ |
|
||||
Parallel.For( |
|
||||
minY, |
|
||||
maxY, |
|
||||
this.ParallelOptions, |
|
||||
y => |
|
||||
{ |
|
||||
int offsetY = y - startY; |
|
||||
for (int x = minX; x < maxX; x++) |
|
||||
{ |
|
||||
int offsetX = x - startX; |
|
||||
TColor color = sourcePixels[offsetX, offsetY]; |
|
||||
|
|
||||
// Any channel will do since it's Grayscale.
|
|
||||
sourcePixels[offsetX, offsetY] = color.ToVector4().X >= threshold ? upper : lower; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,106 +0,0 @@ |
|||||
// <copyright file="BlendProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Numerics; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Combines two images together by blending the pixels.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class BlendProcessor<TColor, TPacked> : ImageFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The image to blend.
|
|
||||
/// </summary>
|
|
||||
private readonly ImageBase<TColor, TPacked> blend; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="BlendProcessor{T,TP}"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="image">
|
|
||||
/// The image to blend with the currently processing image.
|
|
||||
/// Disposal of this image is the responsibility of the developer.
|
|
||||
/// </param>
|
|
||||
/// <param name="alpha">The opacity of the image to blend. Between 0 and 100.</param>
|
|
||||
public BlendProcessor(ImageBase<TColor, TPacked> image, int alpha = 100) |
|
||||
{ |
|
||||
Guard.MustBeBetweenOrEqualTo(alpha, 0, 100, nameof(alpha)); |
|
||||
this.blend = image; |
|
||||
this.Value = alpha; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the alpha percentage value.
|
|
||||
/// </summary>
|
|
||||
public int Value { get; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
protected override void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY) |
|
||||
{ |
|
||||
int startX = sourceRectangle.X; |
|
||||
int endX = sourceRectangle.Right; |
|
||||
Rectangle bounds = this.blend.Bounds; |
|
||||
|
|
||||
// Align start/end positions.
|
|
||||
int minX = Math.Max(0, startX); |
|
||||
int maxX = Math.Min(source.Width, endX); |
|
||||
int minY = Math.Max(0, startY); |
|
||||
int maxY = Math.Min(source.Height, endY); |
|
||||
|
|
||||
// Reset offset if necessary.
|
|
||||
if (minX > 0) |
|
||||
{ |
|
||||
startX = 0; |
|
||||
} |
|
||||
|
|
||||
if (minY > 0) |
|
||||
{ |
|
||||
startY = 0; |
|
||||
} |
|
||||
|
|
||||
float alpha = this.Value / 100F; |
|
||||
|
|
||||
using (PixelAccessor<TColor, TPacked> toBlendPixels = this.blend.Lock()) |
|
||||
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock()) |
|
||||
{ |
|
||||
Parallel.For( |
|
||||
minY, |
|
||||
maxY, |
|
||||
this.ParallelOptions, |
|
||||
y => |
|
||||
{ |
|
||||
int offsetY = y - startY; |
|
||||
for (int x = minX; x < maxX; x++) |
|
||||
{ |
|
||||
int offsetX = x - startX; |
|
||||
Vector4 color = sourcePixels[offsetX, offsetY].ToVector4(); |
|
||||
|
|
||||
if (bounds.Contains(offsetX, offsetY)) |
|
||||
{ |
|
||||
Vector4 blendedColor = toBlendPixels[offsetX, offsetY].ToVector4(); |
|
||||
|
|
||||
if (blendedColor.W > 0) |
|
||||
{ |
|
||||
// Lerping colors is dependent on the alpha of the blended color
|
|
||||
color = Vector4.Lerp(color, blendedColor, alpha > 0 ? alpha : blendedColor.W); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
TColor packed = default(TColor); |
|
||||
packed.PackFromVector4(color); |
|
||||
sourcePixels[offsetX, offsetY] = packed; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,90 +0,0 @@ |
|||||
// <copyright file="BrightnessProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Numerics; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// An <see cref="IImageFilter{TColor,TPacked}"/> to change the brightness of an <see cref="Image{TColor, TPacked}"/>.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class BrightnessProcessor<TColor, TPacked> : ImageFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="BrightnessProcessor{TColor, TPacked}"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="brightness">The new brightness of the image. Must be between -100 and 100.</param>
|
|
||||
/// <exception cref="System.ArgumentException">
|
|
||||
/// <paramref name="brightness"/> is less than -100 or is greater than 100.
|
|
||||
/// </exception>
|
|
||||
public BrightnessProcessor(int brightness) |
|
||||
{ |
|
||||
Guard.MustBeBetweenOrEqualTo(brightness, -100, 100, nameof(brightness)); |
|
||||
this.Value = brightness; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the brightness value.
|
|
||||
/// </summary>
|
|
||||
public int Value { get; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
protected override void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY) |
|
||||
{ |
|
||||
float brightness = this.Value / 100F; |
|
||||
int startX = sourceRectangle.X; |
|
||||
int endX = sourceRectangle.Right; |
|
||||
|
|
||||
// Align start/end positions.
|
|
||||
int minX = Math.Max(0, startX); |
|
||||
int maxX = Math.Min(source.Width, endX); |
|
||||
int minY = Math.Max(0, startY); |
|
||||
int maxY = Math.Min(source.Height, endY); |
|
||||
|
|
||||
// Reset offset if necessary.
|
|
||||
if (minX > 0) |
|
||||
{ |
|
||||
startX = 0; |
|
||||
} |
|
||||
|
|
||||
if (minY > 0) |
|
||||
{ |
|
||||
startY = 0; |
|
||||
} |
|
||||
|
|
||||
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock()) |
|
||||
{ |
|
||||
Parallel.For( |
|
||||
minY, |
|
||||
maxY, |
|
||||
this.ParallelOptions, |
|
||||
y => |
|
||||
{ |
|
||||
int offsetY = y - startY; |
|
||||
for (int x = minX; x < maxX; x++) |
|
||||
{ |
|
||||
int offsetX = x - startX; |
|
||||
|
|
||||
// TODO: Check this with other formats.
|
|
||||
Vector4 vector = sourcePixels[offsetX, offsetY].ToVector4().Expand(); |
|
||||
Vector3 transformed = new Vector3(vector.X, vector.Y, vector.Z) + new Vector3(brightness); |
|
||||
vector = new Vector4(transformed, vector.W); |
|
||||
|
|
||||
TColor packed = default(TColor); |
|
||||
packed.PackFromVector4(vector.Compress()); |
|
||||
|
|
||||
sourcePixels[offsetX, offsetY] = packed; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,36 +0,0 @@ |
|||||
// <copyright file="BlackWhiteProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the colors of the image to their black and white equivalent.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class BlackWhiteProcessor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix => new Matrix4x4() |
|
||||
{ |
|
||||
M11 = 1.5f, |
|
||||
M12 = 1.5f, |
|
||||
M13 = 1.5f, |
|
||||
M21 = 1.5f, |
|
||||
M22 = 1.5f, |
|
||||
M23 = 1.5f, |
|
||||
M31 = 1.5f, |
|
||||
M32 = 1.5f, |
|
||||
M33 = 1.5f, |
|
||||
M41 = -1f, |
|
||||
M42 = -1f, |
|
||||
M43 = -1f, |
|
||||
}; |
|
||||
} |
|
||||
} |
|
||||
@ -1,36 +0,0 @@ |
|||||
// <copyright file="AchromatomalyProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the colors of the image recreating Achromatomaly (Color desensitivity) color blindness.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class AchromatomalyProcessor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix => new Matrix4x4() |
|
||||
{ |
|
||||
M11 = .618f, |
|
||||
M12 = .163f, |
|
||||
M13 = .163f, |
|
||||
M21 = .320f, |
|
||||
M22 = .775f, |
|
||||
M23 = .320f, |
|
||||
M31 = .062f, |
|
||||
M32 = .062f, |
|
||||
M33 = .516f |
|
||||
}; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Compand => false; |
|
||||
} |
|
||||
} |
|
||||
@ -1,36 +0,0 @@ |
|||||
// <copyright file="AchromatopsiaProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the colors of the image recreating Achromatopsia (Monochrome) color blindness.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class AchromatopsiaProcessor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix => new Matrix4x4() |
|
||||
{ |
|
||||
M11 = .299f, |
|
||||
M12 = .299f, |
|
||||
M13 = .299f, |
|
||||
M21 = .587f, |
|
||||
M22 = .587f, |
|
||||
M23 = .587f, |
|
||||
M31 = .114f, |
|
||||
M32 = .114f, |
|
||||
M33 = .114f |
|
||||
}; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Compand => false; |
|
||||
} |
|
||||
} |
|
||||
@ -1,33 +0,0 @@ |
|||||
// <copyright file="DeuteranomalyProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the colors of the image recreating Deuteranomaly (Green-Weak) color blindness.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class DeuteranomalyProcessor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix => new Matrix4x4() |
|
||||
{ |
|
||||
M11 = 0.8f, |
|
||||
M12 = 0.258f, |
|
||||
M21 = 0.2f, |
|
||||
M22 = 0.742f, |
|
||||
M23 = 0.142f, |
|
||||
M33 = 0.858f |
|
||||
}; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Compand => false; |
|
||||
} |
|
||||
} |
|
||||
@ -1,33 +0,0 @@ |
|||||
// <copyright file="DeuteranopiaProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the colors of the image recreating Deuteranopia (Green-Blind) color blindness.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class DeuteranopiaProcessor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix => new Matrix4x4() |
|
||||
{ |
|
||||
M11 = 0.625f, |
|
||||
M12 = 0.7f, |
|
||||
M21 = 0.375f, |
|
||||
M22 = 0.3f, |
|
||||
M23 = 0.3f, |
|
||||
M33 = 0.7f |
|
||||
}; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Compand => false; |
|
||||
} |
|
||||
} |
|
||||
@ -1,33 +0,0 @@ |
|||||
// <copyright file="ProtanomalyProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the colors of the image recreating Protanopia (Red-Weak) color blindness.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class ProtanomalyProcessor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix => new Matrix4x4() |
|
||||
{ |
|
||||
M11 = 0.817f, |
|
||||
M12 = 0.333f, |
|
||||
M21 = 0.183f, |
|
||||
M22 = 0.667f, |
|
||||
M23 = 0.125f, |
|
||||
M33 = 0.875f |
|
||||
}; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Compand => false; |
|
||||
} |
|
||||
} |
|
||||
@ -1,33 +0,0 @@ |
|||||
// <copyright file="ProtanopiaProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the colors of the image recreating Protanopia (Red-Blind) color blindness.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class ProtanopiaProcessor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix => new Matrix4x4() |
|
||||
{ |
|
||||
M11 = 0.567f, |
|
||||
M12 = 0.558f, |
|
||||
M21 = 0.433f, |
|
||||
M22 = 0.442f, |
|
||||
M23 = 0.242f, |
|
||||
M33 = 0.758f |
|
||||
}; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Compand => false; |
|
||||
} |
|
||||
} |
|
||||
@ -1,4 +0,0 @@ |
|||||
Color blindness matrices adapted from and tested against: |
|
||||
|
|
||||
http://web.archive.org/web/20090413045433/http://nofunc.org/Color_Matrix_Library |
|
||||
http://www.color-blindness.com/coblis-color-blindness-simulator/ |
|
||||
@ -1,33 +0,0 @@ |
|||||
// <copyright file="TritanomalyProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the colors of the image recreating Tritanomaly (Blue-Weak) color blindness.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class TritanomalyProcessor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix => new Matrix4x4() |
|
||||
{ |
|
||||
M11 = 0.967f, |
|
||||
M21 = 0.33f, |
|
||||
M22 = 0.733f, |
|
||||
M23 = 0.183f, |
|
||||
M32 = 0.267f, |
|
||||
M33 = 0.817f |
|
||||
}; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Compand => false; |
|
||||
} |
|
||||
} |
|
||||
@ -1,33 +0,0 @@ |
|||||
// <copyright file="TritanopiaProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the colors of the image recreating Tritanopia (Blue-Blind) color blindness.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class TritanopiaProcessor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix => new Matrix4x4() |
|
||||
{ |
|
||||
M11 = 0.95f, |
|
||||
M21 = 0.05f, |
|
||||
M22 = 0.433f, |
|
||||
M23 = 0.475f, |
|
||||
M32 = 0.567f, |
|
||||
M33 = 0.525f |
|
||||
}; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Compand => false; |
|
||||
} |
|
||||
} |
|
||||
@ -1,96 +0,0 @@ |
|||||
// <copyright file="ColorMatrixFilter.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Numerics; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The color matrix filter. Inherit from this class to perform operation involving color matrices.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public abstract class ColorMatrixFilter<TColor, TPacked> : ImageFilter<TColor, TPacked>, IColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public abstract Matrix4x4 Matrix { get; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Compand { get; set; } = true; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
protected override void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY) |
|
||||
{ |
|
||||
int startX = sourceRectangle.X; |
|
||||
int endX = sourceRectangle.Right; |
|
||||
|
|
||||
// Align start/end positions.
|
|
||||
int minX = Math.Max(0, startX); |
|
||||
int maxX = Math.Min(source.Width, endX); |
|
||||
int minY = Math.Max(0, startY); |
|
||||
int maxY = Math.Min(source.Height, endY); |
|
||||
|
|
||||
// Reset offset if necessary.
|
|
||||
if (minX > 0) |
|
||||
{ |
|
||||
startX = 0; |
|
||||
} |
|
||||
|
|
||||
if (minY > 0) |
|
||||
{ |
|
||||
startY = 0; |
|
||||
} |
|
||||
|
|
||||
Matrix4x4 matrix = this.Matrix; |
|
||||
bool compand = this.Compand; |
|
||||
|
|
||||
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock()) |
|
||||
{ |
|
||||
Parallel.For( |
|
||||
minY, |
|
||||
maxY, |
|
||||
this.ParallelOptions, |
|
||||
y => |
|
||||
{ |
|
||||
int offsetY = y - startY; |
|
||||
for (int x = minX; x < maxX; x++) |
|
||||
{ |
|
||||
int offsetX = x - startX; |
|
||||
sourcePixels[offsetX, offsetY] = this.ApplyMatrix(sourcePixels[offsetX, offsetY], matrix, compand); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Applies the color matrix against the given color.
|
|
||||
/// </summary>
|
|
||||
/// <param name="color">The source color.</param>
|
|
||||
/// <param name="matrix">The matrix.</param>
|
|
||||
/// <param name="compand">Whether to compand the color during processing.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="Color"/>.
|
|
||||
/// </returns>
|
|
||||
private TColor ApplyMatrix(TColor color, Matrix4x4 matrix, bool compand) |
|
||||
{ |
|
||||
Vector4 vector = color.ToVector4(); |
|
||||
|
|
||||
if (compand) |
|
||||
{ |
|
||||
vector = vector.Expand(); |
|
||||
} |
|
||||
|
|
||||
Vector3 transformed = Vector3.Transform(new Vector3(vector.X, vector.Y, vector.Z), matrix); |
|
||||
vector = new Vector4(transformed, vector.W); |
|
||||
TColor packed = default(TColor); |
|
||||
packed.PackFromVector4(compand ? vector.Compress() : vector); |
|
||||
return packed; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,34 +0,0 @@ |
|||||
// <copyright file="GrayscaleBt601Processor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the colors of the image to Grayscale applying the formula as specified by
|
|
||||
/// ITU-R Recommendation BT.601 <see href="https://en.wikipedia.org/wiki/Luma_%28video%29#Rec._601_luma_versus_Rec._709_luma_coefficients"/>.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class GrayscaleBt601Processor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix => new Matrix4x4() |
|
||||
{ |
|
||||
M11 = .299f, |
|
||||
M12 = .299f, |
|
||||
M13 = .299f, |
|
||||
M21 = .587f, |
|
||||
M22 = .587f, |
|
||||
M23 = .587f, |
|
||||
M31 = .114f, |
|
||||
M32 = .114f, |
|
||||
M33 = .114f |
|
||||
}; |
|
||||
} |
|
||||
} |
|
||||
@ -1,32 +0,0 @@ |
|||||
// <copyright file="GrayscaleBt709Processor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the colors of the image to Grayscale applying the formula as specified by
|
|
||||
/// ITU-R Recommendation BT.709 <see href="https://en.wikipedia.org/wiki/Rec._709#Luma_coefficients"/>.
|
|
||||
/// </summary>
|
|
||||
public class GrayscaleBt709Processor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix => new Matrix4x4() |
|
||||
{ |
|
||||
M11 = .2126f, |
|
||||
M12 = .2126f, |
|
||||
M13 = .2126f, |
|
||||
M21 = .7152f, |
|
||||
M22 = .7152f, |
|
||||
M23 = .7152f, |
|
||||
M31 = .0722f, |
|
||||
M32 = .0722f, |
|
||||
M33 = .0722f |
|
||||
}; |
|
||||
} |
|
||||
} |
|
||||
@ -1,79 +0,0 @@ |
|||||
// <copyright file="HueProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// An <see cref="ImageProcessor{TColor, TPacked}"/> to change the hue of an <see cref="Image{TColor, TPacked}"/>.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class HueProcessor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="HueProcessor{TColor, TPacked}"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="angle">The new brightness of the image. Must be between -100 and 100.</param>
|
|
||||
public HueProcessor(float angle) |
|
||||
{ |
|
||||
// Wrap the angle round at 360.
|
|
||||
angle = angle % 360; |
|
||||
|
|
||||
// Make sure it's not negative.
|
|
||||
while (angle < 0) |
|
||||
{ |
|
||||
angle += 360; |
|
||||
} |
|
||||
|
|
||||
this.Angle = angle; |
|
||||
|
|
||||
float radians = ImageMaths.DegreesToRadians(angle); |
|
||||
double cosradians = Math.Cos(radians); |
|
||||
double sinradians = Math.Sin(radians); |
|
||||
|
|
||||
float lumR = .213f; |
|
||||
float lumG = .715f; |
|
||||
float lumB = .072f; |
|
||||
|
|
||||
float oneMinusLumR = 1 - lumR; |
|
||||
float oneMinusLumG = 1 - lumG; |
|
||||
float oneMinusLumB = 1 - lumB; |
|
||||
|
|
||||
// The matrix is set up to preserve the luminance of the image.
|
|
||||
// See http://graficaobscura.com/matrix/index.html
|
|
||||
// Number are taken from https://msdn.microsoft.com/en-us/library/jj192162(v=vs.85).aspx
|
|
||||
Matrix4x4 matrix4X4 = new Matrix4x4() |
|
||||
{ |
|
||||
M11 = (float)(lumR + (cosradians * oneMinusLumR) - (sinradians * lumR)), |
|
||||
M12 = (float)(lumR - (cosradians * lumR) - (sinradians * 0.143)), |
|
||||
M13 = (float)(lumR - (cosradians * lumR) - (sinradians * oneMinusLumR)), |
|
||||
M21 = (float)(lumG - (cosradians * lumG) - (sinradians * lumG)), |
|
||||
M22 = (float)(lumG + (cosradians * oneMinusLumG) + (sinradians * 0.140)), |
|
||||
M23 = (float)(lumG - (cosradians * lumG) + (sinradians * lumG)), |
|
||||
M31 = (float)(lumB - (cosradians * lumB) + (sinradians * oneMinusLumB)), |
|
||||
M32 = (float)(lumB - (cosradians * lumB) - (sinradians * 0.283)), |
|
||||
M33 = (float)(lumB + (cosradians * oneMinusLumB) + (sinradians * lumB)) |
|
||||
}; |
|
||||
|
|
||||
this.Matrix = matrix4X4; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the rotation value.
|
|
||||
/// </summary>
|
|
||||
public float Angle { get; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix { get; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Compand => false; |
|
||||
} |
|
||||
} |
|
||||
@ -1,25 +0,0 @@ |
|||||
// <copyright file="IColorMatrixFilter.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Encapsulates properties and methods for creating processors that utilize a matrix to
|
|
||||
/// alter the image pixels.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public interface IColorMatrixFilter<TColor, TPacked> : IImageFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets the <see cref="Matrix4x4"/> used to alter the image.
|
|
||||
/// </summary>
|
|
||||
Matrix4x4 Matrix { get; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,30 +0,0 @@ |
|||||
// <copyright file="KodachromeProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the colors of the image recreating an old Kodachrome camera effect.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class KodachromeProcessor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix => new Matrix4x4() |
|
||||
{ |
|
||||
M11 = 0.6997023f, |
|
||||
M22 = 0.4609577f, |
|
||||
M33 = 0.397218f, |
|
||||
M41 = 0.005f, |
|
||||
M42 = -0.005f, |
|
||||
M43 = 0.005f |
|
||||
}; |
|
||||
} |
|
||||
} |
|
||||
@ -1,38 +0,0 @@ |
|||||
// <copyright file="LomographProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the colors of the image recreating an old Lomograph effect.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class LomographProcessor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix => new Matrix4x4() |
|
||||
{ |
|
||||
M11 = 1.5f, |
|
||||
M22 = 1.45f, |
|
||||
M33 = 1.11f, |
|
||||
M41 = -.1f, |
|
||||
M42 = .0f, |
|
||||
M43 = -.08f |
|
||||
}; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
protected override void AfterApply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle) |
|
||||
{ |
|
||||
TColor packed = default(TColor); |
|
||||
packed.PackFromVector4(new Color(0, 10, 0).ToVector4()); // Very dark (mostly black) lime green.
|
|
||||
new VignetteProcessor<TColor, TPacked> { VignetteColor = packed }.Apply(source, sourceRectangle); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,48 +0,0 @@ |
|||||
// <copyright file="PolaroidProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the colors of the image recreating an old Polaroid effect.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class PolaroidProcessor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix => new Matrix4x4() |
|
||||
{ |
|
||||
M11 = 1.538f, |
|
||||
M12 = -0.062f, |
|
||||
M13 = -0.262f, |
|
||||
M21 = -0.022f, |
|
||||
M22 = 1.578f, |
|
||||
M23 = -0.022f, |
|
||||
M31 = .216f, |
|
||||
M32 = -.16f, |
|
||||
M33 = 1.5831f, |
|
||||
M41 = 0.02f, |
|
||||
M42 = -0.05f, |
|
||||
M43 = -0.05f |
|
||||
}; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
protected override void AfterApply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle) |
|
||||
{ |
|
||||
TColor packedV = default(TColor); |
|
||||
packedV.PackFromVector4(new Color(102, 34, 0).ToVector4()); // Very dark orange [Brown tone]
|
|
||||
new VignetteProcessor<TColor, TPacked> { VignetteColor = packedV }.Apply(source, sourceRectangle); |
|
||||
|
|
||||
TColor packedG = default(TColor); |
|
||||
packedG.PackFromVector4(new Color(255, 153, 102, 178).ToVector4()); // Light orange
|
|
||||
new GlowProcessor<TColor, TPacked> { GlowColor = packedG, Radius = source.Width / 4F }.Apply(source, sourceRectangle); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,62 +0,0 @@ |
|||||
// <copyright file="SaturationProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// An <see cref="ImageProcessor{TColor, TPacked}"/> to change the saturation of an <see cref="Image{TColor, TPacked}"/>.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class SaturationProcessor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="SaturationProcessor{TColor, TPacked}"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="saturation">The new saturation of the image. Must be between -100 and 100.</param>
|
|
||||
/// <exception cref="System.ArgumentException">
|
|
||||
/// <paramref name="saturation"/> is less than -100 or is greater than 100.
|
|
||||
/// </exception>
|
|
||||
public SaturationProcessor(int saturation) |
|
||||
{ |
|
||||
Guard.MustBeBetweenOrEqualTo(saturation, -100, 100, nameof(saturation)); |
|
||||
float saturationFactor = saturation / 100f; |
|
||||
|
|
||||
// Stop at -1 to prevent inversion.
|
|
||||
saturationFactor++; |
|
||||
|
|
||||
// The matrix is set up to "shear" the colour space using the following set of values.
|
|
||||
// Note that each colour component has an effective luminance which contributes to the
|
|
||||
// overall brightness of the pixel.
|
|
||||
// See http://graficaobscura.com/matrix/index.html
|
|
||||
float saturationComplement = 1.0f - saturationFactor; |
|
||||
float saturationComplementR = 0.3086f * saturationComplement; |
|
||||
float saturationComplementG = 0.6094f * saturationComplement; |
|
||||
float saturationComplementB = 0.0820f * saturationComplement; |
|
||||
|
|
||||
Matrix4x4 matrix4X4 = new Matrix4x4() |
|
||||
{ |
|
||||
M11 = saturationComplementR + saturationFactor, |
|
||||
M12 = saturationComplementR, |
|
||||
M13 = saturationComplementR, |
|
||||
M21 = saturationComplementG, |
|
||||
M22 = saturationComplementG + saturationFactor, |
|
||||
M23 = saturationComplementG, |
|
||||
M31 = saturationComplementB, |
|
||||
M32 = saturationComplementB, |
|
||||
M33 = saturationComplementB + saturationFactor, |
|
||||
}; |
|
||||
|
|
||||
this.Matrix = matrix4X4; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix { get; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,37 +0,0 @@ |
|||||
// <copyright file="SepiaProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System.Numerics; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the colors of the image to their sepia equivalent.
|
|
||||
/// The formula used matches the svg specification. <see href="http://www.w3.org/TR/filter-effects/#sepiaEquivalent"/>
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class SepiaProcessor<TColor, TPacked> : ColorMatrixFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public override Matrix4x4 Matrix => new Matrix4x4() |
|
||||
{ |
|
||||
M11 = .393f, |
|
||||
M12 = .349f, |
|
||||
M13 = .272f, |
|
||||
M21 = .769f, |
|
||||
M22 = .686f, |
|
||||
M23 = .534f, |
|
||||
M31 = .189f, |
|
||||
M32 = .168f, |
|
||||
M33 = .131f |
|
||||
}; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public override bool Compand => false; |
|
||||
} |
|
||||
} |
|
||||
@ -1,90 +0,0 @@ |
|||||
// <copyright file="ContrastProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Numerics; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// An <see cref="IImageFilter{TColor,TPacked}"/> to change the contrast of an <see cref="Image{TColor, TPacked}"/>.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>long, float.</example></typeparam>
|
|
||||
public class ContrastProcessor<TColor, TPacked> : ImageFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="ContrastProcessor{TColor, TPacked}"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="contrast">The new contrast of the image. Must be between -100 and 100.</param>
|
|
||||
/// <exception cref="System.ArgumentException">
|
|
||||
/// <paramref name="contrast"/> is less than -100 or is greater than 100.
|
|
||||
/// </exception>
|
|
||||
public ContrastProcessor(int contrast) |
|
||||
{ |
|
||||
Guard.MustBeBetweenOrEqualTo(contrast, -100, 100, nameof(contrast)); |
|
||||
this.Value = contrast; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the contrast value.
|
|
||||
/// </summary>
|
|
||||
public int Value { get; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
protected override void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY) |
|
||||
{ |
|
||||
float contrast = (100F + this.Value) / 100F; |
|
||||
int startX = sourceRectangle.X; |
|
||||
int endX = sourceRectangle.Right; |
|
||||
Vector4 contrastVector = new Vector4(contrast, contrast, contrast, 1); |
|
||||
Vector4 shiftVector = new Vector4(.5F, .5F, .5F, 1); |
|
||||
|
|
||||
// Align start/end positions.
|
|
||||
int minX = Math.Max(0, startX); |
|
||||
int maxX = Math.Min(source.Width, endX); |
|
||||
int minY = Math.Max(0, startY); |
|
||||
int maxY = Math.Min(source.Height, endY); |
|
||||
|
|
||||
// Reset offset if necessary.
|
|
||||
if (minX > 0) |
|
||||
{ |
|
||||
startX = 0; |
|
||||
} |
|
||||
|
|
||||
if (minY > 0) |
|
||||
{ |
|
||||
startY = 0; |
|
||||
} |
|
||||
|
|
||||
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock()) |
|
||||
{ |
|
||||
Parallel.For( |
|
||||
minY, |
|
||||
maxY, |
|
||||
this.ParallelOptions, |
|
||||
y => |
|
||||
{ |
|
||||
int offsetY = y - startY; |
|
||||
for (int x = minX; x < maxX; x++) |
|
||||
{ |
|
||||
int offsetX = x - startX; |
|
||||
|
|
||||
Vector4 vector = sourcePixels[offsetX, offsetY].ToVector4().Expand(); |
|
||||
vector -= shiftVector; |
|
||||
vector *= contrastVector; |
|
||||
vector += shiftVector; |
|
||||
TColor packed = default(TColor); |
|
||||
packed.PackFromVector4(vector.Compress()); |
|
||||
sourcePixels[offsetX, offsetY] = packed; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,94 +0,0 @@ |
|||||
// <copyright file="GlowProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Numerics; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// An <see cref="IImageFilter{TColor,TPacked}"/> that applies a radial glow effect an <see cref="Image{TColor, TPacked}"/>.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class GlowProcessor<TColor, TPacked> : ImageFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="GlowProcessor{T,TP}"/> class.
|
|
||||
/// </summary>
|
|
||||
public GlowProcessor() |
|
||||
{ |
|
||||
TColor color = default(TColor); |
|
||||
color.PackFromVector4(Color.Black.ToVector4()); |
|
||||
this.GlowColor = color; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the glow color to apply.
|
|
||||
/// </summary>
|
|
||||
public TColor GlowColor { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the the radius.
|
|
||||
/// </summary>
|
|
||||
public float Radius { get; set; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
protected override void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY) |
|
||||
{ |
|
||||
int startX = sourceRectangle.X; |
|
||||
int endX = sourceRectangle.Right; |
|
||||
TColor glowColor = this.GlowColor; |
|
||||
Vector2 centre = Rectangle.Center(sourceRectangle).ToVector2(); |
|
||||
float maxDistance = this.Radius > 0 ? Math.Min(this.Radius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F; |
|
||||
Ellipse ellipse = new Ellipse(new Point(centre), maxDistance, maxDistance); |
|
||||
|
|
||||
// Align start/end positions.
|
|
||||
int minX = Math.Max(0, startX); |
|
||||
int maxX = Math.Min(source.Width, endX); |
|
||||
int minY = Math.Max(0, startY); |
|
||||
int maxY = Math.Min(source.Height, endY); |
|
||||
|
|
||||
// Reset offset if necessary.
|
|
||||
if (minX > 0) |
|
||||
{ |
|
||||
startX = 0; |
|
||||
} |
|
||||
|
|
||||
if (minY > 0) |
|
||||
{ |
|
||||
startY = 0; |
|
||||
} |
|
||||
|
|
||||
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock()) |
|
||||
{ |
|
||||
Parallel.For( |
|
||||
minY, |
|
||||
maxY, |
|
||||
this.ParallelOptions, |
|
||||
y => |
|
||||
{ |
|
||||
int offsetY = y - startY; |
|
||||
for (int x = minX; x < maxX; x++) |
|
||||
{ |
|
||||
int offsetX = x - startX; |
|
||||
if (ellipse.Contains(offsetX, offsetY)) |
|
||||
{ |
|
||||
// TODO: Premultiply?
|
|
||||
float distance = Vector2.Distance(centre, new Vector2(offsetX, offsetY)); |
|
||||
Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4(); |
|
||||
TColor packed = default(TColor); |
|
||||
packed.PackFromVector4(Vector4.Lerp(glowColor.ToVector4(), sourceColor, distance / maxDistance)); |
|
||||
sourcePixels[offsetX, offsetY] = packed; |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,36 +0,0 @@ |
|||||
// <copyright file="IImageFilter.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Encapsulates methods to alter the pixels of an image. The processor operates on the original source pixels.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public interface IImageFilter<TColor, TPacked> : IImageProcessor |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Applies the process to the specified portion of the specified <see cref="ImageBase{T, TP}"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="source">The source image. Cannot be null.</param>
|
|
||||
/// <param name="sourceRectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
|
|
||||
/// </param>
|
|
||||
/// <remarks>
|
|
||||
/// The method keeps the source image unchanged and returns the
|
|
||||
/// the result of image processing filter as new image.
|
|
||||
/// </remarks>
|
|
||||
/// <exception cref="System.ArgumentNullException">
|
|
||||
/// <paramref name="source"/> is null.
|
|
||||
/// </exception>
|
|
||||
/// <exception cref="System.ArgumentException">
|
|
||||
/// <paramref name="sourceRectangle"/> doesnt fit the dimension of the image.
|
|
||||
/// </exception>
|
|
||||
void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle); |
|
||||
} |
|
||||
} |
|
||||
@ -1,70 +0,0 @@ |
|||||
// <copyright file="ImageFilter.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Encapsulates methods to alter the pixels of an image. The processor operates on the original source pixels.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public abstract class ImageFilter<TColor, TPacked> : ImageProcessor<TColor, TPacked>, IImageFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
this.OnApply(source, sourceRectangle); |
|
||||
|
|
||||
this.Apply(source, sourceRectangle, sourceRectangle.Y, sourceRectangle.Bottom); |
|
||||
|
|
||||
this.AfterApply(source, sourceRectangle); |
|
||||
} |
|
||||
catch (Exception ex) |
|
||||
{ |
|
||||
throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. See the inner exception for more detail.", ex); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Applies the process to the specified portion of the specified <see cref="ImageBase{TColor, TPacked}"/> at the specified location
|
|
||||
/// and with the specified size.
|
|
||||
/// </summary>
|
|
||||
/// <param name="source">The source image. Cannot be null.</param>
|
|
||||
/// <param name="sourceRectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
|
|
||||
/// </param>
|
|
||||
/// <param name="startY">The index of the row within the source image to start processing.</param>
|
|
||||
/// <param name="endY">The index of the row within the source image to end processing.</param>
|
|
||||
protected abstract void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// This method is called before the process is applied to prepare the processor.
|
|
||||
/// </summary>
|
|
||||
/// <param name="source">The source image. Cannot be null.</param>
|
|
||||
/// <param name="sourceRectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
|
|
||||
/// </param>
|
|
||||
protected virtual void OnApply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// This method is called after the process is applied to prepare the processor.
|
|
||||
/// </summary>
|
|
||||
/// <param name="source">The source image. Cannot be null.</param>
|
|
||||
/// <param name="sourceRectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
|
|
||||
/// </param>
|
|
||||
protected virtual void AfterApply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle) |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,68 +0,0 @@ |
|||||
// <copyright file="InvertProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Numerics; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// An <see cref="IImageFilter{TColor,TPacked}"/> to invert the colors of an <see cref="Image{TColor, TPacked}"/>.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class InvertProcessor<TColor, TPacked> : ImageFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
protected override void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY) |
|
||||
{ |
|
||||
int startX = sourceRectangle.X; |
|
||||
int endX = sourceRectangle.Right; |
|
||||
Vector3 inverseVector = Vector3.One; |
|
||||
|
|
||||
// Align start/end positions.
|
|
||||
int minX = Math.Max(0, startX); |
|
||||
int maxX = Math.Min(source.Width, endX); |
|
||||
int minY = Math.Max(0, startY); |
|
||||
int maxY = Math.Min(source.Height, endY); |
|
||||
|
|
||||
// Reset offset if necessary.
|
|
||||
if (minX > 0) |
|
||||
{ |
|
||||
startX = 0; |
|
||||
} |
|
||||
|
|
||||
if (minY > 0) |
|
||||
{ |
|
||||
startY = 0; |
|
||||
} |
|
||||
|
|
||||
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock()) |
|
||||
{ |
|
||||
Parallel.For( |
|
||||
minY, |
|
||||
maxY, |
|
||||
this.ParallelOptions, |
|
||||
y => |
|
||||
{ |
|
||||
int offsetY = y - startY; |
|
||||
for (int x = minX; x < maxX; x++) |
|
||||
{ |
|
||||
int offsetX = x - startX; |
|
||||
Vector4 color = sourcePixels[offsetX, offsetY].ToVector4(); |
|
||||
Vector3 vector = inverseVector - new Vector3(color.X, color.Y, color.Z); |
|
||||
|
|
||||
TColor packed = default(TColor); |
|
||||
packed.PackFromVector4(new Vector4(vector, color.W)); |
|
||||
sourcePixels[offsetX, offsetY] = packed; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,96 +0,0 @@ |
|||||
// <copyright file="VignetteProcessor.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Processors |
|
||||
{ |
|
||||
using System; |
|
||||
using System.Numerics; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// An <see cref="IImageFilter{TColor,TPacked}"/> that applies a radial vignette effect to an <see cref="Image{TColor, TPacked}"/>.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
public class VignetteProcessor<TColor, TPacked> : ImageFilter<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="VignetteProcessor{TColor, TPacked}"/> class.
|
|
||||
/// </summary>
|
|
||||
public VignetteProcessor() |
|
||||
{ |
|
||||
TColor color = default(TColor); |
|
||||
color.PackFromVector4(Color.Black.ToVector4()); |
|
||||
this.VignetteColor = color; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the vignette color to apply.
|
|
||||
/// </summary>
|
|
||||
public TColor VignetteColor { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the the x-radius.
|
|
||||
/// </summary>
|
|
||||
public float RadiusX { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the the y-radius.
|
|
||||
/// </summary>
|
|
||||
public float RadiusY { get; set; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
protected override void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY) |
|
||||
{ |
|
||||
int startX = sourceRectangle.X; |
|
||||
int endX = sourceRectangle.Right; |
|
||||
TColor vignetteColor = this.VignetteColor; |
|
||||
Vector2 centre = Rectangle.Center(sourceRectangle).ToVector2(); |
|
||||
float rX = this.RadiusX > 0 ? Math.Min(this.RadiusX, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F; |
|
||||
float rY = this.RadiusY > 0 ? Math.Min(this.RadiusY, sourceRectangle.Height * .5F) : sourceRectangle.Height * .5F; |
|
||||
float maxDistance = (float)Math.Sqrt((rX * rX) + (rY * rY)); |
|
||||
|
|
||||
// Align start/end positions.
|
|
||||
int minX = Math.Max(0, startX); |
|
||||
int maxX = Math.Min(source.Width, endX); |
|
||||
int minY = Math.Max(0, startY); |
|
||||
int maxY = Math.Min(source.Height, endY); |
|
||||
|
|
||||
// Reset offset if necessary.
|
|
||||
if (minX > 0) |
|
||||
{ |
|
||||
startX = 0; |
|
||||
} |
|
||||
|
|
||||
if (minY > 0) |
|
||||
{ |
|
||||
startY = 0; |
|
||||
} |
|
||||
|
|
||||
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock()) |
|
||||
{ |
|
||||
Parallel.For( |
|
||||
minY, |
|
||||
maxY, |
|
||||
this.ParallelOptions, |
|
||||
y => |
|
||||
{ |
|
||||
int offsetY = y - startY; |
|
||||
for (int x = minX; x < maxX; x++) |
|
||||
{ |
|
||||
int offsetX = x - startX; |
|
||||
float distance = Vector2.Distance(centre, new Vector2(offsetX, offsetY)); |
|
||||
Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4(); |
|
||||
TColor packed = default(TColor); |
|
||||
packed.PackFromVector4(Vector4.Lerp(vignetteColor.ToVector4(), sourceColor, 1 - (.9F * (distance / maxDistance)))); |
|
||||
sourcePixels[offsetX, offsetY] = packed; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,48 +0,0 @@ |
|||||
// <copyright file="Saturation.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Alters the saturation component of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="amount">The new saturation of the image. Must be between -100 and 100.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Saturation<TColor, TPacked>(this Image<TColor, TPacked> source, int amount) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Saturation(source, amount, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Alters the saturation component of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="amount">The new saturation of the image. Must be between -100 and 100.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Saturation<TColor, TPacked>(this Image<TColor, TPacked> source, int amount, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return source.Process(rectangle, new SaturationProcessor<TColor, TPacked>(amount)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,46 +0,0 @@ |
|||||
// <copyright file="Sepia.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Applies sepia toning to the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <returns>The <see cref="Image"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Sepia<TColor, TPacked>(this Image<TColor, TPacked> source) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Sepia(source, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Applies sepia toning to the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Sepia<TColor, TPacked>(this Image<TColor, TPacked> source, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return source.Process(rectangle, new SepiaProcessor<TColor, TPacked>()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,104 +0,0 @@ |
|||||
// <copyright file="Vignette.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp |
|
||||
{ |
|
||||
using Processors; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Applies a radial vignette effect to an image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Vignette<TColor, TPacked>(this Image<TColor, TPacked> source) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Vignette(source, default(TColor), source.Bounds.Width * .5F, source.Bounds.Height * .5F, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Applies a radial vignette effect to an image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="color">The color to set as the vignette.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Vignette<TColor, TPacked>(this Image<TColor, TPacked> source, TColor color) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Vignette(source, color, source.Bounds.Width * .5F, source.Bounds.Height * .5F, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Applies a radial vignette effect to an image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="radiusX">The the x-radius.</param>
|
|
||||
/// <param name="radiusY">The the y-radius.</param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Vignette<TColor, TPacked>(this Image<TColor, TPacked> source, float radiusX, float radiusY) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Vignette(source, default(TColor), radiusX, radiusY, source.Bounds); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Applies a radial vignette effect to an image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Vignette<TColor, TPacked>(this Image<TColor, TPacked> source, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
return Vignette(source, default(TColor), 0, 0, rectangle); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Applies a radial vignette effect to an image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="source">The image this method extends.</param>
|
|
||||
/// <param name="color">The color to set as the vignette.</param>
|
|
||||
/// <param name="radiusX">The the x-radius.</param>
|
|
||||
/// <param name="radiusY">The the y-radius.</param>
|
|
||||
/// <param name="rectangle">
|
|
||||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|
||||
/// </param>
|
|
||||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|
||||
public static Image<TColor, TPacked> Vignette<TColor, TPacked>(this Image<TColor, TPacked> source, TColor color, float radiusX, float radiusY, Rectangle rectangle) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
VignetteProcessor<TColor, TPacked> processor = new VignetteProcessor<TColor, TPacked> { RadiusX = radiusX, RadiusY = radiusY }; |
|
||||
|
|
||||
if (!color.Equals(default(TColor))) |
|
||||
{ |
|
||||
processor.VignetteColor = color; |
|
||||
} |
|
||||
|
|
||||
return source.Process(rectangle, processor); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,23 +0,0 @@ |
|||||
// <copyright file="BmpBitsPerPixel.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Enumerates the available bits per pixel for bitmap.
|
|
||||
/// </summary>
|
|
||||
public enum BmpBitsPerPixel |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 24 bits per pixel. Each pixel consists of 3 bytes.
|
|
||||
/// </summary>
|
|
||||
Pixel24 = 3, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// 32 bits per pixel. Each pixel consists of 4 bytes.
|
|
||||
/// </summary>
|
|
||||
Pixel32 = 4, |
|
||||
} |
|
||||
} |
|
||||
@ -1,63 +0,0 @@ |
|||||
// <copyright file="BmpCompression.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Defines how the compression type of the image data
|
|
||||
/// in the bitmap file.
|
|
||||
/// </summary>
|
|
||||
internal enum BmpCompression |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Each image row has a multiple of four elements. If the
|
|
||||
/// row has less elements, zeros will be added at the right side.
|
|
||||
/// The format depends on the number of bits, stored in the info header.
|
|
||||
/// If the number of bits are one, four or eight each pixel data is
|
|
||||
/// a index to the palette. If the number of bits are sixteen,
|
|
||||
/// twenty-four or thirty-two each pixel contains a color.
|
|
||||
/// </summary>
|
|
||||
RGB = 0, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Two bytes are one data record. If the first byte is not zero, the
|
|
||||
/// next two half bytes will be repeated as much as the value of the first byte.
|
|
||||
/// If the first byte is zero, the record has different meanings, depending
|
|
||||
/// on the second byte. If the second byte is zero, it is the end of the row,
|
|
||||
/// if it is one, it is the end of the image.
|
|
||||
/// Not supported at the moment.
|
|
||||
/// </summary>
|
|
||||
RLE8 = 1, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Two bytes are one data record. If the first byte is not zero, the
|
|
||||
/// next byte will be repeated as much as the value of the first byte.
|
|
||||
/// If the first byte is zero, the record has different meanings, depending
|
|
||||
/// on the second byte. If the second byte is zero, it is the end of the row,
|
|
||||
/// if it is one, it is the end of the image.
|
|
||||
/// Not supported at the moment.
|
|
||||
/// </summary>
|
|
||||
RLE4 = 2, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Each image row has a multiple of four elements. If the
|
|
||||
/// row has less elements, zeros will be added at the right side.
|
|
||||
/// Not supported at the moment.
|
|
||||
/// </summary>
|
|
||||
BitFields = 3, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The bitmap contains a JPG image.
|
|
||||
/// Not supported at the moment.
|
|
||||
/// </summary>
|
|
||||
JPEG = 4, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The bitmap contains a PNG image.
|
|
||||
/// Not supported at the moment.
|
|
||||
/// </summary>
|
|
||||
PNG = 5 |
|
||||
} |
|
||||
} |
|
||||
@ -1,83 +0,0 @@ |
|||||
// <copyright file="BmpDecoder.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
using System; |
|
||||
using System.IO; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Image decoder for generating an image out of a Windows bitmap stream.
|
|
||||
/// </summary>
|
|
||||
/// <remarks>
|
|
||||
/// Does not support the following formats at the moment:
|
|
||||
/// <list type="bullet">
|
|
||||
/// <item>JPG</item>
|
|
||||
/// <item>PNG</item>
|
|
||||
/// <item>RLE4</item>
|
|
||||
/// <item>RLE8</item>
|
|
||||
/// <item>BitFields</item>
|
|
||||
/// </list>
|
|
||||
/// Formats will be supported in a later releases. We advise always
|
|
||||
/// to use only 24 Bit Windows bitmaps.
|
|
||||
/// </remarks>
|
|
||||
public class BmpDecoder : IImageDecoder |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets the size of the header for this image type.
|
|
||||
/// </summary>
|
|
||||
/// <value>The size of the header.</value>
|
|
||||
public int HeaderSize => 2; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns a value indicating whether the <see cref="IImageDecoder"/> supports the specified
|
|
||||
/// file header.
|
|
||||
/// </summary>
|
|
||||
/// <param name="extension">The <see cref="string"/> containing the file extension.</param>
|
|
||||
/// <returns>
|
|
||||
/// True if the decoder supports the file extension; otherwise, false.
|
|
||||
/// </returns>
|
|
||||
public bool IsSupportedFileExtension(string extension) |
|
||||
{ |
|
||||
Guard.NotNullOrEmpty(extension, "extension"); |
|
||||
|
|
||||
extension = extension.StartsWith(".") ? extension.Substring(1) : extension; |
|
||||
|
|
||||
return extension.Equals("BMP", StringComparison.OrdinalIgnoreCase) |
|
||||
|| extension.Equals("DIP", StringComparison.OrdinalIgnoreCase); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns a value indicating whether the <see cref="IImageDecoder"/> supports the specified
|
|
||||
/// file header.
|
|
||||
/// </summary>
|
|
||||
/// <param name="header">The <see cref="T:byte[]"/> containing the file header.</param>
|
|
||||
/// <returns>
|
|
||||
/// True if the decoder supports the file header; otherwise, false.
|
|
||||
/// </returns>
|
|
||||
public bool IsSupportedFileFormat(byte[] header) |
|
||||
{ |
|
||||
bool isBmp = false; |
|
||||
if (header.Length >= 2) |
|
||||
{ |
|
||||
isBmp = header[0] == 0x42 && // B
|
|
||||
header[1] == 0x4D; // M
|
|
||||
} |
|
||||
|
|
||||
return isBmp; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public void Decode<TColor, TPacked>(Image<TColor, TPacked> image, Stream stream) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
Guard.NotNull(image, "image"); |
|
||||
Guard.NotNull(stream, "stream"); |
|
||||
|
|
||||
new BmpDecoderCore().Decode(image, stream); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,404 +0,0 @@ |
|||||
// <copyright file="BmpDecoderCore.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
using System; |
|
||||
using System.IO; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Performs the bmp decoding operation.
|
|
||||
/// </summary>
|
|
||||
internal sealed class BmpDecoderCore |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The mask for the red part of the color for 16 bit rgb bitmaps.
|
|
||||
/// </summary>
|
|
||||
private const int Rgb16RMask = 0x00007C00; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The mask for the green part of the color for 16 bit rgb bitmaps.
|
|
||||
/// </summary>
|
|
||||
private const int Rgb16GMask = 0x000003E0; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The mask for the blue part of the color for 16 bit rgb bitmaps.
|
|
||||
/// </summary>
|
|
||||
private const int Rgb16BMask = 0x0000001F; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The stream to decode from.
|
|
||||
/// </summary>
|
|
||||
private Stream currentStream; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The file header containing general information.
|
|
||||
/// TODO: Why is this not used? We advance the stream but do not use the values parsed.
|
|
||||
/// </summary>
|
|
||||
private BmpFileHeader fileHeader; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The info header containing detailed information about the bitmap.
|
|
||||
/// </summary>
|
|
||||
private BmpInfoHeader infoHeader; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Decodes the image from the specified this._stream and sets
|
|
||||
/// the data to image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="image">The image, where the data should be set to.
|
|
||||
/// Cannot be null (Nothing in Visual Basic).</param>
|
|
||||
/// <param name="stream">The stream, where the image should be
|
|
||||
/// decoded from. Cannot be null (Nothing in Visual Basic).</param>
|
|
||||
/// <exception cref="System.ArgumentNullException">
|
|
||||
/// <para><paramref name="image"/> is null.</para>
|
|
||||
/// <para>- or -</para>
|
|
||||
/// <para><paramref name="stream"/> is null.</para>
|
|
||||
/// </exception>
|
|
||||
public void Decode<TColor, TPacked>(Image<TColor, TPacked> image, Stream stream) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
this.currentStream = stream; |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
this.ReadFileHeader(); |
|
||||
this.ReadInfoHeader(); |
|
||||
|
|
||||
// see http://www.drdobbs.com/architecture-and-design/the-bmp-file-format-part-1/184409517
|
|
||||
// If the height is negative, then this is a Windows bitmap whose origin
|
|
||||
// is the upper-left corner and not the lower-left.The inverted flag
|
|
||||
// indicates a lower-left origin.Our code will be outputting an
|
|
||||
// upper-left origin pixel array.
|
|
||||
bool inverted = false; |
|
||||
if (this.infoHeader.Height < 0) |
|
||||
{ |
|
||||
inverted = true; |
|
||||
this.infoHeader.Height = -this.infoHeader.Height; |
|
||||
} |
|
||||
|
|
||||
int colorMapSize = -1; |
|
||||
|
|
||||
if (this.infoHeader.ClrUsed == 0) |
|
||||
{ |
|
||||
if (this.infoHeader.BitsPerPixel == 1 || |
|
||||
this.infoHeader.BitsPerPixel == 4 || |
|
||||
this.infoHeader.BitsPerPixel == 8) |
|
||||
{ |
|
||||
colorMapSize = (int)Math.Pow(2, this.infoHeader.BitsPerPixel) * 4; |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
colorMapSize = this.infoHeader.ClrUsed * 4; |
|
||||
} |
|
||||
|
|
||||
byte[] palette = null; |
|
||||
|
|
||||
if (colorMapSize > 0) |
|
||||
{ |
|
||||
// 256 * 4
|
|
||||
if (colorMapSize > 1024) |
|
||||
{ |
|
||||
throw new ImageFormatException($"Invalid bmp colormap size '{colorMapSize}'"); |
|
||||
} |
|
||||
|
|
||||
palette = new byte[colorMapSize]; |
|
||||
|
|
||||
this.currentStream.Read(palette, 0, colorMapSize); |
|
||||
} |
|
||||
|
|
||||
if (this.infoHeader.Width > image.MaxWidth || this.infoHeader.Height > image.MaxHeight) |
|
||||
{ |
|
||||
throw new ArgumentOutOfRangeException( |
|
||||
$"The input bitmap '{this.infoHeader.Width}x{this.infoHeader.Height}' is " |
|
||||
+ $"bigger then the max allowed size '{image.MaxWidth}x{image.MaxHeight}'"); |
|
||||
} |
|
||||
|
|
||||
image.InitPixels(this.infoHeader.Width, this.infoHeader.Height); |
|
||||
|
|
||||
using (PixelAccessor<TColor, TPacked> pixels = image.Lock()) |
|
||||
{ |
|
||||
switch (this.infoHeader.Compression) |
|
||||
{ |
|
||||
case BmpCompression.RGB: |
|
||||
if (this.infoHeader.HeaderSize != 40) |
|
||||
{ |
|
||||
throw new ImageFormatException($"Header Size value '{this.infoHeader.HeaderSize}' is not valid."); |
|
||||
} |
|
||||
|
|
||||
if (this.infoHeader.BitsPerPixel == 32) |
|
||||
{ |
|
||||
this.ReadRgb32(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); |
|
||||
} |
|
||||
else if (this.infoHeader.BitsPerPixel == 24) |
|
||||
{ |
|
||||
this.ReadRgb24(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); |
|
||||
} |
|
||||
else if (this.infoHeader.BitsPerPixel == 16) |
|
||||
{ |
|
||||
this.ReadRgb16(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); |
|
||||
} |
|
||||
else if (this.infoHeader.BitsPerPixel <= 8) |
|
||||
{ |
|
||||
this.ReadRgbPalette(pixels, palette, this.infoHeader.Width, this.infoHeader.Height, this.infoHeader.BitsPerPixel, inverted); |
|
||||
} |
|
||||
|
|
||||
break; |
|
||||
default: |
|
||||
throw new NotSupportedException("Does not support this kind of bitmap files."); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
catch (IndexOutOfRangeException e) |
|
||||
{ |
|
||||
throw new ImageFormatException("Bitmap does not have a valid format.", e); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns the y- value based on the given height.
|
|
||||
/// </summary>
|
|
||||
/// <param name="y">The y- value representing the current row.</param>
|
|
||||
/// <param name="height">The height of the bitmap.</param>
|
|
||||
/// <param name="inverted">Whether the bitmap is inverted.</param>
|
|
||||
/// <returns>The <see cref="int"/> representing the inverted value.</returns>
|
|
||||
private static int Invert(int y, int height, bool inverted) |
|
||||
{ |
|
||||
int row; |
|
||||
|
|
||||
if (!inverted) |
|
||||
{ |
|
||||
row = height - y - 1; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
row = y; |
|
||||
} |
|
||||
|
|
||||
return row; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Calculates the amount of bytes to pad a row.
|
|
||||
/// </summary>
|
|
||||
/// <param name="width">The image width.</param>
|
|
||||
/// <param name="componentCount">The pixel component count.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="int"/>.
|
|
||||
/// </returns>
|
|
||||
private static int CalculatePadding(int width, int componentCount) |
|
||||
{ |
|
||||
int padding = (width * componentCount) % 4; |
|
||||
|
|
||||
if (padding != 0) |
|
||||
{ |
|
||||
padding = 4 - padding; |
|
||||
} |
|
||||
|
|
||||
return padding; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the color palette from the stream.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="pixels">The <see cref="PixelAccessor{TColor, TPacked}"/> to assign the palette to.</param>
|
|
||||
/// <param name="colors">The <see cref="T:byte[]"/> containing the colors.</param>
|
|
||||
/// <param name="width">The width of the bitmap.</param>
|
|
||||
/// <param name="height">The height of the bitmap.</param>
|
|
||||
/// <param name="bits">The number of bits per pixel.</param>
|
|
||||
/// <param name="inverted">Whether the bitmap is inverted.</param>
|
|
||||
private void ReadRgbPalette<TColor, TPacked>(PixelAccessor<TColor, TPacked> pixels, byte[] colors, int width, int height, int bits, bool inverted) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
// Pixels per byte (bits per pixel)
|
|
||||
int ppb = 8 / bits; |
|
||||
|
|
||||
int arrayWidth = (width + ppb - 1) / ppb; |
|
||||
|
|
||||
// Bit mask
|
|
||||
int mask = 0xFF >> (8 - bits); |
|
||||
|
|
||||
// Rows are aligned on 4 byte boundaries
|
|
||||
int padding = arrayWidth % 4; |
|
||||
if (padding != 0) |
|
||||
{ |
|
||||
padding = 4 - padding; |
|
||||
} |
|
||||
|
|
||||
byte[] row = new byte[arrayWidth + padding]; |
|
||||
TColor color = default(TColor); |
|
||||
|
|
||||
for (int y = 0; y < height; y++) |
|
||||
{ |
|
||||
int newY = Invert(y, height, inverted); |
|
||||
|
|
||||
this.currentStream.Read(row, 0, row.Length); |
|
||||
|
|
||||
int offset = 0; |
|
||||
for (int x = 0; x < arrayWidth; x++) |
|
||||
{ |
|
||||
int colOffset = x * ppb; |
|
||||
|
|
||||
for (int shift = 0; shift < ppb && (x + shift) < width; shift++) |
|
||||
{ |
|
||||
int colorIndex = ((row[offset] >> (8 - bits - (shift * bits))) & mask) * 4; |
|
||||
int newX = colOffset + shift; |
|
||||
|
|
||||
// Stored in b-> g-> r order.
|
|
||||
color.PackFromBytes(colors[colorIndex + 2], colors[colorIndex + 1], colors[colorIndex], 255); |
|
||||
pixels[newX, newY] = color; |
|
||||
} |
|
||||
|
|
||||
offset++; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the 16 bit color palette from the stream
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="pixels">The <see cref="PixelAccessor{TColor, TPacked}"/> to assign the palette to.</param>
|
|
||||
/// <param name="width">The width of the bitmap.</param>
|
|
||||
/// <param name="height">The height of the bitmap.</param>
|
|
||||
/// <param name="inverted">Whether the bitmap is inverted.</param>
|
|
||||
private void ReadRgb16<TColor, TPacked>(PixelAccessor<TColor, TPacked> pixels, int width, int height, bool inverted) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
// We divide here as we will store the colors in our floating point format.
|
|
||||
const int ScaleR = 8; // 256/32
|
|
||||
const int ScaleG = 4; // 256/64
|
|
||||
const int ComponentCount = 2; |
|
||||
|
|
||||
TColor color = default(TColor); |
|
||||
using (PixelRow<TColor, TPacked> row = new PixelRow<TColor, TPacked>(width, ComponentOrder.XYZ)) |
|
||||
{ |
|
||||
for (int y = 0; y < height; y++) |
|
||||
{ |
|
||||
row.Read(this.currentStream); |
|
||||
|
|
||||
int newY = Invert(y, height, inverted); |
|
||||
|
|
||||
int offset = 0; |
|
||||
for (int x = 0; x < width; x++) |
|
||||
{ |
|
||||
short temp = BitConverter.ToInt16(row.Bytes, offset); |
|
||||
|
|
||||
byte r = (byte)(((temp & Rgb16RMask) >> 11) * ScaleR); |
|
||||
byte g = (byte)(((temp & Rgb16GMask) >> 5) * ScaleG); |
|
||||
byte b = (byte)((temp & Rgb16BMask) * ScaleR); |
|
||||
|
|
||||
color.PackFromBytes(r, g, b, 255); |
|
||||
pixels[x, newY] = color; |
|
||||
offset += ComponentCount; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the 24 bit color palette from the stream
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="pixels">The <see cref="PixelAccessor{TColor, TPacked}"/> to assign the palette to.</param>
|
|
||||
/// <param name="width">The width of the bitmap.</param>
|
|
||||
/// <param name="height">The height of the bitmap.</param>
|
|
||||
/// <param name="inverted">Whether the bitmap is inverted.</param>
|
|
||||
private void ReadRgb24<TColor, TPacked>(PixelAccessor<TColor, TPacked> pixels, int width, int height, bool inverted) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
int padding = CalculatePadding(width, 3); |
|
||||
using (PixelRow<TColor, TPacked> row = new PixelRow<TColor, TPacked>(width, ComponentOrder.ZYX, padding)) |
|
||||
{ |
|
||||
for (int y = 0; y < height; y++) |
|
||||
{ |
|
||||
row.Read(this.currentStream); |
|
||||
|
|
||||
int newY = Invert(y, height, inverted); |
|
||||
pixels.CopyFrom(row, newY); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the 32 bit color palette from the stream
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="pixels">The <see cref="PixelAccessor{TColor, TPacked}"/> to assign the palette to.</param>
|
|
||||
/// <param name="width">The width of the bitmap.</param>
|
|
||||
/// <param name="height">The height of the bitmap.</param>
|
|
||||
/// <param name="inverted">Whether the bitmap is inverted.</param>
|
|
||||
private void ReadRgb32<TColor, TPacked>(PixelAccessor<TColor, TPacked> pixels, int width, int height, bool inverted) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
int padding = CalculatePadding(width, 4); |
|
||||
using (PixelRow<TColor, TPacked> row = new PixelRow<TColor, TPacked>(width, ComponentOrder.ZYXW, padding)) |
|
||||
{ |
|
||||
for (int y = 0; y < height; y++) |
|
||||
{ |
|
||||
row.Read(this.currentStream); |
|
||||
|
|
||||
int newY = Invert(y, height, inverted); |
|
||||
pixels.CopyFrom(row, newY); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the <see cref="BmpInfoHeader"/> from the stream.
|
|
||||
/// </summary>
|
|
||||
private void ReadInfoHeader() |
|
||||
{ |
|
||||
byte[] data = new byte[BmpInfoHeader.Size]; |
|
||||
|
|
||||
this.currentStream.Read(data, 0, BmpInfoHeader.Size); |
|
||||
|
|
||||
this.infoHeader = new BmpInfoHeader |
|
||||
{ |
|
||||
HeaderSize = BitConverter.ToInt32(data, 0), |
|
||||
Width = BitConverter.ToInt32(data, 4), |
|
||||
Height = BitConverter.ToInt32(data, 8), |
|
||||
Planes = BitConverter.ToInt16(data, 12), |
|
||||
BitsPerPixel = BitConverter.ToInt16(data, 14), |
|
||||
ImageSize = BitConverter.ToInt32(data, 20), |
|
||||
XPelsPerMeter = BitConverter.ToInt32(data, 24), |
|
||||
YPelsPerMeter = BitConverter.ToInt32(data, 28), |
|
||||
ClrUsed = BitConverter.ToInt32(data, 32), |
|
||||
ClrImportant = BitConverter.ToInt32(data, 36), |
|
||||
Compression = (BmpCompression)BitConverter.ToInt32(data, 16) |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the <see cref="BmpFileHeader"/> from the stream.
|
|
||||
/// </summary>
|
|
||||
private void ReadFileHeader() |
|
||||
{ |
|
||||
byte[] data = new byte[BmpFileHeader.Size]; |
|
||||
|
|
||||
this.currentStream.Read(data, 0, BmpFileHeader.Size); |
|
||||
|
|
||||
this.fileHeader = new BmpFileHeader |
|
||||
{ |
|
||||
Type = BitConverter.ToInt16(data, 0), |
|
||||
FileSize = BitConverter.ToInt32(data, 2), |
|
||||
Reserved = BitConverter.ToInt32(data, 6), |
|
||||
Offset = BitConverter.ToInt32(data, 10) |
|
||||
}; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,54 +0,0 @@ |
|||||
// <copyright file="BmpEncoder.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
using System; |
|
||||
using System.IO; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Image encoder for writing an image to a stream as a Windows bitmap.
|
|
||||
/// </summary>
|
|
||||
/// <remarks>The encoder can currently only write 24-bit rgb images to streams.</remarks>
|
|
||||
public class BmpEncoder : IImageEncoder |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets or sets the quality of output for images.
|
|
||||
/// </summary>
|
|
||||
/// <remarks>Bitmap is a lossless format so this is not used in this encoder.</remarks>
|
|
||||
public int Quality { get; set; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public string MimeType => "image/bmp"; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public string Extension => "bmp"; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the number of bits per pixel.
|
|
||||
/// </summary>
|
|
||||
public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool IsSupportedFileExtension(string extension) |
|
||||
{ |
|
||||
Guard.NotNullOrEmpty(extension, nameof(extension)); |
|
||||
|
|
||||
extension = extension.StartsWith(".") ? extension.Substring(1) : extension; |
|
||||
|
|
||||
return extension.Equals(this.Extension, StringComparison.OrdinalIgnoreCase) |
|
||||
|| extension.Equals("dip", StringComparison.OrdinalIgnoreCase); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public void Encode<TColor, TPacked>(Image<TColor, TPacked> image, Stream stream) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
BmpEncoderCore encoder = new BmpEncoderCore(); |
|
||||
encoder.Encode(image, stream, this.BitsPerPixel); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,189 +0,0 @@ |
|||||
// <copyright file="BmpEncoderCore.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
using System.IO; |
|
||||
|
|
||||
using IO; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Image encoder for writing an image to a stream as a Windows bitmap.
|
|
||||
/// </summary>
|
|
||||
internal sealed class BmpEncoderCore |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The number of bits per pixel.
|
|
||||
/// </summary>
|
|
||||
private BmpBitsPerPixel bmpBitsPerPixel; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The amount to pad each row by.
|
|
||||
/// </summary>
|
|
||||
private int padding; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Encodes the image to the specified stream from the <see cref="ImageBase{TColor, TPacked}"/>.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>long, float.</example></typeparam>
|
|
||||
/// <param name="image">The <see cref="ImageBase{TColor, TPacked}"/> to encode from.</param>
|
|
||||
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
|
|
||||
/// <param name="bitsPerPixel">The <see cref="BmpBitsPerPixel"/></param>
|
|
||||
public void Encode<TColor, TPacked>(ImageBase<TColor, TPacked> image, Stream stream, BmpBitsPerPixel bitsPerPixel) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
Guard.NotNull(image, nameof(image)); |
|
||||
Guard.NotNull(stream, nameof(stream)); |
|
||||
|
|
||||
this.bmpBitsPerPixel = bitsPerPixel; |
|
||||
|
|
||||
// Cast to int will get the bytes per pixel
|
|
||||
short bpp = (short)(8 * (int)bitsPerPixel); |
|
||||
int bytesPerLine = 4 * (((image.Width * bpp) + 31) / 32); |
|
||||
this.padding = bytesPerLine - (image.Width * (int)bitsPerPixel); |
|
||||
|
|
||||
// Do not use IDisposable pattern here as we want to preserve the stream.
|
|
||||
EndianBinaryWriter writer = new EndianBinaryWriter(EndianBitConverter.Little, stream); |
|
||||
|
|
||||
BmpInfoHeader infoHeader = new BmpInfoHeader |
|
||||
{ |
|
||||
HeaderSize = BmpInfoHeader.Size, |
|
||||
Height = image.Height, |
|
||||
Width = image.Width, |
|
||||
BitsPerPixel = bpp, |
|
||||
Planes = 1, |
|
||||
ImageSize = image.Height * bytesPerLine, |
|
||||
ClrUsed = 0, |
|
||||
ClrImportant = 0 |
|
||||
}; |
|
||||
|
|
||||
BmpFileHeader fileHeader = new BmpFileHeader |
|
||||
{ |
|
||||
Type = 19778, // BM
|
|
||||
Offset = 54, |
|
||||
FileSize = 54 + infoHeader.ImageSize |
|
||||
}; |
|
||||
|
|
||||
WriteHeader(writer, fileHeader); |
|
||||
this.WriteInfo(writer, infoHeader); |
|
||||
this.WriteImage(writer, image); |
|
||||
|
|
||||
writer.Flush(); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Writes the bitmap header data to the binary stream.
|
|
||||
/// </summary>
|
|
||||
/// <param name="writer">
|
|
||||
/// The <see cref="EndianBinaryWriter"/> containing the stream to write to.
|
|
||||
/// </param>
|
|
||||
/// <param name="fileHeader">
|
|
||||
/// The <see cref="BmpFileHeader"/> containing the header data.
|
|
||||
/// </param>
|
|
||||
private static void WriteHeader(EndianBinaryWriter writer, BmpFileHeader fileHeader) |
|
||||
{ |
|
||||
writer.Write(fileHeader.Type); |
|
||||
writer.Write(fileHeader.FileSize); |
|
||||
writer.Write(fileHeader.Reserved); |
|
||||
writer.Write(fileHeader.Offset); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Writes the bitmap information to the binary stream.
|
|
||||
/// </summary>
|
|
||||
/// <param name="writer">
|
|
||||
/// The <see cref="EndianBinaryWriter"/> containing the stream to write to.
|
|
||||
/// </param>
|
|
||||
/// <param name="infoHeader">
|
|
||||
/// The <see cref="BmpFileHeader"/> containing the detailed information about the image.
|
|
||||
/// </param>
|
|
||||
private void WriteInfo(EndianBinaryWriter writer, BmpInfoHeader infoHeader) |
|
||||
{ |
|
||||
writer.Write(infoHeader.HeaderSize); |
|
||||
writer.Write(infoHeader.Width); |
|
||||
writer.Write(infoHeader.Height); |
|
||||
writer.Write(infoHeader.Planes); |
|
||||
writer.Write(infoHeader.BitsPerPixel); |
|
||||
writer.Write((int)infoHeader.Compression); |
|
||||
writer.Write(infoHeader.ImageSize); |
|
||||
writer.Write(infoHeader.XPelsPerMeter); |
|
||||
writer.Write(infoHeader.YPelsPerMeter); |
|
||||
writer.Write(infoHeader.ClrUsed); |
|
||||
writer.Write(infoHeader.ClrImportant); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Writes the pixel data to the binary stream.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
|
|
||||
/// <param name="image">
|
|
||||
/// The <see cref="ImageBase{TColor, TPacked}"/> containing pixel data.
|
|
||||
/// </param>
|
|
||||
private void WriteImage<TColor, TPacked>(EndianBinaryWriter writer, ImageBase<TColor, TPacked> image) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
using (PixelAccessor<TColor, TPacked> pixels = image.Lock()) |
|
||||
{ |
|
||||
switch (this.bmpBitsPerPixel) |
|
||||
{ |
|
||||
case BmpBitsPerPixel.Pixel32: |
|
||||
this.Write32Bit<TColor, TPacked>(writer, pixels); |
|
||||
break; |
|
||||
|
|
||||
case BmpBitsPerPixel.Pixel24: |
|
||||
this.Write24Bit<TColor, TPacked>(writer, pixels); |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Writes the 32bit color palette to the stream.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
|
|
||||
/// <param name="pixels">The <see cref="PixelAccessor{TColor,TPacked}"/> containing pixel data.</param>
|
|
||||
private void Write32Bit<TColor, TPacked>(EndianBinaryWriter writer, PixelAccessor<TColor, TPacked> pixels) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
using (PixelRow<TColor, TPacked> row = new PixelRow<TColor, TPacked>(pixels.Width, ComponentOrder.ZYXW, this.padding)) |
|
||||
{ |
|
||||
for (int y = pixels.Height - 1; y >= 0; y--) |
|
||||
{ |
|
||||
pixels.CopyTo(row, y); |
|
||||
writer.Write(row.Bytes); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Writes the 24bit color palette to the stream.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
|
|
||||
/// <param name="pixels">The <see cref="PixelAccessor{TColor,TPacked}"/> containing pixel data.</param>
|
|
||||
private void Write24Bit<TColor, TPacked>(EndianBinaryWriter writer, PixelAccessor<TColor, TPacked> pixels) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
using (PixelRow<TColor, TPacked> row = new PixelRow<TColor, TPacked>(pixels.Width, ComponentOrder.ZYX, this.padding)) |
|
||||
{ |
|
||||
for (int y = pixels.Height - 1; y >= 0; y--) |
|
||||
{ |
|
||||
pixels.CopyTo(row, y); |
|
||||
writer.Write(row.Bytes); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,49 +0,0 @@ |
|||||
// <copyright file="BmpFileHeader.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Stores general information about the Bitmap file.
|
|
||||
/// <see href="https://en.wikipedia.org/wiki/BMP_file_format" />
|
|
||||
/// </summary>
|
|
||||
/// <remarks>
|
|
||||
/// The first two bytes of the Bitmap file format
|
|
||||
/// (thus the Bitmap header) are stored in big-endian order.
|
|
||||
/// All of the other integer values are stored in little-endian format
|
|
||||
/// (i.e. least-significant byte first).
|
|
||||
/// </remarks>
|
|
||||
internal class BmpFileHeader |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Defines of the data structure in the bitmap file.
|
|
||||
/// </summary>
|
|
||||
public const int Size = 14; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the Bitmap identifier.
|
|
||||
/// The field used to identify the bitmap file: 0x42 0x4D
|
|
||||
/// (Hex code points for B and M)
|
|
||||
/// </summary>
|
|
||||
public short Type { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the size of the bitmap file in bytes.
|
|
||||
/// </summary>
|
|
||||
public int FileSize { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets any reserved data; actual value depends on the application
|
|
||||
/// that creates the image.
|
|
||||
/// </summary>
|
|
||||
public int Reserved { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the offset, i.e. starting address, of the byte where
|
|
||||
/// the bitmap data can be found.
|
|
||||
/// </summary>
|
|
||||
public int Offset { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,19 +0,0 @@ |
|||||
// <copyright file="BmpFormat.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Encapsulates the means to encode and decode bitmap images.
|
|
||||
/// </summary>
|
|
||||
public class BmpFormat : IImageFormat |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public IImageDecoder Decoder => new BmpDecoder(); |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public IImageEncoder Encoder => new BmpEncoder(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,82 +0,0 @@ |
|||||
// <copyright file="BmpInfoHeader.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// This block of bytes tells the application detailed information
|
|
||||
/// about the image, which will be used to display the image on
|
|
||||
/// the screen.
|
|
||||
/// <see href="https://en.wikipedia.org/wiki/BMP_file_format"/>
|
|
||||
/// </summary>
|
|
||||
internal class BmpInfoHeader |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Defines of the data structure in the bitmap file.
|
|
||||
/// </summary>
|
|
||||
public const int Size = 40; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the size of this header (40 bytes)
|
|
||||
/// </summary>
|
|
||||
public int HeaderSize { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the bitmap width in pixels (signed integer).
|
|
||||
/// </summary>
|
|
||||
public int Width { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the bitmap height in pixels (signed integer).
|
|
||||
/// </summary>
|
|
||||
public int Height { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the number of color planes being used. Must be set to 1.
|
|
||||
/// </summary>
|
|
||||
public short Planes { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the number of bits per pixel, which is the color depth of the image.
|
|
||||
/// Typical values are 1, 4, 8, 16, 24 and 32.
|
|
||||
/// </summary>
|
|
||||
public short BitsPerPixel { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the compression method being used.
|
|
||||
/// See the next table for a list of possible values.
|
|
||||
/// </summary>
|
|
||||
public BmpCompression Compression { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the image size. This is the size of the raw bitmap data (see below),
|
|
||||
/// and should not be confused with the file size.
|
|
||||
/// </summary>
|
|
||||
public int ImageSize { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the horizontal resolution of the image.
|
|
||||
/// (pixel per meter, signed integer)
|
|
||||
/// </summary>
|
|
||||
public int XPelsPerMeter { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the vertical resolution of the image.
|
|
||||
/// (pixel per meter, signed integer)
|
|
||||
/// </summary>
|
|
||||
public int YPelsPerMeter { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the number of colors in the color palette,
|
|
||||
/// or 0 to default to 2^n.
|
|
||||
/// </summary>
|
|
||||
public int ClrUsed { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the number of important colors used,
|
|
||||
/// or 0 when every color is important{ get; set; } generally ignored.
|
|
||||
/// </summary>
|
|
||||
public int ClrImportant { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,8 +0,0 @@ |
|||||
Encoder/Decoder adapted from: |
|
||||
|
|
||||
https://github.com/yufeih/Nine.Imaging/ |
|
||||
https://imagetools.codeplex.com/ |
|
||||
|
|
||||
TODO: |
|
||||
|
|
||||
- Add support for all bitmap formats. |
|
||||
@ -1,37 +0,0 @@ |
|||||
// <copyright file="DisposalMethod.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Provides enumeration for instructing the decoder what to do with the last image
|
|
||||
/// in an animation sequence.
|
|
||||
/// <see href="http://www.w3.org/Graphics/GIF/spec-gif89a.txt"/> section 23
|
|
||||
/// </summary>
|
|
||||
public enum DisposalMethod |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// No disposal specified. The decoder is not required to take any action.
|
|
||||
/// </summary>
|
|
||||
Unspecified = 0, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Do not dispose. The graphic is to be left in place.
|
|
||||
/// </summary>
|
|
||||
NotDispose = 1, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Restore to background color. The area used by the graphic must be restored to
|
|
||||
/// the background color.
|
|
||||
/// </summary>
|
|
||||
RestoreToBackground = 2, |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Restore to previous. The decoder is required to restore the area overwritten by the
|
|
||||
/// graphic with what was there prior to rendering the graphic.
|
|
||||
/// </summary>
|
|
||||
RestoreToPrevious = 3 |
|
||||
} |
|
||||
} |
|
||||
@ -1,83 +0,0 @@ |
|||||
// <copyright file="GifConstants.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Constants that define specific points within a gif.
|
|
||||
/// </summary>
|
|
||||
internal sealed class GifConstants |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The file type.
|
|
||||
/// </summary>
|
|
||||
public const string FileType = "GIF"; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The file version.
|
|
||||
/// </summary>
|
|
||||
public const string FileVersion = "89a"; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The extension block introducer <value>!</value>.
|
|
||||
/// </summary>
|
|
||||
public const byte ExtensionIntroducer = 0x21; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The graphic control label.
|
|
||||
/// </summary>
|
|
||||
public const byte GraphicControlLabel = 0xF9; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The application extension label.
|
|
||||
/// </summary>
|
|
||||
public const byte ApplicationExtensionLabel = 0xFF; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The application identification.
|
|
||||
/// </summary>
|
|
||||
public const string ApplicationIdentification = "NETSCAPE2.0"; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The application block size.
|
|
||||
/// </summary>
|
|
||||
public const byte ApplicationBlockSize = 0x0b; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The comment label.
|
|
||||
/// </summary>
|
|
||||
public const byte CommentLabel = 0xFE; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The maximum comment length.
|
|
||||
/// </summary>
|
|
||||
public const int MaxCommentLength = 1024 * 8; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The image descriptor label <value>,</value>.
|
|
||||
/// </summary>
|
|
||||
public const byte ImageDescriptorLabel = 0x2C; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The plain text label.
|
|
||||
/// </summary>
|
|
||||
public const byte PlainTextLabel = 0x01; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The image label introducer <value>,</value>.
|
|
||||
/// </summary>
|
|
||||
public const byte ImageLabel = 0x2C; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The terminator.
|
|
||||
/// </summary>
|
|
||||
public const byte Terminator = 0; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The end introducer trailer <value>;</value>.
|
|
||||
/// </summary>
|
|
||||
public const byte EndIntroducer = 0x3B; |
|
||||
} |
|
||||
} |
|
||||
@ -1,65 +0,0 @@ |
|||||
// <copyright file="GifDecoder.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
using System; |
|
||||
using System.IO; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Decoder for generating an image out of a gif encoded stream.
|
|
||||
/// </summary>
|
|
||||
public class GifDecoder : IImageDecoder |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets the size of the header for this image type.
|
|
||||
/// </summary>
|
|
||||
/// <value>The size of the header.</value>
|
|
||||
public int HeaderSize => 6; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns a value indicating whether the <see cref="IImageDecoder"/> supports the specified
|
|
||||
/// file header.
|
|
||||
/// </summary>
|
|
||||
/// <param name="extension">The <see cref="string"/> containing the file extension.</param>
|
|
||||
/// <returns>
|
|
||||
/// True if the decoder supports the file extension; otherwise, false.
|
|
||||
/// </returns>
|
|
||||
public bool IsSupportedFileExtension(string extension) |
|
||||
{ |
|
||||
Guard.NotNullOrEmpty(extension, nameof(extension)); |
|
||||
|
|
||||
extension = extension.StartsWith(".") ? extension.Substring(1) : extension; |
|
||||
return extension.Equals("GIF", StringComparison.OrdinalIgnoreCase); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns a value indicating whether the <see cref="IImageDecoder"/> supports the specified
|
|
||||
/// file header.
|
|
||||
/// </summary>
|
|
||||
/// <param name="header">The <see cref="T:byte[]"/> containing the file header.</param>
|
|
||||
/// <returns>
|
|
||||
/// True if the decoder supports the file header; otherwise, false.
|
|
||||
/// </returns>
|
|
||||
public bool IsSupportedFileFormat(byte[] header) |
|
||||
{ |
|
||||
return header.Length >= 6 && |
|
||||
header[0] == 0x47 && // G
|
|
||||
header[1] == 0x49 && // I
|
|
||||
header[2] == 0x46 && // F
|
|
||||
header[3] == 0x38 && // 8
|
|
||||
(header[4] == 0x39 || header[4] == 0x37) && // 9 or 7
|
|
||||
header[5] == 0x61; // a
|
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public void Decode<TColor, TPacked>(Image<TColor, TPacked> image, Stream stream) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
new GifDecoderCore<TColor, TPacked>().Decode(image, stream); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,425 +0,0 @@ |
|||||
// <copyright file="GifDecoderCore.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
using System; |
|
||||
using System.IO; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Performs the gif decoding operation.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
internal class GifDecoderCore<TColor, TPacked> |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The image to decode the information to.
|
|
||||
/// </summary>
|
|
||||
private Image<TColor, TPacked> decodedImage; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The currently loaded stream.
|
|
||||
/// </summary>
|
|
||||
private Stream currentStream; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The global color table.
|
|
||||
/// </summary>
|
|
||||
private byte[] globalColorTable; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The current frame.
|
|
||||
/// </summary>
|
|
||||
private TColor[] currentFrame; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The logical screen descriptor.
|
|
||||
/// </summary>
|
|
||||
private GifLogicalScreenDescriptor logicalScreenDescriptor; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The graphics control extension.
|
|
||||
/// </summary>
|
|
||||
private GifGraphicsControlExtension graphicsControlExtension; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Decodes the stream to the image.
|
|
||||
/// </summary>
|
|
||||
/// <param name="image">The image to decode to.</param>
|
|
||||
/// <param name="stream">The stream containing image data. </param>
|
|
||||
public void Decode(Image<TColor, TPacked> image, Stream stream) |
|
||||
{ |
|
||||
this.decodedImage = image; |
|
||||
|
|
||||
this.currentStream = stream; |
|
||||
|
|
||||
// Skip the identifier
|
|
||||
this.currentStream.Skip(6); |
|
||||
this.ReadLogicalScreenDescriptor(); |
|
||||
|
|
||||
if (this.logicalScreenDescriptor.GlobalColorTableFlag) |
|
||||
{ |
|
||||
this.globalColorTable = new byte[this.logicalScreenDescriptor.GlobalColorTableSize * 3]; |
|
||||
|
|
||||
// Read the global color table from the stream
|
|
||||
stream.Read(this.globalColorTable, 0, this.globalColorTable.Length); |
|
||||
} |
|
||||
|
|
||||
// Loop though the respective gif parts and read the data.
|
|
||||
int nextFlag = stream.ReadByte(); |
|
||||
while (nextFlag != GifConstants.Terminator) |
|
||||
{ |
|
||||
if (nextFlag == GifConstants.ImageLabel) |
|
||||
{ |
|
||||
this.ReadFrame(); |
|
||||
} |
|
||||
else if (nextFlag == GifConstants.ExtensionIntroducer) |
|
||||
{ |
|
||||
int label = stream.ReadByte(); |
|
||||
switch (label) |
|
||||
{ |
|
||||
case GifConstants.GraphicControlLabel: |
|
||||
this.ReadGraphicalControlExtension(); |
|
||||
break; |
|
||||
case GifConstants.CommentLabel: |
|
||||
this.ReadComments(); |
|
||||
break; |
|
||||
case GifConstants.ApplicationExtensionLabel: |
|
||||
this.Skip(12); // No need to read.
|
|
||||
break; |
|
||||
case GifConstants.PlainTextLabel: |
|
||||
this.Skip(13); // Not supported by any known decoder.
|
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
else if (nextFlag == GifConstants.EndIntroducer) |
|
||||
{ |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
nextFlag = stream.ReadByte(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the graphic control extension.
|
|
||||
/// </summary>
|
|
||||
private void ReadGraphicalControlExtension() |
|
||||
{ |
|
||||
byte[] buffer = new byte[6]; |
|
||||
|
|
||||
this.currentStream.Read(buffer, 0, buffer.Length); |
|
||||
|
|
||||
byte packed = buffer[1]; |
|
||||
|
|
||||
this.graphicsControlExtension = new GifGraphicsControlExtension |
|
||||
{ |
|
||||
DelayTime = BitConverter.ToInt16(buffer, 2), |
|
||||
TransparencyIndex = buffer[4], |
|
||||
TransparencyFlag = (packed & 0x01) == 1, |
|
||||
DisposalMethod = (DisposalMethod)((packed & 0x1C) >> 2) |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the image descriptor
|
|
||||
/// </summary>
|
|
||||
/// <returns><see cref="GifImageDescriptor"/></returns>
|
|
||||
private GifImageDescriptor ReadImageDescriptor() |
|
||||
{ |
|
||||
byte[] buffer = new byte[9]; |
|
||||
|
|
||||
this.currentStream.Read(buffer, 0, buffer.Length); |
|
||||
|
|
||||
byte packed = buffer[8]; |
|
||||
|
|
||||
GifImageDescriptor imageDescriptor = new GifImageDescriptor |
|
||||
{ |
|
||||
Left = BitConverter.ToInt16(buffer, 0), |
|
||||
Top = BitConverter.ToInt16(buffer, 2), |
|
||||
Width = BitConverter.ToInt16(buffer, 4), |
|
||||
Height = BitConverter.ToInt16(buffer, 6), |
|
||||
LocalColorTableFlag = ((packed & 0x80) >> 7) == 1, |
|
||||
LocalColorTableSize = 2 << (packed & 0x07), |
|
||||
InterlaceFlag = ((packed & 0x40) >> 6) == 1 |
|
||||
}; |
|
||||
|
|
||||
return imageDescriptor; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the logical screen descriptor.
|
|
||||
/// </summary>
|
|
||||
private void ReadLogicalScreenDescriptor() |
|
||||
{ |
|
||||
byte[] buffer = new byte[7]; |
|
||||
|
|
||||
this.currentStream.Read(buffer, 0, buffer.Length); |
|
||||
|
|
||||
byte packed = buffer[4]; |
|
||||
|
|
||||
this.logicalScreenDescriptor = new GifLogicalScreenDescriptor |
|
||||
{ |
|
||||
Width = BitConverter.ToInt16(buffer, 0), |
|
||||
Height = BitConverter.ToInt16(buffer, 2), |
|
||||
BackgroundColorIndex = buffer[5], |
|
||||
PixelAspectRatio = buffer[6], |
|
||||
GlobalColorTableFlag = ((packed & 0x80) >> 7) == 1, |
|
||||
GlobalColorTableSize = 2 << (packed & 0x07) |
|
||||
}; |
|
||||
|
|
||||
if (this.logicalScreenDescriptor.GlobalColorTableSize > 255 * 4) |
|
||||
{ |
|
||||
throw new ImageFormatException( |
|
||||
$"Invalid gif colormap size '{this.logicalScreenDescriptor.GlobalColorTableSize}'"); |
|
||||
} |
|
||||
|
|
||||
if (this.logicalScreenDescriptor.Width > this.decodedImage.MaxWidth || this.logicalScreenDescriptor.Height > this.decodedImage.MaxHeight) |
|
||||
{ |
|
||||
throw new ArgumentOutOfRangeException( |
|
||||
$"The input gif '{this.logicalScreenDescriptor.Width}x{this.logicalScreenDescriptor.Height}' is bigger then the max allowed size '{this.decodedImage.MaxWidth}x{this.decodedImage.MaxHeight}'"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Skips the designated number of bytes in the stream.
|
|
||||
/// </summary>
|
|
||||
/// <param name="length">The number of bytes to skip.</param>
|
|
||||
private void Skip(int length) |
|
||||
{ |
|
||||
this.currentStream.Skip(length); |
|
||||
|
|
||||
int flag; |
|
||||
|
|
||||
while ((flag = this.currentStream.ReadByte()) != 0) |
|
||||
{ |
|
||||
this.currentStream.Skip(flag); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the gif comments.
|
|
||||
/// </summary>
|
|
||||
private void ReadComments() |
|
||||
{ |
|
||||
int flag; |
|
||||
|
|
||||
while ((flag = this.currentStream.ReadByte()) != 0) |
|
||||
{ |
|
||||
if (flag > GifConstants.MaxCommentLength) |
|
||||
{ |
|
||||
throw new ImageFormatException($"Gif comment length '{flag}' exceeds max '{GifConstants.MaxCommentLength}'"); |
|
||||
} |
|
||||
|
|
||||
byte[] buffer = new byte[flag]; |
|
||||
|
|
||||
this.currentStream.Read(buffer, 0, flag); |
|
||||
|
|
||||
this.decodedImage.Properties.Add(new ImageProperty("Comments", BitConverter.ToString(buffer))); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads an individual gif frame.
|
|
||||
/// </summary>
|
|
||||
private void ReadFrame() |
|
||||
{ |
|
||||
GifImageDescriptor imageDescriptor = this.ReadImageDescriptor(); |
|
||||
|
|
||||
byte[] localColorTable = this.ReadFrameLocalColorTable(imageDescriptor); |
|
||||
|
|
||||
byte[] indices = this.ReadFrameIndices(imageDescriptor); |
|
||||
|
|
||||
// Determine the color table for this frame. If there is a local one, use it
|
|
||||
// otherwise use the global color table.
|
|
||||
byte[] colorTable = localColorTable ?? this.globalColorTable; |
|
||||
|
|
||||
this.ReadFrameColors(indices, colorTable, imageDescriptor); |
|
||||
|
|
||||
// Skip any remaining blocks
|
|
||||
this.Skip(0); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the frame indices marking the color to use for each pixel.
|
|
||||
/// </summary>
|
|
||||
/// <param name="imageDescriptor">The <see cref="GifImageDescriptor"/>.</param>
|
|
||||
/// <returns>The <see cref="T:byte[]"/></returns>
|
|
||||
private byte[] ReadFrameIndices(GifImageDescriptor imageDescriptor) |
|
||||
{ |
|
||||
int dataSize = this.currentStream.ReadByte(); |
|
||||
LzwDecoder lzwDecoder = new LzwDecoder(this.currentStream); |
|
||||
|
|
||||
byte[] indices = lzwDecoder.DecodePixels(imageDescriptor.Width, imageDescriptor.Height, dataSize); |
|
||||
|
|
||||
return indices; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the local color table from the current frame.
|
|
||||
/// </summary>
|
|
||||
/// <param name="imageDescriptor">The <see cref="GifImageDescriptor"/>.</param>
|
|
||||
/// <returns>The <see cref="T:byte[]"/></returns>
|
|
||||
private byte[] ReadFrameLocalColorTable(GifImageDescriptor imageDescriptor) |
|
||||
{ |
|
||||
byte[] localColorTable = null; |
|
||||
|
|
||||
if (imageDescriptor.LocalColorTableFlag) |
|
||||
{ |
|
||||
localColorTable = new byte[imageDescriptor.LocalColorTableSize * 3]; |
|
||||
|
|
||||
this.currentStream.Read(localColorTable, 0, localColorTable.Length); |
|
||||
} |
|
||||
|
|
||||
return localColorTable; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the frames colors, mapping indices to colors.
|
|
||||
/// </summary>
|
|
||||
/// <param name="indices">The indexed pixels.</param>
|
|
||||
/// <param name="colorTable">The color table containing the available colors.</param>
|
|
||||
/// <param name="descriptor">The <see cref="GifImageDescriptor"/></param>
|
|
||||
private void ReadFrameColors(byte[] indices, byte[] colorTable, GifImageDescriptor descriptor) |
|
||||
{ |
|
||||
int imageWidth = this.logicalScreenDescriptor.Width; |
|
||||
int imageHeight = this.logicalScreenDescriptor.Height; |
|
||||
|
|
||||
if (this.currentFrame == null) |
|
||||
{ |
|
||||
this.currentFrame = new TColor[imageWidth * imageHeight]; |
|
||||
} |
|
||||
|
|
||||
TColor[] lastFrame = null; |
|
||||
|
|
||||
if (this.graphicsControlExtension != null && |
|
||||
this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious) |
|
||||
{ |
|
||||
lastFrame = new TColor[imageWidth * imageHeight]; |
|
||||
|
|
||||
Array.Copy(this.currentFrame, lastFrame, lastFrame.Length); |
|
||||
} |
|
||||
|
|
||||
int offset, i = 0; |
|
||||
int interlacePass = 0; // The interlace pass
|
|
||||
int interlaceIncrement = 8; // The interlacing line increment
|
|
||||
int interlaceY = 0; // The current interlaced line
|
|
||||
|
|
||||
for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++) |
|
||||
{ |
|
||||
// Check if this image is interlaced.
|
|
||||
int writeY; // the target y offset to write to
|
|
||||
if (descriptor.InterlaceFlag) |
|
||||
{ |
|
||||
// If so then we read lines at predetermined offsets.
|
|
||||
// When an entire image height worth of offset lines has been read we consider this a pass.
|
|
||||
// With each pass the number of offset lines changes and the starting line changes.
|
|
||||
if (interlaceY >= descriptor.Height) |
|
||||
{ |
|
||||
interlacePass++; |
|
||||
switch (interlacePass) |
|
||||
{ |
|
||||
case 1: |
|
||||
interlaceY = 4; |
|
||||
break; |
|
||||
case 2: |
|
||||
interlaceY = 2; |
|
||||
interlaceIncrement = 4; |
|
||||
break; |
|
||||
case 3: |
|
||||
interlaceY = 1; |
|
||||
interlaceIncrement = 2; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
writeY = interlaceY + descriptor.Top; |
|
||||
|
|
||||
interlaceY += interlaceIncrement; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
writeY = y; |
|
||||
} |
|
||||
|
|
||||
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++) |
|
||||
{ |
|
||||
offset = (writeY * imageWidth) + x; |
|
||||
int index = indices[i]; |
|
||||
|
|
||||
if (this.graphicsControlExtension == null || |
|
||||
this.graphicsControlExtension.TransparencyFlag == false || |
|
||||
this.graphicsControlExtension.TransparencyIndex != index) |
|
||||
{ |
|
||||
// Stored in r-> g-> b-> a order.
|
|
||||
int indexOffset = index * 3; |
|
||||
TColor pixel = default(TColor); |
|
||||
pixel.PackFromVector4(new Color(colorTable[indexOffset], colorTable[indexOffset + 1], colorTable[indexOffset + 2]).ToVector4()); |
|
||||
this.currentFrame[offset] = pixel; |
|
||||
} |
|
||||
|
|
||||
i++; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
TColor[] pixels = new TColor[imageWidth * imageHeight]; |
|
||||
|
|
||||
Array.Copy(this.currentFrame, pixels, pixels.Length); |
|
||||
|
|
||||
ImageBase<TColor, TPacked> currentImage; |
|
||||
|
|
||||
if (this.decodedImage.Pixels == null) |
|
||||
{ |
|
||||
currentImage = this.decodedImage; |
|
||||
currentImage.SetPixels(imageWidth, imageHeight, pixels); |
|
||||
currentImage.Quality = colorTable.Length / 3; |
|
||||
|
|
||||
if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0) |
|
||||
{ |
|
||||
this.decodedImage.FrameDelay = this.graphicsControlExtension.DelayTime; |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
ImageFrame<TColor, TPacked> frame = new ImageFrame<TColor, TPacked>(); |
|
||||
|
|
||||
currentImage = frame; |
|
||||
currentImage.SetPixels(imageWidth, imageHeight, pixels); |
|
||||
currentImage.Quality = colorTable.Length / 3; |
|
||||
|
|
||||
if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0) |
|
||||
{ |
|
||||
currentImage.FrameDelay = this.graphicsControlExtension.DelayTime; |
|
||||
} |
|
||||
|
|
||||
this.decodedImage.Frames.Add(frame); |
|
||||
} |
|
||||
|
|
||||
if (this.graphicsControlExtension != null) |
|
||||
{ |
|
||||
if (this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground) |
|
||||
{ |
|
||||
for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++) |
|
||||
{ |
|
||||
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++) |
|
||||
{ |
|
||||
offset = (y * imageWidth) + x; |
|
||||
|
|
||||
// Stored in r-> g-> b-> a order.
|
|
||||
this.currentFrame[offset] = default(TColor); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
else if (this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious) |
|
||||
{ |
|
||||
this.currentFrame = lastFrame; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,64 +0,0 @@ |
|||||
// <copyright file="GifEncoder.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
using System; |
|
||||
using System.IO; |
|
||||
|
|
||||
using ImageSharp.Quantizers; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Image encoder for writing image data to a stream in gif format.
|
|
||||
/// </summary>
|
|
||||
public class GifEncoder : IImageEncoder |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets or sets the quality of output for images.
|
|
||||
/// </summary>
|
|
||||
/// <remarks>For gifs the value ranges from 1 to 256.</remarks>
|
|
||||
public int Quality { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the transparency threshold.
|
|
||||
/// </summary>
|
|
||||
public byte Threshold { get; set; } = 128; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the quantizer for reducing the color count.
|
|
||||
/// </summary>
|
|
||||
public IQuantizer Quantizer { get; set; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public string Extension => "gif"; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public string MimeType => "image/gif"; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool IsSupportedFileExtension(string extension) |
|
||||
{ |
|
||||
Guard.NotNullOrEmpty(extension, nameof(extension)); |
|
||||
|
|
||||
extension = extension.StartsWith(".") ? extension.Substring(1) : extension; |
|
||||
return extension.Equals(this.Extension, StringComparison.OrdinalIgnoreCase); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public void Encode<TColor, TPacked>(Image<TColor, TPacked> image, Stream stream) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
GifEncoderCore encoder = new GifEncoderCore |
|
||||
{ |
|
||||
Quality = this.Quality, |
|
||||
Quantizer = this.Quantizer, |
|
||||
Threshold = this.Threshold |
|
||||
}; |
|
||||
|
|
||||
encoder.Encode(image, stream); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,349 +0,0 @@ |
|||||
// <copyright file="GifEncoderCore.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
using System; |
|
||||
using System.IO; |
|
||||
using System.Linq; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
using IO; |
|
||||
using Quantizers; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Performs the gif encoding operation.
|
|
||||
/// </summary>
|
|
||||
internal sealed class GifEncoderCore |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The number of bits requires to store the image palette.
|
|
||||
/// </summary>
|
|
||||
private int bitDepth; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the quality of output for images.
|
|
||||
/// </summary>
|
|
||||
/// <remarks>For gifs the value ranges from 1 to 256.</remarks>
|
|
||||
public int Quality { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the transparency threshold.
|
|
||||
/// </summary>
|
|
||||
public byte Threshold { get; set; } = 128; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the quantizer for reducing the color count.
|
|
||||
/// </summary>
|
|
||||
public IQuantizer Quantizer { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Encodes the image to the specified stream from the <see cref="Image{TColor, TPacked}"/>.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="image">The <see cref="Image{TColor, TPacked}"/> to encode from.</param>
|
|
||||
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
|
|
||||
public void Encode<TColor, TPacked>(Image<TColor, TPacked> image, Stream stream) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
Guard.NotNull(image, nameof(image)); |
|
||||
Guard.NotNull(stream, nameof(stream)); |
|
||||
|
|
||||
if (this.Quantizer == null) |
|
||||
{ |
|
||||
this.Quantizer = new OctreeQuantizer<TColor, TPacked>(); |
|
||||
} |
|
||||
|
|
||||
// Do not use IDisposable pattern here as we want to preserve the stream.
|
|
||||
EndianBinaryWriter writer = new EndianBinaryWriter(EndianBitConverter.Little, stream); |
|
||||
|
|
||||
// Ensure that quality can be set but has a fallback.
|
|
||||
int quality = this.Quality > 0 ? this.Quality : image.Quality; |
|
||||
this.Quality = quality > 0 ? quality.Clamp(1, 256) : 256; |
|
||||
|
|
||||
// Get the number of bits.
|
|
||||
this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(this.Quality); |
|
||||
|
|
||||
// Quantize the image returning a palette.
|
|
||||
QuantizedImage<TColor, TPacked> quantized = ((IQuantizer<TColor, TPacked>)this.Quantizer).Quantize(image, this.Quality); |
|
||||
|
|
||||
int index = GetTransparentIndex(quantized); |
|
||||
|
|
||||
// Write the header.
|
|
||||
this.WriteHeader(writer); |
|
||||
|
|
||||
// Write the LSD. We'll use local color tables for now.
|
|
||||
this.WriteLogicalScreenDescriptor(image, writer, index); |
|
||||
|
|
||||
// Write the first frame.
|
|
||||
this.WriteGraphicalControlExtension(image, writer, index); |
|
||||
this.WriteImageDescriptor(image, writer); |
|
||||
this.WriteColorTable(quantized, writer); |
|
||||
this.WriteImageData(quantized, writer); |
|
||||
|
|
||||
// Write additional frames.
|
|
||||
if (image.Frames.Any()) |
|
||||
{ |
|
||||
this.WriteApplicationExtension(writer, image.RepeatCount, image.Frames.Count); |
|
||||
foreach (ImageFrame<TColor, TPacked> frame in image.Frames) |
|
||||
{ |
|
||||
QuantizedImage<TColor, TPacked> quantizedFrame = ((IQuantizer<TColor, TPacked>)this.Quantizer).Quantize(frame, this.Quality); |
|
||||
|
|
||||
this.WriteGraphicalControlExtension(frame, writer, GetTransparentIndex(quantizedFrame)); |
|
||||
this.WriteImageDescriptor(frame, writer); |
|
||||
this.WriteColorTable(quantizedFrame, writer); |
|
||||
this.WriteImageData(quantizedFrame, writer); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// TODO: Write Comments extension etc
|
|
||||
writer.Write(GifConstants.EndIntroducer); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns the index of the most transparent color in the palette.
|
|
||||
/// </summary>
|
|
||||
/// <param name="quantized">
|
|
||||
/// The quantized.
|
|
||||
/// </param>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="int"/>.
|
|
||||
/// </returns>
|
|
||||
private static int GetTransparentIndex<TColor, TPacked>(QuantizedImage<TColor, TPacked> quantized) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
// Find the lowest alpha value and make it the transparent index.
|
|
||||
int index = 255; |
|
||||
float alpha = 1; |
|
||||
for (int i = 0; i < quantized.Palette.Length; i++) |
|
||||
{ |
|
||||
float a = quantized.Palette[i].ToVector4().W; |
|
||||
if (a < alpha) |
|
||||
{ |
|
||||
alpha = a; |
|
||||
index = i; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return index; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Writes the file header signature and version to the stream.
|
|
||||
/// </summary>
|
|
||||
/// <param name="writer">The writer to write to the stream with.</param>
|
|
||||
private void WriteHeader(EndianBinaryWriter writer) |
|
||||
{ |
|
||||
writer.Write((GifConstants.FileType + GifConstants.FileVersion).ToCharArray()); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Writes the logical screen descriptor to the stream.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="image">The image to encode.</param>
|
|
||||
/// <param name="writer">The writer to write to the stream with.</param>
|
|
||||
/// <param name="tranparencyIndex">The transparency index to set the default background index to.</param>
|
|
||||
private void WriteLogicalScreenDescriptor<TColor, TPacked>(Image<TColor, TPacked> image, EndianBinaryWriter writer, int tranparencyIndex) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
GifLogicalScreenDescriptor descriptor = new GifLogicalScreenDescriptor |
|
||||
{ |
|
||||
Width = (short)image.Width, |
|
||||
Height = (short)image.Height, |
|
||||
GlobalColorTableFlag = false, // Always false for now.
|
|
||||
GlobalColorTableSize = this.bitDepth - 1, |
|
||||
BackgroundColorIndex = (byte)(tranparencyIndex > -1 ? tranparencyIndex : 255) |
|
||||
}; |
|
||||
|
|
||||
writer.Write((ushort)descriptor.Width); |
|
||||
writer.Write((ushort)descriptor.Height); |
|
||||
|
|
||||
PackedField field = default(PackedField); |
|
||||
field.SetBit(0, descriptor.GlobalColorTableFlag); // 1 : Global color table flag = 1 || 0 (GCT used/ not used)
|
|
||||
field.SetBits(1, 3, descriptor.GlobalColorTableSize); // 2-4 : color resolution
|
|
||||
field.SetBit(4, false); // 5 : GCT sort flag = 0
|
|
||||
field.SetBits(5, 3, descriptor.GlobalColorTableSize); // 6-8 : GCT size. 2^(N+1)
|
|
||||
|
|
||||
// Reduce the number of writes
|
|
||||
byte[] arr = |
|
||||
{ |
|
||||
field.Byte, |
|
||||
descriptor.BackgroundColorIndex, // Background Color Index
|
|
||||
descriptor.PixelAspectRatio // Pixel aspect ratio. Assume 1:1
|
|
||||
}; |
|
||||
|
|
||||
writer.Write(arr); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Writes the application extension to the stream.
|
|
||||
/// </summary>
|
|
||||
/// <param name="writer">The writer to write to the stream with.</param>
|
|
||||
/// <param name="repeatCount">The animated image repeat count.</param>
|
|
||||
/// <param name="frames">The number of image frames.</param>
|
|
||||
private void WriteApplicationExtension(EndianBinaryWriter writer, ushort repeatCount, int frames) |
|
||||
{ |
|
||||
// Application Extension Header
|
|
||||
if (repeatCount != 1 && frames > 0) |
|
||||
{ |
|
||||
byte[] ext = |
|
||||
{ |
|
||||
GifConstants.ExtensionIntroducer, |
|
||||
GifConstants.ApplicationExtensionLabel, |
|
||||
GifConstants.ApplicationBlockSize |
|
||||
}; |
|
||||
|
|
||||
writer.Write(ext); |
|
||||
|
|
||||
writer.Write(GifConstants.ApplicationIdentification.ToCharArray()); // NETSCAPE2.0
|
|
||||
writer.Write((byte)3); // Application block length
|
|
||||
writer.Write((byte)1); // Data sub-block index (always 1)
|
|
||||
|
|
||||
// 0 means loop indefinitely. Count is set as play n + 1 times.
|
|
||||
repeatCount = (ushort)(Math.Max((ushort)0, repeatCount) - 1); |
|
||||
|
|
||||
writer.Write(repeatCount); // Repeat count for images.
|
|
||||
|
|
||||
writer.Write(GifConstants.Terminator); // Terminator
|
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Writes the graphics control extension to the stream.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="image">The <see cref="ImageBase{TColor, TPacked}"/> to encode.</param>
|
|
||||
/// <param name="writer">The stream to write to.</param>
|
|
||||
/// <param name="transparencyIndex">The index of the color in the color palette to make transparent.</param>
|
|
||||
private void WriteGraphicalControlExtension<TColor, TPacked>(ImageBase<TColor, TPacked> image, EndianBinaryWriter writer, int transparencyIndex) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
// TODO: Check transparency logic.
|
|
||||
bool hasTransparent = transparencyIndex > -1; |
|
||||
DisposalMethod disposalMethod = hasTransparent |
|
||||
? DisposalMethod.RestoreToBackground |
|
||||
: DisposalMethod.Unspecified; |
|
||||
|
|
||||
GifGraphicsControlExtension extension = new GifGraphicsControlExtension() |
|
||||
{ |
|
||||
DisposalMethod = disposalMethod, |
|
||||
TransparencyFlag = hasTransparent, |
|
||||
TransparencyIndex = transparencyIndex, |
|
||||
DelayTime = image.FrameDelay |
|
||||
}; |
|
||||
|
|
||||
// Reduce the number of writes.
|
|
||||
byte[] intro = |
|
||||
{ |
|
||||
GifConstants.ExtensionIntroducer, |
|
||||
GifConstants.GraphicControlLabel, |
|
||||
4 // Size
|
|
||||
}; |
|
||||
|
|
||||
writer.Write(intro); |
|
||||
|
|
||||
PackedField field = default(PackedField); |
|
||||
field.SetBits(3, 3, (int)extension.DisposalMethod); // 1-3 : Reserved, 4-6 : Disposal
|
|
||||
|
|
||||
// TODO: Allow this as an option.
|
|
||||
field.SetBit(6, false); // 7 : User input - 0 = none
|
|
||||
field.SetBit(7, extension.TransparencyFlag); // 8: Has transparent.
|
|
||||
|
|
||||
writer.Write(field.Byte); |
|
||||
writer.Write((ushort)extension.DelayTime); |
|
||||
writer.Write((byte)(extension.TransparencyIndex == -1 ? 255 : extension.TransparencyIndex)); |
|
||||
writer.Write(GifConstants.Terminator); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Writes the image descriptor to the stream.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="image">The <see cref="ImageBase{TColor, TPacked}"/> to be encoded.</param>
|
|
||||
/// <param name="writer">The stream to write to.</param>
|
|
||||
private void WriteImageDescriptor<TColor, TPacked>(ImageBase<TColor, TPacked> image, EndianBinaryWriter writer) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
writer.Write(GifConstants.ImageDescriptorLabel); // 2c
|
|
||||
// TODO: Can we capture this?
|
|
||||
writer.Write((ushort)0); // Left position
|
|
||||
writer.Write((ushort)0); // Top position
|
|
||||
writer.Write((ushort)image.Width); |
|
||||
writer.Write((ushort)image.Height); |
|
||||
|
|
||||
PackedField field = default(PackedField); |
|
||||
field.SetBit(0, true); // 1: Local color table flag = 1 (LCT used)
|
|
||||
field.SetBit(1, false); // 2: Interlace flag 0
|
|
||||
field.SetBit(2, false); // 3: Sort flag 0
|
|
||||
field.SetBits(5, 3, this.bitDepth - 1); // 4-5: Reserved, 6-8 : LCT size. 2^(N+1)
|
|
||||
|
|
||||
writer.Write(field.Byte); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Writes the color table to the stream.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="image">The <see cref="ImageBase{TColor, TPacked}"/> to encode.</param>
|
|
||||
/// <param name="writer">The writer to write to the stream with.</param>
|
|
||||
private void WriteColorTable<TColor, TPacked>(QuantizedImage<TColor, TPacked> image, EndianBinaryWriter writer) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
// Grab the palette and write it to the stream.
|
|
||||
TColor[] palette = image.Palette; |
|
||||
int pixelCount = palette.Length; |
|
||||
|
|
||||
// Get max colors for bit depth.
|
|
||||
int colorTableLength = (int)Math.Pow(2, this.bitDepth) * 3; |
|
||||
byte[] colorTable = new byte[colorTableLength]; |
|
||||
|
|
||||
Parallel.For( |
|
||||
0, |
|
||||
pixelCount, |
|
||||
i => |
|
||||
{ |
|
||||
int offset = i * 3; |
|
||||
Color color = new Color(palette[i].ToVector4()); |
|
||||
|
|
||||
colorTable[offset] = color.R; |
|
||||
colorTable[offset + 1] = color.G; |
|
||||
colorTable[offset + 2] = color.B; |
|
||||
}); |
|
||||
|
|
||||
writer.Write(colorTable, 0, colorTableLength); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Writes the image pixel data to the stream.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
||||
/// <param name="image">The <see cref="QuantizedImage{TColor, TPacked}"/> containing indexed pixels.</param>
|
|
||||
/// <param name="writer">The stream to write to.</param>
|
|
||||
private void WriteImageData<TColor, TPacked>(QuantizedImage<TColor, TPacked> image, EndianBinaryWriter writer) |
|
||||
where TColor : struct, IPackedPixel<TPacked> |
|
||||
where TPacked : struct |
|
||||
{ |
|
||||
byte[] indexedPixels = image.Pixels; |
|
||||
|
|
||||
LzwEncoder encoder = new LzwEncoder(indexedPixels, (byte)this.bitDepth); |
|
||||
encoder.Encode(writer.BaseStream); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,19 +0,0 @@ |
|||||
// <copyright file="GifFormat.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Encapsulates the means to encode and decode gif images.
|
|
||||
/// </summary>
|
|
||||
public class GifFormat : IImageFormat |
|
||||
{ |
|
||||
/// <inheritdoc/>
|
|
||||
public IImageDecoder Decoder => new GifDecoder(); |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public IImageEncoder Encoder => new GifEncoder(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,228 +0,0 @@ |
|||||
// <copyright file="LzwDecoder.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
using System.IO; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Decompresses and decodes data using the dynamic LZW algorithms.
|
|
||||
/// </summary>
|
|
||||
internal sealed class LzwDecoder |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The max decoder pixel stack size.
|
|
||||
/// </summary>
|
|
||||
private const int MaxStackSize = 4096; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The null code.
|
|
||||
/// </summary>
|
|
||||
private const int NullCode = -1; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The stream to decode.
|
|
||||
/// </summary>
|
|
||||
private readonly Stream stream; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="LzwDecoder"/> class
|
|
||||
/// and sets the stream, where the compressed data should be read from.
|
|
||||
/// </summary>
|
|
||||
/// <param name="stream">The stream to read from.</param>
|
|
||||
/// <exception cref="System.ArgumentNullException"><paramref name="stream"/> is null.</exception>
|
|
||||
public LzwDecoder(Stream stream) |
|
||||
{ |
|
||||
Guard.NotNull(stream, nameof(stream)); |
|
||||
|
|
||||
this.stream = stream; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Decodes and decompresses all pixel indices from the stream.
|
|
||||
/// </summary>
|
|
||||
/// <param name="width">The width of the pixel index array.</param>
|
|
||||
/// <param name="height">The height of the pixel index array.</param>
|
|
||||
/// <param name="dataSize">Size of the data.</param>
|
|
||||
/// <returns>The decoded and uncompressed array.</returns>
|
|
||||
public byte[] DecodePixels(int width, int height, int dataSize) |
|
||||
{ |
|
||||
Guard.MustBeLessThan(dataSize, int.MaxValue, nameof(dataSize)); |
|
||||
|
|
||||
// The resulting index table.
|
|
||||
byte[] pixels = new byte[width * height]; |
|
||||
|
|
||||
// Calculate the clear code. The value of the clear code is 2 ^ dataSize
|
|
||||
int clearCode = 1 << dataSize; |
|
||||
|
|
||||
int codeSize = dataSize + 1; |
|
||||
|
|
||||
// Calculate the end code
|
|
||||
int endCode = clearCode + 1; |
|
||||
|
|
||||
// Calculate the available code.
|
|
||||
int availableCode = clearCode + 2; |
|
||||
|
|
||||
// Jillzhangs Code see: http://giflib.codeplex.com/
|
|
||||
// Adapted from John Cristy's ImageMagick.
|
|
||||
int code; |
|
||||
int oldCode = NullCode; |
|
||||
int codeMask = (1 << codeSize) - 1; |
|
||||
int bits = 0; |
|
||||
|
|
||||
int[] prefix = new int[MaxStackSize]; |
|
||||
int[] suffix = new int[MaxStackSize]; |
|
||||
int[] pixelStatck = new int[MaxStackSize + 1]; |
|
||||
|
|
||||
int top = 0; |
|
||||
int count = 0; |
|
||||
int bi = 0; |
|
||||
int xyz = 0; |
|
||||
|
|
||||
int data = 0; |
|
||||
int first = 0; |
|
||||
|
|
||||
for (code = 0; code < clearCode; code++) |
|
||||
{ |
|
||||
prefix[code] = 0; |
|
||||
suffix[code] = (byte)code; |
|
||||
} |
|
||||
|
|
||||
byte[] buffer = null; |
|
||||
while (xyz < pixels.Length) |
|
||||
{ |
|
||||
if (top == 0) |
|
||||
{ |
|
||||
if (bits < codeSize) |
|
||||
{ |
|
||||
// Load bytes until there are enough bits for a code.
|
|
||||
if (count == 0) |
|
||||
{ |
|
||||
// Read a new data block.
|
|
||||
buffer = this.ReadBlock(); |
|
||||
count = buffer.Length; |
|
||||
if (count == 0) |
|
||||
{ |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
bi = 0; |
|
||||
} |
|
||||
|
|
||||
if (buffer != null) |
|
||||
{ |
|
||||
data += buffer[bi] << bits; |
|
||||
} |
|
||||
|
|
||||
bits += 8; |
|
||||
bi++; |
|
||||
count--; |
|
||||
continue; |
|
||||
} |
|
||||
|
|
||||
// Get the next code
|
|
||||
code = data & codeMask; |
|
||||
data >>= codeSize; |
|
||||
bits -= codeSize; |
|
||||
|
|
||||
// Interpret the code
|
|
||||
if (code > availableCode || code == endCode) |
|
||||
{ |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
if (code == clearCode) |
|
||||
{ |
|
||||
// Reset the decoder
|
|
||||
codeSize = dataSize + 1; |
|
||||
codeMask = (1 << codeSize) - 1; |
|
||||
availableCode = clearCode + 2; |
|
||||
oldCode = NullCode; |
|
||||
continue; |
|
||||
} |
|
||||
|
|
||||
if (oldCode == NullCode) |
|
||||
{ |
|
||||
pixelStatck[top++] = suffix[code]; |
|
||||
oldCode = code; |
|
||||
first = code; |
|
||||
continue; |
|
||||
} |
|
||||
|
|
||||
int inCode = code; |
|
||||
if (code == availableCode) |
|
||||
{ |
|
||||
pixelStatck[top++] = (byte)first; |
|
||||
|
|
||||
code = oldCode; |
|
||||
} |
|
||||
|
|
||||
while (code > clearCode) |
|
||||
{ |
|
||||
pixelStatck[top++] = suffix[code]; |
|
||||
code = prefix[code]; |
|
||||
} |
|
||||
|
|
||||
first = suffix[code]; |
|
||||
|
|
||||
pixelStatck[top++] = suffix[code]; |
|
||||
|
|
||||
// Fix for Gifs that have "deferred clear code" as per here :
|
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=55918
|
|
||||
if (availableCode < MaxStackSize) |
|
||||
{ |
|
||||
prefix[availableCode] = oldCode; |
|
||||
suffix[availableCode] = first; |
|
||||
availableCode++; |
|
||||
if (availableCode == codeMask + 1 && availableCode < MaxStackSize) |
|
||||
{ |
|
||||
codeSize++; |
|
||||
codeMask = (1 << codeSize) - 1; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
oldCode = inCode; |
|
||||
} |
|
||||
|
|
||||
// Pop a pixel off the pixel stack.
|
|
||||
top--; |
|
||||
|
|
||||
// Clear missing pixels
|
|
||||
pixels[xyz++] = (byte)pixelStatck[top]; |
|
||||
} |
|
||||
|
|
||||
return pixels; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the next data block from the stream. A data block begins with a byte,
|
|
||||
/// which defines the size of the block, followed by the block itself.
|
|
||||
/// </summary>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="T:byte[]"/>.
|
|
||||
/// </returns>
|
|
||||
private byte[] ReadBlock() |
|
||||
{ |
|
||||
int blockSize = this.stream.ReadByte(); |
|
||||
return this.ReadBytes(blockSize); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the specified number of bytes from the data stream.
|
|
||||
/// </summary>
|
|
||||
/// <param name="length">
|
|
||||
/// The number of bytes to read.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="T:byte[]"/>.
|
|
||||
/// </returns>
|
|
||||
private byte[] ReadBytes(int length) |
|
||||
{ |
|
||||
byte[] buffer = new byte[length]; |
|
||||
this.stream.Read(buffer, 0, length); |
|
||||
return buffer; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,419 +0,0 @@ |
|||||
// <copyright file="LzwEncoder.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageSharp.Formats |
|
||||
{ |
|
||||
using System; |
|
||||
using System.IO; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Encodes and compresses the image data using dynamic Lempel-Ziv compression.
|
|
||||
/// </summary>
|
|
||||
/// <remarks>
|
|
||||
/// Adapted from Jef Poskanzer's Java port by way of J. M. G. Elliott. K Weiner 12/00
|
|
||||
/// <para>
|
|
||||
/// GIFCOMPR.C - GIF Image compression routines
|
|
||||
/// </para>
|
|
||||
/// <para>
|
|
||||
/// Lempel-Ziv compression based on 'compress'. GIF modifications by
|
|
||||
/// David Rowley (mgardi@watdcsu.waterloo.edu)
|
|
||||
/// </para>
|
|
||||
/// GIF Image compression - modified 'compress'
|
|
||||
/// <para>
|
|
||||
/// Based on: compress.c - File compression ala IEEE Computer, June 1984.
|
|
||||
/// By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
|
|
||||
/// Jim McKie (decvax!mcvax!jim)
|
|
||||
/// Steve Davies (decvax!vax135!petsd!peora!srd)
|
|
||||
/// Ken Turkowski (decvax!decwrl!turtlevax!ken)
|
|
||||
/// James A. Woods (decvax!ihnp4!ames!jaw)
|
|
||||
/// Joe Orost (decvax!vax135!petsd!joe)
|
|
||||
/// </para>
|
|
||||
/// </remarks>
|
|
||||
internal sealed class LzwEncoder |
|
||||
{ |
|
||||
private const int Eof = -1; |
|
||||
|
|
||||
private const int Bits = 12; |
|
||||
|
|
||||
private const int HashSize = 5003; // 80% occupancy
|
|
||||
|
|
||||
private readonly byte[] pixelArray; |
|
||||
|
|
||||
private readonly int initialCodeSize; |
|
||||
|
|
||||
private readonly int[] hashTable = new int[HashSize]; |
|
||||
|
|
||||
private readonly int[] codeTable = new int[HashSize]; |
|
||||
|
|
||||
private readonly int[] masks = |
|
||||
{ |
|
||||
0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, |
|
||||
0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF |
|
||||
}; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Define the storage for the packet accumulator.
|
|
||||
/// </summary>
|
|
||||
private readonly byte[] accumulators = new byte[256]; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The current pixel
|
|
||||
/// </summary>
|
|
||||
private int currentPixel; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Number of bits/code
|
|
||||
/// </summary>
|
|
||||
private int bitCount; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// User settable max # bits/code
|
|
||||
/// </summary>
|
|
||||
private int maxbits = Bits; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// maximum code, given bitCount
|
|
||||
/// </summary>
|
|
||||
private int maxcode; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// should NEVER generate this code
|
|
||||
/// </summary>
|
|
||||
private int maxmaxcode = 1 << Bits; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// For dynamic table sizing
|
|
||||
/// </summary>
|
|
||||
private int hsize = HashSize; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// First unused entry
|
|
||||
/// </summary>
|
|
||||
private int freeEntry; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Block compression parameters -- after all codes are used up,
|
|
||||
/// and compression rate changes, start over.
|
|
||||
/// </summary>
|
|
||||
private bool clearFlag; |
|
||||
|
|
||||
// Algorithm: use open addressing double hashing (no chaining) on the
|
|
||||
// prefix code / next character combination. We do a variant of Knuth's
|
|
||||
// algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
|
|
||||
// secondary probe. Here, the modular division first probe is gives way
|
|
||||
// to a faster exclusive-or manipulation. Also do block compression with
|
|
||||
// an adaptive reset, whereby the code table is cleared when the compression
|
|
||||
// ratio decreases, but after the table fills. The variable-length output
|
|
||||
// codes are re-sized at this point, and a special CLEAR code is generated
|
|
||||
// for the decompressor. Late addition: construct the table according to
|
|
||||
// file size for noticeable speed improvement on small files. Please direct
|
|
||||
// questions about this implementation to ames!jaw.
|
|
||||
private int globalInitialBits; |
|
||||
|
|
||||
private int clearCode; |
|
||||
|
|
||||
private int eofCode; |
|
||||
|
|
||||
// output
|
|
||||
//
|
|
||||
// Output the given code.
|
|
||||
// Inputs:
|
|
||||
// code: A bitCount-bit integer. If == -1, then EOF. This assumes
|
|
||||
// that bitCount =< wordsize - 1.
|
|
||||
// Outputs:
|
|
||||
// Outputs code to the file.
|
|
||||
// Assumptions:
|
|
||||
// Chars are 8 bits long.
|
|
||||
// Algorithm:
|
|
||||
// Maintain a BITS character long buffer (so that 8 codes will
|
|
||||
// fit in it exactly). Use the VAX insv instruction to insert each
|
|
||||
// code in turn. When the buffer fills up empty it and start over.
|
|
||||
private int currentAccumulator; |
|
||||
|
|
||||
private int currentBits; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Number of characters so far in this 'packet'
|
|
||||
/// </summary>
|
|
||||
private int accumulatorCount; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="LzwEncoder"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="indexedPixels">The array of indexed pixels.</param>
|
|
||||
/// <param name="colorDepth">The color depth in bits.</param>
|
|
||||
public LzwEncoder(byte[] indexedPixels, int colorDepth) |
|
||||
{ |
|
||||
this.pixelArray = indexedPixels; |
|
||||
this.initialCodeSize = Math.Max(2, colorDepth); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Encodes and compresses the indexed pixels to the stream.
|
|
||||
/// </summary>
|
|
||||
/// <param name="stream">The stream to write to.</param>
|
|
||||
public void Encode(Stream stream) |
|
||||
{ |
|
||||
// Write "initial code size" byte
|
|
||||
stream.WriteByte((byte)this.initialCodeSize); |
|
||||
|
|
||||
this.currentPixel = 0; |
|
||||
|
|
||||
// Compress and write the pixel data
|
|
||||
this.Compress(this.initialCodeSize + 1, stream); |
|
||||
|
|
||||
// Write block terminator
|
|
||||
stream.WriteByte(GifConstants.Terminator); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the maximum code value
|
|
||||
/// </summary>
|
|
||||
/// <param name="bitCount">The number of bits</param>
|
|
||||
/// <returns>See <see cref="int"/></returns>
|
|
||||
private static int GetMaxcode(int bitCount) |
|
||||
{ |
|
||||
return (1 << bitCount) - 1; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Add a character to the end of the current packet, and if it is 254 characters,
|
|
||||
/// flush the packet to disk.
|
|
||||
/// </summary>
|
|
||||
/// <param name="c">The character to add.</param>
|
|
||||
/// <param name="stream">The stream to write to.</param>
|
|
||||
private void AddCharacter(byte c, Stream stream) |
|
||||
{ |
|
||||
this.accumulators[this.accumulatorCount++] = c; |
|
||||
if (this.accumulatorCount >= 254) |
|
||||
{ |
|
||||
this.FlushPacket(stream); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Table clear for block compress
|
|
||||
/// </summary>
|
|
||||
/// <param name="stream">The output stream.</param>
|
|
||||
private void ClearBlock(Stream stream) |
|
||||
{ |
|
||||
this.ResetCodeTable(this.hsize); |
|
||||
this.freeEntry = this.clearCode + 2; |
|
||||
this.clearFlag = true; |
|
||||
|
|
||||
this.Output(this.clearCode, stream); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reset the code table.
|
|
||||
/// </summary>
|
|
||||
/// <param name="size">The hash size.</param>
|
|
||||
private void ResetCodeTable(int size) |
|
||||
{ |
|
||||
for (int i = 0; i < size; ++i) |
|
||||
{ |
|
||||
this.hashTable[i] = -1; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Compress the packets to the stream.
|
|
||||
/// </summary>
|
|
||||
/// <param name="intialBits">The initial bits.</param>
|
|
||||
/// <param name="stream">The stream to write to.</param>
|
|
||||
private void Compress(int intialBits, Stream stream) |
|
||||
{ |
|
||||
int fcode; |
|
||||
int c; |
|
||||
int ent; |
|
||||
int hsizeReg; |
|
||||
int hshift; |
|
||||
|
|
||||
// Set up the globals: globalInitialBits - initial number of bits
|
|
||||
this.globalInitialBits = intialBits; |
|
||||
|
|
||||
// Set up the necessary values
|
|
||||
this.clearFlag = false; |
|
||||
this.bitCount = this.globalInitialBits; |
|
||||
this.maxcode = GetMaxcode(this.bitCount); |
|
||||
|
|
||||
this.clearCode = 1 << (intialBits - 1); |
|
||||
this.eofCode = this.clearCode + 1; |
|
||||
this.freeEntry = this.clearCode + 2; |
|
||||
|
|
||||
this.accumulatorCount = 0; // clear packet
|
|
||||
|
|
||||
ent = this.NextPixel(); |
|
||||
|
|
||||
hshift = 0; |
|
||||
for (fcode = this.hsize; fcode < 65536; fcode *= 2) |
|
||||
{ |
|
||||
++hshift; |
|
||||
} |
|
||||
|
|
||||
hshift = 8 - hshift; // set hash code range bound
|
|
||||
|
|
||||
hsizeReg = this.hsize; |
|
||||
|
|
||||
this.ResetCodeTable(hsizeReg); // clear hash table
|
|
||||
|
|
||||
this.Output(this.clearCode, stream); |
|
||||
|
|
||||
while ((c = this.NextPixel()) != Eof) |
|
||||
{ |
|
||||
fcode = (c << this.maxbits) + ent; |
|
||||
int i = (c << hshift) ^ ent /* = 0 */; |
|
||||
|
|
||||
if (this.hashTable[i] == fcode) |
|
||||
{ |
|
||||
ent = this.codeTable[i]; |
|
||||
continue; |
|
||||
} |
|
||||
|
|
||||
// Non-empty slot
|
|
||||
if (this.hashTable[i] >= 0) |
|
||||
{ |
|
||||
int disp = hsizeReg - i; |
|
||||
if (i == 0) |
|
||||
{ |
|
||||
disp = 1; |
|
||||
} |
|
||||
|
|
||||
do |
|
||||
{ |
|
||||
if ((i -= disp) < 0) |
|
||||
{ |
|
||||
i += hsizeReg; |
|
||||
} |
|
||||
|
|
||||
if (this.hashTable[i] == fcode) |
|
||||
{ |
|
||||
ent = this.codeTable[i]; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
while (this.hashTable[i] >= 0); |
|
||||
|
|
||||
if (this.hashTable[i] == fcode) |
|
||||
{ |
|
||||
continue; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
this.Output(ent, stream); |
|
||||
ent = c; |
|
||||
if (this.freeEntry < this.maxmaxcode) |
|
||||
{ |
|
||||
this.codeTable[i] = this.freeEntry++; // code -> hashtable
|
|
||||
this.hashTable[i] = fcode; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
this.ClearBlock(stream); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// Put out the final code.
|
|
||||
this.Output(ent, stream); |
|
||||
|
|
||||
this.Output(this.eofCode, stream); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Flush the packet to disk, and reset the accumulator.
|
|
||||
/// </summary>
|
|
||||
/// <param name="outStream">The output stream.</param>
|
|
||||
private void FlushPacket(Stream outStream) |
|
||||
{ |
|
||||
if (this.accumulatorCount > 0) |
|
||||
{ |
|
||||
outStream.WriteByte((byte)this.accumulatorCount); |
|
||||
outStream.Write(this.accumulators, 0, this.accumulatorCount); |
|
||||
this.accumulatorCount = 0; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Return the next pixel from the image
|
|
||||
/// </summary>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="int"/>
|
|
||||
/// </returns>
|
|
||||
private int NextPixel() |
|
||||
{ |
|
||||
if (this.currentPixel == this.pixelArray.Length) |
|
||||
{ |
|
||||
return Eof; |
|
||||
} |
|
||||
|
|
||||
if (this.currentPixel == this.pixelArray.Length) |
|
||||
{ |
|
||||
return Eof; |
|
||||
} |
|
||||
|
|
||||
this.currentPixel++; |
|
||||
return this.pixelArray[this.currentPixel - 1] & 0xff; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Output the current code to the stream.
|
|
||||
/// </summary>
|
|
||||
/// <param name="code">The code.</param>
|
|
||||
/// <param name="outs">The stream to write to.</param>
|
|
||||
private void Output(int code, Stream outs) |
|
||||
{ |
|
||||
this.currentAccumulator &= this.masks[this.currentBits]; |
|
||||
|
|
||||
if (this.currentBits > 0) |
|
||||
{ |
|
||||
this.currentAccumulator |= code << this.currentBits; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
this.currentAccumulator = code; |
|
||||
} |
|
||||
|
|
||||
this.currentBits += this.bitCount; |
|
||||
|
|
||||
while (this.currentBits >= 8) |
|
||||
{ |
|
||||
this.AddCharacter((byte)(this.currentAccumulator & 0xff), outs); |
|
||||
this.currentAccumulator >>= 8; |
|
||||
this.currentBits -= 8; |
|
||||
} |
|
||||
|
|
||||
// If the next entry is going to be too big for the code size,
|
|
||||
// then increase it, if possible.
|
|
||||
if (this.freeEntry > this.maxcode || this.clearFlag) |
|
||||
{ |
|
||||
if (this.clearFlag) |
|
||||
{ |
|
||||
this.maxcode = GetMaxcode(this.bitCount = this.globalInitialBits); |
|
||||
this.clearFlag = false; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
++this.bitCount; |
|
||||
this.maxcode = this.bitCount == this.maxbits |
|
||||
? this.maxmaxcode |
|
||||
: GetMaxcode(this.bitCount); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (code == this.eofCode) |
|
||||
{ |
|
||||
// At EOF, write the rest of the buffer.
|
|
||||
while (this.currentBits > 0) |
|
||||
{ |
|
||||
this.AddCharacter((byte)(this.currentAccumulator & 0xff), outs); |
|
||||
this.currentAccumulator >>= 8; |
|
||||
this.currentBits -= 8; |
|
||||
} |
|
||||
|
|
||||
this.FlushPacket(outs); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue