// // Copyright © 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); /// /// 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 = 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 = 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; } } }