Пример #1
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_add_layer(image_id, l_layer_id, 0);

    l_layer_id = gimp_layer_new(image_id, "dummy_02"
                                , 4, 4
                                , l_type
                                , 0.0       /* Opacity full transparent */     
                                , 0         /* NORMAL */
                                );   
    gimp_image_add_layer(image_id, l_layer_id, 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 */
Пример #2
0
static void
explorer (GimpDrawable * drawable)
{
  GimpPixelRgn  srcPR;
  GimpPixelRgn  destPR;
  gint          width;
  gint          height;
  gint          bpp;
  gint          row;
  gint          x1;
  gint          y1;
  gint          x2;
  gint          y2;
  guchar       *src_row;
  guchar       *dest_row;

  /* Get the input area. This is the bounding box of the selection in
   *  the image (or the entire image if there is no selection). Only
   *  operating on the input area is simply an optimization. It doesn't
   *  need to be done for correct operation. (It simply makes it go
   *  faster, since fewer pixels need to be operated on).
   */
  gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);

  /* Get the size of the input image. (This will/must be the same
   *  as the size of the output image.
   */
  width  = drawable->width;
  height = drawable->height;
  bpp  = drawable->bpp;

  /*  allocate row buffers  */
  src_row  = g_new (guchar, bpp * (x2 - x1));
  dest_row = g_new (guchar, bpp * (x2 - x1));

  /*  initialize the pixel regions  */
  gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE);
  gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height, TRUE, TRUE);

  xbild = width;
  ybild = height;
  xdiff = (xmax - xmin) / xbild;
  ydiff = (ymax - ymin) / ybild;

  /* for grayscale drawables */
  if (bpp < 3)
    {
      gint     i;
      for (i = 0; i < MAXNCOLORS; i++)
          valuemap[i] = GIMP_RGB_LUMINANCE (colormap[i].r,
                                            colormap[i].g,
                                            colormap[i].b);
    }

  for (row = y1; row < y2; row++)
    {
      gimp_pixel_rgn_get_row (&srcPR, src_row, x1, row, (x2 - x1));

      explorer_render_row (src_row,
                           dest_row,
                           row,
                           (x2 - x1),
                           bpp);

      /*  store the dest  */
      gimp_pixel_rgn_set_row (&destPR, dest_row, x1, row, (x2 - x1));

      if ((row % 10) == 0)
        gimp_progress_update ((double) row / (double) (y2 - y1));
    }

  /*  update the processed 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));

  g_free (src_row);
  g_free (dest_row);
}
Пример #3
0
static gint
save_image (char   *filename,
	    gint32  image_ID,
	    gint32  drawable_ID)
{
  GPixelRgn pixel_rgn;
  TileDrawable *drawable;
  GDrawableType drawable_type;
  struct jpeg_compress_struct cinfo;
  struct my_error_mgr jerr;
  FILE *outfile;
  guchar *temp, *t;
  guchar *data;
  guchar *src, *s;
  char *name;
  int has_alpha;
  GimpExportReturnType export = GIMP_EXPORT_CANCEL;
  gint32 e_image_ID = -1;
  gint32 e_drawable_ID = -1;
  GPrecisionType precision;

  int rowstride, yend;
  int i, j;

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

  name = malloc (strlen (filename) + 11);

  sprintf (name, "%s %s:",_("Saving"), filename);
  gimp_progress_init (name);
  free (name);

  /* 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 = fopen (filename, "wb")) == NULL)
    {
      fprintf (stderr, "can't open %s\n", filename);
      return FALSE;
    }
  jpeg_stdio_dest (&cinfo, outfile);

  /* Get the input image and a pointer to its data.
   */
  cinfo.input_components = gimp_drawable_num_channels(drawable_ID);
  has_alpha = gimp_drawable_has_alpha(drawable_ID);
  if(has_alpha)
    --cinfo.input_components;

  /* 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 = gimp_drawable_color(drawable_ID) 
    ? 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 4a: write icc profile
  {
    char *buffer = NULL;
    int size = 0;

    if (gimp_image_has_icc_profile (image_ID, ICC_IMAGE_PROFILE)) { 
      buffer = gimp_image_get_icc_profile_by_mem (image_ID, &size, ICC_IMAGE_PROFILE);
      if (buffer) {
        write_icc_profile (&cinfo, buffer, size);
        printf ("%s:%d %s() embedded icc profile\n",__FILE__,__LINE__,__func__);
      }
    }
  }

  /* 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 *) malloc (cinfo.image_width * cinfo.input_components * 4);
  data = (guchar *) malloc (rowstride * gimp_tile_height ());

        export = gimp_export_image (&image_ID, &drawable_ID, "Jpeg",
Пример #4
0
static void
brushdmenuselect (GtkWidget *widget,
                  gpointer   data)
{
  GimpPixelRgn  src_rgn;
  guchar       *src_row;
  guchar       *src;
  gint          id;
  gint          bpp;
  gint          x, y;
  ppm_t        *p;
  gint          x1, y1, w, h;
  gint          row;
  GimpDrawable *drawable;
  gint          rowstride;

  gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &id);

  if (id == -1)
    return;

  if (brush_from_file == 2)
    return; /* Not finished GUI-building yet */

  if (brush_from_file)
    {
#if 0
      unselectall (brush_list);
#endif
      preset_save_button_set_sensitive (FALSE);
    }

  gtk_adjustment_set_value (brush_gamma_adjust, 1.0);
  gtk_adjustment_set_value (brush_aspect_adjust, 0.0);

  drawable = gimp_drawable_get (id);

  if (! gimp_drawable_mask_intersect (drawable->drawable_id, &x1, &y1, &w, &h))
    return;

  bpp = gimp_drawable_bpp (drawable->drawable_id);

  ppm_kill (&brushppm);
  ppm_new (&brushppm, w, h);
  p = &brushppm;

  rowstride = p->width * 3;

  src_row = g_new (guchar, w * bpp);

  gimp_pixel_rgn_init (&src_rgn, drawable,
                       0, 0, w, h, FALSE, FALSE);

  if (bpp == 3)
    { /* RGB */
      gint bpr = w * 3;
      gint y2 = y1 + h;

      for (row = 0, y = y1; y < y2; row++, y++)
        {
          gimp_pixel_rgn_get_row (&src_rgn, src_row, x1, y, w);
          memcpy (p->col + row*rowstride, src_row, bpr);
        }
    }
  else
    { /* RGBA (bpp > 3) GrayA (bpp == 2) or Gray */
      gboolean is_gray = ((bpp > 3) ? TRUE : FALSE);
      gint y2 = y1 + h;

      for (row = 0, y = y1; y < y2; row++, y++)
        {
          guchar *tmprow = p->col + row * rowstride;
          guchar *tmprow_ptr;
	  gint x2 = x1 + w;


          gimp_pixel_rgn_get_row (&src_rgn, src_row, x1, y, w);
          src = src_row;
          tmprow_ptr = tmprow;
          /* Possible micro-optimization here:
           * src_end = src + src_rgn.bpp * w);
           * for ( ; src < src_end ; src += src_rgn.bpp)
           */
          for (x = x1; x < x2; x++)
            {
              *(tmprow_ptr++) = src[0];
              *(tmprow_ptr++) = src[is_gray ? 1 : 0];
              *(tmprow_ptr++) = src[is_gray ? 2 : 0];
              src += src_rgn.bpp;
            }
        }
    }
  g_free (src_row);

  if (bpp >= 3)
    pcvals.color_brushes = 1;
  else
    pcvals.color_brushes = 0;

  brush_from_file = 0;
  update_brush_preview (NULL);
}
Пример #5
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_progress_update (1.0);

    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;
}
Пример #6
0
/* Save a layer from an image */
gboolean save_layer(gint32             drawable_ID,
                    WebPWriterFunction writer,
                    void              *custom_ptr,
#ifdef WEBP_0_5
                    gboolean           animation,
                    WebPAnimEncoder   *enc,
                    int                frame_timestamp,
#endif
                    WebPSaveParams    *params,
                    GError           **error)
{
    gboolean          status   = FALSE;
    gint              bpp;
    gint              width;
    gint              height;
    GimpImageType     drawable_type;
    WebPConfig        config;
    WebPPicture       picture;
    guchar           *buffer   = NULL;
#ifdef GIMP_2_9
    GeglBuffer       *geglbuffer;
    GeglRectangle     extent;
#else
    GimpDrawable     *drawable = NULL;
    GimpPixelRgn      region;
#endif

    /* Retrieve the image data */
    bpp = gimp_drawable_bpp(drawable_ID);
    width = gimp_drawable_width(drawable_ID);
    height = gimp_drawable_height(drawable_ID);
    drawable_type = gimp_drawable_type(drawable_ID);

    /* Initialize the WebP configuration with a preset and fill in the
     * remaining values */
    WebPConfigPreset(&config,
                     webp_preset_by_name(params->preset),
                     params->quality);

    config.lossless      = params->lossless;
    config.method        = 6;  /* better quality */
    config.alpha_quality = params->alpha_quality;

    /* Prepare the WebP structure */
    WebPPictureInit(&picture);
    picture.use_argb      = 1;
    picture.width         = width;
    picture.height        = height;
    picture.writer        = writer;
    picture.custom_ptr    = custom_ptr;
    picture.progress_hook = webp_file_progress;

    do {
        /* Attempt to allocate a buffer of the appropriate size */
        buffer = (guchar *)g_malloc(bpp * width * height);
        if(!buffer) {
            g_set_error(error,
                        G_FILE_ERROR,
                        0,
                        "Unable to allocate buffer for layer");
            break;
        }

#ifdef GIMP_2_9
        /* Obtain the buffer and get its extent */
        geglbuffer = gimp_drawable_get_buffer(drawable_ID);
        extent = *gegl_buffer_get_extent(geglbuffer);

        /* Read the layer buffer into our buffer */
        gegl_buffer_get(geglbuffer, &extent, 1.0, NULL, buffer,
                        GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

        g_object_unref(geglbuffer);
#else
        /* Get the drawable */
        drawable = gimp_drawable_get(drawable_ID);

        /* Obtain the pixel region for the drawable */
        gimp_pixel_rgn_init(&region,
                            drawable,
                            0, 0,
                            width,
                            height,
                            FALSE, FALSE);

        /* Read the region into the buffer */
        gimp_pixel_rgn_get_rect(&region,
                                buffer,
                                0, 0,
                                width,
                                height);

        gimp_drawable_detach(drawable);
#endif

        /* Use the appropriate function to import the data from the buffer */
        if(drawable_type == GIMP_RGB_IMAGE) {
            WebPPictureImportRGB(&picture, buffer, width * bpp);
        } else {
            WebPPictureImportRGBA(&picture, buffer, width * bpp);
        }

#ifdef WEBP_0_5
        if (animation == TRUE) {

            if (!WebPAnimEncoderAdd(enc, &picture, frame_timestamp, &config)) {
                g_set_error(error,
                            G_FILE_ERROR,
                            picture.error_code,
                            "WebP error: '%s'",
                            webp_error_string(picture.error_code));
                break;
            }
        } else {
#endif
            if(!WebPEncode(&config, &picture)) {
                g_set_error(error,
                            G_FILE_ERROR,
                            picture.error_code,
                            "WebP error: '%s'",
                            webp_error_string(picture.error_code));
                break;
            }
#ifdef WEBP_0_5
        }
#endif

        /* Everything succeeded */
        status = TRUE;

    } while(0);

    /* Free the buffer */
    if (buffer) {
        free(buffer);
    }

    return status;
}
Пример #7
0
static void
blur (GimpDrawable *drawable)
{
  gint         i, j, k, channels;
  gint         x1, y1, x2, y2;
  GimpPixelRgn rgn_in, rgn_out;
  guchar       output[4];

  /* Gets upper left and lower right coordinates,
   * and layers number in the image */
  gimp_drawable_mask_bounds (drawable->drawable_id,
                             &x1, &y1,
                             &x2, &y2);
  channels = gimp_drawable_bpp (drawable->drawable_id);

  /* Initialises two PixelRgns, one to read original data,
   * and the other to write output data. That second one will
   * be merged at the end by the call to
   * gimp_drawable_merge_shadow() */
  gimp_pixel_rgn_init (&rgn_in,
                       drawable,
                       x1, y1,
                       x2 - x1, y2 - y1,
                       FALSE, FALSE);
  gimp_pixel_rgn_init (&rgn_out,
                       drawable,
                       x1, y1,
                       x2 - x1, y2 - y1,
                       TRUE, TRUE);

  for (i = x1; i < x2; i++)
    {
      for (j = y1; j < y2; j++)
        {
          guchar pixel[9][4];

          /* Get nine pixels */
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[0],
                                    MAX (i - 1, x1), MAX (j - 1, y1));
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[1],
                                    MAX (i - 1, x1), j);
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[2],
                                    MAX (i - 1, x1), MIN (j + 1, y2 - 1));

          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[3],
                                    i, MAX (j - 1, y1));
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[4],
                                    i, j);
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[5],
                                    i, MIN (j + 1, y2 - 1));

          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[6],
                                    MIN (i + 1, x2 - 1), MAX (j - 1, y1));
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[7],
                                    MIN (i + 1, x2 - 1), j);
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[8],
                                    MIN (i + 1, x2 - 1), MIN (j + 1, y2 - 1));

          /* For each layer, compute the average of the
           * nine */
          for (k = 0; k < channels; k++)
            {
              int tmp, sum = 0;
              for (tmp = 0; tmp < 9; tmp++)
                sum += pixel[tmp][k];
              output[k] = sum / 9;
            }

          gimp_pixel_rgn_set_pixel (&rgn_out,
                                    output,
                                    i, j);
        }

      if (i % 10 == 0)
        gimp_progress_update ((gdouble) (i - x1) / (gdouble) (x2 - x1));
    }

  /* Update the modified 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);
}
Пример #8
0
static void
normalize_invert (GimpDrawable *drawable,
                  gboolean      normalize,
                  guint         maxval,
                  gboolean      invert)
{
  GimpPixelRgn src_rgn, dest_rgn;
  gint         bpp;
  gpointer     pr;
  gint         x, y, k;
  gint         x1, y1, x2, y2;
  gboolean     has_alpha;
  gdouble      factor;

  if (normalize && maxval != 0) {
      factor = 255.0 / maxval;
    }
  else
    factor = 1.0;

  gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
  bpp = drawable->bpp;
  has_alpha = gimp_drawable_has_alpha(drawable->drawable_id);

  gimp_pixel_rgn_init (&src_rgn,
                       drawable, 0, 0, drawable->width, drawable->height,
                       FALSE, FALSE);
  gimp_pixel_rgn_init (&dest_rgn,
                       drawable, 0, 0, drawable->width, drawable->height,
                       TRUE, TRUE);

  for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn);
       pr != NULL;
       pr = gimp_pixel_rgns_process (pr))
    {
      guchar *src  = src_rgn.data;
      guchar *dest = dest_rgn.data;
      gint    row  = src_rgn.y - y1;

      for (y = 0; y < src_rgn.h; y++, row++)
        {
          guchar *s   = src;
          guchar *d   = dest;
          gint    col = src_rgn.x - x1;

          for (x = 0; x < src_rgn.w; x++, col++)
            {

              if (has_alpha)
                {
                  for (k = 0; k < bpp-1; k++)
                    {
                      d[k] = factor * s[k];
                      if (invert)
                        d[k] = 255 - d[k];
                    }
                }
              else
                {
                  for (k = 0; k < bpp; k++)
                    {
                      d[k] = factor * s[k];
                      if (invert)
                        d[k] = 255 - d[k];
                    }
                }

              s += bpp;
              d += bpp;
            }

          src += src_rgn.rowstride;
          dest += dest_rgn.rowstride;
        }
    }
}
Пример #9
0
static void
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
{
  static GimpParam values[1];
  gint sel_x1, sel_y1, sel_x2, sel_y2;
  gint img_height, img_width, img_bpp, img_has_alpha;

  GimpDrawable      *drawable;
  GimpRunMode        run_mode;
  GimpPDBStatusType  status;

  *nreturn_vals = 1;
  *return_vals  = values;

  status = GIMP_PDB_SUCCESS;

  if (param[0].type != GIMP_PDB_INT32)
    status = GIMP_PDB_CALLING_ERROR;
  run_mode = param[0].data.d_int32;

  INIT_I18N ();

  if (param[2].type != GIMP_PDB_DRAWABLE)
    status = GIMP_PDB_CALLING_ERROR;

  drawable = gimp_drawable_get (param[2].data.d_drawable);

  img_width = gimp_drawable_width (drawable->drawable_id);
  img_height = gimp_drawable_height (drawable->drawable_id);
  img_bpp = gimp_drawable_bpp (drawable->drawable_id);
  img_has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);
  gimp_drawable_mask_bounds (drawable->drawable_id,
                             &sel_x1, &sel_y1, &sel_x2, &sel_y2);

  if (!gimp_drawable_is_rgb (drawable->drawable_id))
    status = GIMP_PDB_CALLING_ERROR;

  if (status == GIMP_PDB_SUCCESS)
    {
      gr = g_rand_new ();

      memset (&qbist_info, 0, sizeof (qbist_info));
      create_info (&qbist_info.info);
      qbist_info.oversampling = 4;

      switch (run_mode)
        {
        case GIMP_RUN_INTERACTIVE:
          /* Possibly retrieve data */
          gimp_get_data (PLUG_IN_PROC, &qbist_info);

          /* Get information from the dialog */
          if (dialog_run ())
            {
              status = GIMP_PDB_SUCCESS;
              gimp_set_data (PLUG_IN_PROC, &qbist_info, sizeof (QbistInfo));
            }
          else
            status = GIMP_PDB_EXECUTION_ERROR;
          break;

        case GIMP_RUN_NONINTERACTIVE:
          status = GIMP_PDB_CALLING_ERROR;
          break;

        case GIMP_RUN_WITH_LAST_VALS:
          /* Possibly retrieve data */
          gimp_get_data (PLUG_IN_PROC, &qbist_info);
          status = GIMP_PDB_SUCCESS;
          break;

        default:
          status = GIMP_PDB_CALLING_ERROR;
          break;
        }

      if (status == GIMP_PDB_SUCCESS)
        {
          GimpPixelRgn imagePR;
          gpointer     pr;

          gimp_tile_cache_ntiles ((drawable->width + gimp_tile_width () - 1) /
                                  gimp_tile_width ());
          gimp_pixel_rgn_init (&imagePR, drawable,
                               0, 0, img_width, img_height, TRUE, TRUE);

          optimize (&qbist_info.info);

          gimp_progress_init (_("Qbist"));

          for (pr = gimp_pixel_rgns_register (1, &imagePR);
               pr != NULL;
               pr = gimp_pixel_rgns_process (pr))
            {
              gint row;

              for (row = 0; row < imagePR.h; row++)
                {
                  qbist (&qbist_info.info,
                         imagePR.data + row * imagePR.rowstride,
                         imagePR.x,
                         imagePR.y + row,
                         imagePR.w,
                         sel_x2 - sel_x1,
                         sel_y2 - sel_y1,
                         imagePR.bpp,
                         qbist_info.oversampling);
                }

              gimp_progress_update ((gfloat) (imagePR.y - sel_y1) /
                                    (gfloat) (sel_y2 - sel_y1));
            }

          gimp_drawable_flush (drawable);
          gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
          gimp_drawable_update (drawable->drawable_id,
                                sel_x1, sel_y1,
                                (sel_x2 - sel_x1), (sel_y2 - sel_y1));

          gimp_displays_flush ();
        }

      g_rand_free (gr);
    }

  values[0].type          = GIMP_PDB_STATUS;
  values[0].data.d_status = status;

  gimp_drawable_detach (drawable);
}
Пример #10
0
/*
 * 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)
    {
      gimp_progress_update (1.0);
      /*  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);
    }
}
Пример #11
0
Preview_t *
make_preview (GimpDrawable *drawable)
{
    Preview_t *data = g_new(Preview_t, 1);
    GtkAdjustment *hadj;
    GtkAdjustment *vadj;
    GtkWidget *preview;
    GtkWidget *window;
    GtkWidget *button, *arrow;
    GtkWidget *ruler;
    GtkWidget *table;
    GtkWidget *scrollbar;
    gint width, height;

    data->drawable = drawable;
    data->preview = preview = gimp_preview_area_new ();

    g_object_set_data (G_OBJECT (preview), "preview", data);
    gtk_widget_set_events(GTK_WIDGET(preview), PREVIEW_MASK);
    g_signal_connect_after(preview, "expose-event",
                           G_CALLBACK(preview_expose), data);
    g_signal_connect (preview, "size-allocate",
                      G_CALLBACK (preview_size_allocate), (gpointer)data);

    /* Handle drop of links in preview widget */
    gtk_drag_dest_set(preview, GTK_DEST_DEFAULT_ALL, target_table,
                      2, GDK_ACTION_COPY);
    g_signal_connect(preview, "drag-data-received",
                     G_CALLBACK(handle_drop), NULL);

    data->widget_width = data->width =
                             gimp_drawable_width(drawable->drawable_id);
    data->widget_height = data->height =
                              gimp_drawable_height(drawable->drawable_id);
    gtk_widget_set_size_request (preview, data->widget_width,
                                 data->widget_height);

    /* The main table */
    data->window = table = gtk_table_new(3, 3, FALSE);
    gtk_table_set_col_spacings (GTK_TABLE (table), 1);
    gtk_table_set_row_spacings (GTK_TABLE (table), 1);

    /* Create button with arrow */
    button = gtk_button_new();
    gtk_widget_set_can_focus (button, FALSE);
    gtk_table_attach(GTK_TABLE(table), button, 0, 1, 0, 1, GTK_FILL, GTK_FILL,
                     0, 0);
    gtk_widget_set_events(button,
                          GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
    g_signal_connect(button, "button-press-event",
                     G_CALLBACK(arrow_cb), NULL);
    gtk_widget_show(button);

    arrow = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_OUT);
    gtk_container_add(GTK_CONTAINER(button), arrow);
    gtk_widget_show(arrow);

    /* Create horizontal ruler */
    data->hruler = ruler = gimp_ruler_new (GTK_ORIENTATION_HORIZONTAL);
    g_signal_connect_swapped(preview, "motion-notify-event",
                             G_CALLBACK(GTK_WIDGET_GET_CLASS(ruler)->motion_notify_event),
                             ruler);

    gtk_table_attach(GTK_TABLE(table), ruler, 1, 2, 0, 1,
                     GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_FILL, 0, 0);
    gtk_widget_show(ruler);

    /* Create vertical ruler */
    data->vruler = ruler = gimp_ruler_new (GTK_ORIENTATION_VERTICAL);
    g_signal_connect_swapped(preview, "motion-notify-event",
                             G_CALLBACK(GTK_WIDGET_GET_CLASS(ruler)->motion_notify_event),
                             ruler);
    gtk_table_attach(GTK_TABLE(table), ruler, 0, 1, 1, 2,
                     GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
    gtk_widget_show(ruler);

    window = gtk_scrolled_window_new (NULL, NULL);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(window),
                                   GTK_POLICY_NEVER, GTK_POLICY_NEVER);
    width = (data->width > 600) ? 600 : data->width;
    height = (data->height > 400) ? 400 : data->height;
    gtk_widget_set_size_request(window, width, height);
    gtk_table_attach(GTK_TABLE(table), window, 1, 2, 1, 2, GTK_FILL, GTK_FILL,
                     0, 0);
    gtk_widget_show(window);

    hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (window));

    g_signal_connect (hadj, "changed",
                      G_CALLBACK (scroll_adj_changed),
                      data->hruler);
    g_signal_connect (hadj, "value-changed",
                      G_CALLBACK (scroll_adj_changed),
                      data->hruler);

    vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (window));

    g_signal_connect (vadj, "changed",
                      G_CALLBACK (scroll_adj_changed),
                      data->vruler);
    g_signal_connect (vadj, "value-changed",
                      G_CALLBACK (scroll_adj_changed),
                      data->vruler);

    gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(window), preview);

    scrollbar = gtk_hscrollbar_new (hadj);
    gtk_table_attach(GTK_TABLE(table), scrollbar, 1, 2, 2, 3,
                     GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
    gtk_widget_show (scrollbar);

    scrollbar = gtk_vscrollbar_new (vadj);
    gtk_table_attach(GTK_TABLE(table), scrollbar,  2, 3, 1, 2,
                     GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
    gtk_widget_show (scrollbar);

    gtk_widget_show (preview);

    gimp_pixel_rgn_init(&data->src_rgn, drawable, 0, 0, data->width,
                        data->height, FALSE, FALSE);
    render_preview(data, &data->src_rgn);

    gtk_widget_show(table);

    return data;
}
Пример #12
0
static void dofilter (GimpDrawable *drawable)
{
  gint         i, j, k, channels;
  gint         x1, y1, x2, y2;
  GimpPixelRgn rgn_in, rgn_out;

   guchar      *inrow;
   guchar      *outrow;

  /* Gets upper left and lower right coordinates,
   * and layers number in the image */
  gimp_drawable_mask_bounds (drawable->drawable_id,
                             &x1, &y1,                             &x2, &y2);
  channels = gimp_drawable_bpp (drawable->drawable_id);

  /* Initialises two PixelRgns, one to read original data,
   * and the other to write output data. That second one will
   * be merged at the end by the call to
   * gimp_drawable_merge_shadow() */
  gimp_pixel_rgn_init (&rgn_in,        drawable,
                       x1, y1,        x2 - x1, y2 - y1,         FALSE, FALSE);
  gimp_pixel_rgn_init (&rgn_out,    drawable,
                       x1, y1,        x2 - x1, y2 - y1,         TRUE, TRUE);

 /* Initialise enough memory for inrow, outrow */
        inrow = g_new (guchar, channels * (x2 - x1));
        outrow = g_new (guchar, channels * (x2 - x1));




/* EXAMPLE USAGE of the functions to get the range */
//  guchar minp[4],maxp[4];
// getrange(drawable, minp, maxp, x1, x2, y1, y2);



  
  for (i = y1; i < y2; i++)
     {
         /* Get row i  into inrow array*/
         gimp_pixel_rgn_get_row (&rgn_in, inrow, x1, i, x2 - x1);

         for (j = x1; j < x2; j++)
              {
                /* For each layer get the color
                 * pixels */
            guchar rgb[4];
            for (k = 0; k < 4; k++) 
            {
                if (k<channels)
			rgb[k] = inrow[channels * (j - x1) + k];
		else	rgb[k] = 0;
	    }





/* YOUR MAIN CODE HERE : should modify the values inside the rgb array*/
          for (k = 0; k < channels; k++) {
                    float l = 255.0f * log(1 + rgb[k])/log(256.0f);
                   rgb[k] = (guchar) floor(l);
           }

/* END OF YOUR MAIN CODE HERE */





/* write the new rgb values to the pixels of the outrow */
            for (k = 0; k < channels; k++){ 
                outrow[channels * (j - x1) + k] = rgb[k];
            }

        } /*end for j each pixel of the row*/

      gimp_pixel_rgn_set_row (&rgn_out, outrow, x1, i, x2 - x1);

      if (i % 10 == 0)
        gimp_progress_update ((gdouble) (i - x1) / (gdouble) (x2 - x1));

    } /*end for i each row*/



  g_free (inrow);
  g_free (outrow);


  /* Update the modified 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);

}
Пример #13
0
static gboolean
focusblur_fft_buffer_update_source (FblurFftBuffer *fft,
                                    GimpDrawable   *drawable,
                                    GimpPreview    *preview)
{
  GimpPixelRgn  pr;
  gsize         size;
  gint          x1, x2, y1, y2;
  gint          width, height;
  gint          ntiles;

  fft->source.drawable = drawable;
  fft->source.preview  = preview;

  gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);

  if (preview)
    {
      gint px1, px2, py1, py2;
      gint pw, ph;

      gimp_preview_get_position (GIMP_PREVIEW (preview), &px1, &py1); 
      gimp_preview_get_size (GIMP_PREVIEW (preview), &pw, &ph); 
      px2 = px1 + pw;
      py2 = py1 + ph;

      x1 = MAX (px1, x1);
      x2 = MIN (px2, x2);
      y1 = MAX (py1, y1);
      y2 = MIN (py2, y2);
    }

  g_assert (x1 < x2);
  g_assert (y1 < y2);

  width  = x2 - x1;
  height = y2 - y1;

  ntiles = 1 + x2 / TILE_WIDTH - x1 / TILE_WIDTH;
  gimp_tile_cache_ntiles (ntiles);

  fft->source.has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);
  fft->source.bpp       = drawable->bpp;
  fft->source.channels  = drawable->bpp - (fft->source.has_alpha ? 1 : 0);
  fft->source.rowstride = drawable->bpp * width;

  size = fft->source.rowstride * height;

  if (fft->source.data_preview)
    {
      if (! preview)
        {
          g_free (fft->source.data_preview);
          fft->source.data_preview = NULL;
        }
      else if (size != fft->source.size)
        {
          g_free (fft->source.data_preview);
          goto allocate2;
        }
    }
  else
    {
    allocate2:
      if (preview)
        {
          fft->source.data_preview = g_malloc (size);
          if (! fft->source.data_preview)
            return FALSE;
        }
    }

  if (fft->source.data)
    {
      if (size != fft->source.size)
        {
          g_free (fft->source.data);
          goto allocate;
        }
    }
  else
    {
    allocate:
      fft->source.size = size;
      fft->source.data = g_malloc (size);
      if (! fft->source.data)
        return FALSE;
      goto reload;
    }

  if (x1 == fft->source.x1 &&
      x2 == fft->source.x2 &&
      y1 == fft->source.y1 &&
      y2 == fft->source.y2)
    return TRUE;

 reload:
  fft->source.x1     = x1;
  fft->source.x2     = x2;
  fft->source.y1     = y1;
  fft->source.y2     = y2;
  fft->source.width  = width;
  fft->source.height = height;

  /* need to recount */
  fft->depth.count = 0;

  /* load */
  gimp_pixel_rgn_init (&pr, drawable, x1, y1, width, height, FALSE, FALSE);
  gimp_pixel_rgn_get_rect (&pr, fft->source.data,
                           fft->source.x1, fft->source.y1,
                           fft->source.width, fft->source.height);

  return TRUE;
}
Пример #14
0
/* do the analyzing */
static void
analyze (GimpDrawable *drawable)
{
  GimpPixelRgn  srcPR;
  guchar       *src_row, *cmap;
  gint          x, y, numcol;
  gint          x1, y1, x2, y2;
  guchar        r, g, b;
  gint          a;
  guchar        idx;
  gboolean      gray;
  gboolean      has_alpha;
  gboolean      has_sel;
  guchar       *sel;
  GimpPixelRgn  selPR;
  gint          ofsx, ofsy;
  GimpDrawable *selDrawable;

  gimp_progress_init (_("Colorcube Analysis"));

  gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);

  /*
   * Get the size of the input image (this will/must be the same
   * as the size of the output image).
   */
  width = drawable->width;
  height = drawable->height;
  bpp = drawable->bpp;

  has_sel = !gimp_selection_is_empty (imageID);
  gimp_drawable_offsets (drawable->drawable_id, &ofsx, &ofsy);

  /* initialize the pixel region */
  gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE);

  cmap = gimp_image_get_colormap (imageID, &numcol);
  gray = (gimp_drawable_is_gray (drawable->drawable_id) ||
          gimp_item_is_channel (drawable->drawable_id));
  has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);

  selDrawable = gimp_drawable_get (gimp_image_get_selection (imageID));
  gimp_pixel_rgn_init (&selPR,
                       selDrawable,
                       0, 0, width, height, FALSE, FALSE);

  /* allocate row buffer */
  src_row = g_new (guchar, (x2 - x1) * bpp);
  sel = g_new (guchar, x2 - x1);

  for (y = y1; y < y2; y++)
    {
      gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y, (x2 - x1));
      if (has_sel)
        gimp_pixel_rgn_get_row (&selPR, sel, x1 + ofsx, y + ofsy, (x2 - x1));

      for (x = 0; x < x2 - x1; x++)
        {
          /* Start with full opacity.  */
          a = 255;

          /*
           * If the image is indexed, fetch RGB values
           * from colormap.
           */
          if (cmap)
            {
              idx = src_row[x * bpp];

              r = cmap[idx * 3];
              g = cmap[idx * 3 + 1];
              b = cmap[idx * 3 + 2];
              if (has_alpha)
                a = src_row[x * bpp + 1];
            }
          else if (gray)
            {
              r = g = b = src_row[x * bpp];
              if (has_alpha)
                a = src_row[x * bpp + 1];
            }
          else
            {
              r = src_row[x * bpp];
              g = src_row[x * bpp + 1];
              b = src_row[x * bpp + 2];
              if (has_alpha)
                a = src_row[x * bpp + 3];
            }

          if (has_sel)
            a *= sel[x];
          else
            a *= 255;

          if (a != 0)
            insertcolor (r, g, b, (gdouble) a * (1.0 / (255.0 * 255.0)));
        }

      /* tell the user what we're doing */
      if ((y % 10) == 0)
        gimp_progress_update ((gdouble) y / (gdouble) (y2 - y1));
    }

  gimp_progress_update (1.0);

  /* clean up */
  gimp_drawable_detach (selDrawable);
  g_free (src_row);
  g_free (sel);
}
Пример #15
0
static gint32
do_curl_effect (gint32 drawable_id)
{
  gint          x = 0;
  gint          y = 0;
  gboolean      color_image;
  gint          x1, y1, k;
  guint         alpha_pos, progress, max_progress;
  gdouble       intensity, alpha, beta;
  GimpVector2   v, dl, dr;
  gdouble       dl_mag, dr_mag, angle, factor;
  guchar       *pp, *dest, fore_grayval, back_grayval;
  guchar       *gradsamp;
  GimpPixelRgn  dest_rgn;
  gpointer      pr;
  gint32        curl_layer_id;
  guchar       *grad_samples  = NULL;

  color_image = gimp_drawable_is_rgb (drawable_id);

  curl_layer =
    gimp_drawable_get (gimp_layer_new (image_id,
				       _("Curl Layer"),
				       true_sel_width,
				       true_sel_height,
				       color_image ?
                                       GIMP_RGBA_IMAGE : GIMP_GRAYA_IMAGE,
				       100, GIMP_NORMAL_MODE));

  curl_layer_id = curl_layer->drawable_id;

  gimp_image_insert_layer (image_id, curl_layer->drawable_id,
                           gimp_item_get_parent (drawable_id),
                           drawable_position);
  gimp_drawable_fill (curl_layer->drawable_id, GIMP_TRANSPARENT_FILL);

  gimp_drawable_offsets (drawable_id, &x1, &y1);
  gimp_layer_set_offsets (curl_layer->drawable_id, sel_x1 + x1, sel_y1 + y1);
  gimp_tile_cache_ntiles (2 * (curl_layer->width / gimp_tile_width () + 1));

  gimp_pixel_rgn_init (&dest_rgn, curl_layer,
		       0, 0, true_sel_width, true_sel_height, TRUE, TRUE);

  /* Init shade_under */
  gimp_vector2_set (&dl, -sel_width, -sel_height);
  dl_mag = gimp_vector2_length (&dl);
  gimp_vector2_set (&dr,
		    -(sel_width - right_tangent.x),
		    -(sel_height - right_tangent.y));
  dr_mag = gimp_vector2_length (&dr);
  alpha = acos (gimp_vector2_inner_product (&dl, &dr) / (dl_mag * dr_mag));
  beta = alpha / 2;

  /* Init shade_curl */

  fore_grayval = GIMP_RGB_LUMINANCE (fore_color[0],
                                     fore_color[1],
                                     fore_color[2]) + 0.5;
  back_grayval = GIMP_RGB_LUMINANCE (back_color[0],
                                     back_color[1],
                                     back_color[2]) + 0.5;

  /* Gradient Samples */
  switch (curl.colors)
    {
    case CURL_COLORS_FG_BG:
      break;
    case CURL_COLORS_GRADIENT:
      grad_samples = get_gradient_samples (curl_layer->drawable_id, FALSE);
      break;
    case CURL_COLORS_GRADIENT_REVERSE:
      grad_samples = get_gradient_samples (curl_layer->drawable_id, TRUE);
      break;
    }

  max_progress = 2 * sel_width * sel_height;
  progress = 0;

  alpha_pos = dest_rgn.bpp - 1;

  /* Main loop */
  for (pr = gimp_pixel_rgns_register (1, &dest_rgn);
       pr != NULL;
       pr = gimp_pixel_rgns_process (pr))
    {
      dest = dest_rgn.data;

      for (y1 = dest_rgn.y; y1 < dest_rgn.y + dest_rgn.h; y1++)
	{
	  pp = dest;
	  for (x1 = dest_rgn.x; x1 < dest_rgn.x + dest_rgn.w; x1++)
	    {
	      /* Map coordinates to get the curl correct... */
              switch (curl.orientation)
                {
                case CURL_ORIENTATION_VERTICAL:
		  x = CURL_EDGE_RIGHT (curl.edge) ? x1 : sel_width  - 1 - x1;
		  y = CURL_EDGE_UPPER (curl.edge) ? y1 : sel_height - 1 - y1;
                  break;

                case CURL_ORIENTATION_HORIZONTAL:
                  x = CURL_EDGE_LOWER (curl.edge) ? y1 : sel_width  - 1 - y1;
		  y = CURL_EDGE_LEFT  (curl.edge) ? x1 : sel_height - 1 - x1;
                  break;
		}

	      if (left_of_diagl (x, y))
		{ /* uncurled region */
		  for (k = 0; k <= alpha_pos; k++)
		    pp[k] = 0;
		}
	      else if (right_of_diagr (x, y) ||
		       (right_of_diagm (x, y) &&
			below_diagb (x, y) &&
			!inside_circle (x, y)))
		{
		  /* curled region */
		  for (k = 0; k <= alpha_pos; k++)
		    pp[k] = 0;
		}
	      else
		{
		  v.x = -(sel_width - x);
		  v.y = -(sel_height - y);
		  angle = acos (gimp_vector2_inner_product (&v, &dl) /
				(gimp_vector2_length (&v) * dl_mag));

		  if (inside_circle (x, y) || below_diagb (x, y))
		    {
		      /* Below the curl. */
		      factor = angle / alpha;
		      for (k = 0; k < alpha_pos; k++)
			pp[k] = 0;

		      pp[alpha_pos] = (curl.shade ?
                                       (guchar) ((float) 255 * (float) factor) :
                                       0);
		    }
		  else
		    {
		      /* On the curl */
                      switch (curl.colors)
                        {
                        case CURL_COLORS_FG_BG:
			  intensity = pow (sin (G_PI * angle / alpha), 1.5);
			  if (color_image)
			    {
			      pp[0] = (intensity * back_color[0] +
                                       (1.0 - intensity) * fore_color[0]);
			      pp[1] = (intensity * back_color[1] +
                                       (1.0 - intensity) * fore_color[1]);
			      pp[2] = (intensity * back_color[2] +
                                       (1.0 - intensity) * fore_color[2]);
			    }
			  else
			    pp[0] = (intensity * back_grayval +
                                     (1 - intensity) * fore_grayval);

			  pp[alpha_pos] = (guchar) ((double) 255.99 *
                                                    (1.0 - intensity *
                                                     (1.0 - curl.opacity)));
                          break;

                        case CURL_COLORS_GRADIENT:
                        case CURL_COLORS_GRADIENT_REVERSE:
			  /* Calculate position in Gradient */
                          intensity =
                            (angle/alpha) + sin (G_PI*2 * angle/alpha) * 0.075;

			  /* Check boundaries */
			  intensity = CLAMP (intensity, 0.0, 1.0);
			  gradsamp  = (grad_samples +
                                       ((guint) (intensity * NGRADSAMPLES)) *
                                       dest_rgn.bpp);

			  if (color_image)
			    {
			      pp[0] = gradsamp[0];
			      pp[1] = gradsamp[1];
			      pp[2] = gradsamp[2];
			    }
			  else
			    pp[0] = gradsamp[0];

			  pp[alpha_pos] =
                            (guchar) ((double) gradsamp[alpha_pos] *
                                      (1.0 - intensity * (1.0 - curl.opacity)));
                          break;
                        }
		    }
		}
	      pp += dest_rgn.bpp;
	    }
	  dest += dest_rgn.rowstride;
	}
      progress += dest_rgn.w * dest_rgn.h;
      gimp_progress_update ((double) progress / (double) max_progress);
    }

  gimp_drawable_flush (curl_layer);
  gimp_drawable_merge_shadow (curl_layer->drawable_id, FALSE);
  gimp_drawable_update (curl_layer->drawable_id,
			0, 0, curl_layer->width, curl_layer->height);
  gimp_drawable_detach (curl_layer);

  g_free (grad_samples);

  return curl_layer_id;
}
Пример #16
0
static void
compute_difference (GimpDrawable *drawable,
                    GimpDrawable *drawable1,
                    GimpDrawable *drawable2,
                    guchar       *maxval)
{
  GimpPixelRgn src1_rgn, src2_rgn, dest_rgn;
  gint         width, height;
  gint         bpp;
  gpointer     pr;
  gint         x, y, k;
  gint         x1, y1, x2, y2;
  gboolean     has_alpha;

  *maxval = 0;

  gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);

  width  = (x2 - x1);
  height = (y2 - y1);

  if (width < 1 || height < 1)
    return;

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

  gimp_pixel_rgn_init (&src1_rgn,
                       drawable1, 0, 0, drawable1->width, drawable1->height,
                       FALSE, FALSE);
  gimp_pixel_rgn_init (&src2_rgn,
                       drawable2, 0, 0, drawable1->width, drawable1->height,
                       FALSE, FALSE);
  gimp_pixel_rgn_init (&dest_rgn,
                       drawable, 0, 0, drawable->width, drawable->height,
                       TRUE, TRUE);

  for (pr = gimp_pixel_rgns_register (3, &src1_rgn, &src2_rgn, &dest_rgn);
       pr != NULL;
       pr = gimp_pixel_rgns_process (pr))
    {
      guchar *src1 = src1_rgn.data;
      guchar *src2 = src2_rgn.data;
      guchar *dest = dest_rgn.data;
      gint    row  = src1_rgn.y - y1;

      for (y = 0; y < src1_rgn.h; y++, row++)
        {
          guchar *s1  = src1;
          guchar *s2  = src2;
          guchar *d   = dest;
          gint    col = src1_rgn.x - x1;

          for (x = 0; x < src1_rgn.w; x++, col++)
            {

              if (has_alpha)
                {
                  for (k = 0; k < bpp-1; k++)
                    {
                      d[k] = CLAMP0255 (s1[k] - s2[k]);
                      *maxval = MAX (d[k], *maxval);
                    }
                }
              else
                {
                  for (k = 0; k < bpp; k++)
                    {
                      d[k] = CLAMP0255 (s1[k] - s2[k]);
                      *maxval = MAX (d[k], *maxval);
                    }
                }

              s1 += bpp;
              s2 += bpp;
              d += bpp;
            }

          src1 += src1_rgn.rowstride;
          src2 += src2_rgn.rowstride;
          dest += dest_rgn.rowstride;
        }
    }
}
Пример #17
0
static void
clear_curled_region (gint32 drawable_id)
{
  GimpPixelRgn  src_rgn, dest_rgn;
  gpointer      pr;
  gint          x = 0;
  gint          y = 0;
  guint         x1, y1, i;
  guchar       *dest, *src, *pp, *sp;
  guint         alpha_pos, progress, max_progress;
  GimpDrawable *drawable;

  max_progress = 2 * sel_width * sel_height;
  progress = max_progress / 2;

  drawable = gimp_drawable_get (drawable_id);

  gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
  gimp_pixel_rgn_init (&src_rgn, drawable,
		       sel_x1, sel_y1, true_sel_width, true_sel_height,
		       FALSE, FALSE);
  gimp_pixel_rgn_init (&dest_rgn, drawable,
		       sel_x1, sel_y1, true_sel_width, true_sel_height,
		       TRUE, TRUE);
  alpha_pos = dest_rgn.bpp - 1;

  for (pr = gimp_pixel_rgns_register (2, &dest_rgn, &src_rgn);
       pr != NULL;
       pr = gimp_pixel_rgns_process (pr))
    {
      dest = dest_rgn.data;
      src = src_rgn.data;

      for (y1 = dest_rgn.y; y1 < dest_rgn.y + dest_rgn.h; y1++)
	{
	  sp = src;
	  pp = dest;

	  for (x1 = dest_rgn.x; x1 < dest_rgn.x + dest_rgn.w; x1++)
	    {
	      /* Map coordinates to get the curl correct... */
              switch (curl.orientation)
                {
                case CURL_ORIENTATION_VERTICAL:
		  x = (CURL_EDGE_RIGHT (curl.edge) ?
                       x1 - sel_x1 : sel_width  - 1 - (x1 - sel_x1));
		  y = (CURL_EDGE_UPPER (curl.edge) ?
                       y1 - sel_y1 : sel_height - 1 - (y1 - sel_y1));
                  break;

                case CURL_ORIENTATION_HORIZONTAL:
		  x = (CURL_EDGE_LOWER (curl.edge) ?
                       y1 - sel_y1 : sel_width - 1 - (y1 - sel_y1));
                  y = (CURL_EDGE_LEFT (curl.edge)  ?
                       x1 - sel_x1 : sel_height - 1 - (x1 - sel_x1));
                  break;
                }

	      for (i = 0; i < alpha_pos; i++)
		pp[i] = sp[i];

	      if (right_of_diagr (x, y) ||
		  (right_of_diagm (x, y) &&
		   below_diagb (x, y) &&
		   !inside_circle (x, y)))
		{
		  /* Right of the curl */
		  pp[alpha_pos] = 0;
		}
	      else
		{
		  pp[alpha_pos] = sp[alpha_pos];
		}

	      pp += dest_rgn.bpp;
	      sp += src_rgn.bpp;
	    }

	  src += src_rgn.rowstride;
	  dest += dest_rgn.rowstride;
	}

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

  gimp_drawable_flush (drawable);
  gimp_drawable_merge_shadow (drawable_id, TRUE);
  gimp_drawable_update (drawable_id,
			sel_x1, sel_y1, true_sel_width, true_sel_height);
  gimp_drawable_detach (drawable);
}
Пример #18
0
static void
gauss_rle (GimpDrawable *drawable,
           gdouble       radius,
           gint          pass,
           gboolean      show_progress)
{
  GimpPixelRgn src_rgn, dest_rgn;
  gint     width, height;
  gint     bytes;
  gint     has_alpha;
  guchar  *dest, *dp;
  guchar  *src, *sp;
  gint    *buf, *bb;
  gint     pixels;
  gint     total = 1;
  gint     x1, y1, x2, y2;
  gint     i, row, col, b;
  gint     start, end;
  gdouble  progress, max_progress;
  gint    *curve;
  gint    *sum = NULL;
  gint     val;
  gint     length;
  gint     initial_p, initial_m;
  gdouble  std_dev;

  if (radius <= 0.0)
    return;

  gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);

  width  = (x2 - x1);
  height = (y2 - y1);

  if (width < 1 || height < 1)
    return;

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

  buf = g_new (gint, MAX (width, height) * 2);

  /*  allocate buffers for source and destination pixels  */
  src = g_new (guchar, MAX (width, height) * bytes);
  dest = g_new (guchar, MAX (width, height) * bytes);

  gimp_pixel_rgn_init (&src_rgn,
                       drawable, 0, 0, drawable->width, drawable->height,
                       FALSE, FALSE);
  gimp_pixel_rgn_init (&dest_rgn,
                       drawable, 0, 0, drawable->width, drawable->height,
                       TRUE, TRUE);

  progress = 0.0;
  max_progress  = 2 * width * height;

  /*  First the vertical pass  */
  radius = fabs (radius) + 1.0;
  std_dev = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0)));

  curve = make_curve (std_dev, &length);
  sum = g_new (gint, 2 * length + 1);

  sum[0] = 0;

  for (i = 1; i <= length*2; i++)
    sum[i] = curve[i-length-1] + sum[i-1];
  sum += length;

  total = sum[length] - sum[-length];

  for (col = 0; col < width; col++)
    {
      gimp_pixel_rgn_get_col (&src_rgn, src, col + x1, y1, (y2 - y1));

      if (has_alpha)
        multiply_alpha (src, height, bytes);

      sp = src;
      dp = dest;

      for (b = 0; b < bytes; b++)
        {
          initial_p = sp[b];
          initial_m = sp[(height-1) * bytes + b];

          /*  Determine a run-length encoded version of the row  */
          run_length_encode (sp + b, buf, bytes, height);

          for (row = 0; row < height; row++)
            {
              start = (row < length) ? -row : -length;
              end = (height <= (row + length) ?
                     (height - row - 1) : length);

              val = 0;
              i = start;
              bb = buf + (row + i) * 2;

              if (start != -length)
                val += initial_p * (sum[start] - sum[-length]);

              while (i < end)
                {
                  pixels = bb[0];
                  i += pixels;

                  if (i > end)
                    i = end;

                  val += bb[1] * (sum[i] - sum[start]);
                  bb += (pixels * 2);
                  start = i;
                }

              if (end != length)
                val += initial_m * (sum[length] - sum[end]);

              dp[row * bytes + b] = val / total;
            }
        }

      if (has_alpha)
        separate_alpha (dest, height, bytes);

      gimp_pixel_rgn_set_col (&dest_rgn, dest, col + x1, y1, (y2 - y1));

      if (show_progress)
        {
          progress += height;

          if ((col % 32) == 0)
            gimp_progress_update (0.5 * (pass + (progress / max_progress)));
        }
    }

  /*  prepare for the horizontal pass  */
  gimp_pixel_rgn_init (&src_rgn,
                       drawable, 0, 0, drawable->width, drawable->height,
                       FALSE, TRUE);

  /*  Now the horizontal pass  */
  for (row = 0; row < height; row++)
    {
      gimp_pixel_rgn_get_row (&src_rgn, src, x1, row + y1, (x2 - x1));
      if (has_alpha)
        multiply_alpha (src, width, bytes);

      sp = src;
      dp = dest;

      for (b = 0; b < bytes; b++)
        {
          initial_p = sp[b];
          initial_m = sp[(width-1) * bytes + b];

          /*  Determine a run-length encoded version of the row  */
          run_length_encode (sp + b, buf, bytes, width);

          for (col = 0; col < width; col++)
            {
              start = (col < length) ? -col : -length;
              end = (width <= (col + length)) ? (width - col - 1) : length;

              val = 0;
              i = start;
              bb = buf + (col + i) * 2;

              if (start != -length)
                val += initial_p * (sum[start] - sum[-length]);

              while (i < end)
                {
                  pixels = bb[0];
                  i += pixels;

                  if (i > end)
                    i = end;

                  val += bb[1] * (sum[i] - sum[start]);
                  bb += (pixels * 2);
                  start = i;
                }

              if (end != length)
                val += initial_m * (sum[length] - sum[end]);

              dp[col * bytes + b] = val / total;
            }
        }

      if (has_alpha)
        separate_alpha (dest, width, bytes);

      gimp_pixel_rgn_set_row (&dest_rgn, dest, x1, row + y1, (x2 - x1));

      if (show_progress)
        {
          progress += width;

          if ((row % 32) == 0)
            gimp_progress_update (0.5 * (pass + (progress / max_progress)));
        }
    }

  /*  merge the shadow, update the drawable  */
  gimp_drawable_flush (drawable);
  gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
  gimp_drawable_update (drawable->drawable_id, x1, y1, (x2 - x1), (y2 - y1));

  /*  free buffers  */
  g_free (buf);
  g_free (src);
  g_free (dest);
}
Пример #19
0
static gint32
load_image (char *filename)
{
  GPixelRgn pixel_rgn;
  TileDrawable *drawable;
  gint32 image_ID;
  gint32 layer_ID;
  struct jpeg_decompress_struct cinfo;
  struct my_error_mgr jerr;
  FILE *infile;
  guchar *buf;
  guchar **rowbuf;
  char *name;
  int image_type;
  int layer_type;
  int tile_height;
  int scanlines;
  int i, start, end;
  int m;
  int depth = 8;

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

  if ((infile = fopen (filename, "rb")) == NULL)
    {
      g_warning ("can't open \"%s\"\n", filename);
      gimp_quit ();
    }

  if( strrchr(filename,'.') &&
      strcmp( strrchr(filename, '.'), ".jp4") == 0 )
    depth = 16;

  name = malloc (strlen (filename) + 12);
  sprintf (name, "%s %s:", _("Loading"), filename);
  gimp_progress_init (name);
  free (name);

  image_ID = -1;
  /* 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);
      if (image_ID != -1)
	gimp_image_delete (image_ID);
      gimp_quit ();
    }
  /* 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);

  setup_read_icc_profile(&cinfo);  
  for (m = 0; m < 16; m++)
    jpeg_save_markers(&cinfo, JPEG_APP0 + m, 0xFFFF);

  /* 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.
   */
  prepareColour( &cinfo );

  /* 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 */
  tile_height = gimp_tile_height ();
  buf = g_new (guchar, tile_height * cinfo.output_width * cinfo.output_components);
  rowbuf = g_new (guchar*, tile_height);

  for (i = 0; i < tile_height; i++)
    rowbuf[i] = buf + cinfo.output_width * cinfo.output_components * i;

  /* Create a new image of the proper size and associate the filename with it.
   */
  if(depth == 8)
  {
    switch (cinfo.output_components)
    {
    case 1:
      image_type = GRAY;
      layer_type = GRAY_IMAGE;
      break;
    case 3:
      image_type = RGB;
      layer_type = RGB_IMAGE;
      break;
    case 4:
      image_type = RGB;
      layer_type = RGBA_IMAGE;
      break;
    default:
      gimp_quit ();
    }
  } else {
    switch (cinfo.output_components)
    {
    case 1:
      image_type = U16_GRAY;
      layer_type = U16_GRAY_IMAGE;
      break;
    case 3:
      image_type = U16_RGB;
      layer_type = U16_RGB_IMAGE;
      break;
    case 4:
      image_type = U16_RGB;
      layer_type = U16_RGBA_IMAGE;
      break;
    default:
      gimp_quit ();
    }
  }

  image_ID = gimp_image_new (cinfo.output_width / (depth/8), cinfo.output_height,
                             image_type);
  gimp_image_set_filename (image_ID, filename);

  layer_ID = gimp_layer_new (image_ID, _("Background"),
			     cinfo.output_width / (depth/8),
			     cinfo.output_height,
			     layer_type, 100, NORMAL_MODE);
  gimp_image_add_layer (image_ID, layer_ID, 0);

  drawable = gimp_drawable_get (layer_ID);
  gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE);

  /* 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)
    {
      start = cinfo.output_scanline;
      end = cinfo.output_scanline + tile_height;
      end = MIN (end,CAST(int) cinfo.output_height);
      scanlines = end - start;

      for (i = 0; i < scanlines; i++)
	jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &rowbuf[i], 1);

      /*
      for (i = start; i < end; i++)
	gimp_pixel_rgn_set_row (&pixel_rgn, tilerow[i - start], 0, i, drawable->width);
	*/

      if(cinfo.out_color_space == JCS_CMYK)
        for(i = 0; i < scanlines*drawable->width*cinfo.output_components; ++i)
          buf[i] = 255 - buf[i];

      if(depth == 16 && 0)
        for(i = 0; i < scanlines*drawable->width*cinfo.output_components; ++i)
        {
          unsigned char c = buf[2*i];
          buf[2*i] = buf[2*i+1];
          buf[2*i+1] = c;
        }

      gimp_pixel_rgn_set_rect (&pixel_rgn, buf, 0, start, drawable->width, scanlines);

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

  // Step 6a: read icc profile
  {
    LPBYTE Buffer = NULL;
    size_t Len = 0;
    cmsHPROFILE hProfile=NULL;

    if (read_icc_profile(&cinfo, &Buffer, &Len))
    {
      printf ("%s:%d %s() embedded profile found\n",__FILE__,__LINE__,__func__);
    } else if (read_icc_profile2(&cinfo, &Buffer, &Len)) {
      printf ("%s:%d %s() default profile selected\n",__FILE__,__LINE__,__func__);
    }

    if(Buffer && Len)
    {
      hProfile = cmsOpenProfileFromMem(Buffer, Len);
      if (hProfile) {
        gimp_image_set_icc_profile_by_mem (image_ID, Len, Buffer, ICC_IMAGE_PROFILE);
        cmsCloseProfile (hProfile);
        free(Buffer);
        printf ("%s:%d %s() set profile\n",__FILE__,__LINE__,__func__);
      }
    }
  }

  /* 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 (rowbuf);
  g_free (buf);

  /* 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).
   */

  /* Tell the GIMP to display the image.
   */
  gimp_drawable_flush (drawable);

  return image_ID;
}
Пример #20
0
static void
sobel (TileDrawable *drawable,
	   gint       do_horizontal,
	   gint       do_vertical,
	   gint       keep_sign)
{
  GPixelRgn srcPR, destPR;
  gint width, height;
  gint num_channels;

  guchar *dest;
  guchar *prev_row;
  guchar *cur_row;
  guchar *next_row;
  guchar *pr;
  guchar *cr;
  guchar *nr;
  guchar *tmp;

  gint row, col;
  gint x1, y1, x2, y2;
  gint alpha;
  gint counter;
  GPrecisionType precision = gimp_drawable_precision (drawable->id);

  /* Get the input area. This is the bounding box of the selection in
   *  the image (or the entire image if there is no selection). Only
   *  operating on the input area is simply an optimization. It doesn't
   *  need to be done for correct operation. (It simply makes it go
   *  faster, since fewer pixels need to be operated on).
   */

  gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  gimp_progress_init (_("Sobel Edge Detect"));

  /* Get the size of the input image. (This will/must be the same
   *  as the size of the output image.
   */
  width = drawable->width;
  height = drawable->height;
  num_channels = drawable->num_channels;
  alpha = gimp_drawable_has_alpha (drawable -> id);

  /*  allocate generic data row buffers  */
  prev_row = (guchar *) malloc ((x2 - x1 + 2) * drawable->bpp);
  cur_row = (guchar *) malloc ((x2 - x1 + 2) * drawable->bpp);
  next_row = (guchar *) malloc ((x2 - x1 + 2) * drawable->bpp);
  dest = (guchar *) malloc ((x2 - x1) * drawable->bpp);

  /*  initialize the pixel regions  */
  gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE);
  gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height, TRUE, TRUE);

  /* generic data pointers to the three rows */ 
  pr = prev_row + drawable->bpp;
  cr = cur_row + drawable->bpp;
  nr = next_row + drawable->bpp;

  sobel_prepare_row (&srcPR, pr, x1, y1 - 1, (x2 - x1));
  sobel_prepare_row (&srcPR, cr, x1, y1, (x2 - x1));
  counter = 0;

  /*  loop through the rows, applying the sobel convolution  */
  for (row = y1; row < y2; row++)
    {
      /*  prepare the next row  */
      sobel_prepare_row (&srcPR, nr, x1, row + 1, (x2 - x1));

      switch(precision)
      {
	  case PRECISION_U8:
	    {
	      guint8* d = (guint8*)dest;
	      guint8* p = (guint8*)pr; 
	      guint8* c = (guint8*)cr;
	      guint8* n = (guint8*)nr;
  	      gint gradient, hor_gradient, ver_gradient;

	      for (col = 0; col < (x2 - x1) * num_channels; col++) {
		  if (do_horizontal)
		    hor_gradient = (p[col - num_channels] + 2 * p[col] + p[col + num_channels]) -
				   (n[col - num_channels] + 2 * n[col] + n[col + num_channels]);
		  else
		    hor_gradient = 0;

		  if (do_vertical)
		    ver_gradient = (p[col - num_channels] + 2 * c[col - num_channels] + n[col - num_channels]) -
				   (p[col + num_channels] + 2 * c[col + num_channels] + n[col + num_channels]);
		  else
		    ver_gradient = 0;

		  if (do_vertical && do_horizontal)
		      gradient = ROUND_TO_INT (RMS (hor_gradient, ver_gradient)) / 5.66;
		  else
		    {
		       if (keep_sign)
			 gradient = 127 + (ROUND_TO_INT ((hor_gradient + ver_gradient) / 8.0));
		       else
			 gradient =  ROUND_TO_INT (abs (hor_gradient + ver_gradient) / 4.0);
		    }

		  if (alpha && (((col + 1) % num_channels) == 0))  
		  { 
		    *d++ = (counter == 0) ? 0 : 255;
		    counter = 0; 
		  }
		  else 
		  {
		    *d++ = gradient;
		    if (gradient > 10) counter ++;
		  }
	       }
	     }
	    break;
	  case PRECISION_U16:
	    {
	      guint16* d = (guint16*)dest;
	      guint16* p = (guint16*)pr; 
	      guint16* c = (guint16*)cr;
	      guint16* n = (guint16*)nr;
  	      gint gradient, hor_gradient, ver_gradient;

	      for (col = 0; col < (x2 - x1) * num_channels; col++) {
		  if (do_horizontal)
		    hor_gradient = (p[col - num_channels] + 2 * p[col] + p[col + num_channels]) -
				   (n[col - num_channels] + 2 * n[col] + n[col + num_channels]);
		  else
		    hor_gradient = 0;

		  if (do_vertical)
		    ver_gradient = (p[col - num_channels] + 2 * c[col - num_channels] + n[col - num_channels]) -
				   (p[col + num_channels] + 2 * c[col + num_channels] + n[col + num_channels]);
		  else
		    ver_gradient = 0;

		  if (do_vertical && do_horizontal)
		      gradient = ROUND_TO_INT (RMS (hor_gradient, ver_gradient)) / 5.66;
		  else
		    {
		       if (keep_sign)
			 gradient = 32767 + (ROUND_TO_INT ((hor_gradient + ver_gradient) / 8.0));
		       else
			 gradient =  ROUND_TO_INT (abs (hor_gradient + ver_gradient) / 4.0);
		    }

		  if (alpha && (((col + 1) % num_channels) == 0))  
		  { 
		    *d++ = (counter == 0) ? 0 : 65535;
		    counter = 0; 
		  }
		  else 
		  {
		    *d++ = gradient;
		    if (gradient > (10/255.0) * 65535) counter ++;
		  }
	       }
	     }
	    break;
	  case PRECISION_FLOAT:
	    {
	      gfloat* d = (gfloat*)dest;
	      gfloat* p = (gfloat*)pr; 
	      gfloat* c = (gfloat*)cr;
	      gfloat* n = (gfloat*)nr;
  	      gfloat gradient, hor_gradient, ver_gradient;

	      for (col = 0; col < (x2 - x1) * num_channels; col++) {
		  if (do_horizontal)
		    hor_gradient = (p[col - num_channels] + 2 * p[col] + p[col + num_channels]) -
				   (n[col - num_channels] + 2 * n[col] + n[col + num_channels]);
		  else
		    hor_gradient = 0;

		  if (do_vertical)
		    ver_gradient = (p[col - num_channels] + 2 * c[col - num_channels] + n[col - num_channels]) -
				   (p[col + num_channels] + 2 * c[col + num_channels] + n[col + num_channels]);
		  else
		    ver_gradient = 0;

		  if (do_vertical && do_horizontal)
		      gradient = (RMS (hor_gradient, ver_gradient)) / 5.66;
		  else
		    {
		       if (keep_sign)
			 gradient = .5 + (hor_gradient + ver_gradient) / 8.0;
		       else
			 gradient =  abs (hor_gradient + ver_gradient) / 4.0;
		    }

		  if (alpha && (((col + 1) % num_channels) == 0))  
		  { 
		    *d++ = (counter == 0) ? 0.0 : 1.0;
		    counter = 0; 
		  }
		  else 
		  {
		    *d++ = gradient;
		    if (gradient > (10/255.0)) counter ++;
		  }
	       }
	     }
	    break;
	  case PRECISION_FLOAT16: 
	    {
	      guint16* d = (guint16*)dest;
	      guint16* p = (guint16*)pr; 
	      guint16* c = (guint16*)cr;
	      guint16* n = (guint16*)nr;
  	      gfloat gradient, hor_gradient, ver_gradient;
	      ShortsFloat u,v,s, u1, v1, s1;

	      for (col = 0; col < (x2 - x1) * num_channels; col++) {
		  if (do_horizontal)
		    hor_gradient = (
				      FLT(p[col - num_channels],u) +     
				      2 * FLT(p[col], v) +             
				      FLT(p[col + num_channels], s)          
								) -
				    (
				      FLT(n[col - num_channels],u1) + 
				      2 * FLT(n[col], v1) 
				      + FLT(n[col + num_channels], s1)
								   );
		  else
		    hor_gradient = 0;

		  if (do_vertical)
		    ver_gradient = (
				     FLT(p[col - num_channels], u) + 
				     2 * FLT (c[col - num_channels],v) + 
				     FLT(n[col - num_channels],s)
								) -
				   (
				     FLT(p[col + num_channels], u1) + 
				     2 * FLT (c[col + num_channels],v1) + 
				     FLT(n[col + num_channels], s1)
								);
		  else
		    ver_gradient = 0;

		  if (do_vertical && do_horizontal)
		      gradient = (RMS (hor_gradient, ver_gradient)) / 5.66;
		  else
		    {
		       if (keep_sign)
			 gradient = .5 + (hor_gradient + ver_gradient) / 8.0;
		       else
			 gradient =  abs (hor_gradient + ver_gradient) / 4.0;
		    }

		  if (alpha && (((col + 1) % num_channels) == 0))  
		  { 
		    *d++ = (counter == 0) ? 0.0 : 1.0;
		    counter = 0; 
		  }
		  else 
		  {
		    *d++ = FLT16(gradient, u);
		    if (gradient > (10/255.0)) counter ++;
		  }
	       }
	     }
	    break;
      }

      /*  store the dest  */
      gimp_pixel_rgn_set_row (&destPR, dest, x1, row, (x2 - x1));

      /*  shuffle the row pointers  */
      tmp = pr;
      pr = cr;
      cr = nr;
      nr = tmp;

      if ((row % 5) == 0)
	gimp_progress_update ((double) row / (double) (y2 - y1));
    }

  /*  update the sobeled region  */
  gimp_drawable_flush (drawable);
  gimp_drawable_merge_shadow (drawable->id, TRUE);
  gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));

  free (prev_row);
  free (cur_row);
  free (next_row);
  free (dest);
}
Пример #21
0
ReducedImage*
rcm_reduce_image (GimpDrawable *drawable,
		  GimpDrawable *mask,
		  gint          LongerSize,
		  gint          Slctn)
{
  guint32       image;
  GimpPixelRgn  srcPR, srcMask;
  ReducedImage *temp;
  guchar       *tempRGB, *src_row, *tempmask, *src_mask_row;
  gint          i, j, x1, x2, y1, y2;
  gint          RH, RW, width, height, bytes;
  gboolean      NoSelectionMade;
  gint          offx, offy;
  gdouble      *tempHSV, H, S, V;

  bytes = drawable->bpp;
  temp = g_new0 (ReducedImage, 1);

  /* get bounds of image or selection */

  gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);

  if (((x2-x1) != drawable->width) || ((y2-y1) != drawable->height))
    NoSelectionMade = FALSE;
  else
    NoSelectionMade = TRUE;

  switch (Slctn)
    {
    case ENTIRE_IMAGE:
      x1 = 0;
      x2 = drawable->width;
      y1 = 0;
      y2 = drawable->height;
      break;

    case SELECTION_IN_CONTEXT:
      x1 = MAX (0, x1 - (x2-x1) / 2.0);
      x2 = MIN (drawable->width, x2 + (x2-x1) / 2.0);
      y1 = MAX (0, y1 - (y2-y1) / 2.0);
      y2 = MIN (drawable->height, y2 + (y2-y1) / 2.0);
      break;

    default:
      break; /* take selection dimensions */
    }

  /* clamp to image size since this is the size of the mask */

  gimp_drawable_offsets (drawable->drawable_id, &offx, &offy);
  image = gimp_item_get_image (drawable->drawable_id);

  x1 = CLAMP (x1, - offx, gimp_image_width (image) - offx);
  x2 = CLAMP (x2, - offx, gimp_image_width (image) - offx);
  y1 = CLAMP (y1, - offy, gimp_image_height (image) - offy);
  y2 = CLAMP (y2, - offy, gimp_image_height (image) - offy);

  /* calculate size of preview */

  width  = x2 - x1;
  height = y2 - y1;

  if (width < 1 || height < 1)
    return temp;

  if (width > height)
    {
      RW = LongerSize;
      RH = (float) height * (float) LongerSize / (float) width;
    }
  else
    {
      RH = LongerSize;
      RW = (float)width * (float) LongerSize / (float) height;
    }

  /* allocate memory */

  tempRGB  = g_new (guchar, RW * RH * bytes);
  tempHSV  = g_new (gdouble, RW * RH * bytes);
  tempmask = g_new (guchar, RW * RH);

  gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height, FALSE, FALSE);
  gimp_pixel_rgn_init (&srcMask, mask,
                       x1 + offx, y1 + offy, width, height, FALSE, FALSE);

  src_row = g_new (guchar, width * bytes);
  src_mask_row = g_new (guchar, width * bytes);

  /* reduce image */

  for (i = 0; i < RH; i++)
    {
      gint whichcol, whichrow;

      whichrow = (float)i * (float)height / (float)RH;
      gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1 + whichrow, width);
      gimp_pixel_rgn_get_row (&srcMask, src_mask_row,
                              x1 + offx, y1 + offy + whichrow, width);

      for (j = 0; j < RW; j++)
        {
          whichcol = (float)j * (float)width / (float)RW;

          if (NoSelectionMade)
            tempmask[i*RW+j] = 255;
          else
            tempmask[i*RW+j] = src_mask_row[whichcol];

          gimp_rgb_to_hsv4 (&src_row[whichcol*bytes], &H, &S, &V);

          tempRGB[i*RW*bytes+j*bytes+0] = src_row[whichcol*bytes+0];
          tempRGB[i*RW*bytes+j*bytes+1] = src_row[whichcol*bytes+1];
          tempRGB[i*RW*bytes+j*bytes+2] = src_row[whichcol*bytes+2];

          tempHSV[i*RW*bytes+j*bytes+0] = H;
          tempHSV[i*RW*bytes+j*bytes+1] = S;
          tempHSV[i*RW*bytes+j*bytes+2] = V;

          if (bytes == 4)
            tempRGB[i*RW*bytes+j*bytes+3] = src_row[whichcol*bytes+3];
        }
    }

  /* return values */

  temp->width  = RW;
  temp->height = RH;
  temp->rgb    = tempRGB;
  temp->hsv    = tempHSV;
  temp->mask   = tempmask;

  return temp;
}