gimppixelfetcher.c 8.63 KB
Newer Older
Manish Singh's avatar
Manish Singh committed
1 2 3 4 5
/* LIBGIMP - The GIMP Library
 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
 *
 * gimppixelfetcher.c
 *
6
 * This library is free software: you can redistribute it and/or
Manish Singh's avatar
Manish Singh committed
7 8
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
9
 * version 3 of the License, or (at your option) any later version.
Manish Singh's avatar
Manish Singh committed
10 11 12 13 14 15 16
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17 18
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
Manish Singh's avatar
Manish Singh committed
19 20 21 22
 */

#include "config.h"

23 24
#define GIMP_DISABLE_DEPRECATION_WARNINGS

Manish Singh's avatar
Manish Singh committed
25 26 27
#include "gimp.h"


28 29 30 31 32 33 34 35 36 37 38 39 40
/**
 * SECTION: gimppixelfetcher
 * @title: gimppixelfetcher
 * @short_description: Functions for operating on pixel regions.
 *
 * These functions provide neighbourhood-based algorithms which get
 * dramatically slower on region boundaries, to the point where a
 * special treatment for neighbourhoods which are completely inside a
 * tile is called for. It hides the special treatment of tile borders,
 * making plug-in code more readable and shorter.
 **/


Manish Singh's avatar
Manish Singh committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
struct _GimpPixelFetcher
{
  gint                      col, row;
  gint                      img_width;
  gint                      img_height;
  gint                      sel_x1, sel_y1, sel_x2, sel_y2;
  gint                      img_bpp;
  gint                      tile_width, tile_height;
  guchar                    bg_color[4];
  GimpPixelFetcherEdgeMode  mode;
  GimpDrawable             *drawable;
  GimpTile                 *tile;
  gboolean                  tile_dirty;
  gboolean                  shadow;
};

57 58 59 60 61 62 63 64 65 66

/*  local function prototypes  */

static guchar * gimp_pixel_fetcher_provide_tile (GimpPixelFetcher *pf,
                                                 gint              x,
                                                 gint              y);


/*  public functions  */

67 68 69 70
/**
 * gimp_pixel_fetcher_new:
 * @drawable: the #GimpDrawable the new region will be attached to.
 * @shadow:   a #gboolean indicating whether the region is attached to
71
 *            the shadow tiles or the real @drawable tiles.
72 73 74 75 76
 *
 * Initialize a pixel region from the drawable.
 *
 * Return value: a pointer to a #GimpPixelRgn structure (or NULL).
 **/
Manish Singh's avatar
Manish Singh committed
77
GimpPixelFetcher *
78 79
gimp_pixel_fetcher_new (GimpDrawable *drawable,
                        gboolean      shadow)
Manish Singh's avatar
Manish Singh committed
80 81
{
  GimpPixelFetcher *pf;
82 83 84 85 86 87 88 89 90
  gint              width;
  gint              height;
  gint              bpp;

  g_return_val_if_fail (drawable != NULL, NULL);

  width  = gimp_drawable_width  (drawable->drawable_id);
  height = gimp_drawable_height (drawable->drawable_id);
  bpp    = gimp_drawable_bpp    (drawable->drawable_id);
Manish Singh's avatar
Manish Singh committed
91

92 93
  g_return_val_if_fail (width > 0 && height > 0 && bpp > 0, NULL);

94
  pf = g_slice_new0 (GimpPixelFetcher);
Manish Singh's avatar
Manish Singh committed
95 96 97 98 99 100 101

  gimp_drawable_mask_bounds (drawable->drawable_id,
                             &pf->sel_x1, &pf->sel_y1,
                             &pf->sel_x2, &pf->sel_y2);

  pf->col           = -1;
  pf->row           = -1;
102 103 104
  pf->img_width     = width;
  pf->img_height    = height;
  pf->img_bpp       = bpp;
Manish Singh's avatar
Manish Singh committed
105 106 107 108 109 110 111 112 113 114
  pf->tile_width    = gimp_tile_width ();
  pf->tile_height   = gimp_tile_height ();
  pf->bg_color[0]   = 0;
  pf->bg_color[1]   = 0;
  pf->bg_color[2]   = 0;
  pf->bg_color[3]   = 255;
  pf->mode          = GIMP_PIXEL_FETCHER_EDGE_NONE;
  pf->drawable      = drawable;
  pf->tile          = NULL;
  pf->tile_dirty    = FALSE;
115
  pf->shadow        = shadow;
Manish Singh's avatar
Manish Singh committed
116 117 118 119

  return pf;
}

