예제 #1
0
gint32 execute_plugin(GimpDrawable* d, const char *nome, param_type *p)
{
//	gint i;
	guchar *img, *org;
	gint x,y,x2,y2,w,h;
//	guchar *work;
	GimpPixelRgn region, rgn_org;
	gint bpp = d->bpp;

	gimp_drawable_mask_bounds(d->drawable_id, &x, &y, &x2, &y2);
	w = x2 - x;
	h = y2 - y;

	img = malloc(w * h * bpp);
	org = malloc(w * h * bpp);
//	work = malloc(d.width * d.height * bpp);

	gimp_pixel_rgn_init(&region, d, x, y, w, h, TRUE, TRUE);
	//este é buffer para gravar a imagem modificada.
	gimp_pixel_rgn_init(&rgn_org, d, x, y, w, h, FALSE, FALSE);
	// Esta é a imagem em si 

	gimp_pixel_rgn_get_rect(&region, img, x, y, w, h);
	gimp_pixel_rgn_get_rect(&rgn_org, org, x, y, w, h);

	switch (*nome) {
		case 'S':
			super_grow(p, org, img, w, h, bpp);
			break;
		case 'G':
			memcpy(img, org, w * h * bpp);
			grow(p, org, img, w, h, bpp);
			break;
		case 'A':
			find_iso(p, org, img, w, h, bpp);
			break;
		default:
			make_height_field(p, org, img, w, h, bpp);
			break;
			
	}

	gimp_pixel_rgn_set_rect(&region, img, x, y, w, h);

	/* finish the process */
	gimp_drawable_flush (d);
	gimp_drawable_merge_shadow (d->drawable_id, TRUE);
	gimp_drawable_update (d->drawable_id, x, y, w, h);
	gimp_displays_flush();
	gimp_drawable_detach(d);

	free(img);
	free(org);

	return GIMP_PDB_SUCCESS;	
}
예제 #2
0
파일: dog.c 프로젝트: Amerekanets/gimp
static void
preview_update_preview (GimpPreview  *preview,
                        GimpDrawable *drawable)
{
  gint          x1, y1;
  gint          width, height;
  gint          bpp;
  guchar       *buffer;
  GimpPixelRgn  src_rgn;
  GimpPixelRgn  preview_rgn;
  gint32        image_id, src_image_id;
  gint32        preview_id;
  GimpDrawable *preview_drawable;

  bpp = gimp_drawable_bpp (drawable->drawable_id);

  gimp_preview_get_position (preview, &x1, &y1);
  gimp_preview_get_size (preview, &width, &height);

  buffer = g_new (guchar, width * height * bpp);

  gimp_pixel_rgn_init (&src_rgn, drawable,
                       x1, y1, width, height, FALSE, FALSE);
  gimp_pixel_rgn_get_rect (&src_rgn, buffer,
                           x1, y1, width, height);

  /* set up gimp drawable for rendering preview into */
  src_image_id = gimp_drawable_get_image (drawable->drawable_id);
  image_id = gimp_image_new (width, height,
                             gimp_image_base_type (src_image_id));
  preview_id = gimp_layer_new (image_id, "preview", width, height,
                               gimp_drawable_type (drawable->drawable_id),
                               100,
                               GIMP_NORMAL_MODE);
  preview_drawable = gimp_drawable_get (preview_id);
  gimp_image_add_layer (image_id, preview_id, 0);
  gimp_layer_set_offsets (preview_id, 0, 0);
  gimp_pixel_rgn_init (&preview_rgn, preview_drawable,
                       0, 0, width, height, TRUE, TRUE);
  gimp_pixel_rgn_set_rect (&preview_rgn, buffer,
                           0, 0, width, height);
  gimp_drawable_flush (preview_drawable);
  gimp_drawable_merge_shadow (preview_id, TRUE);
  gimp_drawable_update (preview_id, 0, 0, width, height);

  dog (image_id, preview_drawable, dogvals.inner, dogvals.outer, FALSE);

  gimp_pixel_rgn_get_rect (&preview_rgn, buffer,
                           0, 0, width, height);

  gimp_preview_draw_buffer (preview, buffer, width * bpp);

  gimp_image_delete (image_id);
  g_free (buffer);
}
예제 #3
0
static void
preview_update (GtkWidget *widget)
{
  GimpPixelRgn  src_rgn;        /* Source image region */
  guchar       *dst;            /* Output image */
  GimpPreview  *preview;        /* The preview widget */
  guchar       *src;            /* Source pixel rows */
  gint          img_bpp;
  gint          x1,y1;
  gint          width, height;

  preview = GIMP_PREVIEW (widget);

  img_bpp = gimp_drawable_bpp (drawable->drawable_id);

  width  = preview->width;
  height = preview->height;

  gimp_preview_get_position (preview, &x1, &y1);

  gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE);

  dst = g_new (guchar, width * height * img_bpp);
  src = g_new (guchar, width * height * img_bpp);

  gimp_pixel_rgn_get_rect (&src_rgn, src, x1, y1, width, height);

  despeckle_median (src, dst, width, height, img_bpp, despeckle_radius, TRUE);

  gimp_preview_draw_buffer (preview, dst, width * img_bpp);

  g_free (src);
  g_free (dst);
}
예제 #4
0
파일: waves.c 프로젝트: WilfR/Gimp-Matting
static void
waves (GimpDrawable *drawable)
{
  GimpPixelRgn  srcPr, dstPr;
  guchar       *src, *dst;
  guint         width, height, bpp, has_alpha;

  width     = drawable->width;
  height    = drawable->height;
  bpp       = drawable->bpp;
  has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);

  src = g_new (guchar, width * height * bpp);
  dst = g_new (guchar, width * height * bpp);
  gimp_pixel_rgn_init (&srcPr, drawable, 0, 0, width, height, FALSE, FALSE);
  gimp_pixel_rgn_init (&dstPr, drawable, 0, 0, width, height, TRUE, TRUE);
  gimp_pixel_rgn_get_rect (&srcPr, src, 0, 0, width, height);

  wave (src, dst, width, height, bpp, has_alpha,
        width / 2.0, height / 2.0,
        wvals.amplitude, wvals.wavelength, wvals.phase,
        wvals.type == MODE_SMEAR, wvals.reflective, TRUE);
  gimp_pixel_rgn_set_rect (&dstPr, dst, 0, 0, width, height);

  g_free (src);
  g_free (dst);

  gimp_drawable_flush (drawable);
  gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
  gimp_drawable_update (drawable->drawable_id, 0, 0, width, height);

  gimp_displays_flush ();
}
예제 #5
0
파일: pixelize.c 프로젝트: Amerekanets/gimp
/*
   This function operates on PixelArea, whose width and height are
   multiply of pixel width, and less than the tile size (to enhance
   its speed).

   If any coordinates of mask boundary is not multiply of pixel width
   (e.g.  x1 % pixelwidth != 0), operates on the region whose width
   or height is the remainder.
 */
