spiv: Fix image list counter
[gfxprim.git] / libs / core / GP_Gamma.c
blob26286b03f43add4301162194f6bbf1ec15306c08
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2013 Cyril Hrubis <metan@ucw.cz> *
20 * *
21 *****************************************************************************/
23 #include <math.h>
25 #include "GP_Pixel.h"
26 #include "GP_Debug.h"
28 #include "GP_Gamma.h"
30 static GP_GammaTable *tables = NULL;
32 static void fill_table8(GP_GammaTable *table, float gamma,
33 uint8_t in_bits, uint8_t out_bits)
35 unsigned int i;
36 unsigned int in_max = (1<<in_bits) - 1;
37 unsigned int out_max = (1<<out_bits) - 1;
39 GP_DEBUG(3, "Initalizing gamma table %f", gamma);
41 for (i = 0; i < (1U<<in_bits); i++)
42 table->u8[i] = pow((float)i / in_max, gamma) * out_max + 0.5;
45 static void fill_table16(GP_GammaTable *table, float gamma,
46 uint8_t in_bits, uint8_t out_bits)
48 unsigned int i;
49 unsigned int in_max = (1<<in_bits) - 1;
50 unsigned int out_max = (1<<out_bits) - 1;
52 GP_DEBUG(3, "Initalizing gamma table %f", gamma);
54 for (i = 0; i < (1U<<in_bits); i++)
55 table->u16[i] = pow((float)i / in_max, gamma) * out_max + 0.5;
58 static GP_GammaTable *get_table(float gamma, uint8_t in_bits, uint8_t out_bits)
60 GP_GammaTable *i;
62 for (i = tables; i != NULL; i = i->next)
63 if (gamma == i->gamma && in_bits == i->in_bits &&
64 out_bits == i->out_bits)
65 break;
67 if (i != NULL) {
68 GP_DEBUG(2, "Found Gamma table Gamma %f, in_bits %u, "
69 "out_bits %u, ref_count %u", i->gamma, i->in_bits,
70 i->out_bits, i->ref_count);
71 i->ref_count++;
72 return i;
75 GP_DEBUG(2, "Creating Gamma table Gamma %f, in_bits %u, out_bits %u",
76 gamma, in_bits, out_bits);
78 i = malloc(sizeof(GP_GammaTable) + (1U<<in_bits) * (out_bits > 8 ? 2 : 1));
80 if (i == NULL) {
81 GP_WARN("Malloc failed :(");
82 return NULL;
85 i->gamma = gamma;
86 i->in_bits = in_bits;
87 i->out_bits = out_bits;
88 i->ref_count = 1;
89 i->type = GP_CORRECTION_GAMMA;
91 if (out_bits > 8)
92 fill_table16(i, gamma, in_bits, out_bits);
93 else
94 fill_table8(i, gamma, in_bits, out_bits);
96 /* Insert it into link list */
97 i->next = tables;
98 tables = i;
100 return i;
103 static void put_table(GP_GammaTable *table)
105 if (table == NULL)
106 return;
108 table->ref_count--;
110 GP_DEBUG(2, "Putting gamma table Gamma %f, in_bits %u, out_bits %u, "
111 "ref_count %u", table->gamma, table->in_bits, table->out_bits,
112 table->ref_count);
114 if (table->ref_count == 0) {
115 GP_DEBUG(2, "Gamma table ref_count == 0, removing...");
117 GP_GammaTable *i, *prev = NULL;
119 /* Remove from link list and free */
120 for (i = tables; i != NULL; i = i->next) {
121 if (table == i)
122 break;
123 prev = i;
126 if (prev == NULL)
127 tables = table->next;
128 else
129 prev->next = table->next;
131 free(table);
135 GP_Gamma *GP_GammaAcquire(GP_PixelType pixel_type, float gamma)
137 GP_CHECK_VALID_PIXELTYPE(pixel_type);
138 int channels = GP_PixelTypes[pixel_type].numchannels, i;
140 GP_DEBUG(1, "Acquiring Gamma table %s gamma %f", GP_PixelTypeName(pixel_type), gamma);
142 GP_Gamma *res = malloc(sizeof(struct GP_Gamma) + 2 * channels * sizeof(void*));
144 if (res == NULL) {
145 GP_WARN("Malloc failed :(");
146 return NULL;
149 /* NULL the pointers */
150 for (i = 0; i < 2 * channels; i++)
151 res->tables[i] = NULL;
153 res->pixel_type = pixel_type;
154 res->ref_count = 1;
156 /* Gamma to linear tables n bits -> n + 2 bits */
157 for (i = 0; i < channels; i++) {
158 unsigned int chan_size = GP_PixelTypes[pixel_type].channels[i].size;
159 res->tables[i] = get_table(gamma, chan_size, chan_size + 2);
161 if (res->tables[i] == NULL) {
162 GP_GammaRelease(res);
163 return NULL;
167 /* And reverse tables, n + 2 bits -> n bits */
168 for (i = 0; i < channels; i++) {
169 unsigned int chan_size = GP_PixelTypes[pixel_type].channels[i].size;
170 res->tables[i + channels] = get_table(1/gamma, chan_size + 2, chan_size);
172 if (res->tables[i] == NULL) {
173 GP_GammaRelease(res);
174 return NULL;
178 return res;
181 GP_Gamma *GP_GammaCopy(GP_Gamma *self)
183 self->ref_count++;
184 return self;
187 void GP_GammaRelease(GP_Gamma *self)
189 int channels, i;
191 if (!self)
192 return;
194 channels = GP_PixelTypes[self->pixel_type].numchannels;
196 GP_DEBUG(1, "Releasing Gamma table %s gamma %f", GP_PixelTypeName(self->pixel_type), self->tables[0]->gamma);
198 for (i = 0; i < channels; i++)
199 put_table(self->tables[i]);
201 if (--self->ref_count == 0) {
202 GP_DEBUG(2, "Gamma ref_count == 0, releasing...");
203 free(self);
207 static const char *correction_type_names[] = {
208 "Gamma",
209 "sRGB",
212 static const char *correction_type_name(enum GP_CorrectionType type)
214 if (type > GP_CORRECTION_sRGB)
215 return "Invalid";
217 return correction_type_names[type];
220 void GP_GammaPrint(const GP_Gamma *self)
222 printf("Correction tables:\n");
224 const GP_PixelTypeDescription *desc = GP_PixelTypeDesc(self->pixel_type);
226 unsigned int i;
228 for (i = 0; i < desc->numchannels; i++) {
229 enum GP_CorrectionType type = self->tables[i]->type;
231 printf(" %s: %s", desc->channels[i].name,
232 correction_type_name(type));
234 if (type == GP_CORRECTION_GAMMA)
235 printf(" gamma = %.2f", self->tables[i]->gamma);
237 printf("\n");