Many thanks to all the regulars on #gimp who answered my questions, gave me
advice, and bugged me to write this stuff up.

The GIMP is my friend.  It makes me happy. :-)

Background
----------

I've recently been trying to reproduce really odd film grain to hide image
editing.  This process has three steps:

  1) Extract the old grain.
  2) Make it into a tileable pattern.
  3) Merge the pattern into a new image.

Step (1): To extract the old grain, make a copy of the image, blur it, and
compare it to the original.  The "flat" areas of the image should now
contain some kind of characteristic noise--grains, vertical lines, and so
on.  (The trick here is the comparsion; more details below.)  You may--or
may not--want to desaturate your noise!

Step (2): To make a pattern tileable, use "Make Seamless", the
Resynthesizer & Homogenizer, hand-hacking, or your favorite tricks.

Step (3): To merge the pattern back into the image, create a channel of
solid noise, mask it as needed, and add it to the underlying channel.
Again, the addition is tricky.

Addition & Subtraction
----------------------

>From the "side", a cross-section of film noise might look something like
this:
     __
  __/  \__    __
          \__/

Notice that the noise swings above /and below/ the average...

The "Subtract" mode, however, will clip negative values, and loose half the
noise, because it's now less than 0:
     __
  __/  \________

The "Difference" mode takes an absolute value, which totally changes the
feel of the noise:
     __    __
  __/  \__/  \__

Basically, we need some way to represent "negative" numbers in the GIMP.
We can do this by expressing all values relative to (128,128,128).

Two Sample Modes
----------------

The attached patch implementes "Grey" addition and subtraction, both as a
layer mode and a brush mode.  I've tested it with GIMP 1.2.2, but I'd like
to hear any comments before porting it to 1.3.x.

The names of the transfer modes are highly provisional!

Adding Noise to a Clean Photo
-----------------------------

To apply a noise pattern to an image, add a new layer above your image, and
flood-fill it with noise.  Set the transfer mode to "Grey Addition".  Your
image should now look ugly, which is just what we want. ;-)

Next, let's say that you want lots of noise in your midtones, but none in
your highlights or shadows.  Here's how:

  1) Create a copy of your image, and do a wide-radius blur.  This should
     give you an intensity map.
  2) Use the curves dialog to make your shadows dark, your midtones white,
     and your highlights dark.
  3) Copy this image to the clipboard, create a layer mask for your noise
     layer, and paste it in.
  4) To increase or decrease the noise in one area, you can paint into
     the layer mask with the airbrush.

If you're lazy, you can use the magic want to select an area, switch to the
quick-mask, blur it heavily, switch back, and flood-fill the area with
noise.  Just set the bucket to "Pattern Fill", "Grey Addition".

Feedback welcome.  Share and enjoy!

Cheers,
Eric

diff -ur gimp-1.2.2-old/app/apptypes.h gimp-1.2.2/app/apptypes.h
--- gimp-1.2.2-old/app/apptypes.h       Sat Dec 16 15:33:41 2000
+++ gimp-1.2.2/app/apptypes.h   Wed Sep 26 19:18:40 2001
@@ -78,8 +78,15 @@
   DIVIDE_MODE,
   ERASE_MODE,         /*< skip >*/
   REPLACE_MODE,       /*< skip >*/
-  ANTI_ERASE_MODE     /*< skip >*/
+  ANTI_ERASE_MODE,    /*< skip >*/
+  GREY_ADDITION_MODE,
+  GREY_SUBTRACTION_MODE
 } LayerModeEffects;
+
+/* Is this a regular brush mode? */
+#define GIMP_IS_BRUSH_MODE(mode) \
+  ((NORMAL_MODE <= mode && mode <= DIVIDE_MODE) \
+   || (GREY_ADDITION_MODE <= mode && mode <= GREY_SUBTRACTION_MODE))
 
 /* Types of convolutions  */
 typedef enum 
diff -ur gimp-1.2.2-old/app/brush_select_cmds.c gimp-1.2.2/app/brush_select_cmds.c
--- gimp-1.2.2-old/app/brush_select_cmds.c      Thu Feb 17 06:44:26 2000
+++ gimp-1.2.2/app/brush_select_cmds.c  Wed Sep 26 20:48:56 2001
@@ -83,7 +83,7 @@
   spacing = args[4].value.pdb_int;
 
   paint_mode = args[5].value.pdb_int;
