diff --git a/src/ImageProcessor/Colors/Bgra.cs b/src/ImageProcessor/Colors/Bgra.cs index 861e75c0b9..25b703f6ff 100644 --- a/src/ImageProcessor/Colors/Bgra.cs +++ b/src/ImageProcessor/Colors/Bgra.cs @@ -194,7 +194,7 @@ namespace ImageProcessor /// public static implicit operator Bgra(ColorVector color) { - return new Bgra((255 * color.B).ToByte(), (255 * color.G).ToByte(), (255 * color.R).ToByte(), (255 * color.A).ToByte()); + return new Bgra((255f * color.B).ToByte(), (255f * color.G).ToByte(), (255f * color.R).ToByte(), (255f * color.A).ToByte()); } /// diff --git a/src/ImageProcessor/Common/Helpers/PixelOperations - Copy.cs b/src/ImageProcessor/Common/Helpers/PixelOperations - Copy.cs new file mode 100644 index 0000000000..a876b45efe --- /dev/null +++ b/src/ImageProcessor/Common/Helpers/PixelOperations - Copy.cs @@ -0,0 +1,193 @@ +// +// Copyright (c) James South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessor +{ + using System; + + /// + /// Performs per-pixel operations. + /// + public static class PixelOperations + { + /// + /// The array of bytes representing each possible value of color component + /// converted from sRGB to the linear color space. + /// + private static readonly Lazy LinearBytes = new Lazy(GetLinearBytes); + + /// + /// The array of bytes representing each possible value of color component + /// converted from linear to the sRGB color space. + /// + private static readonly Lazy SrgbBytes = new Lazy(GetSrgbBytes); + + /// + /// The array of bytes representing each possible value of color component + /// converted from gamma to the linear color space. + /// + private static readonly Lazy LinearGammaBytes = new Lazy(GetLinearGammaBytes); + + /// + /// The array of bytes representing each possible value of color component + /// converted from linear to the gamma color space. + /// + private static readonly Lazy GammaLinearBytes = new Lazy(GetGammaLinearBytes); + + /// + /// Converts an pixel from an sRGB color-space to the equivalent linear color-space. + /// + /// + /// The to convert. + /// + /// + /// The . + /// + public static Bgra ToLinear(Bgra composite) + { + // Create only once and lazily. + // byte[] ramp = LinearGammaBytes.Value; + byte[] ramp = LinearBytes.Value; + + return new Bgra(ramp[composite.B], ramp[composite.G], ramp[composite.R], composite.A); + } + + /// + /// Converts a pixel from a linear color-space to the equivalent sRGB color-space. + /// + /// + /// The to convert. + /// + /// + /// The . + /// + public static Bgra ToSrgb(Bgra linear) + { + // Create only once and lazily. + // byte[] ramp = GammaLinearBytes.Value; + byte[] ramp = SrgbBytes.Value; + + return new Bgra(ramp[linear.B], ramp[linear.G], ramp[linear.R], linear.A); + } + + /// + /// Gets an array of bytes representing each possible value of color component + /// converted from sRGB to the linear color space. + /// + /// + /// The . + /// + private static byte[] GetLinearBytes() + { + byte[] ramp = new byte[256]; + for (int x = 0; x < 256; ++x) + { + byte val = (255f * SrgbToLinear(x / 255f)).ToByte(); + ramp[x] = val; + } + + return ramp; + } + + /// + /// Gets an array of bytes representing each possible value of color component + /// converted from linear to the sRGB color space. + /// + /// + /// The . + /// + private static byte[] GetSrgbBytes() + { + byte[] ramp = new byte[256]; + for (int x = 0; x < 256; ++x) + { + byte val = (255f * LinearToSrgb(x / 255f)).ToByte(); + ramp[x] = val; + } + + return ramp; + } + + /// + /// Gets the correct linear value from an sRGB signal. + /// + /// + /// + /// The signal value to convert. + /// + /// The . + /// + private static float SrgbToLinear(float signal) + { + float a = 0.055f; + + if (signal <= 0.04045) + { + return signal / 12.92f; + } + + return (float)Math.Pow((signal + a) / (1 + a), 2.4); + } + + /// + /// Gets the correct sRGB value from an linear signal. + /// + /// + /// + /// The signal value to convert. + /// + /// The . + /// + private static float LinearToSrgb(float signal) + { + float a = 0.055f; + + if (signal <= 0.0031308) + { + return signal * 12.92f; + } + + return ((float)((1 + a) * Math.Pow(signal, 1 / 2.4f))) - a; + } + + /// + /// Gets an array of bytes representing each possible value of color component + /// converted from gamma to the linear color space. + /// + /// + /// The . + /// + private static byte[] GetLinearGammaBytes() + { + byte[] ramp = new byte[256]; + for (int x = 0; x < 256; ++x) + { + byte val = (255f * Math.Pow(x / 255f, 2.2)).ToByte(); + ramp[x] = val; + } + + return ramp; + } + + /// + /// Gets an array of bytes representing each possible value of color component + /// converted from linear to the gamma color space. + /// + /// + /// The . + /// + private static byte[] GetGammaLinearBytes() + { + byte[] ramp = new byte[256]; + for (int x = 0; x < 256; ++x) + { + byte val = (255f * Math.Pow(x / 255f, 1 / 2.2)).ToByte(); + ramp[x] = val; + } + + return ramp; + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor/Common/Helpers/PixelOperations.cs b/src/ImageProcessor/Common/Helpers/PixelOperations.cs index a876b45efe..0a9c437971 100644 --- a/src/ImageProcessor/Common/Helpers/PixelOperations.cs +++ b/src/ImageProcessor/Common/Helpers/PixelOperations.cs @@ -13,16 +13,16 @@ namespace ImageProcessor public static class PixelOperations { /// - /// The array of bytes representing each possible value of color component + /// The array of values representing each possible value of color component /// converted from sRGB to the linear color space. /// - private static readonly Lazy LinearBytes = new Lazy(GetLinearBytes); + private static readonly Lazy LinearLut = new Lazy(GetLinearBytes); /// - /// The array of bytes representing each possible value of color component + /// The array of values representing each possible value of color component /// converted from linear to the sRGB color space. /// - private static readonly Lazy SrgbBytes = new Lazy(GetSrgbBytes); + private static readonly Lazy SrgbLut = new Lazy(GetSrgbBytes); /// /// The array of bytes representing each possible value of color component @@ -45,13 +45,14 @@ namespace ImageProcessor /// /// The . /// - public static Bgra ToLinear(Bgra composite) + public static Bgra ToLinear(ColorVector composite) { // Create only once and lazily. // byte[] ramp = LinearGammaBytes.Value; - byte[] ramp = LinearBytes.Value; + float[] ramp = LinearLut.Value; - return new Bgra(ramp[composite.B], ramp[composite.G], ramp[composite.R], composite.A); + // TODO: This just doesn't seem right to me. + return new ColorVector(ramp[(composite.B * 255).ToByte()], ramp[(composite.G * 255).ToByte()], ramp[(composite.R * 255).ToByte()], composite.A); } /// @@ -63,13 +64,14 @@ namespace ImageProcessor /// /// The . /// - public static Bgra ToSrgb(Bgra linear) + public static Bgra ToSrgb(ColorVector linear) { // Create only once and lazily. // byte[] ramp = GammaLinearBytes.Value; - byte[] ramp = SrgbBytes.Value; + float[] ramp = SrgbLut.Value; - return new Bgra(ramp[linear.B], ramp[linear.G], ramp[linear.R], linear.A); + // TODO: This just doesn't seem right to me. + return new ColorVector(ramp[(linear.B * 255).ToByte()], ramp[(linear.G * 255).ToByte()], (linear.R * 255).ToByte(), linear.A); } /// @@ -79,12 +81,12 @@ namespace ImageProcessor /// /// The . /// - private static byte[] GetLinearBytes() + private static float[] GetLinearBytes() { - byte[] ramp = new byte[256]; + float[] ramp = new float[256]; for (int x = 0; x < 256; ++x) { - byte val = (255f * SrgbToLinear(x / 255f)).ToByte(); + float val = SrgbToLinear(x / 255f); ramp[x] = val; } @@ -98,12 +100,12 @@ namespace ImageProcessor /// /// The . /// - private static byte[] GetSrgbBytes() + private static float[] GetSrgbBytes() { - byte[] ramp = new byte[256]; + float[] ramp = new float[256]; for (int x = 0; x < 256; ++x) { - byte val = (255f * LinearToSrgb(x / 255f)).ToByte(); + float val = LinearToSrgb(x / 255f); ramp[x] = val; } diff --git a/src/ImageProcessor/Samplers/Resize.cs b/src/ImageProcessor/Samplers/Resize.cs index 1010aa17c6..057aedf832 100644 --- a/src/ImageProcessor/Samplers/Resize.cs +++ b/src/ImageProcessor/Samplers/Resize.cs @@ -7,6 +7,7 @@ namespace ImageProcessor.Samplers { using System; using System.Collections.Generic; + using System.Numerics; using System.Threading.Tasks; /// @@ -61,6 +62,7 @@ namespace ImageProcessor.Samplers int targetBottom = targetRectangle.Bottom; int startX = targetRectangle.X; int endX = targetRectangle.Right; + //Vector endVX = new Vector(targetRectangle.Right); Parallel.For( startY, @@ -100,8 +102,8 @@ namespace ImageProcessor.Samplers } int originX = xw.Index; - Bgra sourceColor = source[originX, originY]; - //ColorVector sourceColor = PixelOperations.ToLinear(source[originX, originY]); + ColorVector sourceColor = source[originX, originY]; + //sourceColor = PixelOperations.ToLinear(sourceColor); r += sourceColor.R * (yw.Value / verticalSum) * (xw.Value / horizontalSum); g += sourceColor.G * (yw.Value / verticalSum) * (xw.Value / horizontalSum); @@ -110,9 +112,8 @@ namespace ImageProcessor.Samplers } } - // TODO: Double cast. - Bgra destinationColor = new Bgra(b.ToByte(), g.ToByte(), r.ToByte(), a.ToByte()); - //Bgra destinationColor = PixelOperations.ToSrgb(new ColorVector(b, g, r, a)); + // TODO: Double cast? + Bgra destinationColor = new ColorVector(b, g, r, a);//PixelOperations.ToSrgb(new ColorVector(b, g, r, a)); target[x, y] = destinationColor; } } diff --git a/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs b/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs index 07d9f5e25d..cb22fe8db1 100644 --- a/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs +++ b/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs @@ -20,14 +20,14 @@ namespace ImageProcessor.Tests public static readonly List Files = new List { "../../TestImages/Formats/Jpg/Backdrop.jpg", - "../../TestImages/Formats/Jpg/Calliphora.jpg", - "../../TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg", - "../../TestImages/Formats/Jpg/greyscale.jpg", - "../../TestImages/Formats/Bmp/Car.bmp", - "../../TestImages/Formats/Png/cmyk.png", - "../../TestImages/Formats/Png/gamma-1.0-or-2.2.png", - "../../TestImages/Formats/Gif/leaf.gif", - "../../TestImages/Formats/Gif/rings.gif" + //"../../TestImages/Formats/Jpg/Calliphora.jpg", + //"../../TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg", + //"../../TestImages/Formats/Jpg/greyscale.jpg", + //"../../TestImages/Formats/Bmp/Car.bmp", + //"../../TestImages/Formats/Png/cmyk.png", + //"../../TestImages/Formats/Png/gamma-1.0-or-2.2.png", + //"../../TestImages/Formats/Gif/leaf.gif", + //"../../TestImages/Formats/Gif/rings.gif" // { "../../TestImages/Formats/Gif/ani.gif" }, // { "../../TestImages/Formats/Gif/ani2.gif" },