Rename GP_Context -> GP_Pixmap
[gfxprim.git] / doc / gamma.txt
blob521306a76962245e4c59542a42042814ab2f64f4
1 Gamma Correction
2 ----------------
4 What is gamma and what is it doing in my computer?
5 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 First of all gamma is a function, or better there is a gamma function and
8 it's inverse function. Both gamma function and it's inverse are defined on
9 interval [0,1] and are defined as out = in^(gamma)^ and it's inverse as
10 out = in^(1/gamma)^.
12 The purpose of this function is to compensate nonlinearity of human eye
13 perception. The human eye is more sensitive to dark tones than the light ones
14 so without gamma correction storage and manipulation with image data would
15 either be less efficient in space (in case you decided to use more bits and
16 encode the image linearly) or quantization in darker tones would be more
17 visible resulting in "pixelated" images (aliasing).
19 So there is a gamma, the Internet seems to suggest that usual values for
20 gamma are 2.5 for old CRT monitors and about 2.2 for LCD ones, ideally you
21 should have color profile for your device (you need special hardware to
22 measure it). So if you are trying to draw linear gradient on the screen
23 you need to generate sequence of numbers accordingly to gamma function
24 (the 50% intensity is around 186 for gamma = 2.2 and 8bit grayscale pixel).
26 Moreover image formats tend to save data in nonlinear fashion (some formats
27 include gamma value used to for the image) so before you apply filter that
28 manipulates with pixel values, you need to convert it to linear space (adding
29 some more bits to compensate for rounding errors).
31 Also it's important to take gamma, into an account, when drawing anti aliased
32 shapes, you can't get right results otherwise.
34 NOTE: The gamma support in GFXprim is quite new and at a time of writing this
35 docs, only one filter does support gamma correction. (The anti-aliased drawing
36 and text still use legacy gamma support.)
38 Implementation
39 ~~~~~~~~~~~~~~
41 The 'GP_Gamma' structure defines per pixmap, per channel, gamma tables.
43 The tables for particular gamma are reference counted. There is only one table
44 for particular gamma value and bit depth in memory at a time.
46 Also the table output, for linear values, has two more bits than original in
47 order not to loose precision.
49 The pointers to gamma tables are storied in 'GP_Gamma' structure and are
50 organized in the same order as channels. First N tables for each channel and
51 gamma value gamma, then N tables for inverse 1/gamma function.
53 So when we have RGB888 pixel and gamma 2.2 there are two tables in the memory,
54 one for gamma 2.2 input 8bit output 10bit and it's inverse input 10bit output
55 8bit. The 'GP_Gamma' contains six pointers. First three points to the gamma
56 table for gamma 2.2 with 8bit input (256 array members) and the output format
57 is 10bits so each array member is 'uint16_t'. The other three are for inverse
58 gamma function (gamma = 0.454545...) with 10bit input (1024 array members) and
59 8bit output so each member is 'uint8_t'.
61 The whole interface is designed for speed, so that conversion to linear space
62 or from linear space is just a matter of indexing arrays. Imagine you need to
63 get gamma-corrected pixel value. First you take individual pixel channels then
64 use the GP_Gamma structure as follows:
66 [source,c]
67 -------------------------------------------------------------------------------
69 /* To convert channel gamma value to linear value: */
70 gamma->tables[chan_number].u16[chan_val]
72 /* ... or when result has no more than 8bits ... */
74 gamma->tables[chan_number].u8[chan_val]
76 /* The inverse transformation is done as: */
78 gamma->tables[chan_count + chan_number].u8[chan_val]
80 /* ... or when original pixel channel had more than 8bits ... */
82 gamma->tables[chan_count + chan_number].u16[chan_val]
85  * When doing more than one conversion it's better to save pointers to
86  * individual table (example for RGB888):
87  */
89 uint16_t *R_2_LIN = gamma->tables[0].u16;
90 /* ... */
91 uint8_t *R_2_GAMMA = gamma->tables[3].u8;
92 /* ... */
94 -------------------------------------------------------------------------------
96 Gamma low level API
97 ~~~~~~~~~~~~~~~~~~~
99 [source,c]
100 -------------------------------------------------------------------------------
101 #include <core/GP_Gamma.h>
102 /* or */
103 #include <GP.h>
105 GP_Gamma *GP_GammaAcquire(GP_PixelType pixel_type, float gamma);
106 -------------------------------------------------------------------------------
108 Returns pointer to gamma table for particular pixel_type and gamma value.
110 The same gamma is used for all channels.
112 May fail and return NULL if 'malloc()' has failed.
114 [source,c]
115 -------------------------------------------------------------------------------
116 #include <core/GP_Gamma.h>
117 /* or */
118 #include <GP.h>
120 GP_Gamma *GP_GammaCopy(GP_Gamma *gamma);
121 -------------------------------------------------------------------------------
123 Copies a Gamma table (actually only increases ref_count).
125 Can't fail.
127 [source,c]
128 -------------------------------------------------------------------------------
129 #include <core/GP_Gamma.h>
130 /* or */
131 #include <GP.h>
133 void GP_GammaRelease(GP_Gamma *self);
134 -------------------------------------------------------------------------------
136 Releases Gama table (if ref_count has fallen to zero, frees memory).