1 /* Color Enhance 0.10 --- image filter plug-in for GIMP
2 *
3 * Copyright (C) 1999 Martin Weber
4 * Copyright (C) 1996 Federico Mena Quintero
5 *
6 * You can contact me at martweb@gmx.net
7 * You can contact the original GIMP authors at gimp@xcf.berkeley.edu
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23 #include "config.h"
24
25 #include <libgimp/gimp.h>
26
27 #include "libgimp/stdplugins-intl.h"
28
29
30 #define PLUG_IN_PROC "plug-in-color-enhance"
31
32
33 /* Declare local functions.
34 */
35 static void query (void);
36 static void run (const gchar *name,
37 gint nparams,
38 const GimpParam *param,
39 gint *nreturn_vals,
40 GimpParam **return_vals);
41
42 static void Color_Enhance (GimpDrawable *drawable);
43 static void indexed_Color_Enhance (gint32 image_ID);
44
45
46 const GimpPlugInInfo PLUG_IN_INFO =
47 {
48 NULL, /* init_proc */
49 NULL, /* quit_proc */
50 query, /* query_proc */
51 run, /* run_proc */
52 };
53
54
MAIN()55 MAIN ()
56
57 static void
58 query (void)
59 {
60 static const GimpParamDef args[] =
61 {
62 { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
63 { GIMP_PDB_IMAGE, "image", "Input image" },
64 { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }
65 };
66
67 gimp_install_procedure (PLUG_IN_PROC,
68 N_("Stretch color saturation to cover maximum possible range"),
69 "This simple plug-in does an automatic saturation "
70 "stretch. For each channel in the image, it finds "
71 "the minimum and maximum values... it uses those "
72 "values to stretch the individual histograms to the "
73 "full range. For some images it may do just what "
74 "you want; for others it may not work that well. "
75 "This version differs from Contrast Autostretch in "
76 "that it works in HSV space, and preserves hue.",
77 "Martin Weber",
78 "Martin Weber",
79 "1997",
80 N_("_Color Enhance (legacy)"),
81 "RGB*, INDEXED*",
82 GIMP_PLUGIN,
83 G_N_ELEMENTS (args), 0,
84 args, NULL);
85
86 gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Colors/Auto");
87 }
88
89 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)90 run (const gchar *name,
91 gint nparams,
92 const GimpParam *param,
93 gint *nreturn_vals,
94 GimpParam **return_vals)
95 {
96 static GimpParam values[1];
97 GimpDrawable *drawable;
98 GimpPDBStatusType status = GIMP_PDB_SUCCESS;
99 GimpRunMode run_mode;
100 gint32 image_ID;
101
102 INIT_I18N();
103
104 run_mode = param[0].data.d_int32;
105
106 /* Get the specified drawable */
107 drawable = gimp_drawable_get (param[2].data.d_drawable);
108 image_ID = param[1].data.d_image;
109
110 /* Make sure that the drawable is gray or RGB color */
111 if (gimp_drawable_is_rgb (drawable->drawable_id) ||
112 gimp_drawable_is_gray (drawable->drawable_id))
113 {
114 gimp_progress_init (_("Color Enhance"));
115 gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
116 Color_Enhance (drawable);
117
118 if (run_mode != GIMP_RUN_NONINTERACTIVE)
119 gimp_displays_flush ();
120 }
121 else if (gimp_drawable_is_indexed (drawable->drawable_id))
122 {
123 indexed_Color_Enhance (image_ID);
124
125 if (run_mode != GIMP_RUN_NONINTERACTIVE)
126 gimp_displays_flush ();
127 }
128 else
129 {
130 status = GIMP_PDB_EXECUTION_ERROR;
131 }
132
133 *nreturn_vals = 1;
134 *return_vals = values;
135
136 values[0].type = GIMP_PDB_STATUS;
137 values[0].data.d_status = status;
138
139 gimp_drawable_detach (drawable);
140 }
141
142 static gdouble
get_v(const guchar * src)143 get_v (const guchar *src)
144 {
145 gdouble h, z, v;
146 gint c, m, y;
147 gint k;
148 guchar map[3];
149
150 c = 255 - src[0];
151 m = 255 - src[1];
152 y = 255 - src[2];
153
154 k = c;
155 if (m < k) k = m;
156 if (y < k) k = y;
157
158 map[0] = c - k;
159 map[1] = m - k;
160 map[2] = y - k;
161
162 gimp_rgb_to_hsv4(map, &h, &z, &v);
163
164 return v;
165 }
166
167 static void
enhance_it(const guchar * src,guchar * dest,gdouble vlo,gdouble vhi)168 enhance_it (const guchar *src, guchar *dest, gdouble vlo, gdouble vhi)
169 {
170 gdouble h, z, v;
171 gint c, m, y;
172 gint k;
173 guchar map[3];
174
175 c = 255 - src[0];
176 m = 255 - src[1];
177 y = 255 - src[2];
178
179 k = c;
180 if (m < k) k = m;
181 if (y < k) k = y;
182
183 map[0] = c - k;
184 map[1] = m - k;
185 map[2] = y - k;
186
187 gimp_rgb_to_hsv4 (map, &h, &z, &v);
188
189 if (vhi != vlo)
190 v = (v - vlo) / (vhi - vlo);
191
192 gimp_hsv_to_rgb4 (map, h, z, v);
193
194 c = map[0];
195 m = map[1];
196 y = map[2];
197
198 c += k;
199 if (c > 255) c = 255;
200 m += k;
201 if (m > 255) m = 255;
202 y += k;
203 if (y > 255) y = 255;
204
205 dest[0] = 255 - c;
206 dest[1] = 255 - m;
207 dest[2] = 255 - y;
208 }
209
210 static void
indexed_Color_Enhance(gint32 image_ID)211 indexed_Color_Enhance (gint32 image_ID)
212 {
213 guchar *cmap;
214 gint ncols,i;
215 gdouble vhi = 0.0, vlo = 1.0;
216
217 cmap = gimp_image_get_colormap (image_ID, &ncols);
218
219 if (!cmap)
220 {
221 g_message ("colormap was NULL! Quitting.");
222 gimp_quit();
223 }
224
225 for (i = 0; i < ncols; i++)
226 {
227 gdouble v = get_v (&cmap[3 * i]);
228
229 if (v > vhi) vhi = v;
230 if (v < vlo) vlo = v;
231 }
232
233 for (i = 0; i < ncols; i++)
234 {
235 enhance_it (&cmap[3 * i], &cmap[3 * i], vlo, vhi);
236 }
237
238 gimp_image_set_colormap (image_ID, cmap, ncols);
239 }
240
241 typedef struct
242 {
243 gdouble vhi;
244 gdouble vlo;
245 gboolean has_alpha;
246 } ColorEnhanceParam_t;
247
248 static void
find_vhi_vlo(const guchar * src,gint bpp,gpointer data)249 find_vhi_vlo (const guchar *src,
250 gint bpp,
251 gpointer data)
252 {
253 ColorEnhanceParam_t *param = (ColorEnhanceParam_t*) data;
254
255 if (!param->has_alpha || src[3])
256 {
257 gdouble v = get_v (src);
258
259 if (v > param->vhi) param->vhi = v;
260 if (v < param->vlo) param->vlo = v;
261 }
262 }
263
264 static void
color_enhance_func(const guchar * src,guchar * dest,gint bpp,gpointer data)265 color_enhance_func (const guchar *src,
266 guchar *dest,
267 gint bpp,
268 gpointer data)
269 {
270 ColorEnhanceParam_t *param = (ColorEnhanceParam_t*) data;
271
272 enhance_it (src, dest, param->vlo, param->vhi);
273
274 if (param->has_alpha)
275 dest[3] = src[3];
276 }
277
278 static void
Color_Enhance(GimpDrawable * drawable)279 Color_Enhance (GimpDrawable *drawable)
280 {
281 ColorEnhanceParam_t param;
282
283 param.has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);
284 param.vhi = 0.0;
285 param.vlo = 1.0;
286
287 gimp_rgn_iterate1 (drawable, 0 /* unused */, find_vhi_vlo, ¶m);
288 gimp_rgn_iterate2 (drawable, 0 /* unused */, color_enhance_func, ¶m);
289 }
290