static void
pixelize_small (GimpDrawable *drawable,
                gint          pixelwidth,
                gint          pixelheight,
                gint          tile_width,
                gint          tile_height)
{
  GimpPixelRgn src_rgn, dest_rgn;
  gint         bpp, has_alpha;
  gint         x1, y1, x2, y2;
  gint         progress, max_progress;

  gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
  gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, x2-x1, y2-y1, FALSE, FALSE);
  gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, x2-x1, y2-y1, TRUE, TRUE);

  /* Initialize progress */
  progress = 0;
  max_progress = (x2 - x1) * (y2 - y1);

  bpp = drawable->bpp;
  has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);

  area.width  = (tile_width  / pixelwidth)  * pixelwidth;
  area.height = (tile_height / pixelheight) * pixelheight;
  area.data= g_new (guchar, (glong) bpp * area.width * area.height);

  for (area.y = y1; area.y < y2;
       area.y += area.height - (area.y % area.height))
    {
      area.h = area.height - (area.y % area.height);
      area.h = MIN (area.h, y2 - area.y);

      for (area.x = x1; area.x < x2;
           area.x += area.width - (area.x % area.width))
        {
          area.w = area.width - (area.x % area.width);
          area.w = MIN(area.w, x2 - area.x);

          gimp_pixel_rgn_get_rect (&src_rgn, area.data,
                                   area.x, area.y, area.w, area.h);

          pixelize_sub (pixelwidth, pixelheight, bpp, has_alpha);

          gimp_pixel_rgn_set_rect (&dest_rgn, area.data,
                                   area.x, area.y, area.w, area.h);

          /* Update progress */
          progress += area.w * area.h;
          gimp_progress_update ((double) progress / (double) max_progress);
      }
    }

  g_free(area.data);

  /*  update the pixelized region  */
  gimp_drawable_flush (drawable);
  gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
  gimp_drawable_update (drawable->drawable_id, x1, y1, (x2 - x1), (y2 - y1));
}
/*  Private functions  */
static void draw_preview_area_update(GtkWidget *preview, GimpDrawable *drawable) {
    if(is_3D_preview_active())
    {
        /** Adding all references to preview for second release. */
        if ((local_vals.image_ID != 0) && (drawable != NULL))
        {
            update_preview = 0;
            if (drawable->bpp == 3) {
                GimpPixelRgn amap_rgn;
                gint rowbytes = PREVIEW_SIZE * 3;
                gint nbytes = drawable->width * drawable->height * 3;
                guchar *tmp = g_new(guchar, nbytes);
                guchar dst[PREVIEW_RGB_SIZE];

                gimp_pixel_rgn_init(&amap_rgn, drawable, 0, 0, drawable->width, drawable->height, 0, 0);
                gimp_pixel_rgn_get_rect(&amap_rgn, tmp, 0, 0, drawable->width, drawable->height);

                scale_pixels(dst, PREVIEW_SIZE, PREVIEW_SIZE, tmp, drawable->width, drawable->height, drawable->bpp);

                gimp_preview_area_draw(GIMP_PREVIEW_AREA(preview), 0, 0, PREVIEW_SIZE, PREVIEW_SIZE,
                                       GIMP_RGB_IMAGE, dst, rowbytes);
                gtk_widget_queue_draw (preview);
                g_free (tmp);
                _active = 'w';
            } else if (drawable->bpp == 4) {
                GimpPixelRgn amap_rgn;
                gint rowbytes = PREVIEW_SIZE * 4;
                gint nbytes = drawable->width * drawable->height * 4;
                guchar *tmp = g_new(guchar, nbytes);
                guchar dst[PREVIEW_RGBA_SIZE];

                gimp_pixel_rgn_init(&amap_rgn, drawable, 0, 0, drawable->width, drawable->height, 0, 0);
                gimp_pixel_rgn_get_rect(&amap_rgn, tmp, 0, 0, drawable->width, drawable->height);

                scale_pixels(dst, PREVIEW_SIZE, PREVIEW_SIZE, tmp, drawable->width, drawable->height, drawable->bpp);

                gimp_preview_area_draw(GIMP_PREVIEW_AREA(preview), 0, 0, PREVIEW_SIZE, PREVIEW_SIZE,
                                     GIMP_RGBA_IMAGE, dst, rowbytes);
                
                gtk_widget_queue_draw (preview);
                g_free (tmp);
                _active = 'w';
            }
        }
    }
}
예제 #7
0
void fft_prepare(PluginData *pd)
{
	gint         w = pd->image_width, h = pd->image_height;
	gint         channel_count = pd->channel_count;
	int          x, y;
	float      **image;
	guchar      *img_pixels;
	float        norm;
	image = pd->image = (float**) malloc(sizeof(float*) * channel_count);
	pd->image_freq = (fftwf_complex**) malloc(sizeof(fftwf_complex*) * channel_count);
  img_pixels = pd->img_pixels = g_new (guchar, w * h * channel_count);
  //allocate an array for each channel
  for (int channel = 0; channel < channel_count; channel ++){
	  image[channel] = (float*) fftwf_malloc(sizeof(float) * w * h);
		pd->image_freq[channel] = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * (w/2+1) * h);
	}
	// printf("Image data occupies %lu MB.\n", (sizeof(float) * w * h * channel_count) >> 20);
	// printf("Frequency data occupies %lu MB.\n", (sizeof(fftwf_complex) * (w/2+1) * h * channel_count) >> 20);
	
	// forward plan
	fftwf_plan plan = fftwf_plan_dft_r2c_2d(pd->image_height, pd->image_width, *image, *pd->image_freq, FFTW_ESTIMATE);
	// inverse plan (to be reused)
	pd->plan = fftwf_plan_dft_c2r_2d(pd->image_height, pd->image_width, *pd->image_freq, *image, FFTW_ESTIMATE);

	// set image region to reading mode
	gimp_pixel_rgn_init (&pd->region, pd->drawable, 0, 0, w, h, FALSE, FALSE);
	gimp_pixel_rgn_get_rect(&pd->region, img_pixels, 0, 0, w, h);
	
	// execute forward FFT once
	int pw = w/2+1; // physical width
	float diagonal = sqrt(h*h + w*w)/2.0;
	norm = 1.0/(w*h);
	for(int channel=0; channel<channel_count; channel++)
	{
		// convert one color channel to float[]
		for(int i=0; i < w*h; i ++)
		{
			 image[channel][i] =  (float) img_pixels[(i)*channel_count + channel] * norm;
		}
		// transform the channel
		fftwf_execute_dft_r2c(plan, image[channel], pd->image_freq[channel]);
		for(int i=0; i < w*h; i ++)
		{
			 image[channel][i] =  (float) img_pixels[(i)*channel_count + channel] * norm;
		}
		// copy the channel again, for preview
		for(int i=0; i < w*h; i ++)
		{
			 image[channel][i] =  (float) img_pixels[(i)*channel_count + channel];
		}
	}
	fftwf_destroy_plan(plan);
}
예제 #8
0
static void
color_to_alpha_preview (GimpPreview  *preview,
                        GimpDrawable *drawable)
{
  GimpPixelRgn  src_rgn;
  gint          x, y;
  gint          width, height;
  gint          bpp;
  gint          i;
  guchar       *src, *dest;

  bpp = drawable->bpp;
  gimp_preview_get_position (preview, &x, &y);
  gimp_preview_get_size (preview, &width, &height);

  dest = g_new (guchar, width * height * 4);
  src = g_new (guchar, width * height * bpp);

  gimp_pixel_rgn_init (&src_rgn, drawable,
                       x, y, width, height,
                       FALSE, FALSE);
  gimp_pixel_rgn_get_rect (&src_rgn, src, x, y, width, height);

  for (i = 0; i < width * height; i++)
    to_alpha_func (src + i * bpp, dest + i * 4, bpp, NULL);

  g_free (src);

  /* Our code assumes that the drawable has an alpha channel (and adds
   * one later if the effect is actually performed). For that reason
   * we have to take care when drawing the preview.
   */
  if (bpp == 4)
    {
      gimp_preview_draw_buffer (preview, dest, width * 4);
    }
  else
    {
      /* This is not correct because we ignore the selection, but it
       * is the best we can easily do.
       */
      gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview->area),
                              0, 0, width, height,
                              GIMP_RGBA_IMAGE, dest, width * 4);
    }

  g_free (dest);
}
예제 #9
0
static void
despeckle (void)
{
  GimpPixelRgn  src_rgn;        /* Source image region */
  GimpPixelRgn  dst_rgn;
  guchar       *src;
  guchar       *dst;
  gint          img_bpp;
  gint          x, y;
  gint          width, height;

  img_bpp = gimp_drawable_bpp (drawable->drawable_id);

  if (! gimp_drawable_mask_intersect (drawable->drawable_id,
                                      &x, &y, &width, &height))
    return;

  gimp_pixel_rgn_init (&src_rgn, drawable, x, y, width, height, FALSE, FALSE);
  gimp_pixel_rgn_init (&dst_rgn, drawable, x, y, width, height, TRUE, TRUE);

  src = g_new (guchar, width * height * img_bpp);
  dst = g_new (guchar, width * height * img_bpp);

  gimp_pixel_rgn_get_rect (&src_rgn, src, x, y, width, height);

  despeckle_median (src, dst, width, height, img_bpp, despeckle_radius, FALSE);

  gimp_pixel_rgn_set_rect (&dst_rgn, dst, x, y, width, height);

  gimp_drawable_flush (drawable);
  gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
  gimp_drawable_update (drawable->drawable_id, x, y, width, height);

  g_free (dst);
  g_free (src);
}
예제 #10
0
파일: xjpeg.c 프로젝트: WilfR/Gimp-Matting
gint
xjpg_save_drawable (const char     *filename,
                    gint32          image_ID,
                    gint32          drawable_ID,
                    gint            save_mode,
                    t_JpegSaveVals *jsvals)
{
  GimpPixelRgn pixel_rgn;
  GimpDrawable *drawable;
  GimpImageType drawable_type;
  struct jpeg_compress_struct cinfo;
  struct my_error_mgr jerr;
  FILE * volatile outfile;
  guchar *temp, *t;
  guchar *data;
  guchar *src, *s;
  int has_alpha;
  int rowstride, yend;
  int i, j;
  int alpha_offset;
  guchar alpha_byte;
  guchar volatile l_alpha_sum;

  alpha_offset = 0;
  has_alpha = 0;
  src = NULL;
  temp = NULL;
  data = NULL;
  l_alpha_sum = 0xff;

  drawable = gimp_drawable_get (drawable_ID);
  drawable_type = gimp_drawable_type (drawable_ID);
  switch (drawable_type)
  {
    case GIMP_RGB_IMAGE:
    case GIMP_GRAY_IMAGE:
      if(save_mode == JSVM_ALPHA)
        return FALSE;              /* there is no alpha to save */
      break;
    case GIMP_RGBA_IMAGE:
    case GIMP_GRAYA_IMAGE:
      break;

    case GIMP_INDEXED_IMAGE:
      /*g_message ("jpeg: cannot operate on indexed color images");*/
      return FALSE;
      break;
    default:
      /*g_message ("jpeg: cannot operate on unknown image types");*/
      return FALSE;
      break;
  }



  gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE);


  /* Step 1: allocate and initialize JPEG compression object */

  /* We have to set up the error handler first, in case the initialization
   * step fails.  (Unlikely, but it could happen if you are out of memory.)
   * This routine fills in the contents of struct jerr, and returns jerr's
   * address which we place into the link field in cinfo.
   */
  cinfo.err = jpeg_std_error (&jerr.pub);
  jerr.pub.error_exit = my_error_exit;

  outfile = NULL;
  /* Establish the setjmp return context for my_error_exit to use. */
  if (setjmp (jerr.setjmp_buffer))
    {
      /* If we get here, the JPEG code has signaled an error.
       * We need to clean up the JPEG object, close the input file, and return.
       */
      jpeg_destroy_compress (&cinfo);
      if (outfile)
	fclose (outfile);
      if (drawable)
	gimp_drawable_detach (drawable);

      return FALSE;
    }

  /* Now we can initialize the JPEG compression object. */
  jpeg_create_compress (&cinfo);

  /* Step 2: specify data destination (eg, a file) */
  /* Note: steps 2 and 3 can be done in either order. */

  /* Here we use the library-supplied code to send compressed data to a
   * stdio stream.  You can also write your own code to do something else.
   * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
   * requires it in order to write binary files.
   */
  if ((outfile = g_fopen (filename, "wb")) == NULL)
    {
      g_message ("can't open %s\n", filename);
      return FALSE;
    }
  jpeg_stdio_dest (&cinfo, outfile);

  /* Get the input image and a pointer to its data.
   */
  switch (drawable_type)
  {
    case GIMP_RGB_IMAGE:
    case GIMP_GRAY_IMAGE:
      /* # of color components per pixel */
      cinfo.input_components = drawable->bpp;
      has_alpha = 0;
      alpha_offset = 0;
      break;
    case GIMP_RGBA_IMAGE:
    case GIMP_GRAYA_IMAGE:
      if(save_mode == JSVM_ALPHA)
      {
 	cinfo.input_components = 1;
      }
      else
      {
        /* # of color components per pixel (minus the GIMP alpha channel) */
	cinfo.input_components = drawable->bpp - 1;
      }
      alpha_offset = drawable->bpp -1;
      has_alpha = 1;
      break;
    default:
      return FALSE;
      break;
  }

  /* Step 3: set parameters for compression */

  /* First we supply a description of the input image.
   * Four fields of the cinfo struct must be filled in:
   */
  /* image width and height, in pixels */
  cinfo.image_width = drawable->width;
  cinfo.image_height = drawable->height;
  /* colorspace of input image */
  cinfo.in_color_space = ( (save_mode != JSVM_ALPHA) &&
                          (drawable_type == GIMP_RGB_IMAGE ||
			   drawable_type == GIMP_RGBA_IMAGE))
    ? JCS_RGB : JCS_GRAYSCALE;
  /* Now use the library's routine to set default compression parameters.
   * (You must set at least cinfo.in_color_space before calling this,
   * since the defaults depend on the source color space.)
   */
  jpeg_set_defaults (&cinfo);
  /* Now you can set any non-default parameters you wish to.
   * Here we just illustrate the use of quality (quantization table) scaling:
   */
  jpeg_set_quality (&cinfo, (int) (jsvals->quality * 100), TRUE /* limit to baseline-JPEG values */);
  cinfo.smoothing_factor = (int) (jsvals->smoothing * 100);
  cinfo.optimize_coding = jsvals->optimize;

  /* Step 4: Start compressor */

  /* TRUE ensures that we will write a complete interchange-JPEG file.
   * Pass TRUE unless you are very sure of what you're doing.
   */
  jpeg_start_compress (&cinfo, TRUE);

  /* Step 5: while (scan lines remain to be written) */
  /*           jpeg_write_scanlines(...); */

  /* Here we use the library's state variable cinfo.next_scanline as the
   * loop counter, so that we don't have to keep track ourselves.
   * To keep things simple, we pass one scanline per call; you can pass
   * more if you wish, though.
   */
  /* JSAMPLEs per row in image_buffer */
  rowstride = drawable->bpp * drawable->width;
  temp = (guchar *) g_malloc (cinfo.image_width * cinfo.input_components);
  data = (guchar *) g_malloc (rowstride * gimp_tile_height ());
  src = data;

  while (cinfo.next_scanline < cinfo.image_height)
  {
      if ((cinfo.next_scanline % gimp_tile_height ()) == 0)
      {
	  yend = cinfo.next_scanline + gimp_tile_height ();
	  yend = MIN (yend, cinfo.image_height);
	  gimp_pixel_rgn_get_rect (&pixel_rgn, data, 0, cinfo.next_scanline, cinfo.image_width,
				   (yend - cinfo.next_scanline));
	  src = data;
      }

      t = temp;
      s = src;
      i = cinfo.image_width;

      switch(save_mode)
      {
	case JSVM_DRAWABLE:
	    if(jsvals->clr_transparent)
	    {
	      /* save drawable (clear pixels where alpha is full transparent) */
	      while (i--)
	      {
	          alpha_byte = s[cinfo.input_components];
		  for (j = 0; j < cinfo.input_components; j++)
		  {
		     if(alpha_byte != 0) { *t++ = *s++;   }
		     else                { *t++ = 0; s++; }
		  }
		  if (has_alpha)  /* ignore alpha channel */
		  {
		    s++;
		  }
	      }
	    }
	    else
	    {
	      /* save the drawable as it is (ignore alpha channel) */
	      while (i--)
	      {
		  for (j = 0; j < cinfo.input_components; j++)
		  {
                    *t++ = *s++;
		  }
		  if (has_alpha)  /* ignore alpha channel */
		  {
		    s++;
		  }
	      }
	    }
	    break;
        case JSVM_ALPHA:
	    /* save the drawable's alpha cahnnel */
	    while (i--)
	    {
		s += alpha_offset;
		l_alpha_sum &= (*s);  /* check all alpha bytes for full opacity */
                *t++ = *s++;
	    }
	    break;
      }

      src += rowstride;
      jpeg_write_scanlines (&cinfo, (JSAMPARRAY) &temp, 1);

      if ((cinfo.next_scanline % 5) == 0)
	gimp_progress_update ((double) cinfo.next_scanline / (double) cinfo.image_height);
  }
  gimp_progress_update (1.0);

  /* Step 6: Finish compression */
  jpeg_finish_compress (&cinfo);
  /* After finish_compress, we can close the output file. */
  fclose (outfile);

  if((save_mode == JSVM_ALPHA) && (l_alpha_sum == 0xff))
  {
    /* all bytes in the alpha channel are set to 0xff
     * == full opaque image. We can remove the file
     * to save diskspace
     */
    g_remove(filename);
  }

  /* Step 7: release JPEG compression object */

  /* This is an important step since it will release a good deal of memory. */
  jpeg_destroy_compress (&cinfo);
  /* free the temporary buffer */
  g_free (temp);
  g_free (data);

  gimp_drawable_detach (drawable);

  return TRUE;
}	/* end xjpg_save_drawable */
예제 #11
0
파일: xjpeg.c 프로젝트: WilfR/Gimp-Matting
gint
xjpg_load_layer_alpha (const char *filename,
                       gint32      image_id,
                       gint32      layer_id)
{
  GimpPixelRgn l_pixel_rgn;
  GimpDrawable *l_drawable;
  struct jpeg_decompress_struct cinfo;
  struct my_error_mgr jerr;
  FILE *infile;
  guchar *l_buf;
  guchar *l_dstbuf;
  guchar **l_rowbuf;
  int l_tile_height;
  int l_scanlines;
  int l_idx, l_start, l_end;
  int l_alpha_offset;
  guchar *l_buf_ptr;
  guchar *l_dstbuf_ptr;

  /* We set up the normal JPEG error routines. */
  cinfo.err = jpeg_std_error (&jerr.pub);
  jerr.pub.error_exit = my_error_exit;

  /* add alpha channel */
  gimp_layer_add_alpha (layer_id);

  if ((infile = g_fopen (filename, "rb")) == NULL)
  {
      /* No alpha found, thats OK, use full opaque alpha channel
       * (there is no need not store alpha channels on full opaque channels)
       * (fixme: if filename exists but is not readable
       *         we should return -1 to indicate an error
       */
      return 0;  /* OK */
  }

  /* Establish the setjmp return context for my_error_exit to use. */
  if (setjmp (jerr.setjmp_buffer))
  {
      /* If we get here, the JPEG code has signaled an error.
       * We need to clean up the JPEG object, close the input file, and return.
       */
      jpeg_destroy_decompress (&cinfo);
      if (infile)
	fclose (infile);

      g_printerr ("XJT: JPEG alpha load error\n");
      return -1;
  }

  /* Now we can initialize the JPEG decompression object. */
  jpeg_create_decompress (&cinfo);

  /* Step 2: specify data source (eg, a file) */

  jpeg_stdio_src (&cinfo, infile);

  /* Step 3: read file parameters with jpeg_read_header() */

  (void) jpeg_read_header (&cinfo, TRUE);
  /* We can ignore the return value from jpeg_read_header since
   *   (a) suspension is not possible with the stdio data source, and
   *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
   * See libjpeg.doc for more info.
   */

  /* Step 4: set parameters for decompression */

  /* In this example, we don't need to change any of the defaults set by
   * jpeg_read_header(), so we do nothing here.
   */

  /* Step 5: Start decompressor */

  jpeg_start_decompress (&cinfo);

  /* We may need to do some setup of our own at this point before reading
   * the data.  After jpeg_start_decompress() we have the correct scaled
   * output image dimensions available, as well as the output colormap
   * if we asked for color quantization.
   * In this example, we need to make an output work buffer of the right size.
   */
  /* temporary buffer (for read in jpeg lines) */
  l_tile_height = gimp_tile_height ();
  l_buf = g_new (guchar, l_tile_height * cinfo.output_width * cinfo.output_components);
  l_rowbuf = g_new (guchar*, l_tile_height);

  for (l_idx = 0; l_idx < l_tile_height; l_idx++)
  {
    l_rowbuf[l_idx] = l_buf + cinfo.output_width * cinfo.output_components * l_idx;
  }

  l_drawable = gimp_drawable_get (layer_id);
  if(l_drawable == NULL)
  {
    g_printerr ("XJT: gimp_drawable_get failed on layer id %d\n", (int)layer_id);
    fclose(infile);
    return -1;
  }

  /* Check if jpeg file can be used as alpha channel
   */
  if((cinfo.output_components != 1) ||
     (cinfo.output_width  != l_drawable->width) ||
     (cinfo.output_height != l_drawable->height))
  {
     g_printerr ("XJT: cant load %s as alpha channel\n", filename);
     fclose (infile);
     return -1;
  }

  /* buffer to read in the layer and merge with the alpha from jpeg file */
  l_dstbuf = g_new (guchar, l_tile_height * l_drawable->width * l_drawable->bpp);

  gimp_pixel_rgn_init (&l_pixel_rgn, l_drawable, 0, 0, l_drawable->width, l_drawable->height, TRUE, FALSE);
  l_alpha_offset = l_drawable->bpp -1;

  /* Step 6: while (scan lines remain to be read) */
  /*           jpeg_read_scanlines(...); */

  /* Here we use the library's state variable cinfo.output_scanline as the
   * loop counter, so that we don't have to keep track ourselves.
   */
  while (cinfo.output_scanline < cinfo.output_height)
  {
      l_start = cinfo.output_scanline;
      l_end = cinfo.output_scanline + l_tile_height;
      l_end = MIN (l_end, cinfo.output_height);
      l_scanlines = l_end - l_start;

      for (l_idx = 0; l_idx < l_scanlines; l_idx++)
      {
	jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &l_rowbuf[l_idx], 1);
      }

      gimp_pixel_rgn_get_rect (&l_pixel_rgn, l_dstbuf, 0, l_start, l_drawable->width, l_scanlines);

      /* copy the loaded jpeg data (from buf) to the layers alpha channel data */
      l_idx = l_tile_height * l_drawable->width;
      l_buf_ptr = l_buf;
      l_dstbuf_ptr = l_dstbuf;
      while(l_idx--)
      {
         l_dstbuf_ptr  += l_alpha_offset;
         *l_dstbuf_ptr++ = *l_buf_ptr++;
      }

      gimp_pixel_rgn_set_rect (&l_pixel_rgn, l_dstbuf, 0, l_start, l_drawable->width, l_scanlines);

      gimp_progress_update ((double) cinfo.output_scanline / (double) cinfo.output_height);
  }
  gimp_progress_update (1.0);

  /* Step 7: Finish decompression */

  jpeg_finish_decompress (&cinfo);
  /* We can ignore the return value since suspension is not possible
   * with the stdio data source.
   */

  /* Step 8: Release JPEG decompression object */

  /* This is an important step since it will release a good deal of memory. */
  jpeg_destroy_decompress (&cinfo);

  /* free up the temporary buffers */
  g_free (l_rowbuf);
  g_free (l_buf);
  g_free (l_dstbuf);

  /* After finish_decompress, we can close the input file.
   * Here we postpone it until after no more JPEG errors are possible,
   * so as to simplify the setjmp error logic above.  (Actually, I don't
   * think that jpeg_destroy can do an error exit, but why assume anything...)
   */
  fclose (infile);

  /* At this point you may want to check to see whether any corrupt-data
   * warnings occurred (test whether jerr.num_warnings is nonzero).
   */


  return (0);  /* OK */

}	/* xjpg_load_layer_alpha */
예제 #12
0
static void
c2g_region (GimpPixelRgn *srcPR,
                GimpPixelRgn *destPR,
                gint          bytes, /* Bytes per pixel */
                gdouble       radius,
                gdouble       amount_p,
                gdouble       gamma_p,
                gint          x1,    /* Corners of subregion */
                gint          x2,
                gint          y1,
                gint          y2,
                gboolean      show_progress)
{
  guchar  *src;
  guchar  *dest;
  guchar *bigsrc;
  guchar *bigdest;
  guchar *tmpdest;
 
  gint     width   = x2 - x1;
  gint     height  = y2 - y1;
  gdouble *cmatrix = NULL;
  gint     cmatrix_length;
  gdouble *ctable;
  gint     row, col, idx;
  gint w = c2g_params.radius+10;

  gdouble amount = c2g_params.amount;
  gdouble gamma = c2g_params.gamma;
    
  if (show_progress)
    gimp_progress_init (_("Blurring..."));
  
  iir_init(c2g_params.radius);

  /* allocate buffers */
  src  = g_new (guchar, MAX (width, height) * bytes);
  dest = g_new (guchar, MAX (width, height) * bytes);
  iir.p = g_new(gdouble, MAX (width, height)+2*w);

 
  bigsrc = g_new(guchar, width * height * bytes);
  bigdest = g_new(guchar, width * height * bytes);
  tmpdest = g_new(guchar, width * height * bytes);

  if (show_progress)
    gimp_progress_init (_("Colour converting..."));
  
  // 1. Calculate Nayatani Grey and Blur in LAB
  gimp_pixel_rgn_get_rect (srcPR, bigsrc, x1, y1, width, height);
  extract_lab(bigsrc, bytes, width * height, bigdest);
  nayatani(bigdest,bytes,width * height, bigdest);
  gimp_pixel_rgn_set_rect (destPR, bigdest, x1, y1, width, height);

  // 2. Make a blur of Grey LAB
  for (row = 0, idx=0; row < height; row++, idx+=width)
    {
      gimp_pixel_rgn_get_row (destPR, src, x1, y1 + row, width);
      blur_line (ctable, cmatrix, cmatrix_length, src, dest, width, bytes);   
      gimp_pixel_rgn_set_row (destPR, dest, x1, y1 + row, width);
    }

  for (col = 0; col < width; col++)
    {
      gimp_pixel_rgn_get_col (destPR, src, x1 + col, y1, height);
      blur_line (ctable, cmatrix, cmatrix_length, src, dest, height, bytes);
      gimp_pixel_rgn_set_col (destPR, dest, x1 + col, y1, height);

      if (show_progress && col % 8 == 0)
        gimp_progress_update ((gdouble) col / (3 * width) + 0.33);
    }

  // 3. Convert grey and blur back to RGB.
  compose_lab(bigdest, width * height, bytes, bigdest); // bigdest=greyRGB
  gimp_pixel_rgn_get_rect (destPR, bigsrc, x1, y1, width, height);
  compose_lab(bigsrc, width * height, bytes, bigsrc); // bigsrc= blurgreyRGB

  // 4. Blur Colour RGB and write into destPR
  gimp_pixel_rgn_get_rect (srcPR, tmpdest, x1, y1, width, height);
  gimp_pixel_rgn_set_rect (destPR, tmpdest, x1, y1, width, height);

  for (row = 0, idx=0; row < height; row++, idx+=width)
    {
      gimp_pixel_rgn_get_row (destPR, src, x1, y1 + row, width);
      blur_line (ctable, cmatrix, cmatrix_length, src, dest, width, bytes);   
      gimp_pixel_rgn_set_row (destPR, dest, x1, y1 + row, width);
    }

  for (col = 0; col < width; col++)
    {
      gimp_pixel_rgn_get_col (destPR, src, x1 + col, y1, height);
      blur_line (ctable, cmatrix, cmatrix_length, src, dest, height, bytes);
      gimp_pixel_rgn_set_col (destPR, dest, x1 + col, y1, height);

      if (show_progress && col % 8 == 0)
        gimp_progress_update ((gdouble) col / (3 * width) + 0.33);
    }

  // destPR = blur colour RGB
  chromaunsharp( srcPR, destPR, bigdest, bigsrc, bytes, x1, y1, width, height, amount, gamma, tmpdest );
  compose_lab(tmpdest, width * height, bytes, tmpdest); // tmpdest has unsharp
  gimp_pixel_rgn_set_rect (destPR, tmpdest, x1, y1, width, height);
  

  if (show_progress)
    gimp_progress_update (0.0);

  g_free (bigsrc);
  g_free (bigdest);
  g_free (tmpdest);
  g_free (iir.p);
  g_free (dest);
  g_free (src);
  
}
예제 #13
0
파일: oilify.c 프로젝트: Amerekanets/gimp
/*
 * For all x and y as requested, replace the pixel at (x,y)
 * with a weighted average of the most frequently occurring
 * values in a circle of mask_size diameter centered at (x,y).
 */
