Example #1
0
static gboolean
gimp_crop_tool_execute (GimpRectangleTool  *rectangle,
                        gint                x,
                        gint                y,
                        gint                w,
                        gint                h)
{
  GimpTool        *tool    = GIMP_TOOL (rectangle);
  GimpCropOptions *options = GIMP_CROP_TOOL_GET_OPTIONS (tool);
  GimpImage       *image   = gimp_display_get_image (tool->display);

  gimp_tool_pop_status (tool, tool->display);

  /* if rectangle exists, crop it */
  if (w > 0 && h > 0)
    {
      if (options->layer_only)
        {
          GimpLayer *layer = gimp_image_get_active_layer (image);
          gint       off_x, off_y;

          if (! layer)
            {
              gimp_tool_message_literal (tool, tool->display,
                                         _("There is no active layer to crop."));
              return FALSE;
            }

          if (gimp_item_is_content_locked (GIMP_ITEM (layer)))
            {
              gimp_tool_message_literal (tool, tool->display,
                                         _("The active layer's pixels are locked."));
              return FALSE;
            }

          gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y);

          off_x -= x;
          off_y -= y;

          gimp_item_resize (GIMP_ITEM (layer), GIMP_CONTEXT (options),
                            w, h, off_x, off_y);
        }
      else
        {
          gimp_image_crop (image, GIMP_CONTEXT (options),
                           x, y, w + x, h + y,
                           TRUE);
        }

      gimp_image_flush (image);

      return TRUE;
    }

  return TRUE;
}
Example #2
0
/* --------------------------
 * p_create_corpus_layer
 * --------------------------
 * create the corpus layer that builds the reference pattern
 * for the resynthesizer call. The reference pattern is built
 * as duplicate of the original image reduced to the area around the current selection.
 * (grown by corpus_border_radius)
 * Note that the duplicate image has a selection, that includes the gorwn area
 * around the orignal selection, but EXCLUDES the original selection
 * (that is the area holding the object that has to be replaced
 * by pattern of the surrounding area)
 * returns the layer_id of the reference pattern.
 */
