static void preview_update_preview (GimpPreview *preview, GimpDrawable *drawable) { gint x1, y1; gint width, height; gint bpp; guchar *buffer; GimpPixelRgn src_rgn; GimpPixelRgn preview_rgn; gint32 image_id, src_image_id; gint32 preview_id; GimpDrawable *preview_drawable; bpp = gimp_drawable_bpp (drawable->drawable_id); gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); buffer = g_new (guchar, width * height * bpp); gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE); gimp_pixel_rgn_get_rect (&src_rgn, buffer, x1, y1, width, height); /* set up gimp drawable for rendering preview into */ src_image_id = gimp_drawable_get_image (drawable->drawable_id); image_id = gimp_image_new (width, height, gimp_image_base_type (src_image_id)); preview_id = gimp_layer_new (image_id, "preview", width, height, gimp_drawable_type (drawable->drawable_id), 100, GIMP_NORMAL_MODE); preview_drawable = gimp_drawable_get (preview_id); gimp_image_add_layer (image_id, preview_id, 0); gimp_layer_set_offsets (preview_id, 0, 0); gimp_pixel_rgn_init (&preview_rgn, preview_drawable, 0, 0, width, height, TRUE, TRUE); gimp_pixel_rgn_set_rect (&preview_rgn, buffer, 0, 0, width, height); gimp_drawable_flush (preview_drawable); gimp_drawable_merge_shadow (preview_id, TRUE); gimp_drawable_update (preview_id, 0, 0, width, height); dog (image_id, preview_drawable, dogvals.inner, dogvals.outer, FALSE); gimp_pixel_rgn_get_rect (&preview_rgn, buffer, 0, 0, width, height); gimp_preview_draw_buffer (preview, buffer, width * bpp); gimp_image_delete (image_id); g_free (buffer); }
/* ----------------------- * p_tri_map_preprocessing * ----------------------- * prepare the tri mask for processing * - have bpp == 1 * - have same size and offset as the input drawable (that is a layer) * - pixel values >= 240 are set to value 240 (MATTING_USER_FOREGROUND) * - in case the input layer already has an alpha channel * all fully transparent (alpha == 0) pixels are also set 0 (MATTING_USER_BACKGROUND) * in the tri map to keep pixels fully transparent. (such pixels typicall do not * have a useful color information in the RGB channels) * * * in case the user provided the tri map as layer or channel that is NOT the layermask of the input layer * we create a new dummy layer with same size and offset as the input layer * and add a layermask to this dummy layer. * The layermask of the dummy layer is then filled with the intersecting grayscale copy * of the user-provided triMap drawable and will be used as tri map in the alpha matting processing. * * returns the dawable Id of the relevant TRI MAP that fulfills the conditons listed above. */ static gint32 p_tri_map_preprocessing (GimpDrawable *drawable, GapFgExtractValues *fgValPtr, gint32 *dummyLayerId) { gint32 prepocessedTriMapLayerId; gint32 inputLayerMaskId; gint32 imageId; *dummyLayerId = -1; imageId = gimp_drawable_get_image(drawable->drawable_id); inputLayerMaskId = gimp_layer_get_mask(drawable->drawable_id); if (fgValPtr->tri_map_drawable_id == inputLayerMaskId) { prepocessedTriMapLayerId = inputLayerMaskId; } else { gint offset_x; gint offset_y; gint32 dummyLayerMaskId; gint32 l_fsel_layer_id; *dummyLayerId = gimp_layer_new(imageId , "DUMMY" , drawable->width , drawable->height , GIMP_RGBA_IMAGE , 100.0 /* full opacity */ , GIMP_NORMAL_MODE /* normal mode */ ); /* get offsets of the input drawable (layer) within the image */ gimp_drawable_offsets (drawable->drawable_id, &offset_x, &offset_y); /* add dummy layer (of same size at same offsets) to the same image */ gimp_image_add_layer(imageId, *dummyLayerId, -1 /* stackposition */ ); gimp_layer_set_offsets(*dummyLayerId, offset_x, offset_y); /* create a new layermask (black is full transparent */ dummyLayerMaskId = gimp_layer_create_mask(*dummyLayerId, GIMP_ADD_BLACK_MASK); gimp_layer_add_mask(*dummyLayerId, dummyLayerMaskId); gimp_edit_copy(fgValPtr->tri_map_drawable_id); l_fsel_layer_id = gimp_edit_paste(dummyLayerMaskId, FALSE); gimp_floating_sel_anchor(l_fsel_layer_id); prepocessedTriMapLayerId = dummyLayerMaskId; } gap_fg_rgn_tri_map_normalize(drawable, prepocessedTriMapLayerId); return(prepocessedTriMapLayerId); } /* end p_tri_map_preprocessing */
/* ----------------------------------- * p_set_drawable_offsets * ----------------------------------- * simple 2-point align via offsets (without rotate and scale) */ static gint32 p_set_drawable_offsets(gint32 activeDrawableId, AlingCoords *alingCoords) { gdouble px1, py1, px2, py2; gdouble dx, dy; gint offset_x; gint offset_y; px1 = alingCoords->startCoords.px; py1 = alingCoords->startCoords.py; px2 = alingCoords->currCoords.px; py2 = alingCoords->currCoords.py; dx = px2 - px1; dy = py2 - py1; /* findout the offsets of the original layer within the source Image */ gimp_drawable_offsets(activeDrawableId, &offset_x, &offset_y ); gimp_layer_set_offsets(activeDrawableId, offset_x - dx, offset_y - dy); return (activeDrawableId); } /* end p_set_drawable_offsets */
static gboolean apply_watermark(watermark_settings settings, image_output out) { gboolean success = TRUE; gint32 layerId; gdouble posX, posY; gint wmwidth, wmheight, wmasc, wmdesc; if (settings->mode) { if (strlen(settings->text) == 0) { return TRUE; } GimpRGB old_foreground, new_foreground; gimp_context_get_foreground(&old_foreground); gimp_rgb_parse_hex (&new_foreground, gdk_color_to_string(&(settings->color)), strlen(gdk_color_to_string(&(settings->color)))); gimp_context_set_foreground(&new_foreground); gimp_text_get_extents_fontname( settings->text, pango_font_description_get_size(settings->font) / PANGO_SCALE, GIMP_PIXELS, pango_font_description_get_family(settings->font), &wmwidth, &wmheight, &wmasc, &wmdesc ); if (settings->position == WM_POS_TL) { posX = 10; posY = 5; } else if (settings->position == WM_POS_TC) { posX = (gimp_image_width(out->image_id) / 2) - (wmwidth / 2); posY = 5; } else if (settings->position == WM_POS_TR) { posX = gimp_image_width(out->image_id) - wmwidth - 10; posY = 5; } else if (settings->position == WM_POS_BL) { posX = 10; posY = gimp_image_height(out->image_id) - wmheight - 5; } else if (settings->position == WM_POS_BC) { posX = (gimp_image_width(out->image_id) / 2) - (wmwidth / 2); posY = gimp_image_height(out->image_id) - wmheight - 5; } else if (settings->position == WM_POS_BR) { posX = gimp_image_width(out->image_id) - wmwidth - 10; posY = gimp_image_height(out->image_id) - wmheight - 5; } else if (settings->position == WM_POS_CL) { posX = 10; posY = (gimp_image_height(out->image_id) / 2) - (wmheight / 2); } else if (settings->position == WM_POS_CR) { posX = gimp_image_width(out->image_id) - wmwidth - 10; posY = (gimp_image_height(out->image_id) / 2) - (wmheight / 2); } else { posX = (gimp_image_width(out->image_id) / 2) - (wmwidth / 2); posY = (gimp_image_height(out->image_id) / 2) - (wmheight / 2); } layerId = gimp_text_fontname( out->image_id, -1, posX, posY, settings->text, -1, TRUE, pango_font_description_get_size(settings->font) / PANGO_SCALE, GIMP_PIXELS, pango_font_description_get_family(settings->font) ); gimp_context_set_foreground(&old_foreground); gimp_layer_set_opacity(layerId, settings->opacity); } else { if (!g_file_test(settings->image_file, G_FILE_TEST_IS_REGULAR)) {//((access(settings->image_file, R_OK) == -1)) { // error, can't access image file return TRUE; } layerId = gimp_file_load_layer( GIMP_RUN_NONINTERACTIVE, out->image_id, settings->image_file ); gimp_layer_set_opacity(layerId, settings->opacity); wmwidth = gimp_drawable_width(layerId); wmheight = gimp_drawable_height(layerId); #if USE_API26 gimp_image_add_layer( out->image_id, layerId, 0 ); #else // starting from 2.8, gimp_image_add_layer is deprecated. // use gimp_image_insert_layer instead gimp_image_insert_layer( out->image_id, layerId, 0, 0 ); #endif if (settings->position == WM_POS_TL) { posX = 10; posY = 10; } else if (settings->position == WM_POS_TC) { posX = (gimp_image_width(out->image_id) / 2) - (wmwidth / 2); posY = 10; } else if (settings->position == WM_POS_TR) { posX = gimp_image_width(out->image_id) - wmwidth - 10; posY = 10; } else if (settings->position == WM_POS_BL) { posX = 10; posY = gimp_image_height(out->image_id) - wmheight - 10; } else if (settings->position == WM_POS_BC) { posX = (gimp_image_width(out->image_id) / 2) - (wmwidth / 2); posY = gimp_image_height(out->image_id) - wmheight - 10; } else if (settings->position == WM_POS_BR) { posX = gimp_image_width(out->image_id) - wmwidth - 10; posY = gimp_image_height(out->image_id) - wmheight - 10; } else if (settings->position == WM_POS_CL) { posX = 10; posY = (gimp_image_height(out->image_id) / 2) - (wmheight / 2); } else if (settings->position == WM_POS_CR) { posX = gimp_image_width(out->image_id) - wmwidth - 10; posY = (gimp_image_height(out->image_id) / 2) - (wmheight / 2); } else { posX = (gimp_image_width(out->image_id) / 2) - (wmwidth / 2); posY = (gimp_image_height(out->image_id) / 2) - (wmheight / 2); } gimp_layer_set_offsets( layerId, posX, posY ); } // refresh all drawables g_free(out->drawable_ids); out->drawable_ids = gimp_image_get_layers(out->image_id, &out->drawable_count); return success; }
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; 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_FILL_TRANSPARENT); gimp_drawable_offsets (drawable_id, &x1, &y1); gimp_layer_set_offsets (curl_layer->drawable_id, sel_x + x1, sel_y + 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)); /* 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_progress_update (1.0); 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; }
/* Create a layer with the provided image data and add it to the image */ gboolean create_layer(gint32 image_ID, uint8_t *layer_data, gint32 position, gchar *name, gint width, gint height, gint32 offsetx, gint32 offsety) { gint32 layer_ID; #ifdef GIMP_2_9 GeglBuffer *geglbuffer; GeglRectangle extent; #else GimpDrawable *drawable; GimpPixelRgn region; #endif layer_ID = gimp_layer_new(image_ID, name, width, height, GIMP_RGBA_IMAGE, 100, GIMP_NORMAL_MODE); #ifdef GIMP_2_9 /* Retrieve the buffer for the layer */ geglbuffer = gimp_drawable_get_buffer(layer_ID); /* Copy the image data to the region */ gegl_rectangle_set(&extent, 0, 0, width, height); gegl_buffer_set(geglbuffer, &extent, 0, NULL, layer_data, GEGL_AUTO_ROWSTRIDE); /* Flush the drawable and detach */ gegl_buffer_flush(geglbuffer); g_object_unref(geglbuffer); #else /* Retrieve the drawable for the layer */ drawable = gimp_drawable_get(layer_ID); /* Get a pixel region from the layer */ gimp_pixel_rgn_init(®ion, drawable, 0, 0, width, height, FALSE, FALSE); /* Copy the image data to the region */ gimp_pixel_rgn_set_rect(®ion, layer_data, 0, 0, width, height); /* Flush the drawable and detach */ gimp_drawable_flush(drawable); gimp_drawable_detach(drawable); #endif /* Add the new layer to the image */ gimp_image_insert_layer(image_ID, layer_ID, -1, position); /* If layer offsets were provided, use them to position the image */ if (offsetx || offsety) { gimp_layer_set_offsets(layer_ID, offsetx, offsety); } /* TODO: fix this */ return TRUE; }
/* Compose a roll film image from several images */ static gint32 film (void) { gint width, height; guchar *hole; gint film_height, film_width; gint picture_width, picture_height; gint picture_space, picture_x0, picture_y0; gint hole_offset, hole_width, hole_height, hole_space, hole_x; gint number_height, num_images, num_pictures; gint j, k, picture_count; gdouble f; gint num_layers; gint32 *image_ID_src, image_ID_dst, layer_ID_src, layer_ID_dst; gint image_ID_tmp; gint32 *layers; GimpDrawable *drawable_dst; GimpPixelRgn pixel_rgn_dst; gint new_layer; gint floating_sel; /* initialize */ layers = NULL; num_images = filmvals.num_images; image_ID_src = filmvals.image; if (num_images <= 0) return (-1); gimp_context_push (); gimp_context_set_foreground (&filmvals.number_color); gimp_context_set_background (&filmvals.film_color); if (filmvals.keep_height) /* Search maximum picture height */ { picture_height = 0; for (j = 0; j < num_images; j++) { height = gimp_image_height (image_ID_src[j]); if (height > picture_height) picture_height = height; } film_height = (int)(picture_height / filmvals.picture_height + 0.5); filmvals.film_height = film_height; } else { film_height = filmvals.film_height; picture_height = (int)(film_height * filmvals.picture_height + 0.5); } picture_space = (int)(film_height * filmvals.picture_space + 0.5); picture_y0 = (film_height - picture_height)/2; number_height = film_height * filmvals.number_height; /* Calculate total film width */ film_width = 0; num_pictures = 0; for (j = 0; j < num_images; j++) { layers = gimp_image_get_layers (image_ID_src[j], &num_layers); /* Get scaled image size */ width = gimp_image_width (image_ID_src[j]); height = gimp_image_height (image_ID_src[j]); f = ((double)picture_height) / (double)height; picture_width = width * f; for (k = 0; k < num_layers; k++) { if (gimp_layer_is_floating_sel (layers[k])) continue; film_width += (picture_space/2); /* Leading space */ film_width += picture_width; /* Scaled image width */ film_width += (picture_space/2); /* Trailing space */ num_pictures++; } g_free (layers); } #ifdef FILM_DEBUG g_printerr ("film_height = %d, film_width = %d\n", film_height, film_width); g_printerr ("picture_height = %d, picture_space = %d, picture_y0 = %d\n", picture_height, picture_space, picture_y0); g_printerr ("Number of pictures = %d\n", num_pictures); #endif image_ID_dst = create_new_image (_("Untitled"), (guint) film_width, (guint) film_height, GIMP_RGB_IMAGE, &layer_ID_dst, &drawable_dst, &pixel_rgn_dst); /* Fill film background */ gimp_drawable_fill (layer_ID_dst, GIMP_FILL_BACKGROUND); /* Draw all the holes */ hole_offset = film_height * filmvals.hole_offset; hole_width = film_height * filmvals.hole_width; hole_height = film_height * filmvals.hole_height; hole_space = film_height * filmvals.hole_space; hole_x = hole_space / 2; #ifdef FILM_DEBUG g_printerr ("hole_x %d hole_offset %d hole_width %d hole_height %d hole_space %d\n", hole_x, hole_offset, hole_width, hole_height, hole_space ); #endif hole = create_hole_rgb (hole_width, hole_height); if (hole) { while (hole_x < film_width) { draw_hole_rgb (drawable_dst, hole_x, hole_offset, hole_width, hole_height, hole); draw_hole_rgb (drawable_dst, hole_x, film_height-hole_offset-hole_height, hole_width, hole_height, hole); hole_x += hole_width + hole_space; } g_free (hole); } gimp_drawable_detach (drawable_dst); /* Compose all images and layers */ picture_x0 = 0; picture_count = 0; for (j = 0; j < num_images; j++) { image_ID_tmp = gimp_image_duplicate (image_ID_src[j]); width = gimp_image_width (image_ID_tmp); height = gimp_image_height (image_ID_tmp); f = ((gdouble) picture_height) / (gdouble) height; picture_width = width * f; if (gimp_image_base_type (image_ID_tmp) != GIMP_RGB) gimp_image_convert_rgb (image_ID_tmp); gimp_image_scale (image_ID_tmp, picture_width, picture_height); layers = gimp_image_get_layers (image_ID_tmp, &num_layers); for (k = 0; k < num_layers; k++) { if (gimp_layer_is_floating_sel (layers[k])) continue; picture_x0 += picture_space / 2; layer_ID_src = layers[k]; gimp_layer_resize_to_image_size (layer_ID_src); new_layer = gimp_layer_new_from_drawable (layer_ID_src, image_ID_dst); gimp_image_insert_layer (image_ID_dst, new_layer, -1, -1); gimp_layer_set_offsets (new_layer, picture_x0, picture_y0); /* Draw picture numbers */ if ((number_height > 0) && (filmvals.number_pos[0] || filmvals.number_pos[1])) { if (filmvals.number_pos[0]) draw_number (layer_ID_dst, filmvals.number_start + picture_count, picture_x0 + picture_width/2, (hole_offset-number_height)/2, number_height); if (filmvals.number_pos[1]) draw_number (layer_ID_dst, filmvals.number_start + picture_count, picture_x0 + picture_width/2, film_height - (hole_offset + number_height)/2, number_height); } picture_x0 += picture_width + (picture_space/2); gimp_progress_update (((gdouble) (picture_count + 1)) / (gdouble) num_pictures); picture_count++; } g_free (layers); gimp_image_delete (image_ID_tmp); } gimp_progress_update (1.0); gimp_image_flatten (image_ID_dst); /* Drawing text/numbers leaves us with a floating selection. Stop it */ floating_sel = gimp_image_get_floating_sel (image_ID_dst); if (floating_sel != -1) gimp_floating_sel_anchor (floating_sel); gimp_context_pop (); return image_ID_dst; }
static void rotate_drawable (GimpDrawable *drawable) { GimpPixelRgn srcPR, destPR; gint width, height; gint longside; gint bytes; gint row, col; gint offsetx, offsety; gboolean was_lock_alpha = FALSE; guchar *buffer; guchar *src_row, *dest_row; /* initialize */ row = 0; /* Get the size of the input drawable. */ width = drawable->width; height = drawable->height; bytes = drawable->bpp; if (gimp_layer_get_lock_alpha (drawable->drawable_id)) { was_lock_alpha = TRUE; gimp_layer_set_lock_alpha (drawable->drawable_id, FALSE); } if (rotvals.angle == 2) /* we're rotating by 180° */ { gimp_tile_cache_ntiles (2 * (width / gimp_tile_width() + 1)); gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height, TRUE, TRUE); src_row = (guchar *) g_malloc (width * bytes); dest_row = (guchar *) g_malloc (width * bytes); for (row = 0; row < height; row++) { gimp_pixel_rgn_get_row (&srcPR, src_row, 0, row, width); for (col = 0; col < width; col++) { memcpy (dest_row + col * bytes, src_row + (width - 1 - col) * bytes, bytes); } gimp_pixel_rgn_set_row (&destPR, dest_row, 0, (height - row - 1), width); if ((row % 5) == 0) gimp_progress_update ((double) row / (double) height); } g_free (src_row); g_free (dest_row); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, 0, 0, width, height); } else /* we're rotating by 90° or 270° */ { (width > height) ? (longside = width) : (longside = height); gimp_layer_resize (drawable->drawable_id, longside, longside, 0, 0); drawable = gimp_drawable_get (drawable->drawable_id); gimp_drawable_flush (drawable); gimp_tile_cache_ntiles ((longside / gimp_tile_width () + 1) + (longside / gimp_tile_height () + 1)); gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, longside, longside, FALSE, FALSE); gimp_pixel_rgn_init (&destPR, drawable, 0, 0, longside, longside, TRUE, TRUE); buffer = g_malloc (longside * bytes); if (rotvals.angle == 1) /* we're rotating by 90° */ { for (row = 0; row < height; row++) { gimp_pixel_rgn_get_row (&srcPR, buffer, 0, row, width); gimp_pixel_rgn_set_col (&destPR, buffer, (height - row - 1), 0, width); if ((row % 5) == 0) gimp_progress_update ((double) row / (double) height); } } else /* we're rotating by 270° */ { for (col = 0; col < width; col++) { gimp_pixel_rgn_get_col (&srcPR, buffer, col, 0, height); gimp_pixel_rgn_set_row (&destPR, buffer, 0, (width - col - 1), height); if ((col % 5) == 0) gimp_progress_update ((double) col / (double) width); } } g_free (buffer); gimp_progress_update (1.0); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, 0, 0, height, width); gimp_layer_resize (drawable->drawable_id, height, width, 0, 0); drawable = gimp_drawable_get (drawable->drawable_id); gimp_drawable_flush (drawable); gimp_drawable_update (drawable->drawable_id, 0, 0, height, width); } gimp_drawable_offsets (drawable->drawable_id, &offsetx, &offsety); rotate_compute_offsets (&offsetx, &offsety, gimp_image_width (image_ID), gimp_image_height (image_ID), width, height); gimp_layer_set_offsets (drawable->drawable_id, offsetx, offsety); if (was_lock_alpha) gimp_layer_set_lock_alpha (drawable->drawable_id, TRUE); return; }
/* ------------------------------- * gap_drawable_foreground_extract * ------------------------------- * perform foreground extraction. * This is done in 3 steps INIT, EXTRACTION, DONE (e.g. cleanup) */ static gint32 gap_drawable_foreground_extract (GimpDrawable *drawable, GimpDrawable *maskDrawable, GapFgExtractValues *fgValPtr ) { GappMattingState *state; gint32 resultLayerId; gint mask_offset_x; gint mask_offset_y; resultLayerId = -1; /* get mask offsets within the image * - in case mask is a channel offsets are always 0) * - in case mask is a layer retieve its offsets */ gimp_drawable_offsets (drawable->drawable_id, &mask_offset_x, &mask_offset_y); state = gap_drawable_foreground_extract_matting_init (drawable, mask_offset_x, mask_offset_y, maskDrawable->width, maskDrawable->height ); if (state) { gint32 imageId; imageId = gimp_drawable_get_image(drawable->drawable_id); resultLayerId = gimp_layer_new(imageId , "FG" , drawable->width , drawable->height , GIMP_RGBA_IMAGE , 100.0 /* full opacity */ , GIMP_NORMAL_MODE /* normal mode */ ); if (resultLayerId != -1) { GimpDrawable *resultDrawable; resultDrawable = gimp_drawable_get(resultLayerId); if (resultDrawable != NULL) { gint offset_x; gint offset_y; gboolean resultUpdateRequired; resultUpdateRequired = FALSE; /* get offsets of the input drawable (layer) within the image */ gimp_drawable_offsets (drawable->drawable_id, &offset_x, &offset_y); /* add resulting layer (of same size at same offsets) to the same image */ gimp_image_add_layer(imageId, resultLayerId, -1 /* stackposition */ ); gimp_layer_set_offsets(resultLayerId, offset_x, offset_y); /* perform the foreground extraction */ gap_drawable_foreground_extract_matting (maskDrawable, resultDrawable, state, 0.0 // start_percentage 0 (non-interactive shall always start rendering immediate ); /* clean up after fg extract is done */ gap_drawable_foreground_extract_matting_done (state); /* postprocessing */ if (fgValPtr->lock_color) { if(gap_debug) { printf("postprocessing: restore resultDrawable:%d RGB channels from original drawable:%d\n" ,(int)resultDrawable->drawable_id ,(int)drawable->drawable_id ); } resultUpdateRequired = TRUE; gap_fg_rgn_copy_rgb_channels(drawable, resultDrawable); } if (fgValPtr->create_layermask) { gint32 resultLayerMaskId; /* create a new layermask (from alpha channel) */ resultLayerMaskId = gimp_layer_create_mask(resultLayerId, GIMP_ADD_ALPHA_MASK); gimp_layer_add_mask(resultLayerId, resultLayerMaskId); if (gimp_drawable_has_alpha(drawable->drawable_id)) { if(gap_debug) { printf("postprocessing: restore resultDrawable:%d ALPHA channel from original drawable:%d\n" ,(int)resultDrawable->drawable_id ,(int)drawable->drawable_id ); } /* copy the original alpha channel to the result layer */ gap_fg_rgn_copy_alpha_channel(drawable, resultDrawable); resultUpdateRequired = TRUE; } } if(resultUpdateRequired) { gimp_drawable_update (resultDrawable->drawable_id , 0, 0 , resultDrawable->width, resultDrawable->height ); } gimp_drawable_detach (resultDrawable); } } } return (resultLayerId); } /* end gap_drawable_foreground_extract */
/* ------------------------------------ * gap_image_merge_group_layer * ------------------------------------ * merge the specified group layer and return the id of the resulting layer. * * The merge strategy * o) create a temporary image of same size/type (l_tmp_img_id) * o) copy the specified grouplayer to the temporary image (l_tmp_img_id) * o) call gimp_image_merge_visible_layers on the temporary image (l_tmp_img_id, mode) * o) copy the merged layer back to the original image * to the same group at the position of the original layergroup * o) remove the temporary image * o) remove original layergroup * o) rename the resuling merged layer. * * returns 0 if all done OK * (or -1 on error) */ gint32 gap_image_merge_group_layer(gint32 image_id, gint32 group_layer_id, gint merge_mode) { gint32 l_tmp_img_id; gint32 l_new_layer_id; gint32 l_merged_layer_id; gint32 l_parent_id; gint32 l_position; gint l_src_offset_x; gint l_src_offset_y; gboolean l_visible; char *l_name; if (!gimp_item_is_group(group_layer_id)) { /* the specified group_layer_id is not a group * -- no merge is done, return its id as result -- */ return(group_layer_id); } l_visible = gimp_item_get_visible(group_layer_id); l_name = gimp_item_get_name(group_layer_id); /* create a temporary image */ l_tmp_img_id = gap_image_new_of_samesize(image_id); /* copy the grouplayer to the temporary image */ l_new_layer_id = gap_layer_copy_to_dest_image(l_tmp_img_id, group_layer_id, 100.0, /* full opacity */ 0, /* NORMAL paintmode */ &l_src_offset_x, &l_src_offset_y ); gimp_image_insert_layer (l_tmp_img_id, l_new_layer_id, 0, 0); gimp_layer_set_offsets(l_new_layer_id, l_src_offset_x, l_src_offset_y); gimp_item_set_visible(l_new_layer_id, TRUE); /* merge visible layers in the temporary image */ l_merged_layer_id = gimp_image_merge_visible_layers (l_tmp_img_id, merge_mode); l_new_layer_id = gap_layer_copy_to_dest_image(image_id, l_merged_layer_id, gimp_layer_get_opacity(group_layer_id), gimp_layer_get_mode(group_layer_id), &l_src_offset_x, &l_src_offset_y ); l_position = gimp_image_get_item_position (image_id, group_layer_id); l_parent_id = gimp_item_get_parent(group_layer_id); if (l_parent_id < 0) { l_parent_id = 0; } gimp_image_insert_layer (image_id, l_new_layer_id, l_parent_id, l_position); gimp_layer_set_offsets(l_new_layer_id, l_src_offset_x, l_src_offset_y); /* remove the original group layer from the original image */ gimp_image_remove_layer(image_id, group_layer_id); /* restore the original layer name */ if (l_name != NULL) { gimp_item_set_name(l_new_layer_id, l_name); g_free(l_name); } gimp_item_set_visible(l_new_layer_id, l_visible); /* remove the temporary image */ gap_image_delete_immediate(l_tmp_img_id); return(l_new_layer_id); } /* end gap_image_merge_group_layer */
static GimpPDBStatusType align_layers (gint32 image_id) { gint layer_num = 0; gint visible_layer_num = 0; gint *layers = NULL; gint index; gint vindex; gint step_x = 0; gint step_y = 0; gint x = 0; gint y = 0; gint orig_x = 0; gint orig_y = 0; gint offset_x = 0; gint offset_y = 0; gint base_x = 0; gint base_y = 0; gint bg_index = 0; layers = gimp_image_get_layers (image_id, &layer_num); bg_index = layer_num - 1; for (index = 0; index < layer_num; index++) { if (gimp_item_get_visible (layers[index])) visible_layer_num++; } if (VALS.ignore_bottom) { layer_num--; if (gimp_item_get_visible (layers[bg_index])) visible_layer_num--; } if (0 < visible_layer_num) { gint min_x = G_MAXINT; gint min_y = G_MAXINT; gint max_x = G_MININT; gint max_y = G_MININT; /* 0 is the top layer */ for (index = 0; index < layer_num; index++) { if (gimp_item_get_visible (layers[index])) { gimp_drawable_offsets (layers[index], &orig_x, &orig_y); align_layers_get_align_offsets (layers[index], &offset_x, &offset_y); orig_x += offset_x; orig_y += offset_y; if ( orig_x < min_x ) min_x = orig_x; if ( max_x < orig_x ) max_x = orig_x; if ( orig_y < min_y ) min_y = orig_y; if ( max_y < orig_y ) max_y = orig_y; } } if (VALS.base_is_bottom_layer) { gimp_drawable_offsets (layers[bg_index], &orig_x, &orig_y); align_layers_get_align_offsets (layers[bg_index], &offset_x, &offset_y); orig_x += offset_x; orig_y += offset_y; base_x = min_x = orig_x; base_y = min_y = orig_y; } if (visible_layer_num > 1) { step_x = (max_x - min_x) / (visible_layer_num - 1); step_y = (max_y - min_y) / (visible_layer_num - 1); } if ( (VALS.h_style == LEFT2RIGHT) || (VALS.h_style == RIGHT2LEFT)) base_x = min_x; if ( (VALS.v_style == TOP2BOTTOM) || (VALS.v_style == BOTTOM2TOP)) base_y = min_y; } gimp_image_undo_group_start (image_id); for (vindex = -1, index = 0; index < layer_num; index++) { if (gimp_item_get_visible (layers[index])) vindex++; else continue; gimp_drawable_offsets (layers[index], &orig_x, &orig_y); align_layers_get_align_offsets (layers[index], &offset_x, &offset_y); switch (VALS.h_style) { case H_NONE: x = orig_x; break; case H_COLLECT: x = base_x - offset_x; break; case LEFT2RIGHT: x = (base_x + vindex * step_x) - offset_x; break; case RIGHT2LEFT: x = (base_x + (visible_layer_num - vindex - 1) * step_x) - offset_x; break; case SNAP2HGRID: x = VALS.grid_size * (int) ((orig_x + offset_x + VALS.grid_size /2) / VALS.grid_size) - offset_x; break; } switch (VALS.v_style) { case V_NONE: y = orig_y; break; case V_COLLECT: y = base_y - offset_y; break; case TOP2BOTTOM: y = (base_y + vindex * step_y) - offset_y; break; case BOTTOM2TOP: y = (base_y + (visible_layer_num - vindex - 1) * step_y) - offset_y; break; case SNAP2VGRID: y = VALS.grid_size * (int) ((orig_y + offset_y + VALS.grid_size / 2) / VALS.grid_size) - offset_y; break; } gimp_layer_set_offsets (layers[index], x, y); } gimp_image_undo_group_end (image_id); return GIMP_PDB_SUCCESS; }
/* * Modifies position of each visible layers * according to data. */ static void align_layers_perform_alignment (gint *layers, gint layer_num, AlignData data) { gint index; for (index = 0; index < layer_num; index++) { gint x = 0; gint y = 0; gint orig_x; gint orig_y; gint offset_x; gint offset_y; gimp_drawable_offsets (layers[index], &orig_x, &orig_y); align_layers_get_align_offsets (layers[index], &offset_x, &offset_y); switch (VALS.h_style) { case H_NONE: x = orig_x; break; case H_COLLECT: x = data.base_x - offset_x; break; case LEFT2RIGHT: x = (data.base_x + index * data.step_x) - offset_x; break; case RIGHT2LEFT: x = (data.base_x + (layer_num - index - 1) * data.step_x) - offset_x; break; case SNAP2HGRID: x = VALS.grid_size * (int) ((orig_x + offset_x + VALS.grid_size /2) / VALS.grid_size) - offset_x; break; } switch (VALS.v_style) { case V_NONE: y = orig_y; break; case V_COLLECT: y = data.base_y - offset_y; break; case TOP2BOTTOM: y = (data.base_y + index * data.step_y) - offset_y; break; case BOTTOM2TOP: y = (data.base_y + (layer_num - index - 1) * data.step_y) - offset_y; break; case SNAP2VGRID: y = VALS.grid_size * (int) ((orig_y + offset_y + VALS.grid_size / 2) / VALS.grid_size) - offset_y; break; } gimp_layer_set_offsets (layers[index], x, y); } }