1 /*****************************************************************************
2 * This file is part of gfxprim library. *
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. *
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. *
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 *
19 * Copyright (C) 2009-2013 Cyril Hrubis <metan@ucw.cz> *
21 *****************************************************************************/
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
)
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
)
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
)
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
)
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
);
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));
81 GP_WARN("Malloc failed :(");
87 i
->out_bits
= out_bits
;
89 i
->type
= GP_CORRECTION_GAMMA
;
92 fill_table16(i
, gamma
, in_bits
, out_bits
);
94 fill_table8(i
, gamma
, in_bits
, out_bits
);
96 /* Insert it into link list */
103 static void put_table(GP_GammaTable
*table
)
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
,
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
) {
127 tables
= table
->next
;
129 prev
->next
= table
->next
;
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*));
145 GP_WARN("Malloc failed :(");
149 /* NULL the pointers */
150 for (i
= 0; i
< 2 * channels
; i
++)
151 res
->tables
[i
] = NULL
;
153 res
->pixel_type
= pixel_type
;
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
);
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
);
181 GP_Gamma
*GP_GammaCopy(GP_Gamma
*self
)
187 void GP_GammaRelease(GP_Gamma
*self
)
189 int channels
= GP_PixelTypes
[self
->pixel_type
].numchannels
, i
;
191 GP_DEBUG(1, "Releasing Gamma table %s gamma %f", GP_PixelTypeName(self
->pixel_type
), self
->tables
[0]->gamma
);
193 for (i
= 0; i
< channels
; i
++)
194 put_table(self
->tables
[i
]);
196 if (--self
->ref_count
== 0) {
197 GP_DEBUG(2, "Gamma ref_count == 0, releasing...");
202 static const char *correction_type_names
[] = {
207 static const char *correction_type_name(enum GP_CorrectionType type
)
209 if (type
> GP_CORRECTION_sRGB
)
212 return correction_type_names
[type
];
215 void GP_GammaPrint(const GP_Gamma
*self
)
217 printf("Correction tables:\n");
219 const GP_PixelTypeDescription
*desc
= GP_PixelTypeDesc(self
->pixel_type
);
223 for (i
= 0; i
< desc
->numchannels
; i
++) {
224 enum GP_CorrectionType type
= self
->tables
[i
]->type
;
226 printf(" %s: %s", desc
->channels
[i
].name
,
227 correction_type_name(type
));
229 if (type
== GP_CORRECTION_GAMMA
)
230 printf(" gamma = %.2f", self
->tables
[i
]->gamma
);