Example #1
0
static void
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
{
  static GimpParam   values[1];
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
  gint32             drawable_id;
  gint               x, y, width, height;

  *nreturn_vals = 1;
  *return_vals = values;

  gegl_init (NULL, NULL);

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

  INIT_I18N();

  drawable_id = param[2].data.d_drawable;

  if (gimp_drawable_mask_intersect (drawable_id, &x, &y, &width, &height))
    {
      GeglBuffer *buffer;
      GeglBuffer *shadow_buffer;

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

      gegl_render_op (buffer, shadow_buffer, "gegl:invert", NULL);

      g_object_unref (shadow_buffer); /* flushes the shadow tiles */
      g_object_unref (buffer);

      gimp_drawable_merge_shadow (drawable_id, TRUE);
      gimp_drawable_update (drawable_id, x, y, width, height);
      gimp_displays_flush ();
    }

  values[0].data.d_status = status;
  gegl_exit ();
}
Example #2
0
File: lcms.c Project: K-Sonoda/gimp
static void
lcms_layers_transform_rgb (gint                     *layers,
                           gint                      num_layers,
                           cmsHPROFILE               src_profile,
                           cmsHPROFILE               dest_profile,
                           GimpColorRenderingIntent  intent,
                           gboolean                  bpc)
{
  gint i;

  for (i = 0; i < num_layers; i++)
    {
      gint32           layer_id = layers[i];
      const Babl      *layer_format;
      gboolean         has_alpha;
      const Babl      *type;
      const Babl      *iter_format = NULL;
      cmsUInt32Number  lcms_format = 0;
      cmsHTRANSFORM    transform   = NULL;
      gint            *children;
      gint             num_children;

      children = gimp_item_get_children (layer_id, &num_children);

      if (children)
        {
          lcms_layers_transform_rgb (children, num_children,
                                     src_profile, dest_profile,
                                     intent, bpc);

          g_free (children);

          continue;
        }

      layer_format = gimp_drawable_get_format (layer_id);
      has_alpha    = babl_format_has_alpha (layer_format);
      type         = babl_format_get_type (layer_format, 0);

      if (type == babl_type ("u8"))
        {
          if (has_alpha)
            {
              lcms_format = TYPE_RGBA_8;
              iter_format = babl_format ("R'G'B'A u8");
            }
          else
            {
              lcms_format = TYPE_RGB_8;
              iter_format = babl_format ("R'G'B' u8");
            }
        }
      else if (type == babl_type ("u16"))
        {
          if (has_alpha)
            {
              lcms_format = TYPE_RGBA_16;
              iter_format = babl_format ("R'G'B'A u16");
            }
          else
            {
              lcms_format = TYPE_RGB_16;
              iter_format = babl_format ("R'G'B' u16");
            }
        }
      else if (type == babl_type ("half")) /* 16-bit floating point (half) */
        {
#ifdef TYPE_RGB_HALF_FLT
          /* half float types are only in lcms 2.4 and newer */
          if (has_alpha)
            {
              lcms_format = TYPE_RGBA_HALF_FLT;
              iter_format = babl_format ("R'G'B'A half");
            }
          else
            {
              lcms_format = TYPE_RGB_HALF_FLT;
              iter_format = babl_format ("R'G'B' float");
            }
#endif /* TYPE_RGB_HALF_FLT */
        }
      else if (type == babl_type ("float"))
        {
          if (has_alpha)
            {
              lcms_format = TYPE_RGBA_FLT;
              iter_format = babl_format ("R'G'B'A float");
            }
          else
            {
              lcms_format = TYPE_RGB_FLT;
              iter_format = babl_format ("R'G'B' float");
            }
        }
      else if (type == babl_type ("double"))
        {
          if (has_alpha)
            {
#ifdef TYPE_RGBA_DBL
              /* RGBA double not implemented in lcms */
              lcms_format = TYPE_RGBA_DBL;
              iter_format = babl_format ("R'G'B'A double");
#endif /* TYPE_RGBA_DBL */
            }
          else
            {
              lcms_format = TYPE_RGB_DBL;
              iter_format = babl_format ("R'G'B' double");
            }
        }

      if (lcms_format == 0)
        {
          g_printerr ("lcms: layer format %s not supported, "
                      "falling back to float\n",
                      babl_get_name (layer_format));

          if (has_alpha)
            {
              lcms_format = TYPE_RGBA_FLT;
              iter_format = babl_format ("R'G'B'A float");
            }
          else
            {
              lcms_format = TYPE_RGB_FLT;
              iter_format = babl_format ("R'G'B' float");
            }
        }

      transform = cmsCreateTransform (src_profile,  lcms_format,
                                      dest_profile, lcms_format,
                                      intent,
                                      cmsFLAGS_NOOPTIMIZE |
                                      (bpc ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0));

      if (transform)
        {
          GeglBuffer         *src_buffer;
          GeglBuffer         *dest_buffer;
          GeglBufferIterator *iter;
          gint                layer_width;
          gint                layer_height;
          gint                layer_bpp;
          gboolean            layer_alpha;
          gdouble             progress_start = (gdouble) i / num_layers;
          gdouble             progress_end   = (gdouble) (i + 1) / num_layers;
          gdouble             range          = progress_end - progress_start;
          gint                count          = 0;
          gint                done           = 0;

          src_buffer   = gimp_drawable_get_buffer (layer_id);
          dest_buffer  = gimp_drawable_get_shadow_buffer (layer_id);
          layer_width  = gegl_buffer_get_width (src_buffer);
          layer_height = gegl_buffer_get_height (src_buffer);
          layer_bpp    = babl_format_get_bytes_per_pixel (iter_format);
          layer_alpha  = babl_format_has_alpha (iter_format);

          iter = gegl_buffer_iterator_new (src_buffer, NULL, 0,
                                           iter_format,
                                           GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

          gegl_buffer_iterator_add (iter, dest_buffer, NULL, 0,
                                    iter_format,
                                    GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);

          while (gegl_buffer_iterator_next (iter))
            {
              /*  lcms doesn't touch the alpha channel, simply
               *  copy everything to dest before the transform
               */
              if (layer_alpha)
                memcpy (iter->data[1], iter->data[0],
                        iter->length * layer_bpp);

              cmsDoTransform (transform,
                              iter->data[0], iter->data[1], iter->length);
            }

          g_object_unref (src_buffer);
          g_object_unref (dest_buffer);

          gimp_drawable_merge_shadow (layer_id, TRUE);
          gimp_drawable_update (layer_id, 0, 0, layer_width, layer_height);

          if (count++ % 32 == 0)
            {
              gimp_progress_update (progress_start +
                                    (gdouble) done /
                                    (layer_width * layer_height) * range);
            }

          cmsDeleteTransform (transform);
        }
    }
}
Example #3
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);
}
Example #4
0
static void
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
{
  static GimpParam   values[1];
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
  GimpRunMode        run_mode;
  gint32             drawable_id;
  GeglBuffer        *shadow_buffer;
  GeglBuffer        *buffer;

  run_mode    = param[0].data.d_int32;
  drawable_id = param[2].data.d_drawable;

  INIT_I18N ();
  gegl_init (NULL, NULL);

  *nreturn_vals = 1;
  *return_vals  = values;

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

  /*  Get the specified drawable  */
  shadow_buffer = gimp_drawable_get_shadow_buffer (drawable_id);
  buffer        = gimp_drawable_get_buffer (drawable_id);

  /*  Make sure that the drawable is gray or RGB color  */
  if (gimp_drawable_is_rgb  (drawable_id) ||
      gimp_drawable_is_gray (drawable_id))
    {
      MapMode mode = 0;

      if ( !strcmp (name, GRADMAP_PROC))
        {
          mode = GRADIENT_MODE;
          gimp_progress_init (_("Gradient Map"));
        }
      else if ( !strcmp (name, PALETTEMAP_PROC))
        {
          mode = PALETTE_MODE;
          gimp_progress_init (_("Palette Map"));
        }
      else
        {
          status = GIMP_PDB_CALLING_ERROR;
        }

      if (status == GIMP_PDB_SUCCESS)
        {
          if (mode)
            map (buffer, shadow_buffer, drawable_id, mode);
        }
    }
  else
    {
      status = GIMP_PDB_EXECUTION_ERROR;
    }

  g_object_unref (buffer);
  g_object_unref (shadow_buffer);

  gimp_drawable_merge_shadow (drawable_id, TRUE);

  gimp_drawable_update (drawable_id, 0, 0,
                        gimp_drawable_width (drawable_id),
                        gimp_drawable_height (drawable_id));

  values[0].data.d_status = status;

  if (run_mode != GIMP_RUN_NONINTERACTIVE)
    gimp_displays_flush ();
}
static void
gimp_plug_in_handle_tile_get (GimpPlugIn *plug_in,
                              GPTileReq  *request)
{
  GPTileData       tile_data;
  GimpWireMessage  msg;
  GimpDrawable    *drawable;
  GeglBuffer      *buffer;
  const Babl      *format;
  GeglRectangle    tile_rect;
  gint             tile_size;

  drawable = (GimpDrawable *) gimp_item_get_by_ID (plug_in->manager->gimp,
                                                   request->drawable_ID);

  if (! GIMP_IS_DRAWABLE (drawable))
    {
      gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                    "Plug-In \"%s\"\n(%s)\n\n"
                    "tried reading from invalid drawable %d (killing)",
                    gimp_object_get_name (plug_in),
                    gimp_file_get_utf8_name (plug_in->file),
                    request->drawable_ID);
      gimp_plug_in_close (plug_in, TRUE);
      return;
    }
  else if (gimp_item_is_removed (GIMP_ITEM (drawable)))
    {
      gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                    "Plug-In \"%s\"\n(%s)\n\n"
                    "tried reading from drawable %d which was removed "
                    "from the image (killing)",
                    gimp_object_get_name (plug_in),
                    gimp_file_get_utf8_name (plug_in->file),
                    request->drawable_ID);
      gimp_plug_in_close (plug_in, TRUE);
      return;
    }

  if (request->shadow)
    {
      buffer = gimp_drawable_get_shadow_buffer (drawable);

      gimp_plug_in_cleanup_add_shadow (plug_in, drawable);
    }
  else
    {
      buffer = gimp_drawable_get_buffer (drawable);
    }

  if (! gimp_gegl_buffer_get_tile_rect (buffer,
                                        GIMP_PLUG_IN_TILE_WIDTH,
                                        GIMP_PLUG_IN_TILE_HEIGHT,
                                        request->tile_num,
                                        &tile_rect))
    {
      gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                    "Plug-In \"%s\"\n(%s)\n\n"
                    "requested invalid tile (killing)",
                    gimp_object_get_name (plug_in),
                    gimp_file_get_utf8_name (plug_in->file));
      gimp_plug_in_close (plug_in, TRUE);
      return;
    }

  format = gegl_buffer_get_format (buffer);

  if (! gimp_plug_in_precision_enabled (plug_in))
    {
      format = gimp_babl_compat_u8_format (format);
    }

  tile_size = (babl_format_get_bytes_per_pixel (format) *
               tile_rect.width * tile_rect.height);

  tile_data.drawable_ID = request->drawable_ID;
  tile_data.tile_num    = request->tile_num;
  tile_data.shadow      = request->shadow;
  tile_data.bpp         = babl_format_get_bytes_per_pixel (format);
  tile_data.width       = tile_rect.width;
  tile_data.height      = tile_rect.height;
  tile_data.use_shm     = (plug_in->manager->shm != NULL);

  if (tile_data.use_shm)
    {
      gegl_buffer_get (buffer, &tile_rect, 1.0, format,
                       gimp_plug_in_shm_get_addr (plug_in->manager->shm),
                       GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
    }
  else
    {
      tile_data.data = g_malloc (tile_size);

      gegl_buffer_get (buffer, &tile_rect, 1.0, format,
                       tile_data.data,
                       GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
    }

  if (! gp_tile_data_write (plug_in->my_write, &tile_data, plug_in))
    {
      gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                    "%s: ERROR", G_STRFUNC);
      gimp_plug_in_close (plug_in, TRUE);
      return;
    }

  if (! gimp_wire_read_msg (plug_in->my_read, &msg, plug_in))
    {
      gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                    "%s: ERROR", G_STRFUNC);
      gimp_plug_in_close (plug_in, TRUE);
      return;
    }

  if (msg.type != GP_TILE_ACK)
    {
      gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                    "expected tile ack and received: %d", msg.type);
      gimp_plug_in_close (plug_in, TRUE);
      return;
    }

  gimp_wire_destroy (&msg);
}
static void
gimp_plug_in_handle_tile_put (GimpPlugIn *plug_in,
                              GPTileReq  *request)
{
  GPTileData       tile_data;
  GPTileData      *tile_info;
  GimpWireMessage  msg;
  GimpDrawable    *drawable;
  GeglBuffer      *buffer;
  const Babl      *format;
  GeglRectangle    tile_rect;

  tile_data.drawable_ID = -1;
  tile_data.tile_num    = 0;
  tile_data.shadow      = 0;
  tile_data.bpp         = 0;
  tile_data.width       = 0;
  tile_data.height      = 0;
  tile_data.use_shm     = (plug_in->manager->shm != NULL);
  tile_data.data        = NULL;

  if (! gp_tile_data_write (plug_in->my_write, &tile_data, plug_in))
    {
      gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                    "%s: ERROR", G_STRFUNC);
      gimp_plug_in_close (plug_in, TRUE);
      return;
    }

  if (! gimp_wire_read_msg (plug_in->my_read, &msg, plug_in))
    {
      gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                    "%s: ERROR", G_STRFUNC);
      gimp_plug_in_close (plug_in, TRUE);
      return;
    }

  if (msg.type != GP_TILE_DATA)
    {
      gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                    "expected tile data and received: %d", msg.type);
      gimp_plug_in_close (plug_in, TRUE);
      return;
    }

  tile_info = msg.data;

  drawable = (GimpDrawable *) gimp_item_get_by_ID (plug_in->manager->gimp,
                                                   tile_info->drawable_ID);

  if (! GIMP_IS_DRAWABLE (drawable))
    {
      gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                    "Plug-In \"%s\"\n(%s)\n\n"
                    "tried writing to invalid drawable %d (killing)",
                    gimp_object_get_name (plug_in),
                    gimp_file_get_utf8_name (plug_in->file),
                    tile_info->drawable_ID);
      gimp_plug_in_close (plug_in, TRUE);
      return;
    }
  else if (gimp_item_is_removed (GIMP_ITEM (drawable)))
    {
      gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                    "Plug-In \"%s\"\n(%s)\n\n"
                    "tried writing to drawable %d which was removed "
                    "from the image (killing)",
                    gimp_object_get_name (plug_in),
                    gimp_file_get_utf8_name (plug_in->file),
                    tile_info->drawable_ID);
      gimp_plug_in_close (plug_in, TRUE);
      return;
    }

  if (tile_info->shadow)
    {

      /*  don't check whether the drawable is a group or locked here,
       *  the plugin will get a proper error message when it tries to
       *  merge the shadow tiles, which is much better than just
       *  killing it.
       */
      buffer = gimp_drawable_get_shadow_buffer (drawable);

      gimp_plug_in_cleanup_add_shadow (plug_in, drawable);
    }
  else
    {
      if (gimp_item_is_content_locked (GIMP_ITEM (drawable)))
        {
          gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                        "Plug-In \"%s\"\n(%s)\n\n"
                        "tried writing to a locked drawable %d (killing)",
                        gimp_object_get_name (plug_in),
                        gimp_file_get_utf8_name (plug_in->file),
                        tile_info->drawable_ID);
          gimp_plug_in_close (plug_in, TRUE);
          return;
        }
      else if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)))
        {
          gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                        "Plug-In \"%s\"\n(%s)\n\n"
                        "tried writing to a group layer %d (killing)",
                        gimp_object_get_name (plug_in),
                        gimp_file_get_utf8_name (plug_in->file),
                        tile_info->drawable_ID);
          gimp_plug_in_close (plug_in, TRUE);
          return;
        }

      buffer = gimp_drawable_get_buffer (drawable);
    }

  if (! gimp_gegl_buffer_get_tile_rect (buffer,
                                        GIMP_PLUG_IN_TILE_WIDTH,
                                        GIMP_PLUG_IN_TILE_HEIGHT,
                                        tile_info->tile_num,
                                        &tile_rect))
    {
      gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                    "Plug-In \"%s\"\n(%s)\n\n"
                    "requested invalid tile (killing)",
                    gimp_object_get_name (plug_in),
                    gimp_file_get_utf8_name (plug_in->file));
      gimp_plug_in_close (plug_in, TRUE);
      return;
    }

  format = gegl_buffer_get_format (buffer);

  if (! gimp_plug_in_precision_enabled (plug_in))
    {
      format = gimp_babl_compat_u8_format (format);
    }

  if (tile_data.use_shm)
    {
      gegl_buffer_set (buffer, &tile_rect, 0, format,
                       gimp_plug_in_shm_get_addr (plug_in->manager->shm),
                       GEGL_AUTO_ROWSTRIDE);
    }
  else
    {
      gegl_buffer_set (buffer, &tile_rect, 0, format,
                       tile_info->data,
                       GEGL_AUTO_ROWSTRIDE);
    }

  gimp_wire_destroy (&msg);

  if (! gp_tile_ack_write (plug_in->my_write, plug_in))
    {
      gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                    "%s: ERROR", G_STRFUNC);
      gimp_plug_in_close (plug_in, TRUE);
      return;
    }
}