-  if (paint_mode < NORMAL_MODE || paint_mode > DIVIDE_MODE)
+  if (!GIMP_IS_BRUSH_MODE(paint_mode))
     success = FALSE;
 
   if (success)
@@ -136,7 +136,7 @@
   {
     PDB_INT32,
     "paint_mode",
-    "The initial paint mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE (2), 
MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
(15) }"
+    "The initial paint mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE (2), 
+MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
+ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
+HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
+(15), GREY_ADDITION_MODE (19), GREY_SUBTRACTION_MODE (20) }"
   }
 };
 
@@ -240,7 +240,7 @@
   spacing = args[3].value.pdb_int;
 
   paint_mode = args[4].value.pdb_int;
-  if (paint_mode < NORMAL_MODE || paint_mode > DIVIDE_MODE)
+  if (!GIMP_IS_BRUSH_MODE(paint_mode))
     success = FALSE;
 
   if (success)
@@ -295,7 +295,7 @@
   {
     PDB_INT32,
     "paint_mode",
-    "The initial paint mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE (2), 
MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
(15) }"
+    "The initial paint mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE (2), 
+MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
+ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
+HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
+(15), GREY_ADDITION_MODE (19), GREY_SUBTRACTION_MODE (20) }"
   }
 };
 
diff -ur gimp-1.2.2-old/app/brushes_cmds.c gimp-1.2.2/app/brushes_cmds.c
--- gimp-1.2.2-old/app/brushes_cmds.c   Sun Dec 17 14:25:56 2000
+++ gimp-1.2.2/app/brushes_cmds.c       Wed Sep 26 20:48:56 2001
@@ -369,7 +369,7 @@
   {
     PDB_INT32,
     "paint_mode",
-    "The paint mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE (2), 
MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
(15) }"
+    "The paint mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE (2), 
+MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
+ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
+HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
+(15), GREY_ADDITION_MODE (19), GREY_SUBTRACTION_MODE (20) }"
   }
 };
 
@@ -396,7 +396,7 @@
   gint32 paint_mode;
 
   paint_mode = args[0].value.pdb_int;
-  if (paint_mode < NORMAL_MODE || paint_mode > DIVIDE_MODE)
+  if (!GIMP_IS_BRUSH_MODE(paint_mode))
     success = FALSE;
 
   if (success)
@@ -410,7 +410,7 @@
   {
     PDB_INT32,
     "paint_mode",
-    "The paint mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE (2), 
MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
(15) }"
+    "The paint mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE (2), 
+MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
+ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
+HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
+(15), GREY_ADDITION_MODE (19), GREY_SUBTRACTION_MODE (20) }"
   }
 };
 
@@ -580,7 +580,7 @@
   {
     PDB_INT32,
     "paint_mode",
-    "The paint mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE (2), 
MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
(15) }"
+    "The paint mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE (2), 
+MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
+ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
+HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
+(15), GREY_ADDITION_MODE (19), GREY_SUBTRACTION_MODE (20) }"
   },
   {
     PDB_INT32,
diff -ur gimp-1.2.2-old/app/layer_cmds.c gimp-1.2.2/app/layer_cmds.c
--- gimp-1.2.2-old/app/layer_cmds.c     Thu Dec 28 12:37:23 2000
+++ gimp-1.2.2/app/layer_cmds.c Wed Sep 26 20:48:56 2001
@@ -134,7 +134,7 @@
     success = FALSE;
 
   mode = args[6].value.pdb_int;
-  if (mode < NORMAL_MODE || mode > DIVIDE_MODE)
+  if (!GIMP_IS_BRUSH_MODE(mode))
     success = FALSE;
 
   if (success)
@@ -187,7 +187,7 @@
   {
     PDB_INT32,
     "mode",
-    "The layer combination mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE 
(2), MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
(15) }"
+    "The layer combination mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE 
+(2), MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
+ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
+HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
+(15), GREY_ADDITION_MODE (19), GREY_SUBTRACTION_MODE (20) }"
   }
 };
 
@@ -1683,7 +1683,7 @@
     success = FALSE;
 
   mode = args[1].value.pdb_int;
-  if (mode < NORMAL_MODE || mode > DIVIDE_MODE)
+  if (!GIMP_IS_BRUSH_MODE(mode))
     success = FALSE;
 
   if (success)
