~ubuntu-branches/ubuntu/karmic/gimp/karmic-security

« back to all changes in this revision

Viewing changes to plug-ins/common/colortoalpha.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2008-10-06 13:30:41 UTC
  • mfrom: (1.1.15 upstream)
  • Revision ID: james.westby@ubuntu.com-20081006133041-axco233xt49jobn7
Tags: 2.6.0-1ubuntu1
* Sync on debian and new version (lp: #276839)
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch:
  - updated some strings for ubuntu
* debian/rules:
  - updated translation templates

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Color To Alpha plug-in v1.0 by Seth Burgess, sjburges@gimp.org 1999/05/14
3
 
 *  with algorithm by clahey
4
 
 */
5
 
 
6
 
/* GIMP - The GNU Image Manipulation Program
7
 
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
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 2 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, write to the Free Software
21
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
 
 */
23
 
 
24
 
#include "config.h"
25
 
 
26
 
#include <libgimp/gimp.h>
27
 
#include <libgimp/gimpui.h>
28
 
 
29
 
#include "libgimp/stdplugins-intl.h"
30
 
 
31
 
 
32
 
#define PLUG_IN_PROC   "plug-in-colortoalpha"
33
 
#define PLUG_IN_BINARY "colortoaplha"
34
 
#define PRV_WIDTH      40
35
 
#define PRV_HEIGHT     20
36
 
 
37
 
 
38
 
typedef struct
39
 
{
40
 
  GimpRGB  color;
41
 
} C2AValues;
42
 
 
43
 
 
44
 
/* Declare local functions.
45
 
 */
46
 
static void        query                  (void);
47
 
static void        run                    (const gchar       *name,
48
 
                                           gint               nparams,
49
 
                                           const GimpParam   *param,
50
 
                                           gint              *nreturn_vals,
51
 
                                           GimpParam        **return_vals);
52
 
 
53
 
static inline void color_to_alpha         (GimpRGB           *src,
54
 
                                           const GimpRGB     *color);
55
 
static void        to_alpha_func          (const guchar      *src,
56
 
                                           guchar            *dest,
57
 
                                           gint               bpp,
58
 
                                           gpointer           data);
59
 
 
60
 
/* UI stuff */
61
 
static gboolean    color_to_alpha_dialog  (GimpDrawable      *drawable);
62
 
static void        color_to_alpha_preview (GimpPreview       *preview,
63
 
                                           GimpDrawable      *drawable);
64
 
 
65
 
 
66
 
const GimpPlugInInfo PLUG_IN_INFO =
67
 
{
68
 
  NULL,  /* init_proc  */
69
 
  NULL,  /* quit_proc  */
70
 
  query, /* query_proc */
71
 
  run,   /* run_proc   */
72
 
};
73
 
 
74
 
static C2AValues pvals =
75
 
{
76
 
  { 1.0, 1.0, 1.0, 1.0 } /* white default */
77
 
};
78
 
 
79
 
 
80
 
MAIN ()
81
 
 
82
 
static void
83
 
query (void)
84
 
{
85
 
  static const GimpParamDef args[] =
86
 
  {
87
 
    { GIMP_PDB_INT32,    "run-mode", "Interactive, non-interactive" },
88
 
    { GIMP_PDB_IMAGE,    "image",    "Input image (unused)"         },
89
 
    { GIMP_PDB_DRAWABLE, "drawable", "Input drawable"               },
90
 
    { GIMP_PDB_COLOR,    "color",    "Color to remove"              }
91
 
  };
92
 
 
93
 
  gimp_install_procedure (PLUG_IN_PROC,
94
 
                          N_("Convert a specified color to transparency"),
95
 
                          "This replaces as much of a given color as possible "
96
 
                          "in each pixel with a corresponding amount of alpha, "
97
 
                          "then readjusts the color accordingly.",
98
 
                          "Seth Burgess",
99
 
                          "Seth Burgess <sjburges@gimp.org>",
100
 
                          "7th Aug 1999",
101
 
                          N_("Color to _Alpha..."),
102
 
                          "RGB*",
103
 
                          GIMP_PLUGIN,
104
 
                          G_N_ELEMENTS (args), 0,
105
 
                          args, NULL);
106
 
 
107
 
  gimp_plugin_menu_register (PLUG_IN_PROC,
108
 
                             "<Image>/Colors/Modify");
109
 
  gimp_plugin_menu_register (PLUG_IN_PROC,
110
 
                             "<Image>/Layer/Transparency/Modify");
111
 
}
112
 
 
113
 
static void
114
 
run (const gchar      *name,
115
 
     gint              nparams,
116
 
     const GimpParam  *param,
117
 
     gint             *nreturn_vals,
118
 
     GimpParam       **return_vals)
119
 
{
120
 
  static GimpParam   values[1];
121
 
  GimpDrawable      *drawable;
122
 
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
123
 
  GimpRunMode        run_mode;
124
 
  gint32             image_ID;
125
 
 
126
 
  run_mode = param[0].data.d_int32;
127
 
 
128
 
  *nreturn_vals = 1;
129
 
  *return_vals  = values;
130
 
 
131
 
  INIT_I18N ();
132
 
 
133
 
  values[0].type          = GIMP_PDB_STATUS;
134
 
  values[0].data.d_status = status;
135
 
 
136
 
  image_ID = param[1].data.d_image;
137
 
  drawable = gimp_drawable_get (param[2].data.d_drawable);
138
 
 
139
 
  switch (run_mode)
140
 
    {
141
 
    case GIMP_RUN_INTERACTIVE:
142
 
      gimp_get_data (PLUG_IN_PROC, &pvals);
143
 
      if (! color_to_alpha_dialog (drawable))
144
 
        {
145
 
          gimp_drawable_detach (drawable);
146
 
          return;
147
 
        }
148
 
      break;
149
 
 
150
 
    case GIMP_RUN_NONINTERACTIVE:
151
 
      if (nparams != 4)
152
 
        status = GIMP_PDB_CALLING_ERROR;
153
 
 
154
 
      if (status == GIMP_PDB_SUCCESS)
155
 
        pvals.color = param[3].data.d_color;
156
 
      break;
157
 
 
158
 
    case GIMP_RUN_WITH_LAST_VALS:
159
 
      gimp_get_data (PLUG_IN_PROC, &pvals);
160
 
      break;
161
 
 
162
 
    default:
163
 
      break;
164
 
    }
165
 
 
166
 
  if (status == GIMP_PDB_SUCCESS &&
167
 
      gimp_drawable_is_rgb (drawable->drawable_id) &&
168
 
      gimp_drawable_is_layer (drawable->drawable_id))
169
 
    {
170
 
      gboolean lock_alpha;
171
 
 
172
 
      gimp_image_undo_group_start (image_ID);
173
 
 
174
 
      /*  Add alpha if not present */
175
 
      gimp_layer_add_alpha (drawable->drawable_id);
176
 
 
177
 
      /*  Reget the drawable, bpp might have changed  */
178
 
      drawable = gimp_drawable_get (drawable->drawable_id);
179
 
 
180
 
      /*  Unset 'Lock alpha'  */
181
 
      lock_alpha = gimp_layer_get_lock_alpha (drawable->drawable_id);
182
 
      gimp_layer_set_lock_alpha (drawable->drawable_id, FALSE);
183
 
 
184
 
      gimp_progress_init (_("Removing color"));
185
 
      gimp_rgn_iterate2 (drawable, 0 /* unused */, to_alpha_func, NULL);
186
 
 
187
 
      gimp_layer_set_lock_alpha (drawable->drawable_id, lock_alpha);
188
 
 
189
 
      gimp_image_undo_group_end (image_ID);
190
 
 
191
 
      if (run_mode != GIMP_RUN_NONINTERACTIVE)
192
 
        gimp_displays_flush ();
193
 
    }
194
 
 
195
 
  gimp_drawable_detach (drawable);
196
 
 
197
 
  if (run_mode == GIMP_RUN_INTERACTIVE)
198
 
    gimp_set_data (PLUG_IN_PROC, &pvals, sizeof (pvals));
199
 
 
200
 
  values[0].data.d_status = status;
201
 
}
202
 
 
203
 
static inline void
204
 
color_to_alpha (GimpRGB       *src,
205
 
                const GimpRGB *color)
206
 
{
207
 
  GimpRGB alpha;
208
 
 
209
 
  alpha.a = src->a;
210
 
 
211
 
  if (color->r < 0.0001)
212
 
    alpha.r = src->r;
213
 
  else if (src->r > color->r)
214
 
    alpha.r = (src->r - color->r) / (1.0 - color->r);
215
 
  else if (src->r < color->r)
216
 
    alpha.r = (color->r - src->r) / color->r;
217
 
  else alpha.r = 0.0;
218
 
 
219
 
  if (color->g < 0.0001)
220
 
    alpha.g = src->g;
221
 
  else if (src->g > color->g)
222
 
    alpha.g = (src->g - color->g) / (1.0 - color->g);
223
 
  else if (src->g < color->g)
224
 
    alpha.g = (color->g - src->g) / (color->g);
225
 
  else alpha.g = 0.0;
226
 
 
227
 
  if (color->b < 0.0001)
228
 
    alpha.b = src->b;
229
 
  else if (src->b > color->b)
230
 
    alpha.b = (src->b - color->b) / (1.0 - color->b);
231
 
  else if (src->b < color->b)
232
 
    alpha.b = (color->b - src->b) / (color->b);
233
 
  else alpha.b = 0.0;
234
 
 
235
 
  if (alpha.r > alpha.g)
236
 
    {
237
 
      if (alpha.r > alpha.b)
238
 
        {
239
 
          src->a = alpha.r;
240
 
        }
241
 
      else
242
 
        {
243
 
          src->a = alpha.b;
244
 
        }
245
 
    }
246
 
  else if (alpha.g > alpha.b)
247
 
    {
248
 
      src->a = alpha.g;
249
 
    }
250
 
  else
251
 
    {
252
 
      src->a = alpha.b;
253
 
    }
254
 
 
255
 
  if (src->a < 0.0001)
256
 
    return;
257
 
 
258
 
  src->r = (src->r - color->r) / src->a + color->r;
259
 
  src->g = (src->g - color->g) / src->a + color->g;
260
 
  src->b = (src->b - color->b) / src->a + color->b;
261
 
 
262
 
  src->a *= alpha.a;
263
 
}
264
 
 
265
 
/*
266
 
 * An excerpt from a discussion on #gimp that sheds some light on the ideas
267
 
 * behind the algorithm that is being used here.
268
 
 *
269
 
  <clahey>   so if a1 > c1, a2 > c2, and a3 > c2 and a1 - c1 > a2-c2, a3-c3,
270
 
             then a1 = b1 * alpha + c1 * (1-alpha)
271
 
             So, maximizing alpha without taking b1 above 1 gives
272
 
             a1 = alpha + c1(1-alpha) and therefore alpha = (a1-c1) / (1-c1).
273
 
  <sjburges> clahey: btw, the ordering of that a2, a3 in the white->alpha didn't
274
 
             matter
275
 
  <clahey>   sjburges: You mean that it could be either a1, a2, a3 or
276
 
             a1, a3, a2?
277
 
  <sjburges> yeah
278
 
  <sjburges> because neither one uses the other
279
 
  <clahey>   sjburges: That's exactly as it should be.  They are both just
280
 
             getting reduced to the same amount, limited by the the darkest
281
 
             color.
282
 
  <clahey>   Then a2 = b2 * alpha + c2 * (1- alpha).  Solving for b2 gives
283
 
             b2 = (a1-c2)/alpha + c2.
284
 
  <sjburges> yeah
285
 
  <clahey>   That gives us are formula for if the background is darker than the
286
 
             foreground? Yep.
287
 
  <clahey>   Next if a1 < c1, a2 < c2, a3 < c3, and c1-a1 > c2-a2, c3-a3, and
288
 
             by our desired result a1 = b1 * alpha + c1 * (1-alpha),
289
 
             we maximize alpha without taking b1 negative gives
290
 
             alpha = 1 - a1 / c1.
291
 
  <clahey>   And then again, b2 = (a2-c2) / alpha + c2 by the same formula.
292
 
             (Actually, I think we can use that formula for all cases, though
293
 
             it may possibly introduce rounding error.
294
 
  <clahey>   sjburges: I like the idea of using floats to avoid rounding error.
295
 
             Good call.
296
 
 */
297
 
 
298
 
static void
299
 
to_alpha_func (const guchar *src,
300
 
              guchar       *dest,
301
 
              gint          bpp,
302
 
              gpointer      data)
303
 
{
304
 
  GimpRGB color;
305
 
 
306
 
  if (bpp == 3)
307
 
    gimp_rgba_set_uchar (&color, src[0], src[1], src[2], 255);
308
 
  else
309
 
    gimp_rgba_set_uchar (&color, src[0], src[1], src[2], src[3]);
310
 
 
311
 
  color_to_alpha (&color, &pvals.color);
312
 
  gimp_rgba_get_uchar (&color, &dest[0], &dest[1], &dest[2], &dest[3]);
313
 
}
314
 
 
315
 
static void
316
 
color_to_alpha_preview (GimpPreview  *preview,
317
 
                        GimpDrawable *drawable)
318
 
{
319
 
  GimpPixelRgn  src_rgn;
320
 
  gint          x, y;
321
 
  gint          width, height;
322
 
  gint          bpp;
323
 
  gint          i;
324
 
  guchar       *src, *dest;
325
 
 
326
 
  bpp = drawable->bpp;
327
 
  gimp_preview_get_position (preview, &x, &y);
328
 
  gimp_preview_get_size (preview, &width, &height);
329
 
 
330
 
  dest = g_new (guchar, width * height * 4);
331
 
  src = g_new (guchar, width * height * bpp);
332
 
 
333
 
  gimp_pixel_rgn_init (&src_rgn, drawable,
334
 
                       x, y, width, height,
335
 
                       FALSE, FALSE);
336
 
  gimp_pixel_rgn_get_rect (&src_rgn, src, x, y, width, height);
337
 
 
338
 
  for (i = 0; i < width * height; i++)
339
 
    to_alpha_func (src + i * bpp, dest + i * 4, bpp, NULL);
340
 
 
341
 
  g_free (src);
342
 
 
343
 
  /* Our code assumes that the drawable has an alpha channel (and adds
344
 
   * one later if the effect is actually performed). For that reason
345
 
   * we have to take care when drawing the preview.
346
 
   */
347
 
  if (bpp == 4)
348
 
    {
349
 
      gimp_preview_draw_buffer (preview, dest, width * 4);
350
 
    }
351
 
  else
352
 
    {
353
 
      /* This is not correct because we ignore the selection, but it
354
 
       * is the best we can easily do.
355
 
       */
356
 
      gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview->area),
357
 
                              0, 0, width, height,
358
 
                              GIMP_RGBA_IMAGE, dest, width * 4);
359
 
    }