static gint32
p_create_corpus_layer(gint32 image_id, gint32 drawable_id, TransValues *val_ptr)
{
  gint32 dup_image_id;
  gint32 channel_id;
  gint32 channel_2_id;
  GimpRGB  bck_color;
  GimpRGB  white_opaque_color;
  /* gboolean has_selection; */
  gboolean non_empty;
  gint     x1, y1, x2, y2;
  gint32   active_layer_stackposition;
  gint32   active_dup_layer_id;


  active_layer_stackposition = gap_layer_get_stackposition(image_id, drawable_id);

  dup_image_id = gimp_image_duplicate(image_id);

  channel_id = gimp_selection_save(dup_image_id);
  gimp_selection_grow(dup_image_id, val_ptr->corpus_border_radius);
  gimp_selection_invert(dup_image_id);

  gimp_context_get_background(&bck_color);
  channel_2_id = gimp_selection_save(dup_image_id);

  gimp_image_select_item(dup_image_id, GIMP_CHANNEL_OP_REPLACE, channel_id);

  gimp_rgba_set_uchar (&white_opaque_color, 255, 255, 255, 255);
  gimp_context_set_background(&white_opaque_color);
  gimp_edit_clear(channel_2_id);


  gimp_context_set_background(&bck_color);  /* restore original background color */

  gimp_selection_load(channel_2_id);

  gimp_selection_invert(dup_image_id);

  /* has_selection  = */ gimp_selection_bounds(dup_image_id, &non_empty, &x1, &y1, &x2, &y2);
  gimp_image_crop(dup_image_id, (x2 - x1), (y2 - y1), x1, y1);

  gimp_selection_invert(dup_image_id);
  active_dup_layer_id = gap_layer_get_id_by_stackposition(dup_image_id, active_layer_stackposition);

  if (1==0)
  {
    /* debug code shows the duplicate image by adding a display */
    gimp_display_new(dup_image_id);
  }
  return (active_dup_layer_id);

}  /* end p_create_corpus_layer */
Example #3
0
static gboolean apply_crop(crop_settings settings, image_output out)
{
    gboolean success = TRUE;
    gint newWidth, newHeight, oldWidth, oldHeight, posX, posY;

    oldWidth = gimp_image_width(out->image_id);
    oldHeight = gimp_image_height(out->image_id);

    if (settings->manual) {
        newWidth = settings->new_w;
        newHeight = settings->new_h;
        posX = (oldWidth - newWidth) / 2;
        posY = (oldHeight - newHeight) / 2;
    }
    else {
        float ratio1, ratio2;
        if (settings->ratio == CROP_PRESET_CUSTOM) {
            ratio1 = settings->custom_ratio1;
            ratio2 = settings->custom_ratio2;
        }
        else {
            ratio1 = (float)crop_preset_ratio[settings->ratio][0];
            ratio2 = (float)crop_preset_ratio[settings->ratio][1];
        }

        if (( (float)oldWidth / oldHeight ) > ( ratio1 / ratio2) ) {
            /* crop along the width */
            newHeight = oldHeight;
            newWidth = round(( ratio1 * (float)newHeight ) / ratio2);
            posX = (oldWidth - newWidth) / 2;
            posY = 0;
        } else {
            /* crop along the height */
            newWidth = oldWidth;
            newHeight = round(( ratio2 * (float)newWidth) / ratio1);
            posX = 0;
            posY = (oldHeight - newHeight) / 2;
        }
    }

    success = gimp_image_crop (
                  out->image_id,
                  newWidth,
                  newHeight,
                  posX,
                  posY
              );

    return success;
}
Example #4
0
void
image_crop_cmd_callback (GtkAction *action,
                         gpointer   data)
{
  GimpImage *image;
  GtkWidget *widget;
  gint       x1, y1, x2, y2;
  return_if_no_image (image, data);
  return_if_no_widget (widget, data);

  if (! gimp_channel_bounds (gimp_image_get_mask (image),
                             &x1, &y1, &x2, &y2))
    {
      gimp_message (image->gimp, G_OBJECT (widget), GIMP_MESSAGE_WARNING,
                    _("Cannot crop because the current selection is empty."));
      return;
    }

  gimp_image_crop (image, action_data_get_context (data),
                   x1, y1, x2, y2, FALSE, TRUE);
  gimp_image_flush (image);
}
Example #5
0
static GimpValueArray *
image_crop_invoker (GimpProcedure         *procedure,
                    Gimp                  *gimp,
                    GimpContext           *context,
                    GimpProgress          *progress,
                    const GimpValueArray  *args,
                    GError               **error)
{
  gboolean success = TRUE;
  GimpImage *image;
  gint32 new_width;
  gint32 new_height;
  gint32 offx;
  gint32 offy;

  image = gimp_value_get_image (gimp_value_array_index (args, 0), gimp);
  new_width = g_value_get_int (gimp_value_array_index (args, 1));
  new_height = g_value_get_int (gimp_value_array_index (args, 2));
  offx = g_value_get_int (gimp_value_array_index (args, 3));
  offy = g_value_get_int (gimp_value_array_index (args, 4));

  if (success)
    {
      if (new_width  >  gimp_image_get_width  (image)              ||
          new_height >  gimp_image_get_height (image)              ||
          offx       > (gimp_image_get_width  (image) - new_width) ||
          offy       > (gimp_image_get_height (image) - new_height))
        success = FALSE;
      else
        gimp_image_crop (image, context,
                         offx, offy, offx + new_width, offy + new_height,
                         TRUE);
    }

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}
Example #6
0
static void
guillotine (gint32 image_ID)
{
  gint      guide;
  gint      image_width;
  gint      image_height;
  gboolean  guides_found = FALSE;
  GList    *hguides, *hg;
  GList    *vguides, *vg;

  image_width  = gimp_image_width (image_ID);
  image_height = gimp_image_height (image_ID);

  hguides = g_list_append (NULL,    GINT_TO_POINTER (0));
  hguides = g_list_append (hguides, GINT_TO_POINTER (image_height));

  vguides = g_list_append (NULL,    GINT_TO_POINTER (0));
  vguides = g_list_append (vguides, GINT_TO_POINTER (image_width));

  for (guide = gimp_image_find_next_guide (image_ID, 0);
       guide > 0;
       guide = gimp_image_find_next_guide (image_ID, guide))
    {
      gint position = gimp_image_get_guide_position (image_ID, guide);

      switch (gimp_image_get_guide_orientation (image_ID, guide))
        {
        case GIMP_ORIENTATION_HORIZONTAL:
          if (! g_list_find (hguides, GINT_TO_POINTER (position)))
            {
              hguides = g_list_insert_sorted (hguides,
                                              GINT_TO_POINTER (position),
                                              guide_sort_func);
              guides_found = TRUE;
            }
          break;

        case GIMP_ORIENTATION_VERTICAL:
          if (! g_list_find (vguides, GINT_TO_POINTER (position)))
            {
              vguides = g_list_insert_sorted (vguides,
                                              GINT_TO_POINTER (position),
                                              guide_sort_func);
              guides_found = TRUE;
            }
          break;

        case GIMP_ORIENTATION_UNKNOWN:
          g_assert_not_reached ();
          break;
        }
    }

  if (guides_found)
    {
      gchar *filename;
      gint   h, v, hpad, vpad;
      gint   x, y;
      gchar *hformat;
      gchar *format;

      filename = gimp_image_get_filename (image_ID);
      if (!filename)
        filename = g_strdup (_("Untitled"));

      /* get the number horizontal and vertical slices */
      h = g_list_length (hguides);
      v = g_list_length (vguides);

      /* need the number of digits of h and v for the padding */
      hpad = log10(h) + 1;
      vpad = log10(v) + 1;

      /* format for the x-y coordinates in the filename */
      hformat = g_strdup_printf ("%%0%i", MAX (hpad, vpad));
      format  = g_strdup_printf ("-%si-%si", hformat, hformat);

      /*  Do the actual dup'ing and cropping... this isn't a too naive a
       *  way to do this since we got copy-on-write tiles, either.
       */
      for (y = 0, hg = hguides; hg && hg->next; y++, hg = hg->next)
        {
          for (x = 0, vg = vguides; vg && vg->next; x++, vg = vg->next)
            {
              gint32   new_image = gimp_image_duplicate (image_ID);
              GString *new_filename;
              gchar   *fileextension;
              gchar   *fileindex;
              gint     pos;

              if (new_image == -1)
                {
                  g_warning ("Couldn't create new image.");
                  return;
                }

              gimp_image_undo_disable (new_image);

              gimp_image_crop (new_image,
                               GPOINTER_TO_INT (vg->next->data) -
                               GPOINTER_TO_INT (vg->data),
                               GPOINTER_TO_INT (hg->next->data) -
                               GPOINTER_TO_INT (hg->data),
                               GPOINTER_TO_INT (vg->data),
                               GPOINTER_TO_INT (hg->data));


              new_filename = g_string_new (filename);

              /* show the rough coordinates of the image in the title */
              fileindex    = g_strdup_printf (format, x, y);

              /* get the position of the file extension - last . in filename */
              fileextension = strrchr (new_filename->str, '.');
              pos           = fileextension - new_filename->str;

              /* insert the coordinates before the extension */
              g_string_insert (new_filename, pos, fileindex);
	      g_free (fileindex);

              gimp_image_set_filename (new_image, new_filename->str);
              g_string_free (new_filename, TRUE);

              while ((guide = gimp_image_find_next_guide (new_image, 0)))
                gimp_image_delete_guide (new_image, guide);

              gimp_image_undo_enable (new_image);

              gimp_display_new (new_image);
            }
        }

      g_free (filename);
      g_free (hformat);
      g_free (format);
    }

  g_list_free (hguides);
  g_list_free (vguides);
}
static gboolean apply_crop(crop_settings settings, image_output out) 
{
    gboolean success = TRUE;
    gint newWidth, newHeight, oldWidth, oldHeight, posX = 0, posY = 0;
    gboolean keepX = FALSE, keepY = FALSE;
    
    oldWidth = gimp_image_width(out->image_id);
    oldHeight = gimp_image_height(out->image_id);
    
    if (settings->manual) {
        newWidth = min(oldWidth, settings->new_w);
        newHeight = min(oldHeight, settings->new_h);
    }
    else {
        float ratio1, ratio2;
        if (settings->ratio == CROP_PRESET_CUSTOM) {
            ratio1 = settings->custom_ratio1;
            ratio2 = settings->custom_ratio2;
        }
        else {
            ratio1 = (float)crop_preset_ratio[settings->ratio][0];
            ratio2 = (float)crop_preset_ratio[settings->ratio][1];
        }
        
        if (( (float)oldWidth / oldHeight ) > ( ratio1 / ratio2) ) { 
            // crop along the width 
            newHeight = oldHeight;
            newWidth = round(( ratio1 * (float)newHeight ) / ratio2);
            keepY = TRUE;
        } else { 
            // crop along the height 
            newWidth = oldWidth;
            newHeight = round(( ratio2 * (float)newWidth) / ratio1);
            keepX = TRUE;
        }
    }
    
    switch (settings->start_pos) {
        case CROP_START_TL: 
            posX = 0;
            posY = 0;
            break;
            
        case CROP_START_TR: 
            posX = (oldWidth - newWidth);
            posY = 0;
            break;
            
        case CROP_START_BL: 
            posX = 0;
            posY = (oldHeight - newHeight);
            break;
            
        case CROP_START_BR: 
            posX = (oldWidth - newWidth);
            posY = (oldHeight - newHeight);
            break;
        
        default: 
            if (!keepX) posX = (oldWidth - newWidth) / 2;
            if (!keepY) posY = (oldHeight - newHeight) / 2;
            break;
    }
    
    success = gimp_image_crop (
        out->image_id,
        newWidth,
        newHeight,
        posX,
        posY
    );
    
    return success;
}
Example #8
0
static gboolean
webx_pipeline_check_update (WebxPipeline *pipeline)
{
  gint *layers;
  gint  num_layers;
  gint  i;

  g_return_val_if_fail (WEBX_IS_PIPELINE (pipeline), FALSE);

  if (pipeline->rgb_image != -1)
    {
      gimp_image_delete (pipeline->rgb_image);
      pipeline->rgb_image = -1;
    }
  if (pipeline->indexed_image != -1)
    {
      gimp_image_delete (pipeline->indexed_image);
      pipeline->indexed_image = -1;
    }
  if (pipeline->background)
    {
      g_object_unref (pipeline->background);
      pipeline->background = NULL;
    }

  pipeline->rgb_image = gimp_image_duplicate (pipeline->user_image);
  gimp_image_undo_disable (pipeline->rgb_image);
  pipeline->rgb_layer =
    gimp_image_merge_visible_layers (pipeline->rgb_image,
                                     GIMP_CLIP_TO_IMAGE);

  /* make sure there is only one layer, where all visible layers were merged */
  layers = gimp_image_get_layers (pipeline->rgb_image, &num_layers);
  for (i = 0; i < num_layers; i++)
    {
      if (layers[i] != pipeline->rgb_layer)
        gimp_image_remove_layer (pipeline->rgb_image, layers[i]);
    }
  g_free (layers);

  /* we don't want layer to be smaller than image */
  gimp_layer_resize_to_image_size (pipeline->rgb_layer);
  gimp_image_scale (pipeline->rgb_image,
                    pipeline->resize_width, pipeline->resize_height);
  webx_pipeline_create_background (pipeline);

  pipeline->crop_offsx *= pipeline->crop_scale_x;
  pipeline->crop_offsy *= pipeline->crop_scale_y;
  pipeline->crop_width *= pipeline->crop_scale_x;
  pipeline->crop_height *= pipeline->crop_scale_y;
  pipeline->crop_scale_x = 1.0;
  pipeline->crop_scale_y = 1.0;
  webx_pipeline_crop_clip (pipeline);

  if (pipeline->crop_width != pipeline->resize_width
      || pipeline->crop_height != pipeline->resize_height )
    {
      gimp_image_crop (pipeline->rgb_image,
                       pipeline->crop_width, pipeline->crop_height,
                       pipeline->crop_offsx, pipeline->crop_offsy);
    }
    
  if (gimp_drawable_is_indexed (pipeline->rgb_layer))
    {
      pipeline->indexed_image = gimp_image_duplicate (pipeline->rgb_image);
      gimp_image_undo_disable (pipeline->indexed_image);
      pipeline->indexed_layer =
        gimp_image_merge_visible_layers (pipeline->indexed_image,
                                         GIMP_CLIP_TO_IMAGE);
    }
  else
    {
      pipeline->indexed_image = -1;
      pipeline->indexed_layer = -1;
    }

  if ( ! gimp_drawable_is_rgb (pipeline->rgb_layer))
    gimp_image_convert_rgb (pipeline->rgb_image);

  return TRUE;
}
Example #9
0
static void
do_acrop (GimpDrawable *drawable,
          gint32        image_id)
{
  GimpPixelRgn  srcPR;
  gint          iwidth, iheight;
  gint          x, y, l;
  guchar       *buffer;
  gint          xmin, xmax, ymin, ymax;
  gint         *layers = NULL;
  gint          numlayers;

  iwidth = gimp_image_width(image_id);
  iheight = gimp_image_height(image_id);

  /* Set each edge to the opposite side -- i.e. xmin (the left edge
   * of the final cropped image) starts at the right edge.
   */
  xmin = iwidth - 1;
  xmax = 1;
  ymin = iheight - 1;
  ymax = 1;

  buffer = g_malloc ((iwidth > iheight ? iwidth : iheight) * drawable->bpp);

  layers = gimp_image_get_layers (image_id, &numlayers);

  for (l=0; l<numlayers; ++l)
    {
      gint dwidth, dheight;
      gint layerOffsetX, layerOffsetY;
      gint bytes;
      gint start;

      drawable = gimp_drawable_get(layers[l]);
      dwidth  = drawable->width;
      dheight = drawable->height;
      bytes = drawable->bpp;

      /* Relate the layer coordinates to the image coordinates */
      gimp_drawable_offsets (layers[l], &layerOffsetX, &layerOffsetY);

      /*  initialize the pixel region to this layer */
      gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, dwidth, dheight,
                           FALSE, FALSE);

      /* Update ymin. If the layer offset is greater than ymin,
       * then the region to be cropped already contains the whole layer
       * and we don't have to look any farther.
       */
      start = 0;
      if (layerOffsetY < 0)
          start = -layerOffsetY;
      for (y = start; y < dheight && layerOffsetY + y < ymin; y++)
        {
          gimp_pixel_rgn_get_row (&srcPR, buffer, 0, y, dwidth);

          for (x = 0; x < dwidth * bytes; x += bytes)
            {
              if (!colours_equal (buffer, &buffer[x], bytes))
                {
                  /* convert this layer coordinate back to image coord */
                  ymin = y + layerOffsetY;
                  break;
                }
            }
        }

      /* Update ymax. If the layer's offset plus height is less than
       * ymax, then the region to be cropped already contains the
       * whole layer and we don't have to look any farther.
       */
      start = dheight - 1;
      if (layerOffsetY + dheight > iheight)
          start = iheight - layerOffsetY - 1;
      for (y = start; y > 0 && layerOffsetY + y > ymax; y--)
        {
          gimp_pixel_rgn_get_row (&srcPR, buffer, 0, y, dwidth);

          for (x = 0; x < dwidth * bytes; x += bytes)
            {
              if (!colours_equal (buffer, &buffer[x], bytes))
                {
                  /* convert this layer coordinate back to image coord */
                  ymax = y + layerOffsetY + 1;
                  break;
                }
            }
        }

      /* Update xmin. If the layer offset is greater than ymin,
       * then the region to be cropped already contains the whole layer
       * and we don't have to look any farther.
       */
      start = 0;
      if (layerOffsetX < 0)
          start = -layerOffsetX;
      for (x = start; x < dwidth && layerOffsetX + x < xmin; x++)
        {
          gimp_pixel_rgn_get_col (&srcPR, buffer, x, 0, dheight);

          for (y = 0; y < dheight * bytes; y += bytes)
            {
              if (!colours_equal (buffer, &buffer[y], bytes))
                {
                  /* convert this layer coordinate back to image coord */
                  xmin = x + layerOffsetX;
                  break;
                }
            }
        }

      /* Update xmax. If the layer's offset plus width is less than
       * xmax, then the region to be cropped already contains the
       * whole layer and we don't have to look any farther.
       */
      start = dwidth - 1;
      if (layerOffsetX + dwidth > iwidth)
          start = iwidth - layerOffsetX - 1;
      for (x = start; x > 0 && layerOffsetX + x > xmax; x--)
        {
          gimp_pixel_rgn_get_col (&srcPR, buffer, x, 0, dheight);

          for (y = 0; y < dheight * bytes; y += bytes)
            {
              if (!colours_equal (buffer, &buffer[y], bytes))
                {
                  /* convert this layer coordinate back to image coord */
                  xmax = x + layerOffsetX + 1;
                  break;
                }
            }
        }

      gimp_progress_update ((gdouble)l / numlayers);
    }

  if (xmin == 0 && xmax == iwidth &&
      ymin == 0 && ymax == iheight)
    {
      g_message ("Nothing to crop.");
      return;
    }

  gimp_image_undo_group_start (image_id);

  gimp_image_crop(image_id,
                  xmax - xmin, ymax - ymin,
                  xmin, ymin);

  g_free (layers);
  g_free (buffer);

  gimp_progress_update (1.00);
  gimp_image_undo_group_end (image_id);
}
Example #10
0
static void
do_zcrop (GimpDrawable *drawable,
          gint32        image_id)
{
  GimpPixelRgn  srcPR, destPR;
  gint          width, height, x, y;
  gint          bytes;
  guchar       *buffer;
  gint8        *killrows;
  gint8        *killcols;
  gint32        livingrows, livingcols, destrow, destcol;
  gint          total_area, area;
  gboolean      has_alpha;

  width  = drawable->width;
  height = drawable->height;
  bytes  = drawable->bpp;

  total_area = width * height * 4;
  area = 0;

  killrows = g_new (gint8, height);
  killcols = g_new (gint8, width);

  buffer = g_malloc ((width > height ? width : height) * bytes);

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

  has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);

  livingrows = 0;
  for (y = 0; y < height; y++)
    {
      gimp_pixel_rgn_get_row (&srcPR, buffer, 0, y, width);

      killrows[y] = TRUE;

      for (x = 0; x < width * bytes; x += bytes)
        {
          if (! colors_equal (buffer, &buffer[x], bytes, has_alpha))
            {
              livingrows++;
              killrows[y] = FALSE;
              break;
            }
        }

      area += width;
      if (y % 20 == 0)
        gimp_progress_update ((double) area / (double) total_area);
    }


  livingcols = 0;
  for (x = 0; x < width; x++)
    {
      gimp_pixel_rgn_get_col (&srcPR, buffer, x, 0, height);

      killcols[x] = TRUE;

      for (y = 0; y < height * bytes; y += bytes)
        {
          if (! colors_equal (buffer, &buffer[y], bytes, has_alpha))
            {
              livingcols++;
              killcols[x] = FALSE;
              break;
            }
        }

      area += height;
      if (x % 20 == 0)
        gimp_progress_update ((double) area / (double) total_area);
    }


  if ((livingcols == 0 || livingrows==0) ||
      (livingcols == width && livingrows == height))
    {
      g_message (_("Nothing to crop."));
      g_free (killrows);
      g_free (killcols);
      return;
    }

  destrow = 0;

  for (y = 0; y < height; y++)
    {
      if (!killrows[y])
        {
          gimp_pixel_rgn_get_row (&srcPR, buffer, 0, y, width);
          gimp_pixel_rgn_set_row (&destPR, buffer, 0, destrow, width);
          destrow++;
        }

      area += width;
      if (y % 20 == 0)
        gimp_progress_update ((double) area / (double) total_area);
    }


  destcol = 0;
  gimp_pixel_rgn_init(&srcPR, drawable, 0, 0, width, height, FALSE, TRUE);

  for (x = 0; x < width; x++)
    {
      if (!killcols[x])
        {
          gimp_pixel_rgn_get_col (&srcPR, buffer, x, 0, height);
          gimp_pixel_rgn_set_col (&destPR, buffer, destcol, 0, height);
          destcol++;
        }

      area += height;
      if (x % 20 == 0)
        gimp_progress_update ((double) area / (double) total_area);
    }

  g_free (buffer);

  g_free (killrows);
  g_free (killcols);

  gimp_progress_update (1.00);

  gimp_image_undo_group_start (image_id);

  gimp_drawable_flush (drawable);
  gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
  gimp_image_crop (image_id, livingcols, livingrows, 0, 0);

  gimp_image_undo_group_end (image_id);
}
Example #11
0
static void
do_zcrop (gint32  drawable_id,
          gint32  image_id)
{
  GeglBuffer  *drawable_buffer;
  GeglBuffer  *shadow_buffer;
  gfloat      *linear_buf;
  const Babl  *format;

  gint         x, y, width, height;
  gint         components;
  gint8       *killrows;
  gint8       *killcols;
  gint32       livingrows, livingcols, destrow, destcol;
  gint32       selection_copy_id;
  gboolean     has_alpha;

  drawable_buffer = gimp_drawable_get_buffer (drawable_id);
  shadow_buffer   = gimp_drawable_get_shadow_buffer (drawable_id);

  width  = gegl_buffer_get_width (drawable_buffer);
  height = gegl_buffer_get_height (drawable_buffer);
  has_alpha = gimp_drawable_has_alpha (drawable_id);

  if (has_alpha)
    format = babl_format ("R'G'B'A float");
  else
    format = babl_format ("R'G'B' float");

  components = babl_format_get_n_components (format);

  killrows = g_new (gint8, height);
  killcols = g_new (gint8, width);

  linear_buf = g_new (gfloat, (width > height ? width : height) * components);

  /* search which rows to remove */

  livingrows = 0;
  for (y = 0; y < height; y++)
    {
      gegl_buffer_get (drawable_buffer, GEGL_RECTANGLE (0, y, width, 1),
                       1.0, format, linear_buf,
                       GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

      killrows[y] = TRUE;

      for (x = components; x < width * components; x += components)
        {
          if (! colors_equal (linear_buf, &linear_buf[x], components, has_alpha))
            {
              livingrows++;
              killrows[y] = FALSE;
              break;
            }
        }
    }

  gimp_progress_update (0.25);

  /* search which columns to remove */

  livingcols = 0;
  for (x = 0; x < width; x++)
    {
      gegl_buffer_get (drawable_buffer, GEGL_RECTANGLE (x, 0, 1, height),
                       1.0, format, linear_buf,
                       GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

      killcols[x] = TRUE;

      for (y = components; y < height * components; y += components)
        {
          if (! colors_equal (linear_buf, &linear_buf[y], components, has_alpha))
            {
              livingcols++;
              killcols[x] = FALSE;
              break;
            }
        }
    }

  gimp_progress_update (0.5);

  if ((livingcols == 0 || livingrows == 0) ||
      (livingcols == width && livingrows == height))
    {
      g_message (_("Nothing to crop."));
      g_free (linear_buf);
      g_free (killrows);
      g_free (killcols);
      return;
    }

  /* restitute living rows */

  destrow = 0;
  for (y = 0; y < height; y++)
    {
      if (!killrows[y])
        {
          gegl_buffer_copy (drawable_buffer,
                            GEGL_RECTANGLE (0, y, width, 1),
                            GEGL_ABYSS_NONE,
                            shadow_buffer,
                            GEGL_RECTANGLE (0, destrow, width, 1));

          destrow++;
        }
    }

  gimp_progress_update (0.75);

  /* restitute living columns */

  destcol = 0;
  for (x = 0; x < width; x++)
    {
      if (!killcols[x])
        {
          gegl_buffer_copy (shadow_buffer,
                            GEGL_RECTANGLE (x, 0, 1, height),
                            GEGL_ABYSS_NONE,
                            shadow_buffer,
                            GEGL_RECTANGLE (destcol, 0, 1, height));

          destcol++;
        }
    }

  gimp_progress_update (1.00);

  gimp_image_undo_group_start (image_id);

  selection_copy_id = gimp_selection_save (image_id);
  gimp_selection_none (image_id);

  gegl_buffer_flush (shadow_buffer);
  gimp_drawable_merge_shadow (drawable_id, TRUE);
  gegl_buffer_flush (drawable_buffer);

  gimp_image_select_item (image_id, GIMP_CHANNEL_OP_REPLACE, selection_copy_id);
  gimp_image_remove_channel (image_id, selection_copy_id);

  gimp_image_crop (image_id, livingcols, livingrows, 0, 0);

  gimp_image_undo_group_end (image_id);

  g_object_unref (shadow_buffer);
  g_object_unref (drawable_buffer);

  g_free (linear_buf);
  g_free (killrows);
  g_free (killcols);
}