This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project gfxprim.git.
The branch, master has been updated via ce9e4793af70584532932e14d4adec6c38eefc4d (commit) from e4962e78d7114be162c9c83e6068f03e9455fb01 (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- http://repo.or.cz/w/gfxprim.git/commit/ce9e4793af70584532932e14d4adec6c38eef...
commit ce9e4793af70584532932e14d4adec6c38eefc4d Author: Cyril Hrubis metan@ucw.cz Date: Mon Jun 18 14:04:58 2012 +0200
doc: Add gamma docs + spellchecks.
diff --git a/doc/Makefile b/doc/Makefile index 8d4ffbf..3fdfaad 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -1,7 +1,7 @@ all: api.html examples.html
api.html: general.txt api.txt context.txt loaders.txt filters.txt - basic_types.txt drawing_api.txt backends.txt + basic_types.txt drawing_api.txt backends.txt gamma.txt asciidoc -a toc api.txt
examples.html: examples.txt ../demos/c_simple/*.c ../demos/py_simple/*.py diff --git a/doc/api.txt b/doc/api.txt index c2fca5c..402c6dd 100644 --- a/doc/api.txt +++ b/doc/api.txt @@ -5,6 +5,7 @@ Cyril Hrubis metan@ucw.cz include::general.txt[] include::basic_types.txt[] include::context.txt[] +include::gamma.txt[] include::drawing_api.txt[] include::filters.txt[] include::loaders.txt[] diff --git a/doc/context.txt b/doc/context.txt index f92473c..13d5270 100644 --- a/doc/context.txt +++ b/doc/context.txt @@ -24,6 +24,11 @@ typedef struct GP_Context {
enum GP_PixelType pixel_type; /* pixel format */
+ /* + * Pointer to optional Gamma correction tables. + */ + struct GP_Gamma *gamma; + uint8_t axes_swap:1; /* swap axes */ uint8_t x_swap:1; /* mirror x */ uint8_t y_swap:1; /* mirror y */ @@ -195,8 +200,11 @@ The 'free_pixels' flag for the resulting context is set. void GP_ContextFree(GP_Context *context); -------------------------------------------------------------------------------
-Frees the context memory. If 'free_pixels' flag is set, the pixels buffer is -freed too. +Frees the context memory. + +If 'free_pixels' flag is set, the pixels buffer is freed too. + +If gamma pointer is not 'NULL' the 'GP_GammaRelease()' is called.
Subcontext ~~~~~~~~~~ @@ -274,3 +282,4 @@ void GP_ContextPrintInfo(const GP_Context *self);
This function prints the content of 'GP_Context' structure, in a readable format, into the stdout. + diff --git a/doc/gamma.txt b/doc/gamma.txt new file mode 100644 index 0000000..f15f072 --- /dev/null +++ b/doc/gamma.txt @@ -0,0 +1,137 @@ +Gamma Correction +---------------- + +What is gamma and what is it doing in my computer? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +First of all gamma is a function, or better there is a gamma function and +it's inverse function. Both gamma function and it's inverse are defined on +interval [0,1] and are defined as out = in^(gamma)^ and it's inverse as +out = in^(1/gamma)^. + +The purpose of this function is to compensate nonlinearity of human eye +perception. The human eye is more sensitive to dark tones than the light ones +so without gamma correction storage and manipulation with image data would +either be less efficient in space (in case you decided to use more bits and +encode the image linearly) or quantization in darker tones would be more +visible resulting in "pixelated" images (aliasing). + +So there is a gamma, the Internet seems to suggest that usual values for +gamma are 2.5 for old CRT monitors and about 2.2 for LCD ones, ideally you +should have color profile for your device (you need special hardware to +measure it). So if you are trying to draw linear gradient on the screen +you need to generate sequence of numbers accordingly to gamma function +(the 50% intensity is around 186 for gamma = 2.2 and 8bit grayscale pixel). + +Moreover image formats tend to save data in nonlinear fashion (some formats +include gamma value used to for the image) so before you apply filter that +manipulates with pixel values, you need to convert it to linear space (adding +some more bits to compensate for rounding errors). + +Also it's important to take gamma, into an account, when drawing anti aliased +shapes, you can't get right results otherwise. + +NOTE: The gamma support in GFXprim is quite new and at a time of writing this +docs, only one filter does support gamma correction. (The anti-aliased drawing +and text still use legacy gamma support.) + +Implementation +~~~~~~~~~~~~~~ + +The 'GP_Gamma' structure defines per context, per channel, gamma tables. + +The tables for particular gamma are reference counted. There is only one table +for particular gamma value and bit depth in memory at a time. + +Also the table output, for linear values, has two more bits than original in +order not to loose precision. + +The pointers to gamma tables are storied in 'GP_Gamma' structure and are +organized in the same order as channels. First N tables for each channel and +gamma value gamma, then N tables for inverse 1/gamma function. + +So when we have RGB888 pixel and gamma 2.2 there are two tables in the memory, +one for gamma 2.2 input 8bit output 10bit and it's inverse input 10bit output +8bit. The 'GP_Gamma' contains six pointers. First three points to the gamma +table for gamma 2.2 with 8bit input (256 array members) and the output format +is 10bits so each array member is 'uint16_t'. The other three are for inverse +gamma function (gamma = 0.454545...) with 10bit input (1024 array members) and +8bit output so each member is 'uint8_t'. + +The whole interface is designed for speed, so that conversion to linear space +or from linear space is just a matter of indexing arrays. Imagine you need to +get gamma-corrected pixel value. First you take individual pixel channels then +use the GP_Gamma structure as follows: + +[source,c] +------------------------------------------------------------------------------- + +/* To convert channel gamma value to linear value: */ +gamma->tables[chan_number].u16[chan_val] + +/* ... or when result has no more than 8bits ... */ + +gamma->tables[chan_number].u8[chan_val] + +/* The inverse transformation is done as: */ + +gamma->tables[chan_count + chan_number].u8[chan_val] + +/* ... or when original pixel channel had more than 8bits ... */ + +gamma->tables[chan_count + chan_number].u16[chan_val] + +/* + * When doing more than one conversion it's better to save pointers to + * individual table (example for RGB888): + */ + +uint16_t *R_2_LIN = gamma->tables[0].u16; +/* ... */ +uint8_t *R_2_GAMMA = gamma->tables[3].u8; +/* ... */ + +------------------------------------------------------------------------------- + +Gamma low level API +~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +#include <core/GP_Gamma.h> +/* or */ +#include <GP.h> + +GP_Gamma *GP_GammaAcquire(GP_PixelType pixel_type, float gamma); +------------------------------------------------------------------------------- + +Returns pointer to gamma table for particular pixel_type and gamma value. + +The same gamma is used for all channels. + +May fail and return 'NULL' if 'malloc()' has failed. + +[source,c] +------------------------------------------------------------------------------- +#include <core/GP_Gamma.h> +/* or */ +#include <GP.h> + +GP_Gamma *GP_GammaCopy(GP_Gamma *gamma); +------------------------------------------------------------------------------- + +Copies a Gamma table (actually only increases ref_count). + +Can't fail. + +[source,c] +------------------------------------------------------------------------------- +#include <core/GP_Gamma.h> +/* or */ +#include <GP.h> + +void GP_GammaRelease(GP_Gamma *self); +------------------------------------------------------------------------------- + +Releases Gama table (if ref_count has fallen to zero, frees memory). + diff --git a/include/core/GP_Gamma.h b/include/core/GP_Gamma.h index a4112a7..9a93587 100644 --- a/include/core/GP_Gamma.h +++ b/include/core/GP_Gamma.h @@ -36,22 +36,22 @@ perception. The human eye is more sensitive to dark tones than the light ones so without gamma correction storage and manipulation with image data would either be less efficient in space (in case you decided to use more bits and - encode the image lineary) or quantization in darker tones would be more + encode the image linearly) or quantization in darker tones would be more visible resulting in "pixelated" images (aliasing).
- So there is a gamma, the internet seems to suggest that usual values for + So there is a gamma, the Internet seems to suggest that usual values for gamma are 2.5 for old CRT monitors and about 2.2 for LCD ones, ideally you should have color profile for your device (you need special hardware to measure it). So if you are trying to draw linear gradient on the screen - you need to generate sequence of numbers accordinly to gamma function + you need to generate sequence of numbers accordingly to gamma function (the 50% intensity is around 186 for gamma = 2.2 and 8bit grayscale pixel).
Moreover image formats tend to save data in nonlinear fashion (some formats - include gama value used to for the image) so before you apply filter that + include gamma value used to for the image) so before you apply filter that manipulates with pixel values, you need to convert it to linear space (adding some more bits to compensate for rounding errors).
- Also it's important to take gamma, into an accound, when drawing anti aliased + Also it's important to take gamma, into an account, when drawing anti-aliased shapes, you can't get right results otherwise.
*/ @@ -62,21 +62,21 @@ channel, gamma tables.
The tables for particular gamma are reference counted. There is only one - table for particulal gamma value and bit depth in memory at a time. + table for particular gamma value and bit depth in memory at a time.
Also the table output, for linear values, has two more bits than original in order not to loose precision.
- The pointers to gamma tables are storied in GP_Gamma structure the pointers - are organized in the same order as channes. First N tables for each channel - and gamma value gamma, then N tables for inverse 1/gamma function. + The pointers to gamma tables are storied in GP_Gamma structure and are + organized in the same order as channels. First N tables for each channel and + gamma value gamma, then N tables for inverse 1/gamma function.
So when we have RGB888 pixel and gamma 2.2 there are two tables in the memory, one for gamma 2.2 input 8bit output 10bit and it's inverse input 10bit output 8bit. The GP_Gamma contains six pointers. First three points to - the gamma table for gamma 2.2 whith 8bit input (256 array members) and the + the gamma table for gamma 2.2 with 8bit input (256 array members) and the output format is 10bits so each array member is uint16_t. The other three - are for inverse gamma funcion (gamma = 0.454545...) with 10bit input (1024 + are for inverse gamma function (gamma = 0.454545...) with 10bit input (1024 array members) and 8bit output so each member is uint8_t.
The whole interface is designed for speed, so that conversion to linear @@ -94,16 +94,16 @@
gamma->tables[chan_count + chan_number].u8[chan_val]
- of when original pixel channel had more than 8bits + or when original pixel channel had more than 8bits
gamma->tables[chan_count + chan_number].u16[chan_val]
When doing more than one conversion it's better to save pointers to individual table (example for RGB888):
- uint16_t *R2Lin = gamma->tables[0].u16; + uint16_t *R_2_LIN = gamma->tables[0].u16; ... - uint8_t *R2Gamma = gamma->tables[3].u8; + uint8_t *R_2_GAMMA = gamma->tables[3].u8; ...
*/ @@ -139,9 +139,9 @@ typedef struct GP_GammaTable { * Gamma structure for general pixel type. * * The GP_Gamma structure contains pointers to tables for each pixel - * channel and for gamma and it's inverse transfomation. + * channel and for gamma and it's inverse transformation. * - * The interface is specialy designed so that getting Gamma corrected value is + * The interface is specially designed so that getting Gamma corrected value is * a matter of indexing two arrays. */ typedef struct GP_Gamma { diff --git a/libs/filters/GP_Cubic.h b/libs/filters/GP_Cubic.h index 213031a..5d3c0e6 100644 --- a/libs/filters/GP_Cubic.h +++ b/libs/filters/GP_Cubic.h @@ -53,7 +53,7 @@ extern int16_t GP_CubicTable[]; /* * Fixed point version of above. * - * Both input and output value are multiplied by MUL. + * The input and output are expected in 24.8 fixed point format */ static inline int cubic_int(int x) { diff --git a/libs/filters/GP_ResizeCubic.gen.c.t b/libs/filters/GP_ResizeCubic.gen.c.t index f782b39..901e253 100644 --- a/libs/filters/GP_ResizeCubic.gen.c.t +++ b/libs/filters/GP_ResizeCubic.gen.c.t @@ -1,6 +1,6 @@ %% extends "filter.c.t"
-{% block descr %}Nearest Neighbour resampling{% endblock %} +{% block descr %}Cubic resampling{% endblock %}
%% block body
-----------------------------------------------------------------------
Summary of changes: doc/Makefile | 2 +- doc/api.txt | 1 + doc/context.txt | 13 +++- doc/gamma.txt | 137 +++++++++++++++++++++++++++++++++++ include/core/GP_Gamma.h | 32 ++++---- libs/filters/GP_Cubic.h | 2 +- libs/filters/GP_ResizeCubic.gen.c.t | 2 +- 7 files changed, 168 insertions(+), 21 deletions(-) create mode 100644 doc/gamma.txt
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos@gmail.com if you want to unsubscribe, or site admin admin@repo.or.cz if you receive no reply.