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 (); }
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); } } }
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); }
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; } }