Skip to content

Instantly share code, notes, and snippets.

@5p4k
Last active October 3, 2017 20:18
Show Gist options
  • Save 5p4k/69c684f64188b92f19abff4fbfaab71b to your computer and use it in GitHub Desktop.
Save 5p4k/69c684f64188b92f19abff4fbfaab71b to your computer and use it in GitHub Desktop.
Gamma transfer and correction functions for sRGB.
#
# Copyright (C) 2017 Pietro Saccardi <lizardm4@gmail.com>
#
# This work is free. You can redistribute it and/or modify it under the
# terms of the Do What The Fuck You Want To Public License, Version 2,
# as published by Sam Hocevar. See http://www.wtfpl.net/ for more details.
#
# ----
#
# Blend your RGB colors correctly! Convert them to a linear space first.
# https://www.youtube.com/watch?v=LKnqECcg6Gw (thanks MinutePhysics!)
#
from math import pow
_SRGB_A = 0.055
_SRGB_G = 2.4
_SRGB_S = 12.92
_SRGB_DIR_THR = 0.0031308
_SRGB_INV_THR = 0.04045
def srgb_gamma_dir(c):
"""
The gamma transfer function for sRGB. This takes a linear RGB value and returns its storage representation (i.e.
performs gamma correction of the value).
:param c: A floating point value in the range [0., 1.] representing one of the R, G, B channels.
:return: A floating point value in the range [0., 1.], representing the gamma-corrected channel.
"""
return (1. + _SRGB_A) * pow(c, 1. / _SRGB_G) - _SRGB_A if c > _SRGB_DIR_THR else c * _SRGB_S
def srgb_gamma_inv(c):
"""
The inverse gamma transfer function for sRGB. This takes a stored RGB value and returns its linear representation
(i.e. not gamma-corrected).
:param c: A floating point value in the range [0., 1.] representing the gamma-corrected channel.
:return: A floating point value in the range [0., 1.], representing one of the R, G, B channels.
"""
return pow((c + _SRGB_A) / (1. + _SRGB_A), _SRGB_G) if c > _SRGB_INV_THR else c / _SRGB_S
# A lookup table for the function srgb_gamma_dir, evaluated on all the integers from 0 to 255 (included).
SRGB_GAMMA_DIR_TABLE = [int(0.5 + 255 * srgb_gamma_dir(i / 255)) for i in range(256)]
# A lookup table for the function srgb_gamma_inv, evaluated on all the integers from 0 to 255 (included).
SRGB_GAMMA_INV_TABLE = [int(0.5 + 255 * srgb_gamma_inv(i / 255)) for i in range(256)]
def srgb_to_linear_rgb(rgb):
"""
Convert sRGB values to linear RGB. Linear RGB values are suitable to be interpolated and blended linearly, because
they are not gamma-corrected. For more information, see https://en.wikipedia.org/wiki/SRGB.
:param rgb: A 3-tuple of R, G, B integers in the range 0..255. No check is performed on the input.
:return: A 3-tuple of linear R, G, B integers in the range 0..255.
"""
return SRGB_GAMMA_INV_TABLE[rgb[0]], SRGB_GAMMA_INV_TABLE[rgb[1]], SRGB_GAMMA_INV_TABLE[rgb[2]]
def linear_rgb_to_srgb(rgb):
"""
Convert linear RGB values to sRGB. sRGB values are gamma-corrected and are suitable for storage. This is the format
in which you get data from e.g. PIL. For more information, see https://en.wikipedia.org/wiki/SRGB.
:param rgb: A 3-tuple of linear R, G, B integers in the range 0..255. No check is performed on the input.
:return: A 3-tuple of sRGB R, G, B integers in the range 0..255.
"""
return SRGB_GAMMA_DIR_TABLE[rgb[0]], SRGB_GAMMA_DIR_TABLE[rgb[1]], SRGB_GAMMA_DIR_TABLE[rgb[2]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment