~ubuntu-branches/ubuntu/jaunty/gimp/jaunty-security

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-02 16:33:03 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070502163303-bvzhjzbpw8qglc4y
Tags: 2.3.16-1ubuntu1
* Resynchronized with Debian, remaining Ubuntu changes:
  - debian/rules: i18n magic.
* debian/control.in:
  - Maintainer: Ubuntu Core Developers <ubuntu-devel@lists.ubuntu.com>
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch,
  debian/patches/10_dont_show_wizard.patch: updated.
* debian/patches/04_composite-signedness.patch,
  debian/patches/05_add-letter-spacing.patch: dropped, used upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Value-Invert plug-in v1.1 by Adam D. Moss, adam@foxbox.org.  1999/02/27
3
 
 */
4
 
 
5
 
/* The GIMP -- an image manipulation program
 
1
/* GIMP - The GNU Image Manipulation Program
6
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
7
3
 *
8
4
 * This program is free software; you can redistribute it and/or modify
20
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
17
 */
22
18
 
 
19
/* Value-Invert plug-in v1.1 by Adam D. Moss, adam@foxbox.org.  1999/02/27
 
20
 *
 
21
 * RGB<->HSV math optimizations by Mukund Sivaraman <muks@mukund.org>
 
22
 * makes the plug-in 2-3 times faster. Using gimp_pixel_rgns_process()
 
23
 * also makes memory management nicer. June 12, 2006.
 
24
 *
 
25
 * The plug-in only does v = 255 - v; for each pixel in the image, or
 
26
 * each entry in the colormap depending upon the type of image, where 'v'
 
27
 * is the value in HSV color model.
 
28
 *
 
29
 * The plug-in code is optimized towards this, in that it is not a full
 
30
 * RGB->HSV->RGB transform, but shortcuts many of the calculations to
 
31
 * effectively only do v = 255 - v. In fact, hue (0-360) is never
 
32
 * calculated. The shortcuts can be derived from running a set of r, g, b
 
33
 * values through the RGB->HSV transform and then from HSV->RGB and solving
 
34
 * out the redundant portions.
 
35
 *
 
36
 * The plug-in also uses integer code exclusively for the main transform.
 
37
 */
 
38
 
23
39
#include "config.h"
24
40
 
25
 
#include <stdio.h>
26
 
#include <stdlib.h>
 
41
#include <string.h>
27
42
 
28
43
#include <libgimp/gimp.h>
29
44
 
30
45
#include "libgimp/stdplugins-intl.h"
31
46
 
32
47
 
 
48
#define PLUG_IN_PROC "plug-in-vinvert"
 
49
 
 
50
 
33
51
/* Declare local functions.
34
52
 */
35
53
static void   query              (void);
40
58
                                  GimpParam       **return_vals);
41
59
 
42
60
static void   vinvert            (GimpDrawable     *drawable);
43
 
static void   indexed_vinvert    (gint32            image_ID);
 
61
static void   vinvert_indexed    (gint32            image_ID);
44
62
static void   vinvert_render_row (const guchar     *src,
45
63
                                  guchar           *dest,
46
 
                                  gint              row_width,
 
64
                                  gint              width,
47
65
                                  gint              bpp);
48
66
 
49
67
 
50
 
GimpPlugInInfo PLUG_IN_INFO =
 
68
const GimpPlugInInfo PLUG_IN_INFO =
51
69
{
52
70
  NULL,  /* init_proc  */
53
71
  NULL,  /* quit_proc  */
61
79
static void
62
80
query (void)
63
81
{
64
 
  static GimpParamDef args[] =
 
82
  static const GimpParamDef args[] =
65
83
  {
66
 
    { GIMP_PDB_INT32,    "run_mode", "Interactive, non-interactive" },
 
84
    { GIMP_PDB_INT32,    "run-mode", "Interactive, non-interactive"          },
67
85
    { GIMP_PDB_IMAGE,    "image",    "Input image (used for indexed images)" },
68
 
    { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }
 
86
    { GIMP_PDB_DRAWABLE, "drawable", "Input drawable"                        }
69
87
  };
70
88
 
71
 
  gimp_install_procedure ("plug_in_vinvert",
72
 
                          "Invert the 'value' component of an indexed/RGB "
73
 
                          "image in HSV colorspace",
74
 
                          "This function takes an indexed/RGB image and "
75
 
                          "inverts its 'value' in HSV space.  The upshot of "
76
 
                          "this is that the color and saturation at any given "
77
 
                          "point remains the same, but its brightness is "
78
 
                          "effectively inverted.  Quite strange.  Sometimes "
79
 
                          "produces unpleasant color artifacts on images from "
80
 
                          "lossy sources (ie. JPEG).",
81
 
                          "Adam D. Moss (adam@foxbox.org)",
82
 
                          "Adam D. Moss (adam@foxbox.org)",
83
 
                          "27th March 1997",
84
 
                          N_("_Value Invert"),
85
 
                          "RGB*, INDEXED*",
86
 
                          GIMP_PLUGIN,
87
 
                          G_N_ELEMENTS (args), 0,
88
 
                          args, NULL);
 
89
  gimp_install_procedure (PLUG_IN_PROC,
 
90
                          N_("Invert the brightness of each pixel"),
 
91
                          "This function takes an indexed/RGB image and "
 
92
                          "inverts its 'value' in HSV space.  The upshot of "
 
93
                          "this is that the color and saturation at any given "
 
94
                          "point remains the same, but its brightness is "
 
95
                          "effectively inverted.  Quite strange.  Sometimes "
 
96
                          "produces unpleasant color artifacts on images from "
 
97
                          "lossy sources (ie. JPEG).",
 
98
                          "Adam D. Moss (adam@foxbox.org), "
 
99
                          "Mukund Sivaraman <muks@mukund.org>",
 
100
                          "Adam D. Moss (adam@foxbox.org), "
 
101
                          "Mukund Sivaraman <muks@mukund.org>",
 
102
                          "27th March 1997, "
 
103
                          "12th June 2006",
 
104
                          N_("_Value Invert"),
 
105
                          "RGB*, INDEXED*",
 
106
                          GIMP_PLUGIN,
 
107
                          G_N_ELEMENTS (args), 0,
 
108
                          args, NULL);
89
109
 
90
 
  gimp_plugin_menu_register ("plug_in_vinvert", "<Image>/Filters/Colors");
 
110
  gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Colors/Invert");
91
111
}
92
112
 
93
113
static void
97
117
     gint             *nreturn_vals,
98
118
     GimpParam       **return_vals)
99
119
{
100
 
  static GimpParam   values[1];
101
 
  GimpDrawable      *drawable;
102
 
  gint32             image_ID;
103
 
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
104
 
  GimpRunMode        run_mode;
 
120
  static GimpParam  values[1];
 
121
  GimpPDBStatusType status = GIMP_PDB_SUCCESS;
 
122
  GimpRunMode       run_mode;
 
123
 
 
124
  INIT_I18N();
105
125
 
106
126
  run_mode = param[0].data.d_int32;
107
127
 
111
131
  values[0].type          = GIMP_PDB_STATUS;
112
132
  values[0].data.d_status = status;
113
133
 
114
 
  /*  Get the specified drawable  */
115
 
  drawable = gimp_drawable_get (param[2].data.d_drawable);
116
 
  image_ID = param[1].data.d_image;
117
 
 
118
 
  if (status == GIMP_PDB_SUCCESS)
 
134
  if (strcmp (name, PLUG_IN_PROC) == 0)
119
135
    {
 
136
      GimpDrawable *drawable;
 
137
      gint32        image_ID;
 
138
 
 
139
      /*  Get the specified drawable  */
 
140
 
 
141
      drawable = gimp_drawable_get (param[2].data.d_drawable);
 
142
      image_ID = param[1].data.d_image;
 
143
 
120
144
      /*  Make sure that the drawable is indexed or RGB color  */
 
145
 
121
146
      if (gimp_drawable_is_rgb (drawable->drawable_id))
122
 
        {
123
 
          if (run_mode != GIMP_RUN_NONINTERACTIVE)
124
 
            {
125
 
              INIT_I18N();
126
 
              gimp_progress_init (_("Value Invert..."));
127
 
            }
128
 
 
129
 
          vinvert (drawable);
130
 
          if (run_mode != GIMP_RUN_NONINTERACTIVE)
131
 
            gimp_displays_flush ();
132
 
        }
 
147
        {
 
148
          vinvert (drawable);
 
149
 
 
150
          if (run_mode != GIMP_RUN_NONINTERACTIVE)
 
151
            gimp_displays_flush ();
 
152
        }
 
153
      else if (gimp_drawable_is_indexed (drawable->drawable_id))
 
154
        {
 
155
          vinvert_indexed (image_ID);
 
156
 
 
157
          if (run_mode != GIMP_RUN_NONINTERACTIVE)
 
158
            gimp_displays_flush ();
 
159
        }
133
160
      else
134
 
        if (gimp_drawable_is_indexed (drawable->drawable_id))
135
 
          {
136
 
            indexed_vinvert (image_ID);
137
 
            if (run_mode != GIMP_RUN_NONINTERACTIVE)
138
 
              gimp_displays_flush ();
139
 
          }
140
 
        else
141
 
          {
142
 
            status = GIMP_PDB_EXECUTION_ERROR;
143
 
          }
 
161
        {
 
162
          status = GIMP_PDB_EXECUTION_ERROR;
 
163
        }
 
164
 
 
165
      gimp_drawable_detach (drawable);
 
166
    }
 
167
  else
 
168
    {
 
169
      status = GIMP_PDB_CALLING_ERROR;
144
170
    }
145
171
 
146
172
  values[0].data.d_status = status;
147
 
 
148
 
  gimp_drawable_detach (drawable);
149
 
}
150
 
 
151
 
static void
152
 
indexed_vinvert (gint32 image_ID)
 
173
}
 
174
 
 
175
static void
 
176
vinvert (GimpDrawable *drawable)
 
177
{
 
178
  gint          x, y, width, height;
 
179
  gdouble       total, processed;
 
180
  gint          update;
 
181
  gint          channels;
 
182
  GimpPixelRgn  src_rgn, dest_rgn;
 
183
  guchar        *src_row, *dest_row;
 
184
  gint          i;
 
185
  gpointer      pr;
 
186
 
 
187
  if (! gimp_drawable_mask_intersect (drawable->drawable_id,
 
188
                                      &x, &y, &width, &height))
 
189
    return;
 
190
 
 
191
  gimp_progress_init (_("Value Invert"));
 
192
 
 
193
  channels = gimp_drawable_bpp (drawable->drawable_id);
 
194
 
 
195
  gimp_pixel_rgn_init (&src_rgn,  drawable, x, y, width, height, FALSE, FALSE);
 
196
  gimp_pixel_rgn_init (&dest_rgn, drawable, x, y, width, height, TRUE, TRUE);
 
197
 
 
198
  total = width * height;
 
199
  processed = 0.0;
 
200
 
 
201
  for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn), update = 0;
 
202
       pr != NULL;
 
203
       pr = gimp_pixel_rgns_process (pr), update++)
 
204
    {
 
205
      src_row  = src_rgn.data;
 
206
      dest_row = dest_rgn.data;
 
207
 
 
208
      for (i = 0; i < src_rgn.h; i++)
 
209
        {
 
210
          vinvert_render_row (src_row, dest_row, src_rgn.w, channels);
 
211
 
 
212
          src_row  += src_rgn.rowstride;
 
213
          dest_row += dest_rgn.rowstride;
 
214
        }
 
215
 
 
216
      processed += src_rgn.w * src_rgn.h;
 
217
      update %= 16;
 
218
 
 
219
      if (update == 0)
 
220
        gimp_progress_update (processed / total);
 
221
    }
 
