1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * Colorify. Changes the pixel's luminosity to a specified color
5 * Copyright (C) 1997 Francisco Bustamante
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <libgimp/gimp.h>
24 #include <libgimp/gimpui.h>
25
26 #include "libgimp/stdplugins-intl.h"
27
28
29 #define PLUG_IN_PROC "plug-in-colorify"
30 #define PLUG_IN_BINARY "colorify"
31 #define PLUG_IN_ROLE "gimp-colorify"
32 #define PLUG_IN_VERSION "1.1"
33
34 #define COLOR_SIZE 30
35
36 static void query (void);
37 static void run (const gchar *name,
38 gint nparams,
39 const GimpParam *param,
40 gint *nreturn_vals,
41 GimpParam **return_vals);
42
43 static void colorify (GimpDrawable *drawable,
44 GimpPreview *preview);
45 static gboolean colorify_dialog (GimpDrawable *drawable);
46 static void predefined_color_callback (GtkWidget *widget,
47 gpointer data);
48
49 typedef struct
50 {
51 GimpRGB color;
52 } ColorifyVals;
53
54 static ColorifyVals cvals =
55 {
56 { 1.0, 1.0, 1.0, 1.0 }
57 };
58
59 static GimpRGB button_color[] =
60 {
61 { 1.0, 0.0, 0.0, 1.0 },
62 { 1.0, 1.0, 0.0, 1.0 },
63 { 0.0, 1.0, 0.0, 1.0 },
64 { 0.0, 1.0, 1.0, 1.0 },
65 { 0.0, 0.0, 1.0, 1.0 },
66 { 1.0, 0.0, 1.0, 1.0 },
67 { 1.0, 1.0, 1.0, 1.0 },
68 };
69
70 const GimpPlugInInfo PLUG_IN_INFO =
71 {
72 NULL,
73 NULL,
74 query,
75 run,
76 };
77
78 static GtkWidget *custom_color_button = NULL;
79
80 static gint lum_red_lookup[256];
81 static gint lum_green_lookup[256];
82 static gint lum_blue_lookup[256];
83 static gint final_red_lookup[256];
84 static gint final_green_lookup[256];
85 static gint final_blue_lookup[256];
86
87
MAIN()88 MAIN ()
89
90 static void
91 query (void)
92 {
93 static const GimpParamDef args[] =
94 {
95 { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
96 { GIMP_PDB_IMAGE, "image", "Input image" },
97 { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
98 { GIMP_PDB_COLOR, "color", "Color to apply" }
99 };
100
101 gimp_install_procedure (PLUG_IN_PROC,
102 N_("Replace all colors with shades of a specified color"),
103 "Makes an average of the RGB channels and uses it "
104 "to set the color",
105 "Francisco Bustamante",
106 "Francisco Bustamante",
107 PLUG_IN_VERSION,
108 N_("Colorif_y..."),
109 "RGB*",
110 GIMP_PLUGIN,
111 G_N_ELEMENTS (args), 0,
112 args, NULL);
113 }
114
115 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)116 run (const gchar *name,
117 gint nparams,
118 const GimpParam *param,
119 gint *nreturn_vals,
120 GimpParam **return_vals)
121 {
122 GimpPDBStatusType status;
123 static GimpParam values[1];
124 GimpDrawable *drawable;
125 GimpRunMode run_mode;
126
127 INIT_I18N ();
128
129 status = GIMP_PDB_SUCCESS;
130 run_mode = param[0].data.d_int32;
131
132 values[0].type = GIMP_PDB_STATUS;
133 values[0].data.d_status = status;
134
135 *nreturn_vals = 1;
136 *return_vals = values;
137
138 drawable = gimp_drawable_get (param[2].data.d_drawable);
139
140 switch (run_mode)
141 {
142 case GIMP_RUN_INTERACTIVE:
143 gimp_get_data (PLUG_IN_PROC, &cvals);
144 if (!colorify_dialog (drawable))
145 return;
146 break;
147
148 case GIMP_RUN_NONINTERACTIVE:
149 if (nparams != 4)
150 status = GIMP_PDB_CALLING_ERROR;
151
152 if (status == GIMP_PDB_SUCCESS)
153 cvals.color = param[3].data.d_color;
154 break;
155
156 case GIMP_RUN_WITH_LAST_VALS:
157 /* Possibly retrieve data */
158 gimp_get_data (PLUG_IN_PROC, &cvals);
159 break;
160
161 default:
162 break;
163 }
164
165 if (status == GIMP_PDB_SUCCESS)
166 {
167 gimp_progress_init (_("Colorifying"));
168
169 colorify (drawable, NULL);
170
171 if (run_mode == GIMP_RUN_INTERACTIVE)
172 gimp_set_data (PLUG_IN_PROC, &cvals, sizeof (ColorifyVals));
173
174 if (run_mode != GIMP_RUN_NONINTERACTIVE)
175 gimp_displays_flush ();
176 }
177
178 gimp_drawable_detach (drawable);
179
180 values[0].data.d_status = status;
181 }
182
183 static void
colorify_func(const guchar * src,guchar * dest,gint bpp,gpointer data)184 colorify_func (const guchar *src,
185 guchar *dest,
186 gint bpp,
187 gpointer data)
188 {
189 gint lum;
190
191 lum = lum_red_lookup[src[0]] +
192 lum_green_lookup[src[1]] +
193 lum_blue_lookup[src[2]];
194
195 dest[0] = final_red_lookup[lum];
196 dest[1] = final_green_lookup[lum];
197 dest[2] = final_blue_lookup[lum];
198
199 if (bpp == 4)
200 dest[3] = src[3];
201 }
202
203 static void
colorify(GimpDrawable * drawable,GimpPreview * preview)204 colorify (GimpDrawable *drawable,
205 GimpPreview *preview)
206 {
207 gint i;
208
209 for (i = 0; i < 256; i ++)
210 {
211 lum_red_lookup[i] = i * GIMP_RGB_LUMINANCE_RED;
212 lum_green_lookup[i] = i * GIMP_RGB_LUMINANCE_GREEN;
213 lum_blue_lookup[i] = i * GIMP_RGB_LUMINANCE_BLUE;
214 final_red_lookup[i] = i * cvals.color.r;
215 final_green_lookup[i] = i * cvals.color.g;
216 final_blue_lookup[i] = i * cvals.color.b;
217 }
218
219 if (preview)
220 {
221 gint width, height, bytes;
222 guchar *src;
223
224 src = gimp_zoom_preview_get_source (GIMP_ZOOM_PREVIEW (preview),
225 &width, &height, &bytes);
226 for (i = 0; i < width * height; i++)
227 colorify_func (src + i * bytes, src + i * bytes, bytes, NULL);
228
229 gimp_preview_draw_buffer (preview, src, width * bytes);
230 g_free (src);
231 }
232 else
233 {
234 GimpPixelRgn srcPR, destPR;
235 gint x1, y1, x2, y2;
236 gpointer pr;
237 gint total_area;
238 gint area_so_far;
239 gint count;
240
241 gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
242
243 total_area = (x2 - x1) * (y2 - y1);
244 area_so_far = 0;
245
246 if (total_area <= 0)
247 return;
248
249 /* Initialize the pixel regions. */
250 gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, (x2 - x1), (y2 - y1),
251 FALSE, FALSE);
252 gimp_pixel_rgn_init (&destPR, drawable, x1, y1, (x2 - x1), (y2 - y1),
253 TRUE, TRUE);
254
255 for (pr = gimp_pixel_rgns_register (2, &srcPR, &destPR), count = 0;
256 pr != NULL;
257 pr = gimp_pixel_rgns_process (pr), count++)
258 {
259 const guchar *src = srcPR.data;
260 guchar *dest = destPR.data;
261 gint row;
262
263 for (row = 0; row < srcPR.h; row++)
264 {
265 const guchar *s = src;
266 guchar *d = dest;
267 gint pixels = srcPR.w;
268
269 while (pixels--)
270 {
271 colorify_func (s, d, srcPR.bpp, NULL);
272
273 s += srcPR.bpp;
274 d += destPR.bpp;
275 }
276
277 src += srcPR.rowstride;
278 dest += destPR.rowstride;
279 }
280
281 area_so_far += srcPR.w * srcPR.h;
282
283 if ((count % 16) == 0)
284 gimp_progress_update ((gdouble) area_so_far / (gdouble) total_area);
285 }
286
287 /* update the processed region */
288 gimp_drawable_flush (drawable);
289 gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
290 gimp_drawable_update (drawable->drawable_id, x1, y1, (x2 - x1), (y2 - y1));
291 }
292 }
293
294 static gboolean
colorify_dialog(GimpDrawable * drawable)295 colorify_dialog (GimpDrawable *drawable)
296 {
297 GtkWidget *dialog;
298 GtkWidget *main_vbox;
299 GtkWidget *preview;
300 GtkWidget *label;
301 GtkWidget *button;
302 GtkWidget *table;
303 GtkWidget *color_area;
304 gint i;
305 gboolean run;
306
307 gimp_ui_init (PLUG_IN_BINARY, TRUE);
308
309 dialog = gimp_dialog_new (_("Colorify"), PLUG_IN_ROLE,
310 NULL, 0,
311 gimp_standard_help_func, PLUG_IN_PROC,
312
313 _("_Cancel"), GTK_RESPONSE_CANCEL,
314 _("_OK"), GTK_RESPONSE_OK,
315
316 NULL);
317
318 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
319 GTK_RESPONSE_OK,
320 GTK_RESPONSE_CANCEL,
321 -1);
322
323 gimp_window_set_transient (GTK_WINDOW (dialog));
324
325 main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
326 gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
327 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
328 main_vbox, TRUE, TRUE, 0);
329 gtk_widget_show (main_vbox);
330
331 preview = gimp_zoom_preview_new_from_drawable_id (drawable->drawable_id);
332 gtk_box_pack_start (GTK_BOX (main_vbox), preview, TRUE, TRUE, 0);
333 gtk_widget_show (preview);
334 g_signal_connect_swapped (preview, "invalidated",
335 G_CALLBACK (colorify),
336 drawable);
337
338 table = gtk_table_new (2, 7, TRUE);
339 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
340 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
341 gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
342 gtk_widget_show (table);
343
344 label = gtk_label_new (_("Custom color:"));
345 gtk_table_attach (GTK_TABLE (table), label, 4, 6, 0, 1,
346 GTK_FILL, GTK_FILL, 0, 0);
347 gtk_widget_show (label);
348
349 custom_color_button = gimp_color_button_new (_("Colorify Custom Color"),
350 COLOR_SIZE, COLOR_SIZE,
351 &cvals.color,
352 GIMP_COLOR_AREA_FLAT);
353 g_signal_connect (custom_color_button, "color-changed",
354 G_CALLBACK (gimp_color_button_get_color),
355 &cvals.color);
356 g_signal_connect_swapped (custom_color_button, "color-changed",
357 G_CALLBACK (gimp_preview_invalidate),
358 preview);
359
360 gtk_table_attach (GTK_TABLE (table), custom_color_button, 6, 7, 0, 1,
361 GTK_FILL, GTK_FILL, 0, 0);
362 gtk_widget_show (custom_color_button);
363
364 for (i = 0; i < 7; i++)
365 {
366 button = gtk_button_new ();
367 color_area = gimp_color_area_new (&button_color[i],
368 GIMP_COLOR_AREA_FLAT,
369 GDK_BUTTON2_MASK);
370 gtk_widget_set_size_request (GTK_WIDGET (color_area),
371 COLOR_SIZE, COLOR_SIZE);
372 gtk_container_add (GTK_CONTAINER (button), color_area);
373 g_signal_connect (button, "clicked",
374 G_CALLBACK (predefined_color_callback),
375 &button_color[i]);
376 gtk_widget_show (color_area);
377
378 gtk_table_attach (GTK_TABLE (table), button, i, i + 1, 1, 2,
379 GTK_FILL, GTK_FILL, 0, 0);
380 gtk_widget_show (button);
381 }
382
383 gtk_widget_show (dialog);
384
385 run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
386
387 gtk_widget_destroy (dialog);
388
389 return run;
390 }
391
392 static void
predefined_color_callback(GtkWidget * widget,gpointer data)393 predefined_color_callback (GtkWidget *widget,
394 gpointer data)
395 {
396 gimp_color_button_set_color (GIMP_COLOR_BUTTON (custom_color_button),
397 (GimpRGB *) data);
398 }
399