static void
oilify (GimpDrawable *drawable,
        GimpPreview  *preview)
{
  gboolean      use_inten;
  gboolean      use_msmap = FALSE;
  gboolean      use_emap = FALSE;
  GimpDrawable *mask_size_map_drawable = NULL;
  GimpDrawable *exponent_map_drawable = NULL;
  GimpPixelRgn  mask_size_map_rgn;
  GimpPixelRgn  exponent_map_rgn;
  gint          msmap_bpp = 0;
  gint          emap_bpp = 0;
  GimpPixelRgn  dest_rgn;
  GimpPixelRgn *regions[3];
  gint          n_regions;
  gint          bpp;
  gint         *sqr_lut;
  gint          x1, y1, x2, y2;
  gint          width, height;
  gint          Hist[HISTSIZE];
  gint          Hist_rgb[4][HISTSIZE];
  gpointer      pr;
  gint          progress, max_progress;
  guchar       *src_buf;
  guchar       *src_inten_buf = NULL;
  gint          i;

  use_inten = (ovals.mode == MODE_INTEN);

  /*  Get the selection bounds  */
  if (preview)
    {
      gimp_preview_get_position (preview, &x1, &y1);
      gimp_preview_get_size (preview, &width, &height);

      x2 = x1 + width;
      y2 = y1 + height;
    }
  else
    {
      gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
      width  = x2 - x1;
      height = y2 - y1;
    }

  progress = 0;
  max_progress = width * height;

  bpp = drawable->bpp;

  /*
   * Look-up-table implementation of the square function, for use in the
   * VERY TIGHT inner loops
   */
  {
    gint lut_size = (gint) ovals.mask_size / 2 + 1;

    sqr_lut = g_new (gint, lut_size);

    for (i = 0; i < lut_size; i++)
      sqr_lut[i] = SQR (i);
  }

  /*  Get the map drawables, if applicable  */

  if (ovals.use_mask_size_map && ovals.mask_size_map >= 0)
    {
      use_msmap = TRUE;

      mask_size_map_drawable = gimp_drawable_get (ovals.mask_size_map);
      gimp_pixel_rgn_init (&mask_size_map_rgn, mask_size_map_drawable,
                           x1, y1, width, height, FALSE, FALSE);

      msmap_bpp = mask_size_map_drawable->bpp;
    }

  if (ovals.use_exponent_map && ovals.exponent_map >= 0)
    {
      use_emap = TRUE;

      exponent_map_drawable = gimp_drawable_get (ovals.exponent_map);
      gimp_pixel_rgn_init (&exponent_map_rgn, exponent_map_drawable,
                           x1, y1, width, height, FALSE, FALSE);

      emap_bpp = exponent_map_drawable->bpp;
    }

  gimp_pixel_rgn_init (&dest_rgn, drawable,
                       x1, y1, width, height, (preview == NULL), TRUE);

  {
    GimpPixelRgn src_rgn;

    gimp_pixel_rgn_init (&src_rgn, drawable,
                         x1, y1, width, height, FALSE, FALSE);
    src_buf = g_new (guchar, width * height * bpp);
    gimp_pixel_rgn_get_rect (&src_rgn, src_buf, x1, y1, width, height);
  }

  /*
   * If we're working in intensity mode, then generate a separate intensity
   * map of the source image. This way, we can avoid calculating the
   * intensity of any given source pixel more than once.
   */
  if (use_inten)
    {
      guchar *src;
      guchar *dest;

      src_inten_buf = g_new (guchar, width * height);

      for (i = 0,
           src = src_buf,
           dest = src_inten_buf
           ;
           i < (width * height)
           ;
           i++,
           src += bpp,
           dest++)
        {
          *dest = (guchar) GIMP_RGB_LUMINANCE (src[0], src[1], src[2]);
        }
    }

  n_regions = 0;
  regions[n_regions++] = &dest_rgn;
  if (use_msmap)
    regions[n_regions++] = &mask_size_map_rgn;
  if (use_emap)
    regions[n_regions++] = &exponent_map_rgn;

  for (pr = gimp_pixel_rgns_register2 (n_regions, regions);
       pr != NULL;
       pr = gimp_pixel_rgns_process (pr))
    {
      gint    y;
      guchar *dest_row;
      guchar *src_msmap_row = NULL;
      guchar *src_emap_row = NULL;

      for (y = dest_rgn.y,
           dest_row = dest_rgn.data,
           src_msmap_row = mask_size_map_rgn.data,  /* valid iff use_msmap */
           src_emap_row = exponent_map_rgn.data     /* valid iff use_emap */
           ;
           y < (gint) (dest_rgn.y + dest_rgn.h)
           ;
           y++,
           dest_row += dest_rgn.rowstride,
           src_msmap_row += mask_size_map_rgn.rowstride,  /* valid iff use_msmap */
           src_emap_row += exponent_map_rgn.rowstride)    /* valid iff use_emap */
        {
          gint    x;
          guchar *dest;
          guchar *src_msmap = NULL;
          guchar *src_emap = NULL;

          for (x = dest_rgn.x,
               dest = dest_row,
               src_msmap = src_msmap_row,  /* valid iff use_msmap */
               src_emap = src_emap_row     /* valid iff use_emap */
               ;
               x < (gint) (dest_rgn.x + dest_rgn.w)
               ;
               x++,
               dest += bpp,
               src_msmap += msmap_bpp,  /* valid iff use_msmap */
               src_emap += emap_bpp)    /* valid iff use_emap */
            {
              gint    radius, radius_squared;
              gfloat  exponent;
              gint    mask_x1, mask_y1;
              gint    mask_x2, mask_y2;
              gint    mask_y;
              gint    src_offset;
              guchar *src_row;
              guchar *src_inten_row = NULL;

              if (use_msmap)
                {
                  gfloat factor = get_map_value (src_msmap, msmap_bpp);

                  radius = ROUND (factor * (0.5 * ovals.mask_size));
                }
              else
                {
                  radius = (gint) ovals.mask_size / 2;
                }

              radius_squared = SQR (radius);

              exponent = ovals.exponent;
              if (use_emap)
                exponent *= get_map_value (src_emap, emap_bpp);

              if (use_inten)
                memset (Hist, 0, sizeof (Hist));

              memset (Hist_rgb, 0, sizeof (Hist_rgb));

              mask_x1 = CLAMP ((x - radius), x1, x2);
              mask_y1 = CLAMP ((y - radius), y1, y2);
              mask_x2 = CLAMP ((x + radius + 1), x1, x2);
              mask_y2 = CLAMP ((y + radius + 1), y1, y2);

              src_offset = (mask_y1 - y1) * width + (mask_x1 - x1);

              for (mask_y = mask_y1,
                   src_row = src_buf + src_offset * bpp,
                   src_inten_row = src_inten_buf + src_offset  /* valid iff use_inten */
                   ;
                   mask_y < mask_y2
                   ;
                   mask_y++,
                   src_row += width * bpp,
                   src_inten_row += width)  /* valid iff use_inten */
                {
                  guchar *src;
                  guchar *src_inten = NULL;
                  gint    dy_squared = sqr_lut[ABS (mask_y - y)];
                  gint    mask_x;

                  for (mask_x = mask_x1,
                       src = src_row,
                       src_inten = src_inten_row  /* valid iff use_inten */
                       ;
                       mask_x < mask_x2
                       ;
                       mask_x++,
                       src += bpp,
                       src_inten++)  /* valid iff use_inten */
                    {
                      gint dx_squared = sqr_lut[ABS (mask_x - x)];
                      gint b;

                      /*  Stay inside a circular mask area  */
                      if ((dx_squared + dy_squared) > radius_squared)
                        continue;

                      if (use_inten)
                        {
                          gint inten = *src_inten;
                          ++Hist[inten];
                          for (b = 0; b < bpp; b++)
                            Hist_rgb[b][inten] += src[b];
                        }
                      else
                        {
                          for (b = 0; b < bpp; b++)
                            ++Hist_rgb[b][src[b]];
                        }

                    } /* for mask_x */
                } /* for mask_y */

              if (use_inten)
                {
                  weighted_average_color (Hist, Hist_rgb, exponent, dest, bpp);
                }
              else
                {
                  gint b;

                  for (b = 0; b < bpp; b++)
                    dest[b] = weighted_average_value (Hist_rgb[b], exponent);
                }

            } /* for x */
        } /* for y */

      if (preview)
        {
          gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview),
                                             &dest_rgn);
        }
      else
        {
          progress += dest_rgn.w * dest_rgn.h;
          gimp_progress_update ((gdouble) progress / (gdouble) max_progress);
        }
    } /* for pr */

  /*  Detach from the map drawables  */
  if (mask_size_map_drawable)
    gimp_drawable_detach (mask_size_map_drawable);

  if (exponent_map_drawable)
    gimp_drawable_detach (exponent_map_drawable);

  if (src_inten_buf)
    g_free (src_inten_buf);

  g_free (src_buf);
  g_free (sqr_lut);

  if (!preview)
    {
      /*  Update the oil-painted region  */
      gimp_drawable_flush (drawable);
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
      gimp_drawable_update (drawable->drawable_id, x1, y1, width, height);
    }
}
예제 #14
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);
}
예제 #15
0
guchar *p_drawable_encode_jpeg(GDrawable *drawable, gint32 jpeg_interlaced, gint32 *JPEG_size, 
			       gint32 jpeg_quality, gint32 odd_even, gint32 use_YUV411, 
			       void *app0_buffer, gint32 app0_length)
{
  GPixelRgn pixel_rgn;
  GDrawableType drawable_type;
  struct jpeg_compress_struct cinfo;
  struct jpeg_error_mgr jerr;
  
  guchar *temp, *t;
  guchar *data;
  guchar *src, *s;
  int has_alpha;
  int rowstride, yend;
  int i, j, y;
  guchar *JPEG_data;
  size_t *JPEG_buf_remain;
  size_t totalsize = 0;

  drawable_type = gimp_drawable_type (drawable->id);
  gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE);

  /* Step 1: allocate and initialize JPEG compression object */

  /* We have to set up the error handler first, in case the initialization
   * step fails.  (Unlikely, but it could happen if you are out of memory.)
   * This routine fills in the contents of struct jerr, and returns jerr's
   * address which we place into the link field in cinfo.
   */
  cinfo.err = jpeg_std_error(&jerr);

  /* Now we can initialize the JPEG compression object. */
  jpeg_create_compress (&cinfo);

  /* Step 2: specify data destination (eg, a file) */
  /* Note: steps 2 and 3 can be done in either order. */

  /* We use our own jpeg destination mgr */
  JPEG_data = (guchar *)g_malloc(OUTPUT_BUF_SIZE * sizeof(guchar));

  /* Install my memory destination manager (instead of stdio_dest) */
  jpeg_memio_dest (&cinfo, JPEG_data, &JPEG_buf_remain);

  if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: Cleared the initilization !\n");

  /* Get the input image and a pointer to its data.
   */
  switch (drawable_type)
    {
    case RGB_IMAGE:
    case GRAY_IMAGE:
      /* # of color components per pixel */
      cinfo.input_components = drawable->bpp;
      has_alpha = 0;
      break;
    case RGBA_IMAGE:
    case GRAYA_IMAGE:
      gimp_message ("jpeg: image contains a-channel info which will be lost");
      /* # of color components per pixel (minus the GIMP alpha channel) */
      cinfo.input_components = drawable->bpp - 1;
      has_alpha = 1;
      break;
    case INDEXED_IMAGE:
      gimp_message ("jpeg: cannot operate on indexed color images");
      return FALSE;
      break;
    default:
      gimp_message ("jpeg: cannot operate on unknown image types");
      return FALSE;
      break;
    }

  /* Step 3: set parameters for compression */

  /* First we supply a description of the input image.
   * Four fields of the cinfo struct must be filled in:
   */
  /* image width and height, in pixels */
  cinfo.image_width = drawable->width;
  cinfo.image_height = drawable->height;
  /* colorspace of input image */
  cinfo.in_color_space = (drawable_type == RGB_IMAGE ||
			  drawable_type == RGBA_IMAGE)
    ? JCS_RGB : JCS_GRAYSCALE;
  /* Now use the library's routine to set default compression parameters.
   * (You must set at least cinfo.in_color_space before calling this,
   * since the defaults depend on the source color space.)
   */
  jpeg_set_defaults (&cinfo);
  jpeg_set_quality (&cinfo, (int) (jpeg_quality), TRUE);

  /* Smoothing is not possible for nonstandard sampling rates */
  /*  cinfo.smoothing_factor = (int) (50); */
  /* I wonder if this is slower: */ 
  /* cinfo.optimize_coding = 1; */

  /* Are these the evil AVI destroyers ? */
  cinfo.write_Adobe_marker = FALSE;
  cinfo.write_JFIF_header = FALSE;

  /* That's the only allowed encoding in a movtar */
  if (!use_YUV411)
    {
      cinfo.comp_info[0].h_samp_factor = 2;
      cinfo.comp_info[0].v_samp_factor = 1;
      cinfo.comp_info[1].h_samp_factor = 1;
      cinfo.comp_info[1].v_samp_factor = 1;
      cinfo.comp_info[2].h_samp_factor = 1;
      cinfo.comp_info[2].v_samp_factor = 1;
    }
  else
    if (gap_debug) fprintf(stderr, "Using YUV 4:1:1 encoding !");

  cinfo.restart_interval = 0;
  cinfo.restart_in_rows = FALSE; 
  /* could be _ISLOW or _FLOAT, too, but this is fastest */
  cinfo.dct_method = JDCT_ISLOW; 
  if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: Cleared parameter setting !\n");

  if (jpeg_interlaced)
    {
      cinfo.image_height = drawable->height/2;
      
      rowstride = drawable->bpp * drawable->width;
      temp = (guchar *) g_malloc (cinfo.image_width * cinfo.input_components);
      data = (guchar *) g_malloc (rowstride * gimp_tile_height ());
  
      for (y = (odd_even) ? 1 : 0; (odd_even) ? (y >= 0) : (y <= 1); (odd_even) ? (y--) : (y++))
	{
	  if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: interlaced picture, now coding %s lines\n",
				  y ? "odd" : "even");
	  
	  jpeg_start_compress (&cinfo, TRUE);

	  /* Step 4.1: Write the app0 marker out */
	  if(app0_buffer) 
	    jpeg_write_marker(&cinfo,
			  JPEG_APP0,
			      app0_buffer,
			      app0_length);      
	  
	  while (cinfo.next_scanline < cinfo.image_height)
	    {
	      if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: Line %d !", cinfo.next_scanline); 
	      gimp_pixel_rgn_get_rect (&pixel_rgn, data, 0, 2 * cinfo.next_scanline + y, 
				       cinfo.image_width, 1);
	      
	      /* Get rid of all the bad stuff (tm) (= get the right pixel order for JPEG encoding) */
	      t = temp;
	      s = data;
	      i = cinfo.image_width;
	      
	      while (i--)
		{
		  for (j = 0; j < cinfo.input_components; j++)
		    *t++ = *s++;
		  if (has_alpha)  /* ignore alpha channel */
		    s++;
		}
	      
	      src += 2*rowstride;
	      jpeg_write_scanlines (&cinfo, (JSAMPARRAY) &temp, 1);
	    }
      
	  jpeg_finish_compress(&cinfo);
	  totalsize += (OUTPUT_BUF_SIZE - *JPEG_buf_remain);
	  //JPEG_data = (guchar *)realloc(JPEG_data, sizeof(guchar)* *JPEG_size);
	}
      /* fprintf(stderr, "2 fields written.\n"); */
    }
  else
    {
      /* Step 4: Start compressor */

      /* TRUE ensures that we will write a complete interchange-JPEG file.
       * Pass TRUE unless you are very sure of what you're doing.
       */
      if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: non-interlaced picture.\n"); 
      jpeg_start_compress (&cinfo, TRUE);

      /* Step 4.1: Write the app0 marker out */
      if(app0_buffer) 
	jpeg_write_marker(&cinfo,
			  JPEG_APP0,
			  app0_buffer,
			  app0_length);      
      
      /* Step 5: while (scan lines remain to be written) */
      /*           jpeg_write_scanlines(...); */
      
      /* Here we use the library's state variable cinfo.next_scanline as the
       * loop counter, so that we don't have to keep track ourselves.
       * To keep things simple, we pass one scanline per call; you can pass
       * more if you wish, though.
       */
      /* JSAMPLEs per row in image_buffer */
      rowstride = drawable->bpp * drawable->width;
      temp = (guchar *) g_malloc (cinfo.image_width * cinfo.input_components);
      data = (guchar *) g_malloc (rowstride * gimp_tile_height ());

      /* fault if cinfo.next_scanline isn't initially a multiple of
       * gimp_tile_height */
      src = NULL;

      while (cinfo.next_scanline < cinfo.image_height)
	{
	  if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: Line %d !", cinfo.next_scanline); 
	  if ((cinfo.next_scanline % gimp_tile_height ()) == 0)
	    {
	      yend = cinfo.next_scanline + gimp_tile_height ();
	      yend = MIN (yend, cinfo.image_height);
	      gimp_pixel_rgn_get_rect (&pixel_rgn, data, 0, cinfo.next_scanline, cinfo.image_width,
				       (yend - cinfo.next_scanline));
	      src = data;
	    }
	  
	  t = temp;
	  s = src;
	  i = cinfo.image_width;
	  
	  while (i--)
	    {
	      for (j = 0; j < cinfo.input_components; j++)
		*t++ = *s++;
	      if (has_alpha)  /* ignore alpha channel */
		s++;
	    }
	  
	  src += rowstride;
	  jpeg_write_scanlines (&cinfo, (JSAMPARRAY) &temp, 1);
	}
      
      /* Step 6: Finish compression */
      jpeg_finish_compress (&cinfo);
      totalsize += (OUTPUT_BUF_SIZE - *JPEG_buf_remain);
      // JPEG_data = (guchar *)realloc(JPEG_data, sizeof(guchar)* *JPEG_size);
    }

  /* Step 7: release JPEG compression object */
  /* This is an important step since it will release a good deal of memory. */
  jpeg_destroy_compress (&cinfo);

  /* free the temporary buffer */
  g_free (temp);
  g_free (data);

  *JPEG_size = totalsize;
  return JPEG_data;
}	
예제 #16
0
static void
psd_write_image_data_packbits (int    fd,
                               gint32 imageID,
                               gint32 width,
                               gint32 height)
{
  gint i, x, y, col;
  gint32 current, total;
  gint16 compression;
  GimpDrawable *drw[4];
  GimpPixelRgn region;
  gchar *src_buf, *dst_buf;
  guint16 line_bytes[MAX_PIXELS];
  gint buf_width, buf_height;
  off_t data_head, data_end;
  gchar channel_name[4][2] = { "C", "M", "Y", "K" };

  drw[0] = separate_find_channel (imageID,sep_C);
  drw[1] = separate_find_channel (imageID,sep_M);
  drw[2] = separate_find_channel (imageID,sep_Y);
  drw[3] = separate_find_channel (imageID,sep_K);

  gimp_progress_init ("");

  current = 0;
  total = height * 4;

  buf_width = ceil (width * 1.334);
  buf_height = MIN (MAX_BUFFER_SIZE / buf_width, height);

  if (!(src_buf = g_try_malloc (buf_width * buf_height)))
    return;
  if (!(dst_buf = g_try_malloc (buf_width * buf_height)))
    {
      g_free (src_buf);
      return;
    }

  compression = GINT16_TO_BE (1);
  write (fd, &compression, sizeof (gint16));

  data_head = lseek (fd, 0, SEEK_CUR);
  data_end = data_head + height * 4 * 2;

  for (i = 0; i < 4; i++)
    {
      gint n_lines;
      gint result;

      gimp_progress_set_text_printf (_("Exporting Photoshop PSD (%s channel)..."),
                                     channel_name[i]);

      if (drw[i])
        {
          gimp_pixel_rgn_init (&region, drw[i], 0, 0, width, height, FALSE, FALSE);

          for (y = 0; y < height; y += buf_height, current += buf_height)
            {
              gint read_bytes, write_bytes;

              gimp_progress_update ((gdouble)current / (gdouble)total);

              n_lines = MIN (height - y, buf_height);

              gimp_pixel_rgn_get_rect (&region, src_buf, 0, y, width, n_lines);

              read_bytes = 0;
              write_bytes = 0;

              for (col = 0; col < n_lines; col++)
                {
                  gint _write_bytes = write_bytes;
                  gchar *count = dst_buf + write_bytes++;

                  *count = 0;

                  dst_buf[write_bytes++] = 0xff - src_buf[read_bytes++];

                  for (x = 1; x < width; x++)
                    {
                      gchar tmp = 0xff - src_buf[read_bytes++];

                      if (dst_buf[write_bytes - 1] == tmp) /* 連続 */
                        {
                          if (*count == -127)
                            {
                              /* 128バイトを超えた場合 */
                              count = dst_buf + write_bytes++;
                              *count = 0;
                              dst_buf[write_bytes++] = tmp;
                            }
                          else if (*count <= 0)
                            {
                              /* 通常のカウント */
                              (*count)--;
                            }
                          else
                            {
                              /* 非連続からの切り替え */
                              (*count)--; /* 非連続としてカウントされた1バイト目の分を減らす */
                              count = dst_buf + write_bytes - 1;
                              *count = -1;
                              dst_buf[write_bytes++] = tmp;
                            }
                        }
                      else /* 非連続 */
                        {
                          if (*count >= 0 && *count != 127)
                            {
                              (*count)++;
                              dst_buf[write_bytes++] = tmp;
                            }
                          else
                            {
                              count = dst_buf + write_bytes++;
                              *count = 0;
                              dst_buf[write_bytes++] = tmp;
                            }
                        }
                    }
                  line_bytes[y + col] = GINT16_TO_BE (write_bytes - _write_bytes);
                }

              /* seek to end of pixel data */
              lseek (fd, data_end, SEEK_SET);
              result = write (fd, dst_buf, write_bytes);
              data_end += write_bytes;
            }

          /* seek to bytes per line data */
          lseek (fd, data_head + height * i * 2, SEEK_SET);
          result = write (fd, line_bytes, height * 2);
        }
      else
        {
          gint n_repeat = width / 128;
          gint bytes = 0;

          for (x = 0; x < n_repeat; x++)
            {
              dst_buf[bytes++] = -127;
              dst_buf[bytes++] = 0xff;
            }
          if (width % 128)
            {
              dst_buf[bytes++] = ((width % 128) - 1) * -1;
              dst_buf[bytes++] = 0xff;
            }

          for (col = 1; col < buf_height; col++)
            memcpy (dst_buf + bytes * col, dst_buf, bytes);

          /* seek to end of pixel data */
          lseek (fd, data_end, SEEK_SET);

          for (y = 0; y < height; y += buf_height, current += buf_height)
            {
              gimp_progress_update ((gdouble)current / (gdouble)total);

              n_lines = MIN (height - y, buf_height);

              result = write (fd, dst_buf, bytes * n_lines);

              for (col = 0; col < n_lines; col++)
                line_bytes[y + col] = GINT16_TO_BE (bytes);
            }
          data_end += bytes * height;

          /* seek to bytes per line data */
          lseek (fd, data_head + height * i * 2, SEEK_SET);
          result = write (fd, line_bytes, height * 2);
        }
    }

  gimp_progress_update (1.0);

  g_free (src_buf);
  g_free (dst_buf);
}
예제 #17
0
static void
psd_write_image_data_raw (int    fd,
                          gint32 imageID,
                          gint32 width,
                          gint32 height)
{
  gint i, x, y;
  gint32 current, total;
  gint16 compression;
  GimpDrawable *drw[4];
  GimpPixelRgn region;
  gchar *buf;
  gint buf_height;
  gchar channel_name[4][2] = { "C", "M", "Y", "K" };

  drw[0] = separate_find_channel (imageID,sep_C);
  drw[1] = separate_find_channel (imageID,sep_M);
  drw[2] = separate_find_channel (imageID,sep_Y);
  drw[3] = separate_find_channel (imageID,sep_K);

  gimp_progress_init ("");

  current = 0;
  total = height * 4;

  buf_height = MIN (MAX_BUFFER_SIZE / width, height);

  if (!(buf = g_try_malloc (width * buf_height)))
    return;

  compression = 0;
  write (fd, &compression, sizeof (gint16));

  for (i = 0; i < 4; i++)
    {
      gint n_lines;
      gint result;

      gimp_progress_set_text_printf (_("Exporting Photoshop PSD (%s channel)..."),
                                     channel_name[i]);

      if (drw[i])
        {
          gimp_pixel_rgn_init (&region, drw[i], 0, 0, width, height, FALSE, FALSE);

          for (y = 0; y < height; y += buf_height, current += buf_height)
            {
              gimp_progress_update ((gdouble)current / (gdouble)total);

              n_lines = MIN (height - y, buf_height);

              gimp_pixel_rgn_get_rect (&region, buf, 0, y, width, n_lines);

              for (x = 0; x < width * n_lines; x++)
                buf[x] = 0xff - buf[x];

              result = write (fd, buf, width * n_lines);
            }
        }
      else
        {
          memset (buf, 0xff, width * buf_height);

          for (y = 0; y < height; y += buf_height, current += buf_height)
            {
              gimp_progress_update ((gdouble)current / (gdouble)total);

              n_lines = MIN (height - y, buf_height);

              result = write (fd, buf, width * n_lines);
            }
        }
    }

  gimp_progress_update (1.0);

  g_free (buf);
}
예제 #18
0
파일: edge.c 프로젝트: WilfR/Gimp-Matting
static void
edge_preview_update (GimpPreview *preview)
{
  /* drawable */
  GimpDrawable *drawable;
  glong         bytes;
  gint          alpha;
  gboolean      has_alpha;

  /* preview */
  guchar       *src           = NULL; /* Buffer to hold source image */
  guchar       *render_buffer = NULL; /* Buffer to hold rendered image */
  guchar       *dest;
  gint          width;                /* Width of preview widget */
  gint          height;               /* Height of preview widget */
  gint          x1;                   /* Upper-left X of preview */
  gint          y1;                   /* Upper-left Y of preview */
  GimpPixelRgn  srcPR;                /* Pixel regions */

  /* algorithm */
  gint x, y;

  /* Get drawable info */
  drawable =
    gimp_drawable_preview_get_drawable (GIMP_DRAWABLE_PREVIEW (preview));
  bytes  = gimp_drawable_bpp (drawable->drawable_id);
  alpha  = bytes;
  has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);
  if (has_alpha)
    alpha--;

  /*
   * Setup for filter...
   */
  gimp_preview_get_position (preview, &x1, &y1);
  gimp_preview_get_size (preview, &width, &height);

  /* initialize pixel regions */
  gimp_pixel_rgn_init (&srcPR, drawable,
                       x1, y1, width, height, FALSE, FALSE);
  src = g_new (guchar, width * height * bytes);
  render_buffer = g_new (guchar, width * height * bytes);

  /* render image */
  gimp_pixel_rgn_get_rect(&srcPR, src, x1, y1, width, height);
  dest = render_buffer;

  /* render algorithm */
  for (y = 0 ; y < height ; y++)
    for (x = 0 ; x < width ; x++)
      {
        gint chan;
        for (chan = 0; chan < alpha; chan++)
          {
            guchar kernel[9];

#define SRC(X,Y) src[bytes * (CLAMP((X), 0, width-1) + \
                              width * CLAMP((Y), 0, height-1)) + chan]

            kernel[0] = SRC (x - 1, y - 1);
            kernel[1] = SRC (x - 1, y    );
            kernel[2] = SRC (x - 1, y + 1);
            kernel[3] = SRC (x    , y - 1);
            kernel[4] = SRC (x    , y    );
            kernel[5] = SRC (x    , y + 1);
            kernel[6] = SRC (x + 1, y - 1);
            kernel[7] = SRC (x + 1, y    );
            kernel[8] = SRC (x + 1, y + 1);

