]> git.sesse.net Git - mlt/blob - src/modules/plusgpl/filter_lumaliftgaingamma.c
Merge pull request #37 from jliljebl/luma-lift-gain-gamma
[mlt] / src / modules / plusgpl / filter_lumaliftgaingamma.c
1 /*
2  * filter_lumaliftgaingamma.c -- Lift Gain Gamma filter for luma correction
3  * Copyright (C) 2014 Janne Liljeblad
4  * Author: Janne Liljeblad
5  *
6  * This filter is a port from Gimp and is distributed under a compatible license.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  */
22
23 #include <framework/mlt_filter.h>
24 #include <framework/mlt_frame.h>
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <math.h>
29 #include <string.h>
30
31 static double clamp( double value, double low, double high)
32 {
33         if (value < low)
34                 value = low;
35         if (value > high)
36                 value = high;
37         return value;
38 }
39
40 static double lut_value( double value, double lift, double gain, double gamma )
41 {
42         double nvalue;
43         double power;
44
45         value = clamp( value + lift, 0, 1 );
46
47         if( gain < 0.0)
48                 value = value * (1.0 + gain);
49         else
50                 value = value + ((1.0 - value) * gain);
51
52         if(gamma < 0.0)
53         {
54                 if (value > 0.5)
55                         nvalue = 1.0 - value;
56                 else
57                         nvalue = value;
58
59                 if (nvalue < 0.0)
60                         nvalue = 0.0;
61
62                 nvalue = 0.5 * pow (nvalue * 2.0 , (double) (1.0 + gamma));
63                 
64                 if (value > 0.5)
65                         value = 1.0 - nvalue;
66                 else
67                         value = nvalue;
68         }
69         else
70         {
71                 if (value > 0.5)
72                         nvalue = 1.0 - value;
73                 else
74                         nvalue = value;
75
76                 if (nvalue < 0.0)
77                         nvalue = 0.0;
78
79                 power = (gamma == 1.0) ? 127 : 1.0 / (1.0 - gamma);
80                 nvalue = 0.5 * pow (2.0 * nvalue, power);
81
82                 if (value > 0.5)
83                         value = 1.0 - nvalue;
84                 else
85                         value = nvalue;
86         }
87
88         return value;
89 }
90
91 static void fill_lgg_lut(int lgg_lut[], double lift, double gain, double gamma)
92 {
93         int i;
94         double val;
95         for( i = 0; i < 256; i++ )
96         {
97                 val = (double) i / 255.0;
98                 lgg_lut[ i ] = (int) (lut_value( val, lift, gain, gamma ) * 255.0);
99         }
100 }
101
102 /** Do image filtering.
103 */
104 static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
105 {
106         // Get the image
107         mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame );
108         mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
109         mlt_position position = mlt_filter_get_position( filter, frame );
110         mlt_position length = mlt_filter_get_length2( filter, frame );
111
112         *format = mlt_image_rgb24;
113         int error = mlt_frame_get_image( frame, image, format, width, height, 0 );
114
115         // Only process if we have no error and a valid colour space
116         if ( error == 0 )
117         {
118                 // Get values and force accepted ranges
119                 double lift = mlt_properties_anim_get_double( properties, "lift", position, length );
120                 double gain = mlt_properties_anim_get_double( properties, "gain", position, length );
121                 double gamma = mlt_properties_anim_get_double( properties, "gamma", position, length );
122                 lift = clamp( lift, -0.5, 0.5 );
123                 gain = clamp( gain, -0.5, 0.5 );
124                 gamma = clamp( gamma, -1.0, 1.0 );
125
126                 // Build lut
127                 int lgg_lut[256];
128                 fill_lgg_lut( lgg_lut, lift, gain, gamma);
129
130                 // Filter
131                 int i = *width * *height + 1;
132                 uint8_t *p = *image;
133                 uint8_t *r = *image;
134                 while ( --i )
135                 {
136                         *p ++ = lgg_lut[ *r ++ ];
137                         *p ++ = lgg_lut[ *r ++ ];
138                         *p ++ = lgg_lut[ *r ++ ];
139                 }
140         }
141
142         return error;
143 }
144
145 /** Filter processing.
146 */
147 static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
148 {
149         // Push the frame filter
150         mlt_frame_push_service( frame, filter );
151         mlt_frame_push_get_image( frame, filter_get_image );
152         return frame;
153 }
154
155 /** Constructor for the filter.
156 */
157 mlt_filter filter_lumaliftgaingamma_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
158 {
159         mlt_filter filter = mlt_filter_new( );
160         if ( filter != NULL )
161         {
162                 filter->process = filter_process;
163                 mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "lift", "0" );
164                 mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "gain", "0" );
165                 mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "gamma", "0" );
166         }
167         return filter;
168 }
169