360
 
 
361
 
  g_free (dest);
362
 
}
363
 
 
364
 
static gboolean
365
 
color_to_alpha_dialog (GimpDrawable *drawable)
366
 
{
367
 
  GtkWidget *dialog;
368
 
  GtkWidget *main_vbox;
369
 
  GtkWidget *preview;
370
 
  GtkWidget *hbox;
371
 
  GtkWidget *button;
372
 
  GtkWidget *label;
373
 
  gboolean   run;
374
 
 
375
 
  gimp_ui_init (PLUG_IN_BINARY, TRUE);
376
 
 
377
 
  dialog = gimp_dialog_new (_("Color to Alpha"), PLUG_IN_BINARY,
378
 
                            NULL, 0,
379
 
                            gimp_standard_help_func, PLUG_IN_PROC,
380
 
 
381
 
                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
382
 
                            GTK_STOCK_OK,     GTK_RESPONSE_OK,
383
 
 
384
 
                            NULL);
385
 
 
386
 
  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
387
 
                                           GTK_RESPONSE_OK,
388
 
                                           GTK_RESPONSE_CANCEL,
389
 
                                           -1);
390
 
 
391
 
  gimp_window_set_transient (GTK_WINDOW (dialog));
392
 
 
393
 
  main_vbox = gtk_vbox_new (FALSE, 12);
