//
// 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;
}
}
}