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 6c21c9015f98423f9f880ae220a6956defed011c (commit)
from cdf4a7d83af42ed412a8b705b3ad50cb43a9ecb9 (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/6c21c9015f98423f9f880ae220a6956defed…
commit 6c21c9015f98423f9f880ae220a6956defed011c
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 17 21:10:11 2012 +0200
filters: resize NN: Remove forgotten debug print.
diff --git a/libs/filters/GP_ResizeNN.gen.c.t b/libs/filters/GP_ResizeNN.gen.c.t
index 7c7bd51..cf364a0 100644
--- a/libs/filters/GP_ResizeNN.gen.c.t
+++ b/libs/filters/GP_ResizeNN.gen.c.t
@@ -27,11 +27,8 @@ static int GP_FilterResizeNN_{{ pt.name }}_Raw(const GP_Context *src,
1.00 * dst->w / src->w, 1.00 * dst->h / src->h);
/* Pre-compute mapping for interpolation */
- for (i = 0; i < dst->w; i++) {
+ for (i = 0; i < dst->w; i++)
xmap[i] = ((((i * (src->w - 1))<<8) + (dst->w - 1)/2) / (dst->w - 1) + (1<<7))>>8;
- printf("%i-%i ", i, xmap[i]);
- }
- printf("n%i -> %in", src->w, dst->w);
for (i = 0; i < dst->h; i++)
ymap[i] = ((((i * (src->h - 1))<<8) + (dst->h - 1)/2) / (dst->h - 1) + (1<<7))>>8;
-----------------------------------------------------------------------
Summary of changes:
libs/filters/GP_ResizeNN.gen.c.t | 5 +----
1 files changed, 1 insertions(+), 4 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
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 4dad87b8900261ecaadbc43dedb932683089b414 (commit)
via 84a1d252db8cd13901a64caa34bf68d543c99828 (commit)
from 986b9dbf07932b754d452f84271e0a28c5bfd684 (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/4dad87b8900261ecaadbc43dedb932683089…
commit 4dad87b8900261ecaadbc43dedb932683089b414
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 17 15:58:23 2012 +0200
git: Add more gitignore files.
diff --git a/demos/c_simple/.gitignore b/demos/c_simple/.gitignore
new file mode 100644
index 0000000..a9d725a
--- /dev/null
+++ b/demos/c_simple/.gitignore
@@ -0,0 +1,9 @@
+backend_example
+filters_symmetry
+gfx_koch
+loaders
+loaders_example
+meta_data
+meta_data_dump
+tmp_file
+virtual_backend_example
diff --git a/demos/grinder/.gitignore b/demos/grinder/.gitignore
new file mode 100644
index 0000000..f2b8012
--- /dev/null
+++ b/demos/grinder/.gitignore
@@ -0,0 +1 @@
+grinder
diff --git a/demos/particle/.gitignore b/demos/particle/.gitignore
new file mode 100644
index 0000000..c1293c9
--- /dev/null
+++ b/demos/particle/.gitignore
@@ -0,0 +1 @@
+particle_demo
diff --git a/demos/spiv/.gitignore b/demos/spiv/.gitignore
new file mode 100644
index 0000000..71f7841
--- /dev/null
+++ b/demos/spiv/.gitignore
@@ -0,0 +1 @@
+spiv
diff --git a/demos/ttf2img/.gitignore b/demos/ttf2img/.gitignore
new file mode 100644
index 0000000..2d22d83
--- /dev/null
+++ b/demos/ttf2img/.gitignore
@@ -0,0 +1 @@
+ttf2img
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 0000000..2d19fc7
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1 @@
+*.html
http://repo.or.cz/w/gfxprim.git/commit/84a1d252db8cd13901a64caa34bf68d543c9…
commit 84a1d252db8cd13901a64caa34bf68d543c99828
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 17 15:50:38 2012 +0200
core, filters: Add initial version of gamma correction.
* This commit introduces concept of per-context per-channel
gamma correction.
* The GP_Context structure gets a new pointer to GP_Gamma
structure that describes gamma values and tables for
each individual context channel.
* One of the resampling algorithms gets experimental support
for gamma tables.
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c
index 11d24bf..d6b3da3 100644
--- a/demos/spiv/spiv.c
+++ b/demos/spiv/spiv.c
@@ -159,7 +159,7 @@ GP_Context *load_image(struct loader_params *params, int elevate)
GP_ContextFree(img);
img = tmp;
}
-
+
image_cache_put(params->img_orig_cache, img, params->img_path, 0, 0);
cpu_timer_stop(&timer);
@@ -196,13 +196,22 @@ GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size
return NULL;
img = res;
+
+ // img->gamma = GP_GammaAcquire(img->pixel_type, 2.2);
cpu_timer_stop(&timer);
+ } else {
+ // img->gamma = GP_GammaAcquire(img->pixel_type, 2.2);
}
cpu_timer_start(&timer, "Resampling");
callback.priv = "Resampling Image";
- img = GP_FilterResize(img, NULL, resampling_method, w, h, &callback);
+ GP_Context *i1 = GP_FilterResize(img, NULL, resampling_method, w, h, &callback);
+// img->gamma = NULL;
+// GP_Context *i2 = GP_FilterResize(img, NULL, resampling_method, w, h, &callback);
+// img = GP_FilterDifferenceAlloc(i2, i1, NULL);
+// img = GP_FilterInvert(img, NULL, NULL);
+ img = i1;
cpu_timer_stop(&timer);
/* Free low passed context if needed */
diff --git a/include/core/GP_Context.h b/include/core/GP_Context.h
index feed975..9de8572 100644
--- a/include/core/GP_Context.h
+++ b/include/core/GP_Context.h
@@ -33,6 +33,8 @@
#include "GP_Types.h"
#include "GP_Pixel.h"
+struct GP_Gamma;
+
/* This structure holds all information needed for drawing into an image. */
typedef struct GP_Context {
uint8_t *pixels; /* pointer to image pixels */
@@ -47,7 +49,19 @@ typedef struct GP_Context {
*/
uint8_t offset;
- enum GP_PixelType pixel_type; /* pixel format */
+ /*
+ * Pixel format. See GP_Pixel.gen.h and GP_Pixel.gen.c.
+ */
+ enum GP_PixelType pixel_type;
+
+ /*
+ * Pointer to optional Gamma table.
+ *
+ * If NULL, the channel values are considered linear.
+ *
+ * See GP_GammaCorrection.h.
+ */
+ struct GP_Gamma *gamma;
/*
* Image orientation. Most common is landscape (0, 0, 0),
diff --git a/include/core/GP_Core.h b/include/core/GP_Core.h
index 3987d07..987196e 100644
--- a/include/core/GP_Core.h
+++ b/include/core/GP_Core.h
@@ -41,6 +41,9 @@
/* ... and it's trasformations */
#include "core/GP_Transform.h"
+/* Gamma */
+#include "core/GP_Gamma.h"
+
/* Pixeltypes */
#include "core/GP_Pixel.h"
diff --git a/include/core/GP_Gamma.h b/include/core/GP_Gamma.h
new file mode 100644
index 0000000..a4112a7
--- /dev/null
+++ b/include/core/GP_Gamma.h
@@ -0,0 +1,174 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+/*
+
+ 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 lineary) 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 accordinly 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
+ 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
+ shapes, you can't get right results otherwise.
+
+ */
+
+ /*
+
+ This code implements management functions for easy, per context, per
+ 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.
+
+ 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.
+
+ 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
+ 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
+ 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:
+
+ 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]
+
+ of 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;
+ ...
+ uint8_t *R2Gamma = gamma->tables[3].u8;
+ ...
+
+ */
+
+#ifndef CORE_GP_GAMMA_H
+#define CORE_GP_GAMMA_H
+
+#include <stdint.h>
+
+#include "GP_Context.h"
+
+/*
+ * Gamma table.
+ */
+typedef struct GP_GammaTable {
+ /* Table description */
+ float gamma;
+ uint8_t in_bits;
+ uint8_t out_bits;
+
+ /* Used for internal purpose */
+ unsigned int ref_count;
+ struct GP_GammaTable *next;
+
+ /* The table itself */
+ union {
+ uint8_t u8[0];
+ uint16_t u16[0];
+ };
+} 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.
+ *
+ * The interface is specialy designed so that getting Gamma corrected value is
+ * a matter of indexing two arrays.
+ */
+typedef struct GP_Gamma {
+ GP_PixelType pixel_type;
+
+ unsigned int ref_count;
+
+ GP_GammaTable *tables[];
+} GP_Gamma;
+
+/*
+ * Returns pointer to a gamma translation table, the same gamma is used for all
+ * channels.
+ *
+ * May fail, in case malloc() has failed.
+ */
+GP_Gamma *GP_GammaAcquire(GP_PixelType pixel_type, float gamma);
+
+/*
+ * Copies Gamma table (actually increases ref_count) so it's fast and can't
+ * fail.
+ */
+GP_Gamma *GP_GammaCopy(GP_Gamma *gamma);
+
+/*
+ * Releases gamma table.
+ */
+void GP_GammaRelease(GP_Gamma *self);
+
+#endif /* CORE_GP_GAMMA_H */
diff --git a/include/core/GP_GammaCorrection.h b/include/core/GP_GammaCorrection.h
index e06ab9a..6c47687 100644
--- a/include/core/GP_GammaCorrection.h
+++ b/include/core/GP_GammaCorrection.h
@@ -61,6 +61,8 @@
#include <stdint.h>
-#include "core/GP_GammaCorrection.gen.h"
+#include "GP_Context.h"
+
+#include "GP_GammaCorrection.gen.h"
#endif /* CORE_GP_GAMMA_CORRECTION_H */
diff --git a/include/core/GP_GammaPixel.gen.h.t b/include/core/GP_GammaPixel.gen.h.t
new file mode 100644
index 0000000..3c8f832
--- /dev/null
+++ b/include/core/GP_GammaPixel.gen.h.t
@@ -0,0 +1,73 @@
+%% extends "base.h.t"
+
+{% block descr %}Gamma correction for pixels.{% endblock %}
+
+%% block body
+
+#include "GP_Context.h"
+#include "GP_GammaCorrection.h"
+
+%% for pt in pixeltypes
+%% if not pt.is_unknown() and not pt.is_palette()
+%% set idx = 0
+
+%% for c in pt.chanslist
+
+/*
+ * Converts gamma encoded pixel value to linear value.
+ *
+ * Parameters are, converted value and GP_Gamma structure.
+ */
+#define GP_Gamma2Lin_{{ pt.name }}_{{ c[0] }}(val, gamma) ({ +%% if c[2] > 6
+ gamma->tables[{{ idx }}]->u16[val]; +%% else
+ gamma->tables[{{ idx }}]->u8[val]; +%% endif
+})
+
+/*
+ * Converts linear encoded pixel into gamma encoded pixel.
+ *
+ * Parameters are, converted value and GP_Gamma structure.
+ */
+#define GP_Lin2Gamma_{{ pt.name }}_{{ c[0] }}(val, gamma) ({ +%% if c[2] > 8
+ gamma->tables[{{ len(pt.chanslist) + idx}}]->u16[val]; +%% else
+ gamma->tables[{{ len(pt.chanslist) + idx}}]->u8[val]; +%% endif
+})
+
+static inline GP_GammaTable *GP_GammaTable_{{ pt.name }}_{{ c[0] }}(GP_Gamma *gamma)
+{
+ return gamma->tables[{{ idx }}];
+}
+
+static inline GP_GammaTable *GP_GammaInverseTable_{{ pt.name }}_{{ c[0] }}(GP_Gamma *gamma)
+{
+ return gamma->tables[{{ len(pt.chanslist) + idx }}];
+}
+
+%% set idx = idx + 1
+%% endfor
+%% endif
+%% endfor
+
+#define GP_Gamma2Lin(val, chan_bits, gamma_table) ({ +#if chan_bits > 6
+ gamma_table->u16[val] +#else
+ gamma_table->u8[val] +#endif
+})
+
+#define GP_Lin2Gamma(val, chan_bits, gamma_table) ({ +#if chan_bits > 8
+ gamma_table->table16[val] +#else
+ gamma_table->table8[val] +#endif
+})
+
+%% endblock body
diff --git a/include/core/Makefile b/include/core/Makefile
index 340958b..c68d42e 100644
--- a/include/core/Makefile
+++ b/include/core/Makefile
@@ -1,7 +1,7 @@
TOPDIR=../..
GENHEADERS=GP_Convert_Scale.gen.h GP_Pixel.gen.h GP_GetPutPixel.gen.h GP_Convert.gen.h GP_FnPerBpp.gen.h - GP_MixPixels.gen.h GP_GammaCorrection.gen.h
+ GP_MixPixels.gen.h GP_GammaCorrection.gen.h GP_GammaPixel.gen.h
LIBNAME=core
include $(TOPDIR)/pre.mk
diff --git a/libs/core/GP_Context.c b/libs/core/GP_Context.c
index ee7cc2d..88a0298 100644
--- a/libs/core/GP_Context.c
+++ b/libs/core/GP_Context.c
@@ -30,6 +30,7 @@
#include "GP_Transform.h"
#include "GP_Pixel.h"
#include "GP_GetPutPixel.h"
+#include "GP_GammaCorrection.h"
#include "GP_Context.h"
#include "GP_Blit.h"
@@ -65,6 +66,8 @@ GP_Context *GP_ContextAlloc(GP_Size w, GP_Size h, GP_PixelType type)
context->w = w;
context->h = h;
+ context->gamma = NULL;
+
context->pixel_type = type;
#warning Hmm, bit endianity... Why is not this settled by different pixel types?
context->bit_endian = 0;
@@ -87,6 +90,9 @@ void GP_ContextFree(GP_Context *context)
if (context->free_pixels)
free(context->pixels);
+ if (context->gamma)
+ GP_GammaRelease(context->gamma);
+
free(context);
}
@@ -106,6 +112,8 @@ GP_Context *GP_ContextInit(GP_Context *context, GP_Size w, GP_Size h,
context->pixel_type = type;
context->bit_endian = 0;
+
+ context->gamma = NULL;
/* rotation and mirroring */
GP_ContextSetRotation(context, 0, 0, 0);
@@ -172,6 +180,9 @@ GP_Context *GP_ContextCopy(const GP_Context *src, int flags)
else
GP_ContextSetRotation(new, 0, 0, 0);
+ //TODO: Copy the gamma too
+ new->gamma = NULL;
+
new->free_pixels = 1;
return new;
@@ -239,6 +250,9 @@ GP_Context *GP_SubContext(const GP_Context *context, GP_Context *subcontext,
subcontext->pixel_type = context->pixel_type;
subcontext->bit_endian = context->bit_endian;
+
+ /* gamma */
+ subcontext->gamma = context->gamma;
/* rotation and mirroring */
GP_ContextCopyRotation(context, subcontext);
@@ -262,6 +276,7 @@ void GP_ContextPrintInfo(const GP_Context *self)
printf("Offsett%u (only unaligned pixel types)n", self->offset);
printf("Flagstaxes_swap=%u x_swap=%u y_swap=%u free_pixels=%un",
self->axes_swap, self->x_swap, self->y_swap, self->free_pixels);
+ printf("Gamma table %p", self->gamma);
}
/*
diff --git a/libs/core/GP_Gamma.c b/libs/core/GP_Gamma.c
new file mode 100644
index 0000000..b1f113c
--- /dev/null
+++ b/libs/core/GP_Gamma.c
@@ -0,0 +1,199 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include <math.h>
+
+#include "GP_Pixel.h"
+#include "GP_Debug.h"
+
+#include "GP_Gamma.h"
+
+static GP_GammaTable *tables = NULL;
+
+static void fill_table8(GP_GammaTable *table, float gamma,
+ uint8_t in_bits, uint8_t out_bits)
+{
+ unsigned int i;
+ unsigned int in_max = (1<<in_bits) - 1;
+ unsigned int out_max = (1<<out_bits) - 1;
+
+ GP_DEBUG(3, "Initalizing gamma table %f", gamma);
+
+ for (i = 0; i < (1U<<in_bits); i++)
+ table->u8[i] = pow((float)i / in_max, gamma) * out_max + 0.5;
+}
+
+static void fill_table16(GP_GammaTable *table, float gamma,
+ uint8_t in_bits, uint8_t out_bits)
+{
+ unsigned int i;
+ unsigned int in_max = (1<<in_bits) - 1;
+ unsigned int out_max = (1<<out_bits) - 1;
+
+ GP_DEBUG(3, "Initalizing gamma table %f", gamma);
+
+ for (i = 0; i < (1U<<in_bits); i++)
+ table->u16[i] = pow((float)i / in_max, gamma) * out_max + 0.5;
+}
+
+static GP_GammaTable *get_table(float gamma, uint8_t in_bits, uint8_t out_bits)
+{
+ GP_GammaTable *i;
+
+ for (i = tables; i != NULL; i = i->next)
+ if (gamma == i->gamma && in_bits == i->in_bits &&
+ out_bits == i->out_bits)
+ break;
+
+ if (i != NULL) {
+ GP_DEBUG(2, "Found Gamma table Gamma %f, in_bits %u, "
+ "out_bits %u, ref_count %u", i->gamma, i->in_bits,
+ i->out_bits, i->ref_count);
+ i->ref_count++;
+ return i;
+ }
+
+ GP_DEBUG(2, "Creating Gamma table Gamma %f, in_bits %u, out_bits %u",
+ gamma, in_bits, out_bits);
+
+ i = malloc(sizeof(GP_GammaTable) + (1U<<in_bits) * (out_bits > 8 ? 2 : 1));
+
+ if (i == NULL) {
+ GP_WARN("Malloc failed :(");
+ return NULL;
+ }
+
+ i->gamma = gamma;
+ i->in_bits = in_bits;
+ i->out_bits = out_bits;
+ i->ref_count = 1;
+
+ if (out_bits > 8)
+ fill_table16(i, gamma, in_bits, out_bits);
+ else
+ fill_table8(i, gamma, in_bits, out_bits);
+
+ /* Insert it into link list */
+ i->next = tables;
+ tables = i;
+
+ return i;
+}
+
+static void put_table(GP_GammaTable *table)
+{
+ if (table == NULL)
+ return;
+
+ table->ref_count--;
+
+ GP_DEBUG(2, "Putting gamma table Gamma %f, in_bits %u, out_bits %u, "
+ "ref_count %u", table->gamma, table->in_bits, table->out_bits,
+ table->ref_count);
+
+ if (table->ref_count == 0) {
+ GP_DEBUG(2, "Gamma table ref_count == 0, removing...");
+
+ GP_GammaTable *i, *prev = NULL;
+
+ /* Remove from link list and free */
+ for (i = tables; i != NULL; i = i->next) {
+ if (table == i)
+ break;
+ prev = i;
+ }
+
+ if (prev == NULL)
+ tables = table->next;
+ else
+ prev->next = table->next;
+
+ free(table);
+ }
+}
+
+GP_Gamma *GP_GammaAcquire(GP_PixelType pixel_type, float gamma)
+{
+ GP_CHECK_VALID_PIXELTYPE(pixel_type);
+ int channels = GP_PixelTypes[pixel_type].numchannels, i;
+
+ GP_DEBUG(1, "Acquiring Gamma table %s gamma %f", GP_PixelTypeName(pixel_type), gamma);
+
+ GP_Gamma *res = malloc(sizeof(struct GP_Gamma) + 2 * channels * sizeof(void*));
+
+ if (res == NULL) {
+ GP_WARN("Malloc failed :(");
+ return NULL;
+ }
+
+ /* NULL the pointers */
+ for (i = 0; i < 2 * channels; i++)
+ res->tables[i] = NULL;
+
+ res->pixel_type = pixel_type;
+ res->ref_count = 1;
+
+ /* Gamma to linear tables n bits -> n + 2 bits */
+ for (i = 0; i < channels; i++) {
+ unsigned int chan_size = GP_PixelTypes[pixel_type].channels[i].size;
+ res->tables[i] = get_table(gamma, chan_size, chan_size + 2);
+
+ if (res->tables[i] == NULL) {
+ GP_GammaRelease(res);
+ return NULL;
+ }
+ }
+
+ /* And reverse tables, n + 2 bits -> n bits */
+ for (i = 0; i < channels; i++) {
+ unsigned int chan_size = GP_PixelTypes[pixel_type].channels[i].size;
+ res->tables[i + channels] = get_table(1/gamma, chan_size + 2, chan_size);
+
+ if (res->tables[i] == NULL) {
+ GP_GammaRelease(res);
+ return NULL;
+ }
+ }
+
+ return res;
+}
+
+GP_Gamma *GP_GammaCopy(GP_Gamma *self)
+{
+ self->ref_count++;
+ return self;
+}
+
+void GP_GammaRelease(GP_Gamma *self)
+{
+ int channels = GP_PixelTypes[self->pixel_type].numchannels, i;
+
+ GP_DEBUG(1, "Releasing Gamma table %s gamma %f", GP_PixelTypeName(self->pixel_type), self->tables[0]->gamma);
+
+ for (i = 0; i < channels; i++)
+ put_table(self->tables[i]);
+
+ if (--self->ref_count == 0) {
+ GP_DEBUG(2, "Gamma ref_count == 0, releasing...");
+ free(self);
+ }
+}
diff --git a/libs/filters/GP_Resize.c b/libs/filters/GP_Resize.c
index 81db9ed..5f42da5 100644
--- a/libs/filters/GP_Resize.c
+++ b/libs/filters/GP_Resize.c
@@ -22,12 +22,13 @@
#include <math.h>
-#include <GP_Context.h>
-#include <GP_GetPutPixel.h>
+#include "core/GP_Context.h"
+#include "core/GP_GetPutPixel.h"
+#include "core/GP_Gamma.h"
-#include <GP_Debug.h>
+#include "core/GP_Debug.h"
-#include <GP_Resize.h>
+#include "GP_Resize.h"
int GP_FilterInterpolate_NN(const GP_Context *src, GP_Context *dst,
GP_ProgressCallback *callback)
@@ -246,7 +247,7 @@ int GP_FilterInterpolate_Cubic(const GP_Context *src, GP_Context *dst,
return 0;
}
-#define MUL 2048
+#define MUL 1024
#define MUL_I(a, b) ({ a[0] *= b[0]; @@ -258,6 +259,8 @@ int GP_FilterInterpolate_Cubic(const GP_Context *src, GP_Context *dst,
#define SUM_I(a) ((a)[0] + (a)[1] + (a)[2] + (a)[3])
+#include "core/GP_GammaCorrection.h"
+
int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
GP_ProgressCallback *callback)
{
@@ -268,6 +271,24 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
src->w, src->h, dst->w, dst->h,
1.00 * dst->w / src->w, 1.00 * dst->h / src->h);
+ uint16_t *R_2_LIN = NULL;
+ uint16_t *G_2_LIN = NULL;
+ uint16_t *B_2_LIN = NULL;
+
+ uint8_t *R_2_GAMMA = NULL;
+ uint8_t *G_2_GAMMA = NULL;
+ uint8_t *B_2_GAMMA = NULL;
+
+ if (src->gamma) {
+ R_2_LIN = src->gamma->tables[0]->u16;
+ G_2_LIN = src->gamma->tables[1]->u16;
+ B_2_LIN = src->gamma->tables[2]->u16;
+
+ R_2_GAMMA = src->gamma->tables[3]->u8;
+ G_2_GAMMA = src->gamma->tables[4]->u8;
+ B_2_GAMMA = src->gamma->tables[5]->u8;
+ }
+
for (i = 0; i < dst->h; i++) {
float y = (1.00 * i / dst->h) * src->h;
int32_t cvy[4];
@@ -306,7 +327,7 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
rv[1] = GP_Pixel_GET_R_RGB888(pix[1]);
rv[2] = GP_Pixel_GET_R_RGB888(pix[2]);
rv[3] = GP_Pixel_GET_R_RGB888(pix[3]);
-
+
gv[0] = GP_Pixel_GET_G_RGB888(pix[0]);
gv[1] = GP_Pixel_GET_G_RGB888(pix[1]);
gv[2] = GP_Pixel_GET_G_RGB888(pix[2]);
@@ -316,6 +337,24 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
bv[1] = GP_Pixel_GET_B_RGB888(pix[1]);
bv[2] = GP_Pixel_GET_B_RGB888(pix[2]);
bv[3] = GP_Pixel_GET_B_RGB888(pix[3]);
+
+
+ if (src->gamma) {
+ rv[0] = R_2_LIN[rv[0]];
+ rv[1] = R_2_LIN[rv[1]];
+ rv[2] = R_2_LIN[rv[2]];
+ rv[3] = R_2_LIN[rv[3]];
+
+ gv[0] = G_2_LIN[gv[0]];
+ gv[1] = G_2_LIN[gv[1]];
+ gv[2] = G_2_LIN[gv[2]];
+ gv[3] = G_2_LIN[gv[3]];
+
+ bv[0] = G_2_LIN[bv[0]];
+ bv[1] = G_2_LIN[bv[1]];
+ bv[2] = G_2_LIN[bv[2]];
+ bv[3] = G_2_LIN[bv[3]];
+ }
MUL_I(rv, cvy);
MUL_I(gv, cvy);
@@ -374,10 +413,30 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
r = (SUM_I(rv) + MUL*MUL/2) / MUL / MUL;
g = (SUM_I(gv) + MUL*MUL/2) / MUL / MUL;
b = (SUM_I(bv) + MUL*MUL/2) / MUL / MUL;
-
- CLAMP(r);
- CLAMP(g);
- CLAMP(b);
+
+ if (src->gamma) {
+ if (r > 1023)
+ r = 1023;
+ if (g > 1023)
+ g = 1023;
+ if (b > 1023)
+ b = 1023;
+
+ if (r < 0)
+ r = 0;
+ if (g < 0)
+ g = 0;
+ if (b < 0)
+ b = 0;
+
+ r = R_2_GAMMA[r];
+ g = G_2_GAMMA[g];
+ b = B_2_GAMMA[b];
+ } else {
+ CLAMP(r);
+ CLAMP(g);
+ CLAMP(b);
+ }
GP_Pixel pix = GP_Pixel_CREATE_RGB888((uint8_t)r, (uint8_t)g, (uint8_t)b);
GP_PutPixel_Raw_24BPP(dst, j, i, pix);
-----------------------------------------------------------------------
Summary of changes:
demos/c_simple/.gitignore | 9 ++
demos/grinder/.gitignore | 1 +
demos/particle/.gitignore | 1 +
demos/spiv/.gitignore | 1 +
demos/spiv/spiv.c | 13 ++-
demos/ttf2img/.gitignore | 1 +
doc/.gitignore | 1 +
include/core/GP_Context.h | 16 +++-
include/core/GP_Core.h | 3 +
include/core/GP_Gamma.h | 174 +++++++++++++++++++++++++++++++
include/core/GP_GammaCorrection.h | 4 +-
include/core/GP_GammaPixel.gen.h.t | 73 +++++++++++++
include/core/Makefile | 2 +-
libs/core/GP_Context.c | 15 +++
libs/core/GP_Gamma.c | 199 ++++++++++++++++++++++++++++++++++++
libs/filters/GP_Resize.c | 79 +++++++++++++--
16 files changed, 577 insertions(+), 15 deletions(-)
create mode 100644 demos/c_simple/.gitignore
create mode 100644 demos/grinder/.gitignore
create mode 100644 demos/particle/.gitignore
create mode 100644 demos/spiv/.gitignore
create mode 100644 demos/ttf2img/.gitignore
create mode 100644 doc/.gitignore
create mode 100644 include/core/GP_Gamma.h
create mode 100644 include/core/GP_GammaPixel.gen.h.t
create mode 100644 libs/core/GP_Gamma.c
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")