diff -ur gimp-1.2.2-old/app/layers_dialog.c gimp-1.2.2/app/layers_dialog.c
--- gimp-1.2.2-old/app/layers_dialog.c  Thu Jun 21 04:27:22 2001
+++ gimp-1.2.2/app/layers_dialog.c      Wed Sep 26 15:20:37 2001
@@ -384,6 +384,8 @@
                           _("Difference"),      (gpointer) DIFFERENCE_MODE,   NULL,
                           _("Addition"),        (gpointer) ADDITION_MODE,     NULL,
                           _("Subtract"),        (gpointer) SUBTRACT_MODE,     NULL,
+                          _("Grey Addition"),   (gpointer) GREY_ADDITION_MODE,NULL,
+                          _("Grey Subtraction"),(gpointer) GREY_SUBTRACTION_MODE, 
+NULL,
                           _("Darken Only"),     (gpointer) DARKEN_ONLY_MODE,  NULL,
                           _("Lighten Only"),    (gpointer) LIGHTEN_ONLY_MODE, NULL,
                           _("Hue"),             (gpointer) HUE_MODE,          NULL,
diff -ur gimp-1.2.2-old/app/paint_funcs.c gimp-1.2.2/app/paint_funcs.c
--- gimp-1.2.2-old/app/paint_funcs.c    Tue Jun 26 04:59:24 2001
+++ gimp-1.2.2/app/paint_funcs.c        Wed Sep 26 16:35:07 2001
@@ -103,7 +103,9 @@
   { 0, 0, 0, N_("Divide (Dodge)") },
   { 1, 0, 1, N_("Erase") },
   { 1, 1, 1, N_("Replace") },
-  { 1, 0, 1, N_("Anti Erase") }
+  { 1, 0, 1, N_("Anti Erase") },
+  { 0, 0, 0, N_("Grey Addition") },
+  { 0, 0, 0, N_("Grey Subtraction") }
 };
 
 /*  ColorHash structure  */
@@ -1081,6 +1083,76 @@
     }
 }
 
+void
+grey_add_pixels (const unsigned char *src1,
+                const unsigned char *src2,
+                unsigned char *dest,
+                int            length,
+                int            bytes1,
+                int            bytes2,
+                int            has_alpha1,
+                int            has_alpha2)
+{
+  int alpha, b;
+  int sum;
+
+  alpha = (has_alpha1 || has_alpha2) ? MAX (bytes1, bytes2) - 1 : bytes1;
+
+  while (length --)
+    {
+      for (b = 0; b < alpha; b++)
+       {
+         /* Add, re-center and clip. */
+         sum = src1[b] + src2[b] - 128;
+         dest[b] = MAX(MIN(sum, 255), 0);
+       }
+
+      if (has_alpha1 && has_alpha2)
+       dest[alpha] = MIN (src1[alpha], src2[alpha]);
+      else if (has_alpha2)
+       dest[alpha] = src2[alpha];
+
+      src1 += bytes1;
+      src2 += bytes2;
+      dest += bytes2;
+    }
+}
+
+
+void
+grey_subtract_pixels (const unsigned char *src1,
+                     const unsigned char *src2,
+                     unsigned char *dest,
+                     int            length,
+                     int            bytes1,
+                     int            bytes2,
+                     int            has_alpha1,
+                     int            has_alpha2)
+{
+  int alpha, b;
+  int diff;
+
+  alpha = (has_alpha1 || has_alpha2) ? MAX (bytes1, bytes2) - 1 : bytes1;
+
+  while (length --)
+    {
+      for (b = 0; b < alpha; b++)
+       {
+         diff = src1[b] - src2[b] + 128;
+         dest[b] = MAX(MIN(diff, 255), 0);
+       }
+
+      if (has_alpha1 && has_alpha2)
+       dest[alpha] = MIN (src1[alpha], src2[alpha]);
+      else if (has_alpha2)
+       dest[alpha] = src2[alpha];
+
+      src1 += bytes1;
+      src2 += bytes2;
+      dest += bytes2;
+    }
+}
+
 
 void
 difference_pixels (const unsigned char *src1,
@@ -5820,6 +5892,14 @@
 
     case SUBTRACT_MODE:
       subtract_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, 
has_alpha2);
+      break;
+
+    case GREY_ADDITION_MODE:
+      grey_add_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, 
+has_alpha2);
+      break;
+
+    case GREY_SUBTRACTION_MODE:
+      grey_subtract_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, 
+has_alpha2);
       break;
 
     case DARKEN_ONLY_MODE:
diff -ur gimp-1.2.2-old/app/paint_funcs.h gimp-1.2.2/app/paint_funcs.h
--- gimp-1.2.2-old/app/paint_funcs.h    Sat Dec 16 12:26:28 2000
+++ gimp-1.2.2/app/paint_funcs.h        Wed Sep 26 19:17:57 2001
@@ -114,6 +114,18 @@
                             int bytes1, int bytes2,
                             int has_alpha1, int has_alpha2);
 
+void  grey_add_pixels       (const unsigned char *src1,
+                            const unsigned char *src2,
+                            unsigned char *dest, int length,
+                            int bytes1, int bytes2,
+                            int has_alpha1, int has_alpha2);
+
+void  grey_subtract_pixels  (const unsigned char *src1,
+                            const unsigned char *src2,
+                            unsigned char *dest, int length,
+                            int bytes1, int bytes2,
+                            int has_alpha1, int has_alpha2);
+
 void  difference_pixels     (const unsigned char *src1,
                             const unsigned char *src2,
                             unsigned char *dest, int length,
diff -ur gimp-1.2.2-old/app/tool_options.c gimp-1.2.2/app/tool_options.c
--- gimp-1.2.2-old/app/tool_options.c   Sat Dec 16 14:44:25 2000
+++ gimp-1.2.2/app/tool_options.c       Wed Sep 26 15:22:39 2001
@@ -929,6 +929,8 @@
      _("Difference"),      (gpointer) DIFFERENCE_MODE, NULL,
      _("Addition"),        (gpointer) ADDITION_MODE, NULL,
      _("Subtract"),        (gpointer) SUBTRACT_MODE, NULL,
+     _("Grey Addition"),   (gpointer) GREY_ADDITION_MODE, NULL,
+     _("Grey Subtraction"),(gpointer) GREY_SUBTRACTION_MODE, NULL,
      _("Darken Only"),     (gpointer) DARKEN_ONLY_MODE, NULL,
      _("Lighten Only"),    (gpointer) LIGHTEN_ONLY_MODE, NULL,
      _("Hue"),             (gpointer) HUE_MODE, NULL,
diff -ur gimp-1.2.2-old/app/tools_cmds.c gimp-1.2.2/app/tools_cmds.c
--- gimp-1.2.2-old/app/tools_cmds.c     Mon Apr 24 11:22:56 2000
+++ gimp-1.2.2/app/tools_cmds.c Wed Sep 26 20:50:19 2001
@@ -277,7 +277,7 @@
     success = FALSE;
 
   paint_mode = args[2].value.pdb_int;
-  if (paint_mode < NORMAL_MODE || paint_mode > DIVIDE_MODE)
+  if (!GIMP_IS_BRUSH_MODE(paint_mode))
     success = FALSE;
 
   gradient_type = args[3].value.pdb_int;
@@ -340,7 +340,7 @@
   {
     PDB_INT32,
     "paint_mode",
-    "The paint application mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE 
(2), MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
(15) }"
+    "The paint application mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE 
+(2), MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
+ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
+HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
+(15), GREY_ADDITION_MODE (19), GREY_SUBTRACTION_MODE (20) }"
   },
   {
     PDB_INT32,
@@ -438,7 +438,7 @@
     success = FALSE;
 
   paint_mode = args[2].value.pdb_int;
-  if (paint_mode < NORMAL_MODE || paint_mode > DIVIDE_MODE)
+  if (!GIMP_IS_BRUSH_MODE(paint_mode))
     success = FALSE;
 
   opacity = args[3].value.pdb_float;
@@ -480,7 +480,7 @@
   {
     PDB_INT32,
     "paint_mode",
-    "The paint application mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE 
(2), MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
(15) }"
+    "The paint application mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE 
+(2), MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), 
+ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), 
+HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE 
+(15), GREY_ADDITION_MODE (19), GREY_SUBTRACTION_MODE (20) }"
   },
   {
     PDB_FLOAT,
_______________________________________________
Gimp-developer mailing list
[EMAIL PROTECTED]
http://lists.xcf.berkeley.edu/mailman/listinfo/gimp-developer

Reply via email to