120 121 122 123
/**
 * gimp_pixel_fetcher_destroy:
 * @pf: a pointer to a previously initialized #GimpPixelFetcher.
 *
124
 * Close a previously initialized pixel region.
125
 **/
126 127 128 129 130 131 132 133
void
gimp_pixel_fetcher_destroy (GimpPixelFetcher *pf)
{
  g_return_if_fail (pf != NULL);

  if (pf->tile)
    gimp_tile_unref (pf->tile, pf->tile_dirty);

134
  g_slice_free (GimpPixelFetcher, pf);
135 136
}

137 138 139 140 141
/**
 * gimp_pixel_fetcher_set_edge_mode:
 * @pf:   a pointer to a previously initialized #GimpPixelFetcher.
 * @mode: the new edge mode from #GimpPixelFetcherEdgeMode.
 *
142
 * Change the edge mode of a previously initialized pixel region.
143
 **/
Manish Singh's avatar
Manish Singh committed
144 145 146 147
void
gimp_pixel_fetcher_set_edge_mode (GimpPixelFetcher         *pf,
                                  GimpPixelFetcherEdgeMode  mode)
{
148 149
  g_return_if_fail (pf != NULL);

Manish Singh's avatar
Manish Singh committed
150 151 152
  pf->mode = mode;
}

153 154 155 156 157 158 159
/**
 * gimp_pixel_fetcher_set_bg_color:
 * @pf:    a pointer to a previously initialized #GimpPixelFetcher.
 * @color: the color to be used as bg color.
 *
 * Change the background color of a previously initialized pixel region.
 **/
Manish Singh's avatar
Manish Singh committed
160
void
161 162
gimp_pixel_fetcher_set_bg_color (GimpPixelFetcher *pf,
                                 const GimpRGB    *color)
Manish Singh's avatar
Manish Singh committed
163
{
164 165
  g_return_if_fail (pf != NULL);
  g_return_if_fail (color != NULL);
Manish Singh's avatar
Manish Singh committed
166 167 168 169 170

  switch (pf->img_bpp)
    {
    case 2: pf->bg_color[1] = 255;
    case 1:
171
      pf->bg_color[0] = gimp_rgb_luminance_uchar (color);
Manish Singh's avatar
Manish Singh committed
172 173 174 175
      break;

    case 4: pf->bg_color[3] = 255;
    case 3:
176
      gimp_rgb_get_uchar (color,
Manish Singh's avatar
Manish Singh committed
177 178 179 180 181
                          pf->bg_color, pf->bg_color + 1, pf->bg_color + 2);
      break;
    }
}

182 183 184 185 186 187 188 189 190
/**
 * gimp_pixel_fetcher_get_pixel:
 * @pf:    a pointer to a previously initialized #GimpPixelFetcher.
 * @x:     the x coordinate of the pixel to get.
 * @y:     the y coordinate of the pixel to get.
 * @pixel: the memory location where to return the pixel.
 *
 * Get a pixel from the pixel region.
 **/
Manish Singh's avatar
Manish Singh committed
191
void
192
gimp_pixel_fetcher_get_pixel (GimpPixelFetcher *pf,
Manish Singh's avatar
Manish Singh committed
193 194
                              gint              x,
                              gint              y,
195
                              guchar           *pixel)
