noise-spread.c 4.77 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* This file is an image processing operation for GEGL
 *
 * GEGL is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * GEGL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright (C) 2011 Barak Itkin <lightningismyname@gmail.org>
 *
 * Based on "Spread" (Noise) GIMP plugin
 * Copyright (C) 1997 Brian Degenhardt and Federico Mena Quintero
 *
Barak Itkin's avatar
Barak Itkin committed
21 22
 * The workshop/whirl-pinch.c and common/pixelise.c were used as
 * templates for this op file.
23 24 25 26
 */
#include "config.h"
#include <glib/gi18n-lib.h>

27
#ifdef GEGL_PROPERTIES
28

29 30 31 32 33 34 35 36 37 38 39 40 41
property_int    (amount_x, _("Horizontal"), 5)
    description (_("Horizontal spread amount"))
    value_range (0, 512)
    ui_meta     ("unit", "pixel-distance")
    ui_meta     ("axis", "x")

property_int    (amount_y, _("Vertical"), 5)
    description (_("Vertical spread amount"))
    value_range (0, 512)
    ui_meta     ("unit", "pixel-distance")
    ui_meta     ("axis", "y")

property_seed (seed, _("Random seed"), rand)
42 43 44

#else

45 46
#define GEGL_OP_AREA_FILTER
#define GEGL_OP_C_FILE "noise-spread.c"
47

48
#include "gegl-op.h"
49 50
#include <math.h>

51
static inline void
52 53 54 55 56 57 58
calc_sample_coords (gint        src_x,
                    gint        src_y,
                    gint        amount_x,
                    gint        amount_y,
                    GeglRandom *rand,
                    gint       *x,
                    gint       *y)
59
{
60 61
  gdouble angle;
  gint    xdist, ydist;
62 63

  /* get random angle, x distance, and y distance */
64
  xdist = amount_x > 0 ? gegl_random_int_range (rand, src_x, src_y, 0, 0,
65
                                                -amount_x, amount_x + 1) : 0;
66
  ydist = amount_y > 0 ? gegl_random_int_range (rand, src_x, src_y, 0, 1,
67
                                                -amount_y, amount_y + 1) : 0;
68
  angle = gegl_random_float_range (rand, src_x, src_y, 0, 2, -G_PI, G_PI);
69 70 71 72 73 74 75 76 77

  *x = src_x + floor (sin (angle) * xdist);
  *y = src_y + floor (cos (angle) * ydist);
}


static void
prepare (GeglOperation *operation)
{
78
  GeglProperties          *o       = GEGL_PROPERTIES (operation);
79
  GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation);
80
  const Babl              *format;
81 82

  op_area->left   =
83
  op_area->right  = (o->amount_x + 1) / 2;
84
  op_area->top    =
85
  op_area->bottom = (o->amount_y + 1) / 2;
86

87 88 89 90
  format = gegl_operation_get_source_format (operation, "input");

  gegl_operation_set_format (operation, "input", format);
  gegl_operation_set_format (operation, "output", format);
91 92 93 94 95 96
}

static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
97 98
         const GeglRectangle *result,
         gint                 level)
99
{
100
  GeglProperties         *o;
101 102 103 104 105 106
  const Babl         *format;
  gint                bpp;
  GeglBufferIterator *gi;
  gint                amount_x;
  gint                amount_y;

107
  o = GEGL_PROPERTIES (operation);
108 109 110 111 112 113 114 115

  amount_x = (o->amount_x + 1) / 2;
  amount_y = (o->amount_y + 1) / 2;

  format = gegl_operation_get_source_format (operation, "input");
  bpp = babl_format_get_bytes_per_pixel (format);

  gi = gegl_buffer_iterator_new (output, result, 0, format,
116
                                 GEGL_ACCESS_WRITE, GEGL_ABYSS_CLAMP);
117 118 119 120 121 122 123 124 125 126 127 128

  while (gegl_buffer_iterator_next (gi))
    {
      gchar        *data = gi->data[0];
      GeglRectangle roi  = gi->roi[0];
      gint          i, j;

      for (j = roi.y; j < roi.y + roi.height ; j++)
        for (i = roi.x; i < roi.x + roi.width ; i++)
          {
            gint x, y;

129
            calc_sample_coords (i, j, amount_x, amount_y, o->rand, &x, &y);
130

131
            gegl_buffer_sample_at_level (input, x, y, NULL, data, format, level,
132 133 134 135 136
                                GEGL_SAMPLER_NEAREST, GEGL_ABYSS_CLAMP);
            data += bpp;
          }
    }

137 138 139 140
  return TRUE;
}

static void
141
gegl_op_class_init (GeglOpClass *klass)
142 143 144 145 146 147 148 149
{
  GeglOperationClass       *operation_class;
  GeglOperationFilterClass *filter_class;

  operation_class = GEGL_OPERATION_CLASS (klass);
  filter_class    = GEGL_OPERATION_FILTER_CLASS (klass);

  operation_class->prepare = prepare;
150
  filter_class->process    = process;
151

152
  gegl_operation_class_set_keys (operation_class,
153
    "name",        "gegl:noise-spread",
154
    "title",       _("Noise Spread"),
155 156
    "categories",  "noise",
    "description", _("Move pixels around randomly"),
157
    NULL);
158 159 160
}

#endif