#undef SRC
            dest[chan] = edge_detect (kernel);
          }
        if (has_alpha)
          dest[alpha] = src[bytes * (x + width * y) + alpha];
        dest += bytes;
      }
  /*
   * Draw the preview image on the screen...
   */
  gimp_preview_draw_buffer (preview, render_buffer, width * bytes);

  g_free (render_buffer);
  g_free (src);
}
예제 #19
0
static void
ico_dialog_update_icon_preview (GtkWidget *dialog,
                                gint32     layer,
                                gint       bpp)
{
  GtkWidget *preview = ico_dialog_get_layer_preview (dialog, layer);
  GdkPixbuf *pixbuf;
  gint       w       = gimp_drawable_width (layer);
  gint       h       = gimp_drawable_height (layer);

  if (! preview)
    return;

  if (bpp <= 8)
    {
      GimpDrawable *drawable;
      GimpDrawable *tmp;
      GimpPixelRgn  src_pixel_rgn, dst_pixel_rgn;
      gint32        image;
      gint32        tmp_image;
      gint32        tmp_layer;
      guchar       *buffer;
      guchar       *cmap;
      gint          num_colors;

      image = gimp_item_get_image (layer);

      tmp_image = gimp_image_new (w, h, gimp_image_base_type (image));
      gimp_image_undo_disable (tmp_image);

      if (gimp_drawable_is_indexed (layer))
        {
          cmap = gimp_image_get_colormap (image, &num_colors);
          gimp_image_set_colormap (tmp_image, cmap, num_colors);
          g_free (cmap);
        }

      tmp_layer = gimp_layer_new (tmp_image, "temporary", w, h,
                                  gimp_drawable_type (layer),
                                  100, GIMP_NORMAL_MODE);
      gimp_image_insert_layer (tmp_image, tmp_layer, -1, 0);

      drawable = gimp_drawable_get (layer);
      tmp      = gimp_drawable_get (tmp_layer);

      gimp_pixel_rgn_init (&src_pixel_rgn, drawable, 0, 0, w, h, FALSE, FALSE);
      gimp_pixel_rgn_init (&dst_pixel_rgn, tmp,      0, 0, w, h, TRUE, FALSE);

      buffer = g_malloc (w * h * 4);
      gimp_pixel_rgn_get_rect (&src_pixel_rgn, buffer, 0, 0, w, h);
      gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h);

      gimp_drawable_detach (tmp);
      gimp_drawable_detach (drawable);

      if (gimp_drawable_is_indexed (layer))
        gimp_image_convert_rgb (tmp_image);

      gimp_image_convert_indexed (tmp_image,
                                  GIMP_FS_DITHER, GIMP_MAKE_PALETTE,
                                  1 <<bpp, TRUE, FALSE, "dummy");

      cmap = gimp_image_get_colormap (tmp_image, &num_colors);
      if ( num_colors == (1 << bpp) &&
           !ico_cmap_contains_black (cmap, num_colors))
        {
          /* Windows icons with color maps need the color black.
           * We need to eliminate one more color to make room for black.
           */
          if (gimp_drawable_is_indexed (layer))
            {
              g_free (cmap);
              cmap = gimp_image_get_colormap (image, &num_colors);
              gimp_image_set_colormap (tmp_image, cmap, num_colors);
            }
          else if (gimp_drawable_is_gray (layer))
            {
              gimp_image_convert_grayscale (tmp_image);
            }
          else
            {
              gimp_image_convert_rgb (tmp_image);
            }

          tmp = gimp_drawable_get (tmp_layer);
          gimp_pixel_rgn_init (&dst_pixel_rgn,
                               tmp, 0, 0, w, h, TRUE, FALSE);
          gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h);
          gimp_drawable_detach (tmp);

          if (!gimp_drawable_is_rgb (layer))
            gimp_image_convert_rgb (tmp_image);

          gimp_image_convert_indexed (tmp_image,
                                      GIMP_FS_DITHER, GIMP_MAKE_PALETTE,
                                      (1<<bpp) - 1, TRUE, FALSE, "dummy");
        }
      g_free (cmap);
      g_free (buffer);

      pixbuf = gimp_drawable_get_thumbnail (tmp_layer,
                                            MIN (w, 128), MIN (h, 128),
                                            GIMP_PIXBUF_SMALL_CHECKS);

      gimp_image_delete (tmp_image);
    }
  else if (bpp == 24)
    {
      GimpDrawable *drawable;
      GimpDrawable *tmp;
      GimpPixelRgn  src_pixel_rgn, dst_pixel_rgn;
      gint32        image;
      gint32        tmp_image;
      gint32        tmp_layer;
      guchar       *buffer;
      GimpParam    *return_vals;
      gint          n_return_vals;

      image = gimp_item_get_image (layer);

      tmp_image = gimp_image_new (w, h, gimp_image_base_type (image));
      gimp_image_undo_disable (tmp_image);

      if (gimp_drawable_is_indexed (layer))
        {
          guchar *cmap;
          gint    num_colors;

          cmap = gimp_image_get_colormap (image, &num_colors);
          gimp_image_set_colormap (tmp_image, cmap, num_colors);
          g_free (cmap);
        }

      tmp_layer = gimp_layer_new (tmp_image, "temporary", w, h,
                                  gimp_drawable_type (layer),
                                  100, GIMP_NORMAL_MODE);
      gimp_image_insert_layer (tmp_image, tmp_layer, -1, 0);

      drawable = gimp_drawable_get (layer);
      tmp      = gimp_drawable_get (tmp_layer);

      gimp_pixel_rgn_init (&src_pixel_rgn, drawable, 0, 0, w, h, FALSE, FALSE);
      gimp_pixel_rgn_init (&dst_pixel_rgn, tmp,      0, 0, w, h, TRUE, FALSE);

      buffer = g_malloc (w * h * 4);
      gimp_pixel_rgn_get_rect (&src_pixel_rgn, buffer, 0, 0, w, h);
      gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h);
      g_free (buffer);

      gimp_drawable_detach (tmp);
      gimp_drawable_detach (drawable);

      if (gimp_drawable_is_indexed (layer))
        gimp_image_convert_rgb (tmp_image);

      return_vals =
        gimp_run_procedure ("plug-in-threshold-alpha", &n_return_vals,
                            GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
                            GIMP_PDB_IMAGE, tmp_image,
                            GIMP_PDB_DRAWABLE, tmp_layer,
                            GIMP_PDB_INT32, ICO_ALPHA_THRESHOLD,
                            GIMP_PDB_END);
      gimp_destroy_params (return_vals, n_return_vals);

      pixbuf = gimp_drawable_get_thumbnail (tmp_layer,
                                            MIN (w, 128), MIN (h, 128),
                                            GIMP_PIXBUF_SMALL_CHECKS);

      gimp_image_delete (tmp_image);
    }
  else
    {
      pixbuf = gimp_drawable_get_thumbnail (layer,
                                            MIN (w, 128), MIN (h, 128),
                                            GIMP_PIXBUF_SMALL_CHECKS);
    }

  gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf);
  g_object_unref (pixbuf);
}
예제 #20
0
static void
drawlens (GimpDrawable *drawable,
          GimpPreview  *preview)
{
  GimpImageType  drawtype = gimp_drawable_type (drawable->drawable_id);
  GimpPixelRgn   srcPR, destPR;
  gint           width, height;
  gint           bytes;
  gint           row;
  gint           x1, y1, x2, y2;
  guchar        *src, *dest;
  gint           i, col;
  gfloat         regionwidth, regionheight, dx, dy, xsqr, ysqr;
  gfloat         a, b, c, asqr, bsqr, csqr, x, y;
  glong          pixelpos, pos;
  GimpRGB        background;
  guchar         bgr_red, bgr_blue, bgr_green;
  guchar         alphaval;

  gimp_context_get_background (&background);
  gimp_rgb_get_uchar (&background,
                      &bgr_red, &bgr_green, &bgr_blue);

  bytes = drawable->bpp;

  if (preview)
    {
      gimp_preview_get_position (preview, &x1, &y1);
      gimp_preview_get_size (preview, &width, &height);
      x2 = x1 + width;
      y2 = y1 + height;
      src = gimp_drawable_get_thumbnail_data (drawable->drawable_id,
                                              &width, &height, &bytes);
      regionwidth  = width;
      regionheight = height;
    }
  else
    {
      gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
      regionwidth = x2 - x1;
      regionheight = y2 - y1;
      width = drawable->width;
      height = drawable->height;
      gimp_pixel_rgn_init (&srcPR, drawable,
                           0, 0, width, height, FALSE, FALSE);
      gimp_pixel_rgn_init (&destPR, drawable,
                           0, 0, width, height, TRUE, TRUE);

      src  = g_new (guchar, regionwidth * regionheight * bytes);
      gimp_pixel_rgn_get_rect (&srcPR, src,
                               x1, y1, regionwidth, regionheight);
    }

  dest = g_new (guchar, regionwidth * regionheight * bytes);

  a = regionwidth / 2;
  b = regionheight / 2;

  c = MIN (a, b);

  asqr = a * a;
  bsqr = b * b;
  csqr = c * c;

  for (col = 0; col < regionwidth; col++)
    {
      dx = (gfloat) col - a + 0.5;
      xsqr = dx * dx;
      for (row = 0; row < regionheight; row++)
        {
          pixelpos = (col + row * regionwidth) * bytes;
          dy = -((gfloat) row - b) - 0.5;
          ysqr = dy * dy;
          if (ysqr < (bsqr - (bsqr * xsqr) / asqr))
            {
              find_projected_pos (asqr, bsqr, csqr, dx, dy, &x, &y);
              y = -y;
              pos = ((gint) (y + b) * regionwidth + (gint) (x + a)) * bytes;

              for (i = 0; i < bytes; i++)
                {
                  dest[pixelpos + i] = src[pos + i];
                }
            }
          else
            {
              if (lvals.keep_surr)
                {
                  for (i = 0; i < bytes; i++)
                    {
                      dest[pixelpos + i] = src[pixelpos + i];
                    }
                }
              else
                {
                  if (lvals.set_transparent)
                    alphaval = 0;
                  else
                    alphaval = 255;

                  switch (drawtype)
                    {
                    case GIMP_INDEXEDA_IMAGE:
                      dest[pixelpos + 1] = alphaval;
                    case GIMP_INDEXED_IMAGE:
                      dest[pixelpos + 0] = 0;
                      break;

                    case GIMP_RGBA_IMAGE:
                      dest[pixelpos + 3] = alphaval;
                    case GIMP_RGB_IMAGE:
                      dest[pixelpos + 0] = bgr_red;
                      dest[pixelpos + 1] = bgr_green;
                      dest[pixelpos + 2] = bgr_blue;
                      break;

                    case GIMP_GRAYA_IMAGE:
                      dest[pixelpos + 1] = alphaval;
                    case GIMP_GRAY_IMAGE:
                      dest[pixelpos+0] = bgr_red;
                      break;
                    }
                }
            }
        }

      if (!preview)
        {
          if (((gint) (regionwidth-col) % 5) == 0)
            gimp_progress_update ((gdouble) col / (gdouble) regionwidth);
        }
    }

  if (preview)
    {
      gimp_preview_draw_buffer (preview, dest, bytes * regionwidth);
    }
  else
    {
      gimp_progress_update (1.0);
      gimp_pixel_rgn_set_rect (&destPR, dest, x1, y1,
                               regionwidth, regionheight);

      gimp_drawable_flush (drawable);
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
      gimp_drawable_update (drawable->drawable_id, x1, y1, x2 - x1, y2 - y1);
    }

  g_free (src);
  g_free (dest);
}
예제 #21
0
/*
 * Applies the algorithm
 */