Manish Singh's avatar
Manish Singh committed
196 197 198 199
{
  guchar *p;
  gint    i;

200 201 202 203 204 205
  g_return_if_fail (pf != NULL);
  g_return_if_fail (pixel != NULL);

  if (pf->mode == GIMP_PIXEL_FETCHER_EDGE_NONE &&
      (x < pf->sel_x1 || x >= pf->sel_x2 ||
       y < pf->sel_y1 || y >= pf->sel_y2))
Manish Singh's avatar
Manish Singh committed
206 207 208 209
    {
      return;
    }

210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
  if (x < 0 || x >= pf->img_width ||
      y < 0 || y >= pf->img_height)
    {
      switch (pf->mode)
        {
        case GIMP_PIXEL_FETCHER_EDGE_WRAP:
          if (x < 0 || x >= pf->img_width)
            {
              x %= pf->img_width;

              if (x < 0)
                x += pf->img_width;
            }

          if (y < 0 || y >= pf->img_height)
            {
              y %= pf->img_height;

              if (y < 0)
                y += pf->img_height;
            }
          break;

        case GIMP_PIXEL_FETCHER_EDGE_SMEAR:
          x = CLAMP (x, 0, pf->img_width - 1);
          y = CLAMP (y, 0, pf->img_height - 1);
          break;

        case GIMP_PIXEL_FETCHER_EDGE_BLACK:
          for (i = 0; i < pf->img_bpp; i++)
            pixel[i] = 0;
          return;

        case GIMP_PIXEL_FETCHER_EDGE_BACKGROUND:
          for (i = 0; i < pf->img_bpp; i++)
            pixel[i] = pf->bg_color[i];
          return;

        default:
          return;
        }
    }

Manish Singh's avatar
Manish Singh committed
253 254 255
  p = gimp_pixel_fetcher_provide_tile (pf, x, y);

  i = pf->img_bpp;
256

Manish Singh's avatar
Manish Singh committed
257
  do
258 259 260
    {
      *pixel++ = *p++;
    }
Manish Singh's avatar
Manish Singh committed
261 262 263
  while (--i);
}

264 265 266 267 268 269 270 271 272
/**
 * gimp_pixel_fetcher_put_pixel:
 * @pf:    a pointer to a previously initialized #GimpPixelFetcher.
 * @x:     the x coordinate of the pixel to set.
 * @y:     the y coordinate of the pixel to set.
 * @pixel: the pixel to set.
 *
 * Set a pixel in the pixel region.
 **/
Manish Singh's avatar
Manish Singh committed
273
void
274
gimp_pixel_fetcher_put_pixel (GimpPixelFetcher *pf,
Manish Singh's avatar
Manish Singh committed
275 276
                              gint              x,
                              gint              y,
277
                              const guchar     *pixel)
Manish Singh's avatar
Manish Singh committed
278 279 280 281
{
  guchar *p;
  gint    i;

282 283 284 285 286
  g_return_if_fail (pf != NULL);
  g_return_if_fail (pixel != NULL);

  if (x < pf->sel_x1 || x >= pf->sel_x2 ||
      y < pf->sel_y1 || y >= pf->sel_y2)
Manish Singh's avatar
Manish Singh committed
287 288 289 290 291 292 293
    {
      return;
    }

  p = gimp_pixel_fetcher_provide_tile (pf, x, y);

  i = pf->img_bpp;
294

Manish Singh's avatar
Manish Singh committed
295
  do
296 297 298
    {
      *p++ = *pixel++;
    }
Manish Singh's avatar
Manish Singh committed
299
  while (--i);
300 301

  pf->tile_dirty = TRUE;
Manish Singh's avatar
Manish Singh committed
302 303 304
}


305
/*  private functions  */
Manish Singh's avatar
Manish Singh committed
306

307 308 309 310
static guchar *
gimp_pixel_fetcher_provide_tile (GimpPixelFetcher *pf,
                                 gint              x,
                                 gint              y)
Manish Singh's avatar
Manish Singh committed
311
{
312 313
  gint col, row;
  gint coloff, rowoff;
Manish Singh's avatar
Manish Singh committed
314

315 316 317 318
  col    = x / pf->tile_width;
  coloff = x % pf->tile_width;
  row    = y / pf->tile_height;
  rowoff = y % pf->tile_height;
Manish Singh's avatar
Manish Singh committed
319

320 321 322 323
  if ((col != pf->col) || (row != pf->row) || (pf->tile == NULL))
    {
      if (pf->tile != NULL)
        gimp_tile_unref (pf->tile, pf->tile_dirty);
Manish Singh's avatar
Manish Singh committed
324

325 326 327
      pf->tile = gimp_drawable_get_tile (pf->drawable, pf->shadow, row, col);
      pf->tile_dirty = FALSE;
      gimp_tile_ref (pf->tile);
Manish Singh's avatar
Manish Singh committed
328

329 330
      pf->col = col;
      pf->row = row;
Manish Singh's avatar
Manish Singh committed
331 332
    }

333
  return pf->tile->data + pf->img_bpp * (pf->tile->ewidth * rowoff + coloff);
Manish Singh's avatar
Manish Singh committed
334
}