about summary refs log tree commit diff
path: root/lib/pm_gamma.h
blob: 00d551fc68ec5de0817d62ba6d8d4d33b4533aa3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#ifndef _PM_GAMMA_H_
#define _PM_GAMMA_H_

#include <netpbm/pm_config.h>

#include <math.h>

#ifdef __cplusplus
extern "C" {
#endif
#if 0
} /* to fake out automatic code indenters */
#endif

static __inline__ float
pm_gamma709(float const intensity) {

    /* Here are parameters of the gamma transfer function for the Netpbm
       formats.  This is ITU-R Recommendation BT.709, FKA CIE Rec 709.  It is
       also ITU-R Recommendation BT.601, FKA CCIR 601.

       This transfer function is linear for sample values 0 .. .018
       and an exponential for larger sample values.
       The exponential is slightly stretched and translated, though,
       unlike the popular pure exponential gamma transfer function.

       The standard actually defines the linear expansion as 4.500, which
       means there is a discontinuity at linear intensity .018.  We instead
       use ~4.514 to make a continuous function.  This may have been simply
       a mistake when this code was written or based on an actual benefit
       to having a continuous function -- The history is not clear.

       Note that the discrepancy is below the precision of a maxval 255
       image.
    */
    float const gamma = 2.2;
    float const oneOverGamma = 1.0 / gamma;
    float const linearCutoff = 0.018;
    float const linearExpansion =
        (1.099 * pow(linearCutoff, oneOverGamma) - 0.099) / linearCutoff;

    float brightness;

    if (intensity < linearCutoff)
        brightness = intensity * linearExpansion;
    else
        brightness = 1.099 * pow(intensity, oneOverGamma) - 0.099;

    return brightness;
}



static __inline__ float
pm_ungamma709(float const brightness) {

    /* These are the same parameters as in pm_gamma, above */

    float const gamma = 2.2;
    float const oneOverGamma = 1.0 / gamma;
    float const linearCutoff = 0.018;
    float const linearExpansion =
        (1.099 * pow(linearCutoff, oneOverGamma) - 0.099) / linearCutoff;

    float intensity;

    if (brightness < linearCutoff * linearExpansion)
        intensity = brightness / linearExpansion;
    else
        intensity = pow((brightness + 0.099) / 1.099, gamma);

    return intensity;
}

#ifdef __cplusplus
}
#endif
#endif