static void
retinex (GimpDrawable *drawable,
         GimpPreview  *preview)
{
  gint          x, y, width, height;
  gint          size, bytes;
  guchar       *src  = NULL;
  guchar       *psrc = NULL;
  GimpPixelRgn  dst_rgn, src_rgn;

  bytes = drawable->bpp;

  /*
   * Get the size of the current image or its selection.
   */
  if (preview)
    {
      src = gimp_zoom_preview_get_source (GIMP_ZOOM_PREVIEW (preview),
                                          &width, &height, &bytes);
    }
  else
    {
      if (! gimp_drawable_mask_intersect (drawable->drawable_id,
                                          &x, &y, &width, &height))
        return;

      /* Allocate memory */
      size = width * height * bytes;
      src = g_try_malloc (sizeof (guchar) * size);

      if (src == NULL)
        {
          g_warning ("Failed to allocate memory");
          return;
        }

      memset (src, 0, sizeof (guchar) * size);

      /* Fill allocated memory with pixel data */
      gimp_pixel_rgn_init (&src_rgn, drawable,
                           x, y, width, height,
                           FALSE, FALSE);
      gimp_pixel_rgn_get_rect (&src_rgn, src, x, y, width, height);
    }

  /*
    Algorithm for Multi-scale Retinex with color Restoration (MSRCR).
   */
  psrc = src;
  MSRCR (psrc, width, height, bytes, preview != NULL);

  if (preview)
    {
      gimp_preview_draw_buffer (preview, psrc, width * bytes);
    }
  else
    {
      gimp_pixel_rgn_init (&dst_rgn, drawable,
                           x, y, width, height,
                           TRUE, TRUE);
      gimp_pixel_rgn_set_rect (&dst_rgn, psrc, x, y, width, height);

      gimp_progress_update (1.0);

      gimp_drawable_flush (drawable);
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
      gimp_drawable_update (drawable->drawable_id, x, y, width, height);
    }

  g_free (src);
}
예제 #22
0
/* Decompose an image. It returns the number of new (gray) images.
   The image IDs for the new images are returned in image_ID_dst.
   On failure, -1 is returned.
*/
static gint32
decompose (gint32       image_ID,
           gint32       drawable_ID,
           const gchar *extract_type,
           gint32      *image_ID_dst,
           gint32      *nlayers,
           gint32      *layer_ID_dst)
{
  const gchar  *layername;
  gint          i, j, extract_idx, scan_lines;
  gint          height, width, tile_height, num_layers;
  gchar        *filename;
  guchar       *src;
  guchar       *dst[MAX_EXTRACT_IMAGES];
  GimpDrawable *drawable_src;
  GimpDrawable *drawable_dst[MAX_EXTRACT_IMAGES];
  GimpPixelRgn  pixel_rgn_src;
  GimpPixelRgn  pixel_rgn_dst[MAX_EXTRACT_IMAGES];

  extract_idx = -1;   /* Search extract type */
  for (j = 0; j < G_N_ELEMENTS (extract); j++)
    {
      if (g_ascii_strcasecmp (extract_type, extract[j].type) == 0)
	{
	  extract_idx = j;
	  break;
	}
    }
  if (extract_idx < 0)
    return -1;

  /* Check structure of source image */
  drawable_src = gimp_drawable_get (drawable_ID);
  if (drawable_src->bpp < 3)
    {
      g_message ("Not an RGB image.");
      return -1;
    }
  if ((extract[extract_idx].extract_fun == extract_alpha ||
       extract[extract_idx].extract_fun == extract_rgba) &&
      (!gimp_drawable_has_alpha (drawable_ID)))
    {
      g_message ("No alpha channel available.");
      return -1;
    }

  width  = drawable_src->width;
  height = drawable_src->height;

  tile_height = gimp_tile_height ();
  gimp_pixel_rgn_init (&pixel_rgn_src, drawable_src, 0, 0, width, height,
                       FALSE, FALSE);

  /* allocate a buffer for retrieving information from the src pixel region  */
  src = g_new (guchar, tile_height * width * drawable_src->bpp);

  /* Create all new gray images */
  num_layers = extract[extract_idx].num_images;
  if (num_layers > MAX_EXTRACT_IMAGES)
    num_layers = MAX_EXTRACT_IMAGES;

  for (j = 0; j < num_layers; j++)
    {
      /* Build a filename like <imagename>-<channel>.<extension> */
      gchar   *fname;
      gchar   *extension;
      gdouble  xres, yres;

      fname = gimp_image_get_filename (image_ID);

      if (fname)
        {
          extension = fname + strlen (fname) - 1;

          while (extension >= fname)
            {
              if (*extension == '.') break;
              extension--;
            }
          if (extension >= fname)
            {
              *(extension++) = '\0';

              if (decovals.as_layers)
                filename = g_strdup_printf ("%s-%s.%s", fname,
                                            gettext (extract[extract_idx].type),
                                            extension);
              else
                filename = g_strdup_printf ("%s-%s.%s", fname,
                                            gettext (extract[extract_idx].channel_name[j]),
                                            extension);
            }
          else
            {
              if (decovals.as_layers)
                filename = g_strdup_printf ("%s-%s", fname,
                                            gettext (extract[extract_idx].type));
              else
                filename = g_strdup_printf ("%s-%s", fname,
                                            gettext (extract[extract_idx].channel_name[j]));
            }
        }
      else
        {
          filename = g_strdup (gettext (extract[extract_idx].channel_name[j]));
        }

      gimp_image_get_resolution (image_ID, &xres, &yres);

      if (decovals.as_layers)
        {
          layername = gettext (extract[extract_idx].channel_name[j]);

          if (j == 0)
            image_ID_dst[j] = create_new_image (filename, layername,
                                                width, height, GIMP_GRAY,
                                                xres, yres,
                                                layer_ID_dst + j,
                                                drawable_dst + j,
                                                pixel_rgn_dst + j);
          else
            layer_ID_dst[j] = create_new_layer (image_ID_dst[0], j, layername,
                                                width, height, GIMP_GRAY,
                                                drawable_dst + j,
                                                pixel_rgn_dst + j);
        }
      else
        {
          image_ID_dst[j] = create_new_image (filename, NULL,
                                              width, height, GIMP_GRAY,
                                              xres, yres,
                                              layer_ID_dst + j,
                                              drawable_dst + j,
                                              pixel_rgn_dst + j);
        }

      g_free (filename);
      g_free (fname);
      dst[j] = g_new (guchar, tile_height * width);
    }

  i = 0;
  while (i < height)
    {
      /* Get source pixel region */
      scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i);
      gimp_pixel_rgn_get_rect (&pixel_rgn_src, src, 0, i, width, scan_lines);

      /* Extract the channel information */
      extract[extract_idx].extract_fun (src, drawable_src->bpp, scan_lines*width,
					dst);

      /* Transfer the registration color */
      if (decovals.use_registration)
        transfer_registration_color (src, drawable_src->bpp, scan_lines*width,
                                     dst, extract[extract_idx].num_images);

      /* Set destination pixel regions */
      for (j = 0; j < num_layers; j++)
	gimp_pixel_rgn_set_rect (&(pixel_rgn_dst[j]), dst[j], 0, i, width,
				 scan_lines);
      i += scan_lines;

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

  g_free (src);

  for (j = 0; j < num_layers; j++)
    {
      gimp_drawable_detach (drawable_dst[j]);
      gimp_drawable_update (layer_ID_dst[j], 0, 0,
                            gimp_drawable_width (layer_ID_dst[j]),
                            gimp_drawable_height (layer_ID_dst[j]));
      gimp_layer_add_alpha (layer_ID_dst[j]);
      g_free (dst[j]);
    }

  gimp_drawable_detach (drawable_src);

  *nlayers = num_layers;

  return (decovals.as_layers ? 1 : num_layers);
}
예제 #23
0
static gboolean
pluginCore (piArgs *argp)
{
  GimpDrawable *drw, *ndrw = NULL;
  GimpPixelRgn  srcPr, dstPr;
  gboolean      success = TRUE;
  gint          nl      = 0;
  gint          y, i;
  gint          Y, I, Q;
  guint         width, height, bpp;
  gint          sel_x1, sel_x2, sel_y1, sel_y2;
  gint          prog_interval;
  guchar       *src, *s, *dst, *d;
  guchar        r, prev_r=0, new_r=0;
  guchar        g, prev_g=0, new_g=0;
  guchar        b, prev_b=0, new_b=0;
  gdouble       fy, fc, t, scale;
  gdouble       pr, pg, pb;
  gdouble       py;

  drw = gimp_drawable_get (argp->drawable);

  width  = drw->width;
  height = drw->height;
  bpp    = drw->bpp;

  if (argp->new_layerp)
    {
      gchar        name[40];
      const gchar *mode_names[] =
      {
        "ntsc",
        "pal",
      };
      const gchar *action_names[] =
      {
        "lum redux",
        "sat redux",
        "flag",
      };

      g_snprintf (name, sizeof (name), "hot mask (%s, %s)",
                  mode_names[argp->mode],
                  action_names[argp->action]);

      nl = gimp_layer_new (argp->image, name, width, height,
                           GIMP_RGBA_IMAGE, (gdouble)100, GIMP_NORMAL_MODE);
      ndrw = gimp_drawable_get (nl);
      gimp_drawable_fill (nl, GIMP_TRANSPARENT_FILL);
      gimp_image_insert_layer (argp->image, nl, -1, 0);
    }

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

  width  = sel_x2 - sel_x1;
  height = sel_y2 - sel_y1;

  src = g_new (guchar, width * height * bpp);
  dst = g_new (guchar, width * height * 4);
  gimp_pixel_rgn_init (&srcPr, drw, sel_x1, sel_y1, width, height,
                       FALSE, FALSE);

  if (argp->new_layerp)
    {
      gimp_pixel_rgn_init (&dstPr, ndrw, sel_x1, sel_y1, width, height,
                           FALSE, FALSE);
    }
  else
    {
      gimp_pixel_rgn_init (&dstPr, drw, sel_x1, sel_y1, width, height,
                           TRUE, TRUE);
    }

  gimp_pixel_rgn_get_rect (&srcPr, src, sel_x1, sel_y1, width, height);

  s = src;
  d = dst;

  build_tab (argp->mode);

  gimp_progress_init (_("Hot"));
  prog_interval = height / 10;

  for (y = sel_y1; y < sel_y2; y++)
    {
      gint x;

      if (y % prog_interval == 0)
        gimp_progress_update ((double) y / (double) (sel_y2 - sel_y1));

      for (x = sel_x1; x < sel_x2; x++)
        {
          if (hotp (r = *(s + 0), g = *(s + 1), b = *(s + 2)))
            {
              if (argp->action == ACT_FLAG)
                {
                  for (i = 0; i < 3; i++)
                    *d++ = 0;
                  s += 3;
                  if (bpp == 4)
                    *d++ = *s++;
                  else if (argp->new_layerp)
                    *d++ = 255;
                }
              else
                {
                  /*
                   * Optimization: cache the last-computed hot pixel.
                   */
                  if (r == prev_r && g == prev_g && b == prev_b)
                    {
                      *d++ = new_r;
                      *d++ = new_g;
                      *d++ = new_b;
                      s += 3;
                      if (bpp == 4)
                        *d++ = *s++;
                      else if (argp->new_layerp)
                        *d++ = 255;
                    }
                  else
                    {
                      Y = tab[0][0][r] + tab[0][1][g] + tab[0][2][b];
                      I = tab[1][0][r] + tab[1][1][g] + tab[1][2][b];
                      Q = tab[2][0][r] + tab[2][1][g] + tab[2][2][b];

                      prev_r = r;
                      prev_g = g;
                      prev_b = b;
                      /*
                       * Get Y and chroma amplitudes in floating point.
                       *
                       * If your C library doesn't have hypot(), just use
                       * hypot(a,b) = sqrt(a*a, b*b);
                       *
                       * Then extract linear (un-gamma-corrected)
                       * floating-point pixel RGB values.
                       */
                      fy = (double)Y / (double)SCALE;
                      fc = hypot ((double) I / (double) SCALE,
                                  (double) Q / (double) SCALE);

                      pr = (double) pix_decode (r);
                      pg = (double) pix_decode (g);
                      pb = (double) pix_decode (b);

                      /*
                       * Reducing overall pixel intensity by scaling R,
                       * G, and B reduces Y, I, and Q by the same factor.
                       * This changes luminance but not saturation, since
                       * saturation is determined by the chroma/luminance
                       * ratio.
                       *
                       * On the other hand, by linearly interpolating
                       * between the original pixel value and a grey
                       * pixel with the same luminance (R=G=B=Y), we
                       * change saturation without affecting luminance.
                       */
                      if (argp->action == ACT_LREDUX)
                        {
                          /*
                           * Calculate a scale factor that will bring the pixel
                           * within both chroma and composite limits, if we scale
                           * luminance and chroma simultaneously.
                           *
                           * The calculated chrominance reduction applies
                           * to the gamma-corrected RGB values that are
                           * the input to the RGB-to-YIQ operation.
                           * Multiplying the original un-gamma-corrected
                           * pixel values by the scaling factor raised to
                           * the "gamma" power is equivalent, and avoids
                           * calling gc() and inv_gc() three times each.  */
                          scale = chroma_lim / fc;
                          t = compos_lim / (fy + fc);
                          if (t < scale)
                            scale = t;
                          scale = pow (scale, mode[argp->mode].gamma);

                          r = (guint8) pix_encode (scale * pr);
                          g = (guint8) pix_encode (scale * pg);
                          b = (guint8) pix_encode (scale * pb);
                        }
                      else
                        { /* ACT_SREDUX hopefully */
                          /*
                           * Calculate a scale factor that will bring the
                           * pixel within both chroma and composite
                           * limits, if we scale chroma while leaving
                           * luminance unchanged.
                           *
                           * We have to interpolate gamma-corrected RGB
                           * values, so we must convert from linear to
                           * gamma-corrected before interpolation and then
                           * back to linear afterwards.
                           */
                          scale = chroma_lim / fc;
                          t = (compos_lim - fy) / fc;
                          if (t < scale)
                            scale = t;

                          pr = gc (pr, argp->mode);
                          pg = gc (pg, argp->mode);
                          pb = gc (pb, argp->mode);

                          py = pr * mode[argp->mode].code[0][0] +
                               pg * mode[argp->mode].code[0][1] +
                               pb * mode[argp->mode].code[0][2];

                          r = pix_encode (inv_gc (py + scale * (pr - py),
                                                  argp->mode));
                          g = pix_encode (inv_gc (py + scale * (pg - py),
                                                  argp->mode));
                          b = pix_encode (inv_gc (py + scale * (pb - py),
                                                  argp->mode));
                        }

                      *d++ = new_r = r;
                      *d++ = new_g = g;
                      *d++ = new_b = b;

                      s += 3;

                      if (bpp == 4)
                        *d++ = *s++;
                      else if (argp->new_layerp)
                        *d++ = 255;
                    }
                }
            }
          else
            {
              if (!argp->new_layerp)
                {
                  for (i = 0; i < bpp; i++)
                    *d++ = *s++;
                }
              else
                {
                  s += bpp;
                  d += 4;
                }
            }
        }
    }

  gimp_pixel_rgn_set_rect (&dstPr, dst, sel_x1, sel_y1, width, height);

  g_free (src);
  g_free (dst);

  if (argp->new_layerp)
    {
      gimp_drawable_flush (ndrw);
      gimp_drawable_update (nl, sel_x1, sel_y1, width, height);
    }
  else
    {
      gimp_drawable_flush (drw);
      gimp_drawable_merge_shadow (drw->drawable_id, TRUE);
      gimp_drawable_update (drw->drawable_id, sel_x1, sel_y1, width, height);
    }

  gimp_displays_flush ();

  return success;
}
예제 #24
0
static PyObject *
pr_subscript(PyGimpPixelRgn *self, PyObject *key)
{
    GimpPixelRgn *pr = &(self->pr);
    PyObject *x, *y;
    Py_ssize_t x1, y1, x2, y2, xs, ys;
    PyObject *ret;

    if (!PyTuple_Check(key) || PyTuple_Size(key) != 2) {
        PyErr_SetString(PyExc_TypeError, "subscript must be a 2-tuple");
        return NULL;
    }

    if (!PyArg_ParseTuple(key, "OO", &x, &y))
        return NULL;

    if (PyInt_Check(x)) {
        x1 = PyInt_AsSsize_t(x);

        if (x1 < pr->x || x1 >= pr->x + pr->w) {
            PyErr_SetString(PyExc_IndexError, "x subscript out of range");
            return NULL;
        }

        if (PyInt_Check(y)) {
            y1 = PyInt_AsSsize_t(y);

            if (y1 < pr->y || y1 >= pr->y + pr->h) {
                PyErr_SetString(PyExc_IndexError, "y subscript out of range");
                return NULL;
            }

            ret = PyString_FromStringAndSize(NULL, pr->bpp);
            gimp_pixel_rgn_get_pixel(pr, (guchar*)PyString_AS_STRING(ret),
                                     x1, y1);

        } else if (PySlice_Check(y)) {
            if (PySlice_GetIndices((PySliceObject*)y, pr->y + pr->h,
                                   &y1, &y2, &ys) ||
                y1 >= y2 || ys != 1) {
                PyErr_SetString(PyExc_IndexError, "invalid y slice");
                return NULL;
            }

            if(y1 == 0)
                y1 = pr->y;

            if(y1 < pr->y || y2 < pr->y) {
                PyErr_SetString(PyExc_IndexError, "y subscript out of range");
                return NULL;
            }

            ret = PyString_FromStringAndSize(NULL, pr->bpp * (y2 - y1));
            gimp_pixel_rgn_get_col(pr, (guchar*)PyString_AS_STRING(ret),
                                   x1, y1, y2-y1);
	    }
        else {
            PyErr_SetString(PyExc_TypeError, "invalid y subscript");
            return NULL;
        }
    } else if (PySlice_Check(x)) {
        if (PySlice_GetIndices((PySliceObject *)x, pr->x + pr->w,
                               &x1, &x2, &xs) ||
            x1 >= x2 || xs != 1) {
            PyErr_SetString(PyExc_IndexError, "invalid x slice");
            return NULL;
        }
        if (x1 == 0)
            x1 = pr->x;
        if(x1 < pr->x || x2 < pr->x) {
            PyErr_SetString(PyExc_IndexError, "x subscript out of range");
            return NULL;
        }

        if (PyInt_Check(y)) {
            y1 = PyInt_AsSsize_t(y);
            if (y1 < pr->y || y1 >= pr->y + pr->h) {
                PyErr_SetString(PyExc_IndexError, "y subscript out of range");
                return NULL;
            }
            ret = PyString_FromStringAndSize(NULL, pr->bpp * (x2 - x1));
            gimp_pixel_rgn_get_row(pr, (guchar*)PyString_AS_STRING(ret),
                                   x1, y1, x2 - x1);

        } else if (PySlice_Check(y)) {
            if (PySlice_GetIndices((PySliceObject*)y, pr->y + pr->h,
                                   &y1, &y2, &ys) ||
                y1 >= y2 || ys != 1) {
                PyErr_SetString(PyExc_IndexError, "invalid y slice");
                return NULL;
            }

            if(y1 == 0)
                y1 = pr->y;
            if(y1 < pr->y || y2 < pr->y) {
                PyErr_SetString(PyExc_IndexError, "y subscript out of range");
                return NULL;
            }

            ret = PyString_FromStringAndSize(NULL,
                                             pr->bpp * (x2 - x1) * (y2 - y1));
            gimp_pixel_rgn_get_rect(pr, (guchar*)PyString_AS_STRING(ret),
                                    x1, y1, x2 - x1, y2 - y1);
	    }
        else {
            PyErr_SetString(PyExc_TypeError, "invalid y subscript");
            return NULL;
        }

    } else {
        PyErr_SetString(PyExc_TypeError, "invalid x subscript");
        return NULL;
    }
    return ret;
}
예제 #25
0
파일: icnssave.c 프로젝트: brion/gimp-icns
GimpPDBStatusType
SaveICNS (const gchar *file_name,
          gint32       image_ID)
{
  // Horrible awful temporary hack
  ResourceHeader icnsHeader;
  ResourceHeader it32Header;
  ResourceHeader t8mkHeader;
  
  guchar *compData, *alphaData;
  FILE *outfile;
  
  guchar *pixels;
  gint dataSize;
  

  if (gimp_image_base_type (image_ID) != GIMP_RGB)
    {
      if (! gimp_image_convert_rgb (image_ID))
        return GIMP_PDB_EXECUTION_ERROR;
    }

  gint *layers;
  gint nlayers;
  GimpPixelRgn region;
  
  layers = gimp_image_get_layers (image_ID, &nlayers);
  GimpDrawable *drawable = gimp_drawable_get (layers[0]);
  
  pixels = g_new (guchar, 128*128*4);
  gimp_pixel_rgn_init (&region, drawable, 0, 0, 128, 128, TRUE, FALSE);
  gimp_pixel_rgn_get_rect (&region, pixels, 0, 0, 128, 128);
  
  compData = icns_compress (128, 128, pixels, &dataSize);
  alphaData = icns_get_alpha (128, 128, pixels);
  
  it32Header.type = GUINT32_TO_BE ('it32');
  it32Header.size = GUINT32_TO_BE (sizeof (ResourceHeader) + dataSize);
  
  t8mkHeader.type = GUINT32_TO_BE ('t8mk');
  t8mkHeader.size = GUINT32_TO_BE (sizeof (ResourceHeader) + 128*128);
  
  icnsHeader.type = GUINT32_TO_BE ('icns');
  icnsHeader.size = dataSize + 128*128 + 3 * sizeof (ResourceHeader);
  
  outfile = fopen (file_name, "wb");
  if (outfile)
    {
      fwrite (&icnsHeader, 1, sizeof (ResourceHeader), outfile);
      fwrite (&it32Header, 1, sizeof (ResourceHeader), outfile);
      fwrite (compData, 1, dataSize, outfile);
      fwrite (&t8mkHeader, 1, sizeof (ResourceHeader), outfile);
      fwrite (alphaData, 1, 128*128, outfile);
      fclose (outfile);
    }
  else
    {
      g_warning ("SaveICNS: couldn't open output file");
    }

  g_free (pixels);
  g_free (compData);
  g_free (alphaData);
  return GIMP_PDB_SUCCESS;
}
static void
compose_row (gint          frame_num,
             DisposeType   dispose,
             gint          row_num,
             guchar       *dest,
             gint          dest_width,
             GimpDrawable *drawable,
             gboolean      cleanup)
{
  static guchar *line_buf = NULL;
  guchar        *srcptr;
  GimpPixelRgn   pixel_rgn;
  gint           rawx, rawy, rawbpp, rawwidth, rawheight;
  gint           i;
  gboolean       has_alpha;

  if (cleanup)
    {
      if (line_buf)
        {
          g_free (line_buf);
          line_buf = NULL;
        }

      return;
    }

  if (dispose == DISPOSE_REPLACE)
    {
      total_alpha (dest, dest_width, pixelstep);
    }

  gimp_drawable_offsets (drawable->drawable_id,
                         &rawx,
                         &rawy);

  rawheight = gimp_drawable_height (drawable->drawable_id);

  /* this frame has nothing to give us for this row; return */
  if (row_num >= rawheight + rawy ||
      row_num < rawy)
    return;

  rawbpp = gimp_drawable_bpp (drawable->drawable_id);
  rawwidth = gimp_drawable_width (drawable->drawable_id);
  has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);

  if (line_buf)
    {
      g_free (line_buf);
      line_buf = NULL;
    }
  line_buf = g_malloc (rawwidth * rawbpp);

  /* Initialise and fetch the raw new frame row */

  gimp_pixel_rgn_init (&pixel_rgn,
                       drawable,
                       0, row_num - rawy,
                       rawwidth, 1,
                       FALSE,
                       FALSE);
  gimp_pixel_rgn_get_rect (&pixel_rgn,
                           line_buf,
                           0, row_num - rawy,
                           rawwidth, 1);

  /* render... */

  srcptr = line_buf;

  for (i=rawx; i<rawwidth+rawx; i++)
    {
      if (i>=0 && i<dest_width)
        {
          if ((!has_alpha) || ((*(srcptr+rawbpp-1))&128))
            {
              gint pi;

              for (pi = 0; pi < pixelstep-1; pi++)
                {
                  dest[i*pixelstep +pi] = *(srcptr + pi);
                }
              dest[i*pixelstep + pixelstep - 1] = 255;
            }
        }

      srcptr += rawbpp;
    }

}
예제 #27
0
/* ------------------------------
 * gap_pview_render_f_from_image
 * ------------------------------
 * render preview widget from image.
 * IMPORTANT: the image is scaled to preview size
 *            and the visible layers in the image are merged together !
 *            If the supplied image shall stay unchanged,
 *            you may use  gap_pview_render_f_from_image_duplicate
 *
 * hint: call gtk_widget_queue_draw(pv_ptr->da_widget);
 * after this procedure to make the changes appear on screen.
 */