222
 
 
223
  gimp_progress_update (1.0);
 
224
 
 
225
  gimp_drawable_flush (drawable);
 
226
  gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
 
227
  gimp_drawable_update (drawable->drawable_id, x, y, width, height);
 
228
 
 
229
}
 
230
 
 
231
static void
 
232
vinvert_indexed (gint32 image_ID)
153
233
{
154
234
  guchar *cmap;
155
235
  gint    ncols;
166
246
}
167
247
 
168
248
static void
169
 
vinvert_func (const guchar *src,
170
 
              guchar       *dest,
171
 
              gint          bpp,
172
 
              gpointer      data)
173
 
{
174
 
  gint v1, v2, v3;
175
 
 
176
 
  v1 = src[0];
177
 
  v2 = src[1];
178
 
  v3 = src[2];
179
 
 
180
 
  gimp_rgb_to_hsv_int (&v1, &v2, &v3);
181
 
  v3 = 255 - v3;
182
 
  gimp_hsv_to_rgb_int (&v1, &v2, &v3);
183
 
 
184
 
  dest[0] = v1;
185
 
  dest[1] = v2;
186
 
  dest[2] = v3;
187
 
 
188
 
  if (bpp == 4)
189
 
    dest[3] = src[3];
190
 
}
191
 
 
192
 
static void
193
249
vinvert_render_row (const guchar *src,
194
 
                    guchar       *dest,
195
 
                    gint          row_width, /* in pixels */
196
 
                    gint          bpp)
 
250
                    guchar       *dest,
 
251
                    gint          width, /* in pixels */
 
252
                    gint          bpp)
197
253
{
198
 
  while (row_width--)
 
254
  gint j;
 
255
  gint r, g, b;
 
256
  gint value, value2, min;
 
257
  gint delta;
 
258
 
 
259
  for (j = 0; j < width; j++)
199
260
    {
200
 
      vinvert_func (src, dest, bpp, NULL);
201
 
      src += bpp;
202
 
      dest += bpp;
 
261
      r = *src++;
 
262
      g = *src++;
 
263
      b = *src++;
 
264
 
 
265
      if (r > g)
 
266
        {
 
267
          value = MAX (r, b);
 
268
          min = MIN (g, b);
 
269
        }
 
270
      else
 
271
        {
 
272
          value = MAX (g, b);
 
273
          min = MIN (r, b);
 
274
        }
 
275
 
 
276
      delta = value - min;
 
277
      if ((value == 0) || (delta == 0))
 
278
        {
 
279
          r = 255 - value;
 
280
          g = 255 - value;
 
281
          b = 255 - value;
 
282
        }
 
283
      else
 
284
        {
 
285
          value2 = value / 2;
 
286
 
 
287
          if (r == value)
 
288
            {
 
289
              r = 255 - r;
 
290
              b = ((r * b) + value2) / value;
 
291
              g = ((r * g) + value2) / value;
 
292
            }
 
293
          else if (g == value)
 
294
            {
 
295
              g = 255 - g;
 
296
              r = ((g * r) + value2) / value;
 
297
              b = ((g * b) + value2) / value;
 
298
            }
 
299
          else
 
300
            {
 
301
              b = 255 - b;
 
302
              g = ((b * g) + value2) / value;
 
303
              r = ((b * r) + value2) / value;
 
304
            }
 
305
        }
 
306
 
 
307
      *dest++ = r;
 
308
      *dest++ = g;
 
309
      *dest++ = b;
 
310
 
 
311
      if (bpp == 4)
 
312
        *dest++ = *src++;
203
313
    }
204
314
}
205
 
 
206
 
static void
207
 
vinvert (GimpDrawable *drawable)
208
 
{
209
 
  gimp_rgn_iterate2 (drawable, 0 /* unused */, vinvert_func, NULL);
210
 
}