394
 
  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
395
 
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
396
 
  gtk_widget_show (main_vbox);
397
 
 
398
 
  preview = gimp_drawable_preview_new (drawable, NULL);
399
 
  gtk_box_pack_start_defaults (GTK_BOX (main_vbox), preview);
400
 
  gtk_widget_show (preview);
401
 
  g_signal_connect (preview, "invalidated",
402
 
                    G_CALLBACK (color_to_alpha_preview),
403
 
                    drawable);
404
 
 
405
 
  hbox = gtk_hbox_new (FALSE, 6);
406
 
  gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
407
 
  gtk_widget_show (hbox);
408
 
 
409
 
  label = gtk_label_new (_("From:"));
410
 
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
411
 
  gtk_widget_show (label);
412
 
 
413
 
  button = gimp_color_button_new (_("Color to Alpha Color Picker"),
414
 
                                  PRV_WIDTH, PRV_HEIGHT,
415
 
                                  &pvals.color,
416
 
                                  GIMP_COLOR_AREA_FLAT);
417
 
  gimp_color_button_set_update (GIMP_COLOR_BUTTON (button), TRUE);
418
 
  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
419
 
  gtk_widget_show (button);
420
 
 
421
 
  g_signal_connect (button, "color-changed",
422
 
                    G_CALLBACK (gimp_color_button_get_color),
423
 
                    &pvals.color);
424
 
  g_signal_connect_swapped (button, "color-changed",
425
 
                            G_CALLBACK (gimp_preview_invalidate),
426
 
                            preview);
427
 
 
428
 
  label = gtk_label_new (_("to alpha"));
429
 
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
430
 
  gtk_widget_show (label);
431
 
 
432
 
  gtk_widget_show (dialog);
433
 
 
434
 
  run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
435
 
 
436
 
  gtk_widget_destroy (dialog);
437
 
 
438
 
  return run;
439
 
}