void
gap_pview_render_f_from_image (GapPView *pv_ptr
    , gint32 image_id
    , gint32 flip_request
    , gint32 flip_status
)
{
  gint32 layer_id;
  guchar *frame_data;
  GimpPixelRgn pixel_rgn;
  GimpDrawable *drawable;

  if(image_id < 0)
  {
    if(gap_debug)
    {
      printf("gap_pview_render_f_from_image: have no image, cant render image_id:%d\n"
            ,(int)image_id
            );
    }
    return;
  }
  p_free_desaturated_area_data(pv_ptr);

  if((gimp_image_width(image_id) != pv_ptr->pv_width)
  || ( gimp_image_height(image_id) != pv_ptr->pv_height))
  {
    gimp_image_scale(image_id, pv_ptr->pv_width, pv_ptr->pv_height);
  }

  /* workaround: gimp_image_merge_visible_layers
   * needs at least 2 layers to work without complaining
   * therefore add 2 full transparent dummy layers
   */
  {
    gint32  l_layer_id;
    GimpImageBaseType l_type;

    l_type   = gimp_image_base_type(image_id);
    l_type   = (l_type * 2); /* convert from GimpImageBaseType to GimpImageType */

    l_layer_id = gimp_layer_new(image_id, "dummy_01"
                                , 4, 4
                                , l_type
                                , 0.0       /* Opacity full transparent */     
                                , 0         /* NORMAL */
                                );   
    gimp_image_insert_layer(image_id, l_layer_id, 0, 0);

    l_layer_id = gimp_layer_new(image_id, "dummy_02"
                                , 4, 4
                                , l_type
                                , 0.0       /* Opacity full transparent */     
                                , 0         /* NORMAL */
                                );   
    gimp_image_insert_layer(image_id, l_layer_id, 0, 0);
    gimp_layer_resize_to_image_size(l_layer_id);
  }
  
    
  layer_id = gimp_image_merge_visible_layers (image_id, GIMP_CLIP_TO_IMAGE);
  drawable = gimp_drawable_get (layer_id);

  frame_data = g_malloc(drawable->width * drawable->height * drawable->bpp);
  
  gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0
                      , drawable->width, drawable->height
                      , FALSE     /* dirty */
                      , FALSE     /* shadow */
                       );
  gimp_pixel_rgn_get_rect (&pixel_rgn, frame_data
                          , 0
                          , 0
                          , drawable->width
                          , drawable->height);
                          
 
 {
    gboolean frame_data_was_grabbed;

    frame_data_was_grabbed = gap_pview_render_f_from_buf (pv_ptr
                   , frame_data
                   , drawable->width
                   , drawable->height
                   , drawable->bpp
                   , TRUE            /* allow_grab_src_data */
                   , flip_request
                   , flip_status

                 );
  
    if(!frame_data_was_grabbed) g_free(frame_data);
    gimp_drawable_detach (drawable);
  }
  
}  /* end gap_pview_render_f_from_image */
예제 #28
0
static void
chromaunsharp (GimpPixelRgn *cPR,
               GimpPixelRgn *bcPR,
	       guchar  *g,
	       guchar  *bg,
	       gint     bpp,
	       gint x1,
	       gint y1,
	       gint width,
	       gint height,
	       gdouble amount,
	       gdouble gamma,
	       guchar   *dest)
{

  register guchar *lab_dest = dest;

  guchar *c = g_new(guchar, width*height*bpp);
  guchar *bc = g_new(guchar, width*height*bpp);
  gimp_pixel_rgn_get_rect (cPR, c, x1, y1, width, height);
  gimp_pixel_rgn_get_rect (bcPR, bc, x1, y1, width, height);
  
  guchar *ptr[4];
  ptr[0] = c;
  ptr[1] = bc;
  ptr[2] = g;
  ptr[3] = bg;

  register gint count = width*height, offset = bpp;

  gint i;
  gdouble red, green, blue;
  gdouble x, y, z;
  gdouble tl, l[4], a[4], b[4];
  gdouble tx, ty, tz;
  gdouble ftx, fty, ftz;
  gdouble lambda, de, hg, deg;
  gdouble sixteenth = 16.0 / 116.0;

  while (count-- > 0)
    {
    for ( i=0; i < 4; i++ ) {
      // C to RGB
      red   = *(ptr[i]+0) / 255.0;
      green = *(ptr[i]+1) / 255.0;
      blue  = *(ptr[i]+2) / 255.0;

      //apply gamma function to convert to sRGB
      if ( red <=0.03928 ) red = red/12.92;
      else red = pow((red+0.055)/1.055,2.4);
      if ( green <=0.03928 ) green = green/12.92;
      else green = pow((green+0.055)/1.055,2.4);
      if ( blue <=0.03928 ) blue = blue/12.92;
      else blue = pow((blue+0.055)/1.055,2.4);

      x = 0.431 * red + 0.342 * green + 0.178 * blue;
      y = 0.222 * red + 0.707 * green + 0.071 * blue;
      z = 0.020 * red + 0.130 * green + 0.939 * blue;

      if (( ty = y/Yn ) > 0.008856)
        {
          tl   = 116.0 * cbrt( ty ) - 16.0;
          fty = cbrt( ty );
        }
      else
        {
          tl   = 903.3 * ty;
          fty = 7.78*ty + sixteenth;
        }

      ftx = ((tx = x/Xn) > 0.008856) ? cbrt (tx) : 7.78 * tx + sixteenth;
      ftz = ((tz = z/Zn) > 0.008856) ? cbrt (tz) : 7.78 * tz + sixteenth;

      l[i] = tl;
      a[i] = ftx - fty;
      b[i] = fty - ftz;

      ptr[i] += offset;
    }  // end for

    // Calculate lambda
    hg = l[2]-l[3];
    de = pow(pow(l[0]-l[1],2)+pow(a[0]-a[1],2)+pow(b[0]-b[1],2),0.5);
    deg = pow(pow(hg,2),0.5);
    if ( deg == 0 ) 
      lambda = de/0.00001;
     else
       lambda = de/deg;

    lambda = pow(lambda,gamma);
    tl = l[2] + (amount*lambda*hg); 

    // Keep the old chromatic greyimage's channels.
    lab_dest[0] = CLAMP( (gint)( tl*2.5599) , 0, 255);
    lab_dest[1] = (guchar) (128.0 + a[2] * 635 );
    lab_dest[2] = (guchar) (128.0 + b[2] * 254 ); 
    lab_dest += offset;
    
  }

  g_free (c);
  g_free (bc);
}
static void
util_fillReducedBuffer (guchar       *dest,
                        gint          destWidth,
                        gint          destHeight,
                        gint          destBPP,
                        gboolean      destHasAlpha,
                        GimpDrawable *sourceDrawable,
                        gint          x0,
                        gint          y0,
                        gint          sourceWidth,
                        gint          sourceHeight)
{
  GimpPixelRgn  rgn;
  guchar       *sourceBuffer,    *reducedRowBuffer;
  guchar       *sourceBufferPos, *reducedRowBufferPos;
  guchar       *sourceBufferRow;
  gint          x, y, i, yPrime;
  gboolean      sourceHasAlpha;
  gint          sourceBpp;
  gint         *sourceRowOffsetLookup;

  if ((sourceDrawable == NULL) || (sourceWidth == 0) || (sourceHeight == 0))
    {
      for (x = 0; x < destWidth * destHeight * destBPP; x++)
        dest[x] = 0;
      return;
    }

  sourceBpp = sourceDrawable->bpp;

  sourceBuffer          = g_new (guchar, sourceWidth * sourceHeight * sourceBpp);
  reducedRowBuffer      = g_new (guchar, destWidth   * sourceBpp);
  sourceRowOffsetLookup = g_new (int, destWidth);
  gimp_pixel_rgn_init (&rgn, sourceDrawable,
                       x0, y0, sourceWidth, sourceHeight,
                       FALSE, FALSE);
  sourceHasAlpha = gimp_drawable_has_alpha (sourceDrawable->drawable_id);

  for (x = 0; x < destWidth; x++)
    sourceRowOffsetLookup[x] = (x * (sourceWidth - 1) / (destWidth - 1)) * sourceBpp;

  gimp_pixel_rgn_get_rect (&rgn, sourceBuffer,
                           x0, y0, sourceWidth, sourceHeight);

  for (y = 0; y < destHeight; y++)
    {
      yPrime = y * (sourceHeight - 1) / (destHeight - 1);
      sourceBufferRow = &(sourceBuffer[yPrime * sourceWidth * sourceBpp]);
      sourceBufferPos = sourceBufferRow;
      reducedRowBufferPos = reducedRowBuffer;
      for (x = 0; x < destWidth; x++)
        {
          sourceBufferPos = sourceBufferRow + sourceRowOffsetLookup[x];
          for (i = 0; i < sourceBpp; i++)
            reducedRowBufferPos[i] = sourceBufferPos[i];
          reducedRowBufferPos += sourceBpp;
        }
      util_convertColorspace(&(dest[y * destWidth * destBPP]), destBPP, destHasAlpha,
                             reducedRowBuffer, sourceDrawable->bpp, sourceHasAlpha,
                             destWidth);
    }

  g_free (sourceBuffer);
  g_free (reducedRowBuffer);
  g_free (sourceRowOffsetLookup);
}
예제 #30
0
static void
preview_update (GimpPreview *preview)
{
  GimpDrawable *drawable;
  GimpPixelRgn  src_rgn;        /* Source image region */
  guchar       *src_ptr;        /* Current source pixel */
  guchar       *dst_ptr;        /* Current destination pixel */
  intneg       *neg_ptr;        /* Current negative pixel */
  gint          i;              /* Looping var */
  gint          y;              /* Current location in image */
  gint          width;          /* Byte width of the image */
  gint          x1, y1;
  gint          preview_width, preview_height;
  guchar       *preview_src, *preview_dst;
  intneg       *preview_neg;
  gint          img_bpp;        /* Bytes-per-pixel in image */

  void          (*filter)(int, guchar *, guchar *, intneg *, intneg *, intneg *);

  filter = NULL;

  compute_luts();

  gimp_preview_get_position (preview, &x1, &y1);
  gimp_preview_get_size (preview, &preview_width, &preview_height);

  drawable =
    gimp_drawable_preview_get_drawable (GIMP_DRAWABLE_PREVIEW (preview));

  img_bpp = gimp_drawable_bpp (drawable->drawable_id);


  preview_src = g_new (guchar, preview_width * preview_height * img_bpp);
  preview_neg = g_new (intneg, preview_width * preview_height * img_bpp);
  preview_dst = g_new (guchar, preview_width * preview_height * img_bpp);

  gimp_pixel_rgn_init (&src_rgn, drawable,
                       x1, y1, preview_width, preview_height,
                       FALSE, FALSE);

  width = preview_width * img_bpp;

  /*
   * Load the preview area...
   */

  gimp_pixel_rgn_get_rect (&src_rgn, preview_src, x1, y1,
                           preview_width, preview_height);

  for (i = width * preview_height, src_ptr = preview_src, neg_ptr = preview_neg;
       i > 0;
       i --)
    *neg_ptr++ = neg_lut[*src_ptr++];

  /*
   * Select the filter...
   */

  switch (img_bpp)
    {
    case 1:
      filter = gray_filter;
      break;
    case 2:
      filter = graya_filter;
      break;
    case 3:
      filter = rgb_filter;
      break;
    case 4:
      filter = rgba_filter;
      break;
    default:
      g_error ("Programmer stupidity error: img_bpp is %d\n",
               img_bpp);
    }

  /*
   * Sharpen...
   */

  memcpy (preview_dst, preview_src, width);
  memcpy (preview_dst + width * (preview_height - 1),
          preview_src + width * (preview_height - 1),
          width);

  for (y = preview_height - 2, src_ptr = preview_src + width,
           neg_ptr = preview_neg + width + img_bpp,
           dst_ptr = preview_dst + width;
       y > 0;
       y --, src_ptr += width, neg_ptr += width, dst_ptr += width)
    (*filter)(preview_width, src_ptr, dst_ptr, neg_ptr - width,
              neg_ptr, neg_ptr + width);

  gimp_preview_draw_buffer (preview, preview_dst, preview_width * img_bpp);

  g_free (preview_src);
  g_free (preview_neg);
  g_free (preview_dst);
}