gimppixelfetcher.c 7.89 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
 * License along with this library.  If not, see
18
 * <https://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 160 161
/**
 * 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
162
void
163
gimp_pixel_fetcher_get_pixel (GimpPixelFetcher *pf,
Manish Singh's avatar
Manish Singh committed
164 165
                              gint              x,
                              gint              y,
166
                              guchar           *pixel)
Manish Singh's avatar
Manish Singh committed
167 168 169 170
{
  guchar *p;
  gint    i;

171 172 173 174 175 176
  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
177 178 179 180
    {
      return;
    }

181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
  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
224 225 226
  p = gimp_pixel_fetcher_provide_tile (pf, x, y);

  i = pf->img_bpp;
227

Manish Singh's avatar
Manish Singh committed
228
  do
229 230 231
    {
      *pixel++ = *p++;
    }
Manish Singh's avatar
Manish Singh committed
232 233 234
  while (--i);
}

235 236 237 238 239 240 241 242 243
/**
 * 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
244
void
245
gimp_pixel_fetcher_put_pixel (GimpPixelFetcher *pf,
Manish Singh's avatar
Manish Singh committed
246 247
                              gint              x,
                              gint              y,
248
                              const guchar     *pixel)
Manish Singh's avatar
Manish Singh committed
249 250 251 252
{
  guchar *p;
  gint    i;

253 254 255 256 257
  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
258 259 260 261 262 263 264
    {
      return;
    }

  p = gimp_pixel_fetcher_provide_tile (pf, x, y);

  i = pf->img_bpp;
265

Manish Singh's avatar
Manish Singh committed
266
  do
267 268 269
    {
      *p++ = *pixel++;
    }
Manish Singh's avatar
Manish Singh committed
270
  while (--i);
271 272

  pf->tile_dirty = TRUE;
Manish Singh's avatar
Manish Singh committed
273 274 275
}


276
/*  private functions  */
Manish Singh's avatar
Manish Singh committed
277

278 279 280 281
static guchar *
gimp_pixel_fetcher_provide_tile (GimpPixelFetcher *pf,
                                 gint              x,
                                 gint              y)
Manish Singh's avatar
Manish Singh committed
282
{
283 284
  gint col, row;
  gint coloff, rowoff;
Manish Singh's avatar
Manish Singh committed
285

286 287 288 289
  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
290

291 292 293 294
  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
295

296 297 298
      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
299

300 301
      pf->col = col;
      pf->row = row;
Manish Singh's avatar
Manish Singh committed
302 303
    }

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