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, &param);
288   gimp_rgn_iterate2 (drawable, 0 /* unused */, color_enhance_func, &param);
289 }
290