Пример #1
0
cairo_pattern_t *
gimp_cairo_stipple_pattern_create (const GimpRGB *fg,
                                   const GimpRGB *bg,
                                   gint           index)
{
  cairo_surface_t *surface;
  cairo_pattern_t *pattern;
  guchar          *data;
  guchar          *d;
  guchar           fg_r, fg_g, fg_b, fg_a;
  guchar           bg_r, bg_g, bg_b, bg_a;
  gint             x, y;

  g_return_val_if_fail (fg != NULL, NULL);
  g_return_val_if_fail (bg != NULL, NULL);

  data = g_malloc (8 * 8 * 4);

  gimp_rgba_get_uchar (fg, &fg_r, &fg_g, &fg_b, &fg_a);
  gimp_rgba_get_uchar (bg, &bg_r, &bg_g, &bg_b, &bg_a);

  d = data;

  for (y = 0; y < 8; y++)
    {
      for (x = 0; x < 8; x++)
        {
          if ((x + y + index) % 8 >= 4)
            GIMP_CAIRO_ARGB32_SET_PIXEL (d, fg_r, fg_g, fg_b, fg_a);
          else
            GIMP_CAIRO_ARGB32_SET_PIXEL (d, bg_r, bg_g, bg_b, bg_a);

          d += 4;
        }
    }

  surface = cairo_image_surface_create_for_data (data,
                                                 CAIRO_FORMAT_ARGB32,
                                                 8, 8, 8 * 4);
  cairo_surface_set_user_data (surface, &surface_data_key,
                               data, (cairo_destroy_func_t) g_free);

  pattern = cairo_pattern_create_for_surface (surface);
  cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);

  cairo_surface_destroy (surface);

  return pattern;
}
Пример #2
0
static void
gimp_view_renderer_gradient_render (GimpViewRenderer *renderer,
                                    GtkWidget        *widget)
{
  GimpViewRendererGradient *rendergrad = GIMP_VIEW_RENDERER_GRADIENT (renderer);
  GimpGradient             *gradient   = GIMP_GRADIENT (renderer->viewable);
  GimpGradientSegment      *seg        = NULL;
  GimpColorTransform       *transform;
  guchar                   *buf;
  guchar                   *dest;
  gint                      dest_stride;
  gint                      x;
  gint                      y;
  gdouble                   dx, cur_x;
  GimpRGB                   color;

  buf   = g_alloca (4 * renderer->width);
  dx    = (rendergrad->right - rendergrad->left) / (renderer->width - 1);
  cur_x = rendergrad->left;

  for (x = 0, dest = buf; x < renderer->width; x++, dest += 4)
    {
      guchar r, g, b, a;

      seg = gimp_gradient_get_color_at (gradient, renderer->context, seg,
                                        cur_x, rendergrad->reverse, &color);
      cur_x += dx;

      gimp_rgba_get_uchar (&color, &r, &g, &b, &a);

      GIMP_CAIRO_ARGB32_SET_PIXEL (dest, r, g, b, a);
    }

  if (! renderer->surface)
    renderer->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                                                    renderer->width,
                                                    renderer->height);

  cairo_surface_flush (renderer->surface);

  dest        = cairo_image_surface_get_data (renderer->surface);
  dest_stride = cairo_image_surface_get_stride (renderer->surface);

  transform = gimp_view_renderer_get_color_transform (renderer, widget,
                                                      babl_format ("cairo-ARGB32"),
                                                      babl_format ("cairo-ARGB32"));

  if (transform)
    gimp_color_transform_process_pixels (transform,
                                         babl_format ("cairo-ARGB32"), buf,
                                         babl_format ("cairo-ARGB32"), buf,
                                         renderer->width);

  for (y = 0; y < renderer->height; y++, dest += dest_stride)
    {
      memcpy (dest, buf, renderer->width * 4);
    }

  cairo_surface_mark_dirty (renderer->surface);
}
Пример #3
0
static void
gimp_levels_tool_color_picked (GimpColorTool      *color_tool,
                               GimpColorPickState  pick_state,
                               GimpImageType       sample_type,
                               GimpRGB            *color,
                               gint                color_index)
{
  GimpLevelsTool *tool = GIMP_LEVELS_TOOL (color_tool);
  guchar          col[5];
  guint           value;

  gimp_rgba_get_uchar (color,
                       col + RED_PIX,
                       col + GREEN_PIX,
                       col + BLUE_PIX,
                       col + ALPHA_PIX);

  value = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (tool->active_picker),
                                               "pick_value"));

  if (value & ALL_CHANNELS && GIMP_IMAGE_TYPE_IS_RGB (sample_type))
    {
      GimpHistogramChannel  channel;

      /*  first reset the value channel  */
      switch (value & 0xF)
        {
        case LOW_INPUT:
          tool->levels->low_input[GIMP_HISTOGRAM_VALUE] = 0;
          break;
        case GAMMA:
          tool->levels->gamma[GIMP_HISTOGRAM_VALUE] = 1.0;
          break;
        case HIGH_INPUT:
          tool->levels->high_input[GIMP_HISTOGRAM_VALUE] = 255;
          break;
        default:
          break;
        }

      /*  then adjust all color channels  */
      for (channel = GIMP_HISTOGRAM_RED;
           channel <= GIMP_HISTOGRAM_BLUE;
           channel++)
        {
          levels_input_adjust_by_color (tool->levels,
                                        value, channel, col);
        }
    }
  else
    {
      levels_input_adjust_by_color (tool->levels,
                                    value, tool->channel, col);
    }

  levels_update (tool, ALL);

  gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool));
}
Пример #4
0
static VALUE
rb_gimp_rgba_get_uchar (VALUE self)
{
  Get_TypedStruct(self, GimpRGB, color);

  guchar r, g, b, a;
  gimp_rgba_get_uchar(color, &r, &g, &b, &a);

  return rb_ary_new3(4, INT2FIX(r), INT2FIX(g), INT2FIX(b), INT2FIX(a));
}
Пример #5
0
static void
poke (GimpPixelRgn *dest_rgn,
      gint          x,
      gint          y,
      GimpRGB      *color)
{
  static guchar data[4];

  gimp_rgba_get_uchar (color, &data[0], &data[1], &data[2], &data[3]);
  gimp_pixel_rgn_set_pixel (dest_rgn, data, x, y);
}
Пример #6
0
void
poke (gint      x,
      gint      y,
      GimpRGB  *color,
      gpointer  data)
{
  static guchar col[4];

  gimp_rgba_get_uchar (color, &col[0], &col[1], &col[2], &col[3]);

  gimp_pixel_rgn_set_pixel (&dest_region, col, x, y);
}
Пример #7
0
void
gimp_drawable_get_color_uchar (gint32         drawable_ID,
                               const GimpRGB *color,
                               guchar        *color_uchar)
{
  g_return_if_fail (color != NULL);
  g_return_if_fail (color_uchar != NULL);

  switch (gimp_drawable_type (drawable_ID))
    {
    case GIMP_RGB_IMAGE:
      gimp_rgb_get_uchar (color,
                          &color_uchar[0], &color_uchar[1], &color_uchar[2]);
      color_uchar[3] = 255;
      break;

    case GIMP_RGBA_IMAGE:
      gimp_rgba_get_uchar (color,
                           &color_uchar[0], &color_uchar[1], &color_uchar[2],
                           &color_uchar[3]);
      break;

    case GIMP_GRAY_IMAGE:
      color_uchar[0] = gimp_rgb_luminance_uchar (color);
      color_uchar[1] = 255;
      break;

    case GIMP_GRAYA_IMAGE:
      color_uchar[0] = gimp_rgb_luminance_uchar (color);
      gimp_rgba_get_uchar (color, NULL, NULL, NULL, &color_uchar[1]);
      break;

    default:
      break;
    }
}
Пример #8
0
static void
to_alpha_func (const guchar *src,
              guchar       *dest,
              gint          bpp,
              gpointer      data)
{
  GimpRGB color;

  if (bpp == 3)
    gimp_rgba_set_uchar (&color, src[0], src[1], src[2], 255);
  else
    gimp_rgba_set_uchar (&color, src[0], src[1], src[2], src[3]);

  color_to_alpha (&color, &pvals.color);
  gimp_rgba_get_uchar (&color, &dest[0], &dest[1], &dest[2], &dest[3]);
}
Пример #9
0
static inline void
filter (void)
{
  static void (* overlap)(guchar *, const guchar *);
  GimpPixelRgn  src;
  GimpPixelRgn  dst;
  GimpRGB       color;
  guchar     pixel[4];
  gint       division_x;
  gint       division_y;
  gint       offset_x;
  gint       offset_y;
  Tile      *tiles;
  gint       numof_tiles;
  Tile      *t;
  gint       i;
  gint       x;
  gint       y;
  gint       move_max_pixels;
  gint       clear_x0;
  gint       clear_y0;
  gint       clear_x1;
  gint       clear_y1;
  gint       clear_width;
  gint       clear_height;
  guchar    *pixels;
  guchar    *buffer;
  gint       dindex;
  gint       sindex;
  gint       px, py;
  GRand     *gr;

  gr = g_rand_new ();

  /* INITIALIZE */
  gimp_pixel_rgn_init (&src, p.drawable, 0, 0,
                       p.drawable->width, p.drawable->height, FALSE, FALSE);
  gimp_pixel_rgn_init (&dst, p.drawable, 0, 0,
                       p.drawable->width, p.drawable->height, TRUE, TRUE);
  pixels = g_new (guchar,
                  p.drawable->bpp * p.drawable->width * p.drawable->height);
  buffer = g_new (guchar,
                  p.drawable->bpp * p.params.tile_width * p.params.tile_height);

  overlap = p.drawable_has_alpha ? overlap_RGBA : overlap_RGB;

  gimp_progress_init (_("Paper Tile"));

  gimp_drawable_mask_bounds (p.drawable->drawable_id,
                             &p.selection.x0, &p.selection.y0,
                             &p.selection.x1, &p.selection.y1);
  p.selection.width  = p.selection.x1 - p.selection.x0;
  p.selection.height = p.selection.y1 - p.selection.y0;

  gimp_tile_cache_ntiles (2 * (p.selection.width / gimp_tile_width () + 1));

  /* TILES */
  division_x = p.params.division_x;
  division_y = p.params.division_y;
  if (p.params.fractional_type == FRACTIONAL_TYPE_FORCE)
    {
      if (0 < p.drawable->width  % p.params.tile_width) division_x++;
      if (0 < p.drawable->height % p.params.tile_height) division_y++;
      if (p.params.centering)
        {
          if (1 < p.drawable->width % p.params.tile_width)
            {
              division_x++;
              offset_x =
                (p.drawable->width % p.params.tile_width) / 2 -
                p.params.tile_width;
            }
          else
            {
              offset_x = 0;
            }

          if (1 < p.drawable->height % p.params.tile_height)
            {
              division_y++;
              offset_y =
                (p.drawable->height % p.params.tile_height) / 2 -
                p.params.tile_height;
            }
          else
            {
              offset_y = 0;
            }
        }
      else
        {
          offset_x = 0;
          offset_y = 0;
        }
    }
  else
    {
      if (p.params.centering)
        {
          offset_x = (p.drawable->width  % p.params.tile_width) / 2;
          offset_y = (p.drawable->height % p.params.tile_height) / 2;
        }
      else
        {
          offset_x = 0;
          offset_y = 0;
        }
    }

  move_max_pixels = p.params.move_max_rate * p.params.tile_width / 100.0;
  numof_tiles = division_x * division_y;
  t = tiles = g_new(Tile, numof_tiles);

  for (y = 0; y < division_y; y++)
    {
      gint srcy = offset_y + p.params.tile_height * y;

      for (x = 0; x < division_x; x++, t++)
        {
          gint srcx = offset_x + p.params.tile_width * x;

          if (srcx < 0)
            {
              t->x     = 0;
              t->width = srcx + p.params.tile_width;
            }
          else if (srcx + p.params.tile_width < p.drawable->width)
            {
              t->x     = srcx;
              t->width = p.params.tile_width;
            }
          else
            {
              t->x     = srcx;
              t->width = p.drawable->width - srcx;
            }

          if (srcy < 0)
            {
              t->y      = 0;
              t->height = srcy + p.params.tile_height;
            }
          else if (srcy + p.params.tile_height < p.drawable->height)
            {
              t->y      = srcy;
              t->height = p.params.tile_height;
            }
          else
            {
              t->y      = srcy;
              t->height = p.drawable->height - srcy;
            }

          t->z = g_rand_int (gr);
          random_move (&t->move_x, &t->move_y, move_max_pixels);
        }
    }

  qsort (tiles, numof_tiles, sizeof *tiles, tile_compare);

  gimp_pixel_rgn_get_rect (&src, pixels, 0, 0, p.drawable->width,
                           p.drawable->height);

  if (p.params.fractional_type == FRACTIONAL_TYPE_IGNORE)
    {
      clear_x0     = offset_x;
      clear_y0     = offset_y;
      clear_width  = p.params.tile_width * division_x;
      clear_height = p.params.tile_height * division_y;
    }
  else
    {
      clear_x0     = 0;
      clear_y0     = 0;
      clear_width  = p.drawable->width;
      clear_height = p.drawable->height;
    }

  clear_x1 = clear_x0 + clear_width;
  clear_y1 = clear_y0 + clear_height;

  switch (p.params.background_type)
    {
    case BACKGROUND_TYPE_TRANSPARENT:
      for (y = clear_y0; y < clear_y1; y++)
        {
          for (x = clear_x0; x < clear_x1; x++)
            {
              dindex = p.drawable->bpp * (p.drawable->width * y + x);
              for (i = 0; i < p.drawable->bpp; i++)
                {
                  pixels[dindex+i] = 0;
                }
            }
        }
      break;

    case BACKGROUND_TYPE_INVERTED:
      for (y = clear_y0; y < clear_y1; y++)
        {
          for (x = clear_x0; x < clear_x1; x++)
            {
              dindex = p.drawable->bpp * (p.drawable->width * y + x);
              pixels[dindex+0] = 255 - pixels[dindex+0];
              pixels[dindex+1] = 255 - pixels[dindex+1];
              pixels[dindex+2] = 255 - pixels[dindex+2];
            }
        }
      break;

    case BACKGROUND_TYPE_IMAGE:
      break;

    case BACKGROUND_TYPE_FOREGROUND:
      gimp_context_get_foreground (&color);
      gimp_rgb_get_uchar (&color, &pixel[0], &pixel[1], &pixel[2]);
      pixel[3] = 255;
      for (y = clear_y0; y < clear_y1; y++)
        {
          for (x = clear_x0; x < clear_x1; x++)
            {
              dindex = p.drawable->bpp * (p.drawable->width * y + x);
              for (i = 0; i < p.drawable->bpp; i++)
                {
                  pixels[dindex+i] = pixel[i];
                }
            }
        }
      break;

    case BACKGROUND_TYPE_BACKGROUND:
      gimp_context_get_background (&color);
      gimp_rgb_get_uchar (&color, &pixel[0], &pixel[1], &pixel[2]);
      pixel[3] = 255;
      for (y = clear_y0; y < clear_y1; y++)
        {
          for (x = clear_x0; x < clear_x1; x++)
            {
              dindex = p.drawable->bpp * (p.drawable->width * y + x);
              for(i = 0; i < p.drawable->bpp; i++)
                {
                  pixels[dindex+i] = pixel[i];
                }
            }
        }
      break;

    case BACKGROUND_TYPE_COLOR:
      gimp_rgba_get_uchar (&p.params.background_color,
                           pixel, pixel + 1, pixel + 2, pixel + 3);
      for (y = clear_y0; y < clear_y1; y++)
        {
          for (x = clear_x0; x < clear_x1; x++)
            {
              dindex = p.drawable->bpp * (p.drawable->width * y + x);
              for(i = 0; i < p.drawable->bpp; i++)
                {
                  pixels[dindex+i] = pixel[i];
                }
            }
        }
      break;
    }

  /* DRAW */
  for (t = tiles, i = 0; i < numof_tiles; i++, t++)
    {
      gint x0 = t->x + t->move_x;
      gint y0 = t->y + t->move_y;

      gimp_pixel_rgn_get_rect (&src, buffer, t->x, t->y, t->width, t->height);

      for (y = 0; y < t->height; y++)
        {
          py = y0 + y;
          for (x = 0; x < t->width; x++)
            {
              px = x0 + x;
              sindex = p.drawable->bpp * (t->width * y + x);
              if (0 <= px && px < p.drawable->width &&
                  0 <= py && py < p.drawable->height)
                {
                  dindex = p.drawable->bpp * (p.drawable->width * py + px);
                  overlap(&pixels[dindex], &buffer[sindex]);
                }
              else if (p.params.wrap_around)
                {
                  px = (px + p.drawable->width)  % p.drawable->width;
                  py = (py + p.drawable->height) % p.drawable->height;
                  dindex = p.drawable->bpp * (p.drawable->width * py + px);
                  overlap(&pixels[dindex], &buffer[sindex]);
                }
            }
        }

      gimp_progress_update ((gdouble) i / (gdouble) numof_tiles);
    }

  gimp_pixel_rgn_set_rect (&dst, pixels, 0, 0, p.drawable->width,
                           p.drawable->height);

  gimp_progress_update (1.0);
  gimp_drawable_flush (p.drawable);
  gimp_drawable_merge_shadow (p.drawable->drawable_id, TRUE);
  gimp_drawable_update (p.drawable->drawable_id,
                        p.selection.x0, p.selection.y0,
                        p.selection.width, p.selection.height);

  g_rand_free (gr);
  g_free (buffer);
  g_free (pixels);
  g_free (tiles);
}
Пример #10
0
static void
prepare_coef (params *p)
{
  GimpRGB color1;
  GimpRGB color2;
  gdouble scalex = svals.scalex;
  gdouble scaley = svals.scaley;
  GRand *gr;

  gr = g_rand_new ();

  g_rand_set_seed (gr, svals.seed);

  switch (svals.colorization)
    {
    case BILINEAR:
      p->blend = bilinear;
      break;
    case SINUS:
      p->blend = cosinus;
      break;
    case LINEAR:
    default:
      p->blend = linear;
    }

  if (svals.perturbation==IDEAL)
    {
      /* Presumably the 0 * g_rand_int ()s are to pop random
       * values off the prng, I don't see why though. */
      p->c11= 0 * g_rand_int (gr);
      p->c12= g_rand_double_range (gr, -1, 1) * scaley;
      p->c13= g_rand_double_range (gr, 0, 2 * G_PI);
      p->c21= 0 * g_rand_int (gr);
      p->c22= g_rand_double_range (gr, -1, 1)  * scaley;
      p->c23= g_rand_double_range (gr, 0, 2 * G_PI);
      p->c31= g_rand_double_range (gr, -1, 1) * scalex;
      p->c32= 0 * g_rand_int (gr);
      p->c33= g_rand_double_range (gr, 0, 2 * G_PI);
    }
  else
    {
      p->c11= g_rand_double_range (gr, -1, 1) * scalex;
      p->c12= g_rand_double_range (gr, -1, 1) * scaley;
      p->c13= g_rand_double_range (gr, 0, 2 * G_PI);
      p->c21= g_rand_double_range (gr, -1, 1) * scalex;
      p->c22= g_rand_double_range (gr, -1, 1) * scaley;
      p->c23= g_rand_double_range (gr, 0, 2 * G_PI);
      p->c31= g_rand_double_range (gr, -1, 1) * scalex;
      p->c32= g_rand_double_range (gr, -1, 1) * scaley;
      p->c33= g_rand_double_range (gr, 0, 2 * G_PI);
    }

  if (svals.tiling)
    {
      p->c11= ROUND (p->c11/(2*G_PI))*2*G_PI;
      p->c12= ROUND (p->c12/(2*G_PI))*2*G_PI;
      p->c21= ROUND (p->c21/(2*G_PI))*2*G_PI;
      p->c22= ROUND (p->c22/(2*G_PI))*2*G_PI;
      p->c31= ROUND (p->c31/(2*G_PI))*2*G_PI;
      p->c32= ROUND (p->c32/(2*G_PI))*2*G_PI;
    }

  color1 = svals.col1;
  color2 = svals.col2;

  if (drawable_is_grayscale)
    {
      gimp_rgb_set (&color1, 1.0, 1.0, 1.0);
      gimp_rgb_set (&color2, 0.0, 0.0, 0.0);
    }
  else
    {
      switch (svals.colors)
        {
        case USE_COLORS:
          break;
        case B_W:
          gimp_rgb_set (&color1, 1.0, 1.0, 1.0);
          gimp_rgb_set (&color2, 0.0, 0.0, 0.0);
          break;
        case USE_FG_BG:
          gimp_context_get_background (&color1);
          gimp_context_get_foreground (&color2);
          break;
        }
    }

  gimp_rgba_get_uchar (&color1, &p->r, &p->g, &p->b, &p->a);

  gimp_rgba_subtract (&color2, &color1);
  p->dr = color2.r * 255.0;
  p->dg = color2.g * 255.0;
  p->db = color2.b * 255.0;
  p->da = color2.a * 255.0;

  g_rand_free (gr);
}
Пример #11
0
static void
grid (gint32        image_ID,
      GimpDrawable *drawable,
      GimpPreview  *preview)
{
  GimpPixelRgn  srcPR, destPR;
  gint          bytes;
  gint          x_offset, y_offset;
  guchar       *dest, *buffer = NULL;
  gint          x, y;
  gboolean      alpha;
  gboolean      blend;
  guchar        hcolor[4];
  guchar        vcolor[4];
  guchar        icolor[4];
  guchar       *cmap;
  gint          ncolors;

  gimp_rgba_get_uchar (&grid_cfg.hcolor,
                       hcolor, hcolor + 1, hcolor + 2, hcolor + 3);
  gimp_rgba_get_uchar (&grid_cfg.vcolor,
                       vcolor, vcolor + 1, vcolor + 2, vcolor + 3);
  gimp_rgba_get_uchar (&grid_cfg.icolor,
                       icolor, icolor + 1, icolor + 2, icolor + 3);

  switch (gimp_image_base_type (image_ID))
    {
    case GIMP_RGB:
      blend = TRUE;
      break;

    case GIMP_GRAY:
      hcolor[0] = gimp_rgb_luminance_uchar (&grid_cfg.hcolor);
      vcolor[0] = gimp_rgb_luminance_uchar (&grid_cfg.vcolor);
      icolor[0] = gimp_rgb_luminance_uchar (&grid_cfg.icolor);
      blend = TRUE;
      break;

    case GIMP_INDEXED:
      cmap = gimp_image_get_colormap (image_ID, &ncolors);

      hcolor[0] = best_cmap_match (cmap, ncolors, &grid_cfg.hcolor);
      vcolor[0] = best_cmap_match (cmap, ncolors, &grid_cfg.vcolor);
      icolor[0] = best_cmap_match (cmap, ncolors, &grid_cfg.icolor);

      g_free (cmap);
      blend = FALSE;
      break;

    default:
      g_assert_not_reached ();
      blend = FALSE;
    }

  bytes = drawable->bpp;
  alpha = gimp_drawable_has_alpha (drawable->drawable_id);

  if (preview)
    {
      gimp_preview_get_position (preview, &sx1, &sy1);
      gimp_preview_get_size (preview, &sx2, &sy2);

      buffer = g_new (guchar, bytes * sx2 * sy2);

      sx2 += sx1;
      sy2 += sy1;
    }
  else
    {
      gimp_drawable_mask_bounds (drawable->drawable_id, &sx1, &sy1, &sx2, &sy2);

      gimp_pixel_rgn_init (&destPR,
                           drawable, 0, 0, sx2 - sx1, sy2 - sy1, TRUE, TRUE);
    }

  gimp_pixel_rgn_init (&srcPR,
                       drawable, 0, 0, sx2 - sx1, sy2 - sy1, FALSE, FALSE);

  dest = g_new (guchar, (sx2 - sx1) * bytes);

  for (y = sy1; y < sy2; y++)
    {
      gimp_pixel_rgn_get_row (&srcPR, dest, sx1, y, (sx2 - sx1));

      y_offset = y - grid_cfg.hoffset;
      while (y_offset < 0)
        y_offset += grid_cfg.hspace;

      if ((y_offset +
           (grid_cfg.hwidth / 2)) % grid_cfg.hspace < grid_cfg.hwidth)
        {
          for (x = sx1; x < sx2; x++)
            {
              pix_composite (&dest[(x-sx1) * bytes],
                             hcolor, bytes, blend, alpha);
            }
        }

      for (x = sx1; x < sx2; x++)
        {
          x_offset = grid_cfg.vspace + x - grid_cfg.voffset;
          while (x_offset < 0)
            x_offset += grid_cfg.vspace;

          if ((x_offset +
               (grid_cfg.vwidth / 2)) % grid_cfg.vspace < grid_cfg.vwidth)
            {
              pix_composite (&dest[(x-sx1) * bytes],
                             vcolor, bytes, blend, alpha);
            }

          if ((x_offset +
               (grid_cfg.iwidth / 2)) % grid_cfg.vspace < grid_cfg.iwidth
              &&
              ((y_offset % grid_cfg.hspace >= grid_cfg.ispace
                &&
                y_offset % grid_cfg.hspace < grid_cfg.ioffset)
               ||
               (grid_cfg.hspace -
                (y_offset % grid_cfg.hspace) >= grid_cfg.ispace
                &&
                grid_cfg.hspace -
                (y_offset % grid_cfg.hspace) < grid_cfg.ioffset)))
            {
              pix_composite (&dest[(x-sx1) * bytes],
                             icolor, bytes, blend, alpha);
            }
        }

      if ((y_offset +
           (grid_cfg.iwidth / 2)) % grid_cfg.hspace < grid_cfg.iwidth)
        {
          for (x = sx1; x < sx2; x++)
            {
              x_offset = grid_cfg.vspace + x - grid_cfg.voffset;
              while (x_offset < 0)
                x_offset += grid_cfg.vspace;

              if ((x_offset % grid_cfg.vspace >= grid_cfg.ispace
                   &&
                   x_offset % grid_cfg.vspace < grid_cfg.ioffset)
                  ||
                  (grid_cfg.vspace -
                   (x_offset % grid_cfg.vspace) >= grid_cfg.ispace
                   &&
                   grid_cfg.vspace -
                   (x_offset % grid_cfg.vspace) < grid_cfg.ioffset))
                {
                  pix_composite (&dest[(x-sx1) * bytes],
                                 icolor, bytes, blend, alpha);
                }
            }
        }

      if (preview)
        {
          memcpy (buffer + (y - sy1) * (sx2 - sx1) * bytes,
                  dest,
                  (sx2 - sx1) * bytes);
        }
      else
        {
          gimp_pixel_rgn_set_row (&destPR, dest, sx1, y, (sx2 - sx1));

          if (y % 16 == 0)
            gimp_progress_update ((gdouble) y / (gdouble) (sy2 - sy1));
        }
    }

  g_free (dest);

  if (preview)
    {
      gimp_preview_draw_buffer (preview, buffer, bytes * (sx2 - sx1));
      g_free (buffer);
    }
  else
    {
      gimp_progress_update (1.0);
      gimp_drawable_flush (drawable);
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
      gimp_drawable_update (drawable->drawable_id,
                            sx1, sy1, sx2 - sx1, sy2 - sy1);
    }
}