/* ============================================================================ * gap_image_merge_visible_layers * merge visible layer an return layer_id of the resulting merged layer. * (with workaround, for empty images return transparent layer) * ============================================================================ */ gint32 gap_image_merge_visible_layers(gint32 image_id, GimpMergeType mergemode) { GimpImageBaseType l_type; guint l_width, l_height; gint32 l_layer_id; /* get info about the image */ l_width = gimp_image_width(image_id); l_height = gimp_image_height(image_id); l_type = gimp_image_base_type(image_id); l_type = (l_type * 2); /* convert from GimpImageBaseType to GimpImageType */ /* add 2 full transparent dummy layers at top * (because gimp_image_merge_visible_layers complains * if there are less than 2 visible layers) */ l_layer_id = gimp_layer_new(image_id, "dummy", l_width, l_height, l_type, 0.0, /* Opacity full transparent */ 0); /* NORMAL */ gimp_image_insert_layer(image_id, l_layer_id, 0, 0); l_layer_id = gimp_layer_new(image_id, "dummy", 10, 10, l_type, 0.0, /* Opacity full transparent */ 0); /* NORMAL */ gimp_image_insert_layer(image_id, l_layer_id, 0, 0); return gimp_image_merge_visible_layers (image_id, mergemode); } /* end gap_image_merge_visible_layers */
static gint32 create_new_layer (gint32 image_ID, gint position, const gchar *layername, guint width, guint height, GimpImageBaseType type) { gint32 layer_ID; GimpImageType gdtype = GIMP_RGB_IMAGE; switch (type) { case GIMP_RGB: gdtype = GIMP_RGB_IMAGE; break; case GIMP_GRAY: gdtype = GIMP_GRAY_IMAGE; break; case GIMP_INDEXED: gdtype = GIMP_INDEXED_IMAGE; break; } if (!layername) layername = _("Background"); layer_ID = gimp_layer_new (image_ID, layername, width, height, gdtype, 100, GIMP_NORMAL_MODE); gimp_image_insert_layer (image_ID, layer_ID, -1, position); return layer_ID; }
/* ---------------------------------------------------- * gap_image_create_unicolor_image * ---------------------------------------------------- * - create a new image with one black filled layer * (both have the requested size) * * return the new created image_id * and the layer_id of the black_layer */ gint32 gap_image_create_unicolor_image(gint32 *layer_id, gint32 width , gint32 height , gdouble r_f, gdouble g_f, gdouble b_f, gdouble a_f) { gint32 l_empty_layer_id; gint32 l_image_id; *layer_id = -1; l_image_id = gimp_image_new(width, height, GIMP_RGB); if(l_image_id >= 0) { l_empty_layer_id = gimp_layer_new(l_image_id, "black_background", width, height, GIMP_RGBA_IMAGE, 100.0, /* Opacity full opaque */ GIMP_NORMAL_MODE); gimp_image_insert_layer(l_image_id, l_empty_layer_id, 0, 0); /* clear layer to unique color */ gap_layer_clear_to_color(l_empty_layer_id, r_f, g_f, b_f, a_f); *layer_id = l_empty_layer_id; } return(l_image_id); } /* end gap_image_create_unicolor_image */
/* ============================================================================ * gap_image_new_with_layer_of_samesize * ============================================================================ * create empty image * if layer_id is NOT NULL then create one full transparent layer at full image size * and return the layer_id */ gint32 gap_image_new_with_layer_of_samesize(gint32 old_image_id, gint32 *layer_id) { GimpImageBaseType l_type; guint l_width; guint l_height; gint32 new_image_id; gdouble l_xresoulution, l_yresoulution; gint32 l_unit; /* create empty image */ l_width = gimp_image_width(old_image_id); l_height = gimp_image_height(old_image_id); l_type = gimp_image_base_type(old_image_id); l_unit = gimp_image_get_unit(old_image_id); gimp_image_get_resolution(old_image_id, &l_xresoulution, &l_yresoulution); new_image_id = gimp_image_new(l_width, l_height,l_type); gimp_image_set_resolution(new_image_id, l_xresoulution, l_yresoulution); gimp_image_set_unit(new_image_id, l_unit); if(layer_id) { l_type = (l_type * 2); /* convert from GimpImageBaseType to GimpImageType */ *layer_id = gimp_layer_new(new_image_id, "dummy", l_width, l_height, l_type, 0.0, /* Opacity full transparent */ 0); /* NORMAL */ gimp_image_insert_layer(new_image_id, *layer_id, 0, 0); } return (new_image_id); } /* end gap_image_new_with_layer_of_samesize */
void gap_image_prevent_empty_image(gint32 image_id) { GimpImageBaseType l_type; guint l_width, l_height; gint32 l_layer_id; gint l_nlayers; gint32 *l_layers_list; l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(l_layers_list != NULL) { g_free (l_layers_list); } else l_nlayers = 0; if(l_nlayers == 0) { /* the resulting image has no layer, add a transparent dummy layer */ /* get info about the image */ l_width = gimp_image_width(image_id); l_height = gimp_image_height(image_id); l_type = gimp_image_base_type(image_id); l_type = (l_type * 2); /* convert from GimpImageBaseType to GimpImageType */ /* add a transparent dummy layer */ l_layer_id = gimp_layer_new(image_id, "dummy", l_width, l_height, l_type, 0.0, /* Opacity full transparent */ 0); /* NORMAL */ gimp_image_insert_layer(image_id, l_layer_id, 0, 0); } } /* end gap_image_prevent_empty_image */
/* * sendBMPToGIMP * * Take the captured data and send it across * to GIMP. */ static void sendBMPToGimp(HBITMAP hBMP, HDC hDC, RECT rect) { int width, height; int imageType, layerType; gint32 image_id; gint32 layer_id; GimpPixelRgn pixel_rgn; GimpDrawable *drawable; /* Our width and height */ width = (rect.right - rect.left); height = (rect.bottom - rect.top); /* Check that we got the memory */ if (!capBytes) { g_message (_("No data captured")); return; } /* Flip the red and blue bytes */ flipRedAndBlueBytes(width, height); /* Set up the image and layer types */ imageType = GIMP_RGB; layerType = GIMP_RGB_IMAGE; /* Create the GIMP image and layers */ image_id = gimp_image_new(width, height, imageType); layer_id = gimp_layer_new(image_id, _("Background"), ROUND4(width), height, layerType, 100, GIMP_NORMAL_MODE); gimp_image_insert_layer(image_id, layer_id, -1, 0); /* Get our drawable */ drawable = gimp_drawable_get(layer_id); gimp_tile_cache_size(ROUND4(width) * gimp_tile_height() * 3); /* Initialize a pixel region for writing to the image */ gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, ROUND4(width), height, TRUE, FALSE); gimp_pixel_rgn_set_rect(&pixel_rgn, (guchar *) capBytes, 0, 0, ROUND4(width), height); /* HB: update data BEFORE size change */ gimp_drawable_flush(drawable); /* Now resize the layer down to the correct size if necessary. */ if (width != ROUND4(width)) { gimp_layer_resize (layer_id, width, height, 0, 0); gimp_image_resize (image_id, width, height, 0, 0); } /* Finish up */ gimp_drawable_detach(drawable); gimp_display_new (image_id); return; }
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_item_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_insert_layer (image_id, preview_id, -1, 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); }
/* ----------------------------- * gap_image_reorder_layer * ----------------------------- * move the specified layer to another position within the same image. * (done by removing and then re-inserting the layer) * new_groupname * Name of a group or group/subgroup where the specified layer_id shall be moved to. * Note that the string new_groupname uses the delimiter string * to split nested group/sugrup names. * use new_groupname = NULL to move the specified layer_id to image toplevel. * enableGroupCreation * TRUE: * in case the group layer with new_groupname does not exist * it will be created automatically. * FALSE: * in case the group layer with new_groupname does not exist * -1 is returned and the reorder operation is not performed. * new_position * the desired new stackposition within the specified new_groupname * or toplevel image (when new_groupname is NULL or empty) * returns -1 on error */ gint32 gap_image_reorder_layer(gint32 image_id, gint32 layer_id, gint32 new_position, char *new_groupname, char *delimiter, gboolean enableGroupCreation, char *new_layername) { gint32 l_parent_id; gint32 l_dup_layer_id; gchar *l_name; l_parent_id = gap_image_find_or_create_group_layer(image_id , new_groupname , delimiter , 0 /* stackposition for the group in case it is created at toplevel */ , enableGroupCreation ); if (l_parent_id < 0) { return (-1); } l_dup_layer_id = gimp_layer_copy(layer_id); l_name = NULL; if (new_layername != NULL) { if (*new_layername != '\0') { l_name = g_strdup(new_layername); } } if (l_name == NULL) { l_name = gimp_item_get_name(layer_id); } gimp_image_remove_layer(image_id, layer_id); gimp_image_insert_layer(image_id, l_dup_layer_id, l_parent_id, new_position); gimp_item_set_name(l_dup_layer_id, l_name); g_free(l_name); return (0); /* OK */ } /* end gap_image_reorder_layer */
static gint32 layer_from_pixbuf (gint32 image, const gchar *layer_name, gint position, GdkPixbuf *pixbuf, gdouble progress_start, gdouble progress_scale) { gint32 layer = gimp_layer_new_from_pixbuf (image, layer_name, pixbuf, 100.0, GIMP_NORMAL_MODE, progress_start, progress_start + progress_scale); gimp_image_insert_layer (image, layer, -1, position); return layer; }
static gint32 load_image (const gchar *filename, GError **load_error) { gint32 image; gint32 layer; GdkPixbuf *pixbuf; gint width; gint height; GError *error = NULL; pixbuf = load_rsvg_pixbuf (filename, &load_vals, &error); if (! pixbuf) { /* Do not rely on librsvg setting GError on failure! */ g_set_error (load_error, error ? error->domain : 0, error ? error->code : 0, _("Could not open '%s' for reading: %s"), gimp_filename_to_utf8 (filename), error ? error->message : _("Unknown reason")); g_clear_error (&error); return -1; } gimp_progress_init (_("Rendering SVG")); width = gdk_pixbuf_get_width (pixbuf); height = gdk_pixbuf_get_height (pixbuf); image = gimp_image_new (width, height, GIMP_RGB); gimp_image_undo_disable (image); gimp_image_set_filename (image, filename); gimp_image_set_resolution (image, load_vals.resolution, load_vals.resolution); layer = gimp_layer_new_from_pixbuf (image, _("Rendered SVG"), pixbuf, 100, GIMP_NORMAL_MODE, 0.0, 1.0); gimp_image_insert_layer (image, layer, -1, 0); gimp_image_undo_enable (image); return image; }
/* ----------------------------------------------- * gap_image_greate_group_layer_path * ----------------------------------------------- * create group layer specified by nameArray starting with * the element at start_idx end at 1st NULL pointer element. * in case the rest in this nameArray contains more than one name * a hierarchy of group layers is created, where each name * has the previous name as parent. */ gint32 gap_image_greate_group_layer_path(gint32 image_id , gint32 parent_id /* or 0 for top imagelevel */ , gint32 stackposition /* where 0 is on top position */ , gchar **nameArray , gint start_idx ) { gint32 parent_layer_id; gint32 group_layer_id; gint32 position; gchar *namePtr; gint l_ii; position = stackposition; parent_layer_id = 0; if (nameArray != NULL) { for(l_ii = 0; nameArray[l_ii] != NULL; l_ii++) { if(l_ii >= start_idx) { namePtr = nameArray[l_ii]; group_layer_id = gimp_layer_group_new(image_id); gimp_item_set_name(group_layer_id, namePtr); gimp_image_insert_layer(image_id, group_layer_id, parent_layer_id, position); if(gap_debug) { printf("gap_image_greate_group_layer_path: name[%d]:%s group_layer_id:%d\n" , (int)l_ii , namePtr , (int)group_layer_id ); } parent_layer_id = group_layer_id; } position = 0; } } return (group_layer_id); } /* end gap_image_greate_group_layer_path */
/* ---------------------------------------- * p_createEmptyEdgeDrawable * ---------------------------------------- * create the (empty) edge drawable as layer of a new image * */ static void p_createEmptyEdgeDrawable(GapEdgeContext *ectx) { ectx->edgeImageId = gimp_image_new(ectx->refDrawable->width , ectx->refDrawable->height , GIMP_GRAY ); ectx->edgeDrawableId = gimp_layer_new(ectx->edgeImageId , "edge" , ectx->refDrawable->width , ectx->refDrawable->height , GIMP_GRAY_IMAGE , 100.0 /* full opacity */ , 0 /* normal mode */ ); gimp_image_insert_layer (ectx->edgeImageId, ectx->edgeDrawableId, 0, 0 /* stackposition */ ); ectx->edgeDrawable = gimp_drawable_get(ectx->edgeDrawableId); } /* end p_createEmptyEdgeDrawable */
static gboolean file_vtf_load_layer (Vtf::HiresImageResource *vres, gint32 image, gint16 frame) { uint8_t *rgba = vres->getImageRGBA(0, frame, 0, 0); g_return_val_if_fail (rgba != NULL, FALSE); gchar *name = g_strdup_printf ("Frame %d", frame); gint32 layer = gimp_layer_new (image, name, vres->width (), vres->height(), GIMP_RGBA_IMAGE, 100, GIMP_NORMAL_MODE); gimp_image_insert_layer (image, layer, -1, frame); g_free (name); GimpPixelRgn pixel_rgn; GimpDrawable *drawable = gimp_drawable_get (layer); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE); gimp_pixel_rgn_set_rect (&pixel_rgn, rgba, 0, 0, drawable->width, drawable->height); gimp_drawable_detach (drawable); return TRUE; }
static gint32 create_new_layer (gint32 image_ID, gint position, const gchar *layername, guint width, guint height, GimpImageBaseType type, GimpDrawable **drawable, GimpPixelRgn *pixel_rgn) { gint32 layer_ID; GimpImageType gdtype = GIMP_RGB_IMAGE; switch (type) { case GIMP_RGB: gdtype = GIMP_RGB_IMAGE; break; case GIMP_GRAY: gdtype = GIMP_GRAY_IMAGE; break; case GIMP_INDEXED: gdtype = GIMP_INDEXED_IMAGE; break; } if (!layername) layername = _("Background"); layer_ID = gimp_layer_new (image_ID, layername, width, height, gdtype, 100, GIMP_NORMAL_MODE); gimp_image_insert_layer (image_ID, layer_ID, -1, position); *drawable = gimp_drawable_get (layer_ID); gimp_pixel_rgn_init (pixel_rgn, *drawable, 0, 0, (*drawable)->width, (*drawable)->height, TRUE, FALSE); return layer_ID; }
/* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */ static gint32 create_new_image (const gchar *filename, guint width, guint height, GimpImageType gdtype, gint32 *layer_ID, GimpDrawable **drawable, GimpPixelRgn *pixel_rgn) { gint32 image_ID; GimpImageBaseType gitype; if ((gdtype == GIMP_GRAY_IMAGE) || (gdtype == GIMP_GRAYA_IMAGE)) gitype = GIMP_GRAY; else if ((gdtype == GIMP_INDEXED_IMAGE) || (gdtype == GIMP_INDEXEDA_IMAGE)) gitype = GIMP_INDEXED; else gitype = GIMP_RGB; image_ID = gimp_image_new (width, height, gitype); gimp_image_set_filename (image_ID, filename); gimp_image_undo_disable (image_ID); *layer_ID = gimp_layer_new (image_ID, _("Background"), width, height, gdtype, 100, GIMP_NORMAL_MODE); gimp_image_insert_layer (image_ID, *layer_ID, -1, 0); if (drawable) { *drawable = gimp_drawable_get (*layer_ID); if (pixel_rgn != NULL) gimp_pixel_rgn_init (pixel_rgn, *drawable, 0, 0, (*drawable)->width, (*drawable)->height, TRUE, FALSE); } return image_ID; }
static void snapshot_ready (GObject *source_object, GAsyncResult *result, gpointer user_data) { WebKitWebView *view = WEBKIT_WEB_VIEW (source_object); cairo_surface_t *surface; surface = webkit_web_view_get_snapshot_finish (view, result, &webpagevals.error); if (surface) { gint width; gint height; gint32 layer; width = cairo_image_surface_get_width (surface); height = cairo_image_surface_get_height (surface); webpagevals.image = gimp_image_new (width, height, GIMP_RGB); gimp_image_undo_disable (webpagevals.image); layer = gimp_layer_new_from_surface (webpagevals.image, _("Webpage"), surface, 0.25, 1.0); gimp_image_insert_layer (webpagevals.image, layer, -1, 0); gimp_image_undo_enable (webpagevals.image); cairo_surface_destroy (surface); } gimp_progress_update (1.0); gtk_main_quit (); }
/* * 'load_image()' - Load a WMF image into a new image window. */ static gint32 load_image (const gchar *filename, GError **error) { gint32 image; gint32 layer; GimpDrawable *drawable; guchar *pixels; GimpPixelRgn pixel_rgn; guint width, height; guint rowstride; guint count = 0; guint done = 0; gpointer pr; pixels = wmf_load_file (filename, &width, &height, error); if (! pixels) return -1; rowstride = width * 4; gimp_progress_init_printf (_("Opening '%s'"), gimp_filename_to_utf8 (filename)); image = gimp_image_new (width, height, GIMP_RGB); gimp_image_set_filename (image, filename); gimp_image_set_resolution (image, load_vals.resolution, load_vals.resolution); layer = gimp_layer_new (image, _("Rendered WMF"), width, height, GIMP_RGBA_IMAGE, 100, GIMP_NORMAL_MODE); drawable = gimp_drawable_get (layer); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, TRUE, FALSE); for (pr = gimp_pixel_rgns_register (1, &pixel_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { const guchar *src = pixels + pixel_rgn.y * rowstride + pixel_rgn.x * 4; guchar *dest = pixel_rgn.data; gint y; for (y = 0; y < pixel_rgn.h; y++) { memcpy (dest, src, pixel_rgn.w * pixel_rgn.bpp); src += rowstride; dest += pixel_rgn.rowstride; } done += pixel_rgn.h * pixel_rgn.w; if (count++ % 16 == 0) gimp_progress_update ((gdouble) done / (width * height)); } g_free (pixels); gimp_drawable_detach (drawable); gimp_progress_update (1.0); /* Tell GIMP to display the image. */ gimp_image_insert_layer (image, layer, -1, 0); gimp_drawable_flush (drawable); return image; }
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 gboolean apply_resize(resize_settings settings, image_output out) { gboolean success = FALSE; gint orig_w, orig_h, final_w, final_h, view_w, view_h; gdouble orig_res_x, orig_res_y; if (settings->change_res) { success = gimp_image_get_resolution( out->image_id, &orig_res_x, &orig_res_y ); if ((settings->new_res_x != orig_res_x) || (settings->new_res_y != orig_res_y)) { // change resolution success = gimp_image_set_resolution( out->image_id, settings->new_res_x, settings->new_res_y ); } } orig_w = gimp_image_width(out->image_id); orig_h = gimp_image_height(out->image_id); if (settings->resize_mode == RESIZE_PERCENT) { if (settings->stretch_mode == STRETCH_ASPECT) { gdouble newpct = min(settings->new_w_pc, settings->new_h_pc); final_w = view_w = round((orig_w * newpct) / 100.0); final_h = view_h = round((orig_h * newpct) / 100.0); } else if (settings->stretch_mode == STRETCH_PADDED) { gdouble newpct = min(settings->new_w_pc, settings->new_h_pc); final_w = round((orig_w * newpct) / 100.0); final_h = round((orig_h * newpct) / 100.0); view_w = round((orig_w * settings->new_w_pc) / 100.0); view_h = round((orig_h * settings->new_h_pc) / 100.0); } else { final_w = view_w = round((orig_w * settings->new_w_pc) / 100.0); final_h = view_h = round((orig_h * settings->new_h_pc) / 100.0); } } else { // user typed exact pixel size if (settings->resize_mode == RESIZE_PIXEL_WIDTH) { view_w = settings->new_w_px; // width is fixed if (settings->stretch_mode == STRETCH_ASPECT) { final_w = view_w; final_h = view_h = round(((float)final_w * orig_h) / orig_w); } else if (settings->stretch_mode == STRETCH_PADDED) { final_w = min(view_w, orig_w); final_h = round(((float)final_w * orig_h) / orig_w); view_h = max(orig_h, final_h); } else { final_w = view_w; final_h = view_h = orig_h; } } else if (settings->resize_mode == RESIZE_PIXEL_HEIGHT) { view_h = settings->new_h_px; // height is fixed if (settings->stretch_mode == STRETCH_ASPECT) { final_h = view_h; final_w = view_w = round(((float)final_h * orig_w) / orig_h); } else if (settings->stretch_mode == STRETCH_PADDED) { final_h = min(view_h, orig_h); final_w = round(((float)final_h * orig_w) / orig_h); view_w = max(orig_w, final_w); } else { final_h = view_h; final_w = view_w = orig_w; } } else { // both dimensions are defined if (settings->stretch_mode == STRETCH_ASPECT) { // Find which new dimension is the smallest percentage of the existing image dimension gdouble newwpct = (float)settings->new_w_px / (float)orig_w; gdouble newhpct = (float)settings->new_h_px / (float)orig_h; gdouble newpct = min(newwpct, newhpct); final_w = view_w = round(orig_w * newpct); final_h = view_h = round(orig_h * newpct); } else if (settings->stretch_mode == STRETCH_PADDED) { // Find which new dimension is the smallest percentage of the existing image dimension gdouble newwpct = (float)settings->new_w_px / (float)orig_w; gdouble newhpct = (float)settings->new_h_px / (float)orig_h; gdouble newpct = min(newwpct, newhpct); final_w = round(orig_w * newpct); final_h = round(orig_h * newpct); view_w = round(orig_w * newwpct); view_h = round(orig_h * newhpct); } else { final_w = view_w = settings->new_w_px; final_h = view_h = settings->new_h_px; } } } // do resize #if USE_API26 success = gimp_image_scale_full ( out->image_id, final_w, final_h, settings->interpolation ); #else // starting from 2.8, gimp_image_scale_full is deprecated. // use gimp_image_scale instead GimpInterpolationType old_interpolation; old_interpolation = gimp_context_get_interpolation(); success = gimp_context_set_interpolation (settings->interpolation); success = gimp_image_scale ( out->image_id, final_w, final_h ); success = gimp_context_set_interpolation (old_interpolation); #endif // add a padding if requested if (settings->stretch_mode == STRETCH_PADDED) { // the padding will be drawn using a coloured layer at the bottom of the image gint32 layerId = gimp_layer_new( out->image_id, "padding_layer", view_w, view_h, GIMP_RGBA_IMAGE, (settings->padding_color_alpha / (float)G_MAXUINT16) * 100, GIMP_NORMAL_MODE ); #if USE_API26 gimp_image_add_layer ( out->image_id, layerId, 0 ); gimp_image_lower_layer_to_bottom(out->image_id, layerId); #else gimp_image_insert_layer( out->image_id, layerId, 0, 0 ); gimp_image_lower_item_to_bottom(out->image_id, layerId); #endif // fill it with the selected color GimpRGB old_background, new_background; gimp_context_get_background(&old_background); gimp_rgb_parse_hex (&new_background, gdk_color_to_string(&(settings->padding_color)), strlen(gdk_color_to_string(&(settings->padding_color)))); gimp_context_set_background(&new_background); gimp_drawable_fill(layerId, GIMP_BACKGROUND_FILL); gimp_context_set_background(&old_background); // move it to the center gimp_layer_translate(layerId, -abs(view_w - final_w) / 2, -abs(view_h - final_h) / 2); // finish changing the canvas size accordingly success = gimp_image_resize_to_layers(out->image_id); } return success; }
void ptRun(const gchar* Name, gint NrParameters, const GimpParam* Parameter, gint *nreturn_vals, GimpParam **return_vals) { printf("(%s,%d) '%s'\n",__FILE__,__LINE__,__PRETTY_FUNCTION__); printf("Name : '%s'\n",Name); printf("NrParameters : %d\n",NrParameters); if (!strcmp(Name,"photivoSendToGimp")) { printf("RunMode : %d\n",Parameter[0].data.d_int32); printf("FileName1 : '%s'\n",Parameter[1].data.d_string); printf("FileName2 : '%s'\n",Parameter[2].data.d_string); QFile GimpFile(Parameter[1].data.d_string); bool result = GimpFile.open(QIODevice::ReadOnly | QIODevice::Text); assert(result); QTextStream In(&GimpFile); QString ImageFileName = In.readLine(); QString ExifFileName = In.readLine(); QString ICCFileName = In.readLine(); // Read image FILE *InputFile = fopen(ImageFileName.toLocal8Bit().data(),"rb"); if (!InputFile) { ptLogError(1,ImageFileName.toLocal8Bit().data()); return; // ptError_FileOpen; } short Colors; unsigned short Width; unsigned short Height; unsigned short BitsPerColor; char Buffer[128]; // Extremely naive. Probably just enough for testcases. char *s = fgets(Buffer,127,InputFile); assert ( s ); int n = sscanf(Buffer,"P%hd",&Colors); assert ( 1 == n ); assert(Colors == 6 ); do { s = fgets(Buffer,127,InputFile); assert ( s ); } while (Buffer[0] == '#'); sscanf(Buffer,"%hd %hd",&Width,&Height); s = fgets(Buffer,127,InputFile); assert ( s ); sscanf(Buffer,"%hd",&BitsPerColor); assert(BitsPerColor == 0xffff); Colors = 3; unsigned short (* ImageForGimp)[3] = (unsigned short (*)[3]) CALLOC2(Width*Height,sizeof(*ImageForGimp)); ptMemoryError(ImageForGimp,__FILE__,__LINE__); unsigned short* PpmRow = (unsigned short *) CALLOC2(Width*Height,sizeof(*PpmRow)); ptMemoryError(PpmRow,__FILE__,__LINE__); for (unsigned short Row=0; Row<Height; Row++) { size_t RV = fread(PpmRow,Colors*2,Width,InputFile); if (RV != (size_t) Width) { printf("ReadPpm error. Expected %d bytes. Got %d\n",Width,(int)RV); exit(EXIT_FAILURE); } if (htons(0x55aa) != 0x55aa) { swab((char *)PpmRow,(char *)PpmRow,Width*Colors*2); } for (unsigned short Col=0; Col<Width; Col++) { for (short c=0;c<3;c++) { ImageForGimp[Row*Width+Col][c] = PpmRow[Col*Colors+c]; } } } FREE2(PpmRow); FCLOSE(InputFile); QFile ExifFile(ExifFileName); result = ExifFile.open(QIODevice::ReadOnly); assert(result); qint64 FileSize = ExifFile.size(); QDataStream ExifIn(&ExifFile); char* ExifBuffer = (char *) MALLOC2(FileSize); ptMemoryError(ExifBuffer,__FILE__,__LINE__); unsigned ExifBufferLength = ExifIn.readRawData(ExifBuffer,FileSize); ExifFile.close(); QFile ICCFile(ICCFileName); result = ICCFile.open(QIODevice::ReadOnly); assert(result); qint64 FileSize2 = ICCFile.size(); QDataStream ICCIn(&ICCFile); char* ICCBuffer = (char *) MALLOC2(FileSize2); ptMemoryError(ICCBuffer,__FILE__,__LINE__); unsigned ICCBufferLength = ICCIn.readRawData(ICCBuffer,FileSize2); ICCFile.close(); // And now copy to gimp. gint32 GimpImage = gimp_image_new(Width, Height, GIMP_RGB); assert (GimpImage != -1); gint32 GimpLayer = gimp_layer_new(GimpImage, "BG", Width, Height, GIMP_RGB_IMAGE, 100.0, GIMP_NORMAL_MODE); #if GIMP_MINOR_VERSION<=6 gimp_image_add_layer(GimpImage,GimpLayer,0); #else gimp_image_insert_layer(GimpImage,GimpLayer,0,0); #endif GimpDrawable* Drawable = gimp_drawable_get(GimpLayer); GimpPixelRgn PixelRegion; gimp_pixel_rgn_init(&PixelRegion, Drawable, 0, 0, Drawable->width, Drawable->height, true, false); unsigned short TileHeight = gimp_tile_height(); for (unsigned short Row=0; Row<Height; Row+=TileHeight) { unsigned short NrRows = MIN(Height-Row, (int)TileHeight); guint8* Buffer = g_new(guint8,TileHeight*Width*3); for (unsigned short i=0; i<NrRows; i++) { for (unsigned short j=0; j<Width; j++) { for (short c=0;c<3;c++) { Buffer[3*(i*Width+j)+c] = ImageForGimp[(Row+i)*Width+j][c]>>8; } } } gimp_pixel_rgn_set_rect(&PixelRegion, Buffer, 0, Row, Width, NrRows); g_free(Buffer); } gimp_drawable_flush(Drawable); gimp_drawable_detach(Drawable); FREE2(ImageForGimp); GimpParasite* GimpExifData = gimp_parasite_new("exif-data", GIMP_PARASITE_PERSISTENT, ExifBufferLength, ExifBuffer); gimp_image_parasite_attach(GimpImage,GimpExifData); gimp_parasite_free(GimpExifData); FREE2(ExifBuffer); GimpParasite* GimpICCData = gimp_parasite_new("icc-profile", GIMP_PARASITE_PERSISTENT, ICCBufferLength, ICCBuffer); gimp_image_parasite_attach(GimpImage,GimpICCData); gimp_parasite_free(GimpICCData); FREE2(ICCBuffer); static GimpParam Values[2]; *nreturn_vals = 2; *return_vals = Values; Values[0].type = GIMP_PDB_STATUS; Values[0].data.d_status = GIMP_PDB_SUCCESS; Values[1].type = GIMP_PDB_IMAGE; Values[1].data.d_image = GimpImage; QFile::remove(ImageFileName); QFile::remove(ExifFileName); QFile::remove(ICCFileName); QFile::remove(Parameter[1].data.d_string); }
static gboolean pluginCore (piArgs *argp) { GimpDrawable *drw, *ndrw = NULL; GimpPixelRgn srcPr, dstPr; gboolean success = TRUE; gint nl = 0; gint y, i; gint Y, I, Q; guint width, height, bpp; gint sel_x1, sel_x2, sel_y1, sel_y2; gint prog_interval; guchar *src, *s, *dst, *d; guchar r, prev_r=0, new_r=0; guchar g, prev_g=0, new_g=0; guchar b, prev_b=0, new_b=0; gdouble fy, fc, t, scale; gdouble pr, pg, pb; gdouble py; drw = gimp_drawable_get (argp->drawable); width = drw->width; height = drw->height; bpp = drw->bpp; if (argp->new_layerp) { gchar name[40]; const gchar *mode_names[] = { "ntsc", "pal", }; const gchar *action_names[] = { "lum redux", "sat redux", "flag", }; g_snprintf (name, sizeof (name), "hot mask (%s, %s)", mode_names[argp->mode], action_names[argp->action]); nl = gimp_layer_new (argp->image, name, width, height, GIMP_RGBA_IMAGE, (gdouble)100, GIMP_NORMAL_MODE); ndrw = gimp_drawable_get (nl); gimp_drawable_fill (nl, GIMP_TRANSPARENT_FILL); gimp_image_insert_layer (argp->image, nl, -1, 0); } gimp_drawable_mask_bounds (drw->drawable_id, &sel_x1, &sel_y1, &sel_x2, &sel_y2); width = sel_x2 - sel_x1; height = sel_y2 - sel_y1; src = g_new (guchar, width * height * bpp); dst = g_new (guchar, width * height * 4); gimp_pixel_rgn_init (&srcPr, drw, sel_x1, sel_y1, width, height, FALSE, FALSE); if (argp->new_layerp) { gimp_pixel_rgn_init (&dstPr, ndrw, sel_x1, sel_y1, width, height, FALSE, FALSE); } else { gimp_pixel_rgn_init (&dstPr, drw, sel_x1, sel_y1, width, height, TRUE, TRUE); } gimp_pixel_rgn_get_rect (&srcPr, src, sel_x1, sel_y1, width, height); s = src; d = dst; build_tab (argp->mode); gimp_progress_init (_("Hot")); prog_interval = height / 10; for (y = sel_y1; y < sel_y2; y++) { gint x; if (y % prog_interval == 0) gimp_progress_update ((double) y / (double) (sel_y2 - sel_y1)); for (x = sel_x1; x < sel_x2; x++) { if (hotp (r = *(s + 0), g = *(s + 1), b = *(s + 2))) { if (argp->action == ACT_FLAG) { for (i = 0; i < 3; i++) *d++ = 0; s += 3; if (bpp == 4) *d++ = *s++; else if (argp->new_layerp) *d++ = 255; } else { /* * Optimization: cache the last-computed hot pixel. */ if (r == prev_r && g == prev_g && b == prev_b) { *d++ = new_r; *d++ = new_g; *d++ = new_b; s += 3; if (bpp == 4) *d++ = *s++; else if (argp->new_layerp) *d++ = 255; } else { Y = tab[0][0][r] + tab[0][1][g] + tab[0][2][b]; I = tab[1][0][r] + tab[1][1][g] + tab[1][2][b]; Q = tab[2][0][r] + tab[2][1][g] + tab[2][2][b]; prev_r = r; prev_g = g; prev_b = b; /* * Get Y and chroma amplitudes in floating point. * * If your C library doesn't have hypot(), just use * hypot(a,b) = sqrt(a*a, b*b); * * Then extract linear (un-gamma-corrected) * floating-point pixel RGB values. */ fy = (double)Y / (double)SCALE; fc = hypot ((double) I / (double) SCALE, (double) Q / (double) SCALE); pr = (double) pix_decode (r); pg = (double) pix_decode (g); pb = (double) pix_decode (b); /* * Reducing overall pixel intensity by scaling R, * G, and B reduces Y, I, and Q by the same factor. * This changes luminance but not saturation, since * saturation is determined by the chroma/luminance * ratio. * * On the other hand, by linearly interpolating * between the original pixel value and a grey * pixel with the same luminance (R=G=B=Y), we * change saturation without affecting luminance. */ if (argp->action == ACT_LREDUX) { /* * Calculate a scale factor that will bring the pixel * within both chroma and composite limits, if we scale * luminance and chroma simultaneously. * * The calculated chrominance reduction applies * to the gamma-corrected RGB values that are * the input to the RGB-to-YIQ operation. * Multiplying the original un-gamma-corrected * pixel values by the scaling factor raised to * the "gamma" power is equivalent, and avoids * calling gc() and inv_gc() three times each. */ scale = chroma_lim / fc; t = compos_lim / (fy + fc); if (t < scale) scale = t; scale = pow (scale, mode[argp->mode].gamma); r = (guint8) pix_encode (scale * pr); g = (guint8) pix_encode (scale * pg); b = (guint8) pix_encode (scale * pb); } else { /* ACT_SREDUX hopefully */ /* * Calculate a scale factor that will bring the * pixel within both chroma and composite * limits, if we scale chroma while leaving * luminance unchanged. * * We have to interpolate gamma-corrected RGB * values, so we must convert from linear to * gamma-corrected before interpolation and then * back to linear afterwards. */ scale = chroma_lim / fc; t = (compos_lim - fy) / fc; if (t < scale) scale = t; pr = gc (pr, argp->mode); pg = gc (pg, argp->mode); pb = gc (pb, argp->mode); py = pr * mode[argp->mode].code[0][0] + pg * mode[argp->mode].code[0][1] + pb * mode[argp->mode].code[0][2]; r = pix_encode (inv_gc (py + scale * (pr - py), argp->mode)); g = pix_encode (inv_gc (py + scale * (pg - py), argp->mode)); b = pix_encode (inv_gc (py + scale * (pb - py), argp->mode)); } *d++ = new_r = r; *d++ = new_g = g; *d++ = new_b = b; s += 3; if (bpp == 4) *d++ = *s++; else if (argp->new_layerp) *d++ = 255; } } } else { if (!argp->new_layerp) { for (i = 0; i < bpp; i++) *d++ = *s++; } else { s += bpp; d += 4; } } } } gimp_pixel_rgn_set_rect (&dstPr, dst, sel_x1, sel_y1, width, height); g_free (src); g_free (dst); if (argp->new_layerp) { gimp_drawable_flush (ndrw); gimp_drawable_update (nl, sel_x1, sel_y1, width, height); } else { gimp_drawable_flush (drw); gimp_drawable_merge_shadow (drw->drawable_id, TRUE); gimp_drawable_update (drw->drawable_id, sel_x1, sel_y1, width, height); } gimp_displays_flush (); return success; }
static gint32 load_image (const gchar *filename, gboolean interactive, GError **error) { gint32 status = -1; EXRLoader *loader; int width; int height; gboolean has_alpha; GimpImageBaseType image_type; GimpPrecision image_precision; gint32 image = -1; GimpImageType layer_type; int layer; const Babl *format; GeglBuffer *buffer = NULL; int bpp; int tile_height; gchar *pixels = NULL; int begin; int end; int num; loader = exr_loader_new (filename); if (!loader) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Error opening file '%s' for reading"), gimp_filename_to_utf8 (filename)); goto out; } width = exr_loader_get_width (loader); height = exr_loader_get_height (loader); if ((width < 1) || (height < 1)) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Error querying image dimensions from '%s'"), gimp_filename_to_utf8 (filename)); goto out; } has_alpha = exr_loader_has_alpha (loader) ? TRUE : FALSE; switch (exr_loader_get_precision (loader)) { case PREC_UINT: image_precision = GIMP_PRECISION_U32; break; case PREC_HALF: image_precision = GIMP_PRECISION_HALF; break; case PREC_FLOAT: image_precision = GIMP_PRECISION_FLOAT; break; default: g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Error querying image precision from '%s'"), gimp_filename_to_utf8 (filename)); goto out; } switch (exr_loader_get_image_type (loader)) { case IMAGE_TYPE_RGB: image_type = GIMP_RGB; layer_type = has_alpha ? GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE; break; case IMAGE_TYPE_GRAY: image_type = GIMP_GRAY; layer_type = has_alpha ? GIMP_GRAYA_IMAGE : GIMP_GRAY_IMAGE; break; default: g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Error querying image type from '%s'"), gimp_filename_to_utf8 (filename)); goto out; } gimp_progress_init_printf (_("Opening '%s'"), gimp_filename_to_utf8 (filename)); image = gimp_image_new_with_precision (width, height, image_type, image_precision); if (image == -1) { g_set_error (error, 0, 0, _("Could not create new image for '%s': %s"), gimp_filename_to_utf8 (filename), gimp_get_pdb_error ()); goto out; } gimp_image_set_filename (image, filename); layer = gimp_layer_new (image, _("Background"), width, height, layer_type, 100, GIMP_NORMAL_MODE); gimp_image_insert_layer (image, layer, -1, 0); buffer = gimp_drawable_get_buffer (layer); format = gimp_drawable_get_format (layer); bpp = babl_format_get_bytes_per_pixel (format); tile_height = gimp_tile_height (); pixels = g_new0 (gchar, tile_height * width * bpp); for (begin = 0; begin < height; begin += tile_height) { int retval; int i; end = MIN (begin + tile_height, height); num = end - begin; for (i = 0; i < num; i++) { retval = exr_loader_read_pixel_row (loader, pixels + (i * width * bpp), bpp, begin + i); if (retval < 0) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Error reading pixel data from '%s'"), gimp_filename_to_utf8 (filename)); goto out; } } gegl_buffer_set (buffer, GEGL_RECTANGLE (0, begin, width, num), 0, NULL, pixels, GEGL_AUTO_ROWSTRIDE); gimp_progress_update ((gdouble) begin / (gdouble) height); } gimp_progress_update (1.0); status = image; out: if (buffer) g_object_unref (buffer); if ((status != image) && (image != -1)) { /* This should clean up any associated layers too. */ gimp_image_delete (image); } if (pixels) g_free (pixels); if (loader) exr_loader_unref (loader); return status; }
static void ico_image_get_reduced_buf (guint32 layer, gint bpp, gint *num_colors, guchar **cmap_out, guchar **buf_out) { gint32 tmp_image; gint32 tmp_layer; gint w, h; guchar *buf; guchar *cmap = NULL; GeglBuffer *buffer = gimp_drawable_get_buffer (layer); const Babl *format; w = gegl_buffer_get_width (buffer); h = gegl_buffer_get_height (buffer); switch (gimp_drawable_type (layer)) { case GIMP_RGB_IMAGE: format = babl_format ("R'G'B' u8"); break; case GIMP_RGBA_IMAGE: format = babl_format ("R'G'B'A u8"); break; case GIMP_GRAY_IMAGE: format = babl_format ("Y' u8"); break; case GIMP_GRAYA_IMAGE: format = babl_format ("Y'A u8"); break; case GIMP_INDEXED_IMAGE: case GIMP_INDEXEDA_IMAGE: format = gegl_buffer_get_format (buffer); default: g_return_if_reached (); } *num_colors = 0; buf = g_new (guchar, w * h * 4); if (bpp <= 8 || bpp == 24 || babl_format_get_bytes_per_pixel (format) != 4) { gint32 image = gimp_item_get_image (layer); GeglBuffer *tmp; tmp_image = gimp_image_new (w, h, gimp_image_base_type (image)); gimp_image_undo_disable (tmp_image); if (gimp_drawable_is_indexed (layer)) { guchar *cmap; gint num_colors; cmap = gimp_image_get_colormap (image, &num_colors); gimp_image_set_colormap (tmp_image, cmap, num_colors); g_free (cmap); } tmp_layer = gimp_layer_new (tmp_image, "tmp", w, h, gimp_drawable_type (layer), 100, GIMP_NORMAL_MODE); gimp_image_insert_layer (tmp_image, tmp_layer, -1, 0); tmp = gimp_drawable_get_buffer (tmp_layer); gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, w, h), 1.0, format, buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE, tmp, NULL); g_object_unref (tmp); if (! gimp_drawable_is_rgb (tmp_layer)) gimp_image_convert_rgb (tmp_image); if (bpp <= 8) { gimp_image_convert_indexed (tmp_image, GIMP_FS_DITHER, GIMP_MAKE_PALETTE, 1 << bpp, TRUE, FALSE, "dummy"); cmap = gimp_image_get_colormap (tmp_image, num_colors); if (*num_colors == (1 << bpp) && ! ico_cmap_contains_black (cmap, *num_colors)) { /* Windows icons with color maps need the color black. * We need to eliminate one more color to make room for black. */ if (gimp_drawable_is_indexed (layer)) { g_free (cmap); cmap = gimp_image_get_colormap (image, num_colors); gimp_image_set_colormap (tmp_image, cmap, *num_colors); } else if (gimp_drawable_is_gray (layer)) { gimp_image_convert_grayscale (tmp_image); } else { gimp_image_convert_rgb (tmp_image); } tmp = gimp_drawable_get_buffer (tmp_layer); gegl_buffer_set (tmp, GEGL_RECTANGLE (0, 0, w, h), 0, format, buf, GEGL_AUTO_ROWSTRIDE); g_object_unref (tmp); if (! gimp_drawable_is_rgb (layer)) gimp_image_convert_rgb (tmp_image); gimp_image_convert_indexed (tmp_image, GIMP_FS_DITHER, GIMP_MAKE_PALETTE, (1<<bpp) - 1, TRUE, FALSE, "dummy"); g_free (cmap); cmap = gimp_image_get_colormap (tmp_image, num_colors); } gimp_image_convert_rgb (tmp_image); } else if (bpp == 24) { GimpParam *return_vals; gint n_return_vals; return_vals = gimp_run_procedure ("plug-in-threshold-alpha", &n_return_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, tmp_image, GIMP_PDB_DRAWABLE, tmp_layer, GIMP_PDB_INT32, ICO_ALPHA_THRESHOLD, GIMP_PDB_END); gimp_destroy_params (return_vals, n_return_vals); } gimp_layer_add_alpha (tmp_layer); tmp = gimp_drawable_get_buffer (tmp_layer); gegl_buffer_get (tmp, GEGL_RECTANGLE (0, 0, w, h), 1.0, NULL, buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); g_object_unref (tmp); gimp_image_delete (tmp_image); } else { gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, w, h), 1.0, format, buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); } g_object_unref (buffer); *cmap_out = cmap; *buf_out = buf; }
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; }
static gint32 ReadImage (FILE *fd, const gchar *filename, gint len, gint height, CMap cmap, gint ncols, gint format, gint interlace, gint number, guint leftpos, guint toppos, guint screenwidth, guint screenheight) { static gint32 image_ID = -1; static gint frame_number = 1; gint32 layer_ID; GimpPixelRgn pixel_rgn; GimpDrawable *drawable; guchar *dest, *temp; guchar c; gint xpos = 0, ypos = 0, pass = 0; gint cur_progress, max_progress; gint v; gint i, j; gchar *framename; gchar *framename_ptr; gboolean alpha_frame = FALSE; static gint previous_disposal; /* Guard against bogus frame size */ if (len < 1 || height < 1) { g_message ("Bogus frame dimensions"); return -1; } /* ** Initialize the Compression routines */ if (! ReadOK (fd, &c, 1)) { g_message ("EOF / read error on image data"); return -1; } if (LZWReadByte (fd, TRUE, c) < 0) { g_message ("Error while reading"); return -1; } if (frame_number == 1) { /* Guard against bogus logical screen size values */ if (screenwidth == 0) screenwidth = len; if (screenheight == 0) screenheight = height; image_ID = gimp_image_new (screenwidth, screenheight, GIMP_INDEXED); gimp_image_set_filename (image_ID, filename); for (i = 0, j = 0; i < ncols; i++) { used_cmap[0][i] = gimp_cmap[j++] = cmap[0][i]; used_cmap[1][i] = gimp_cmap[j++] = cmap[1][i]; used_cmap[2][i] = gimp_cmap[j++] = cmap[2][i]; } gimp_image_set_colormap (image_ID, gimp_cmap, ncols); if (Gif89.delayTime < 0) framename = g_strdup (_("Background")); else framename = g_strdup_printf (_("Background (%d%s)"), 10 * Gif89.delayTime, "ms"); previous_disposal = Gif89.disposal; if (Gif89.transparent == -1) { layer_ID = gimp_layer_new (image_ID, framename, len, height, GIMP_INDEXED_IMAGE, 100, GIMP_NORMAL_MODE); } else { layer_ID = gimp_layer_new (image_ID, framename, len, height, GIMP_INDEXEDA_IMAGE, 100, GIMP_NORMAL_MODE); alpha_frame=TRUE; } g_free (framename); } else /* NOT FIRST FRAME */ { gimp_progress_set_text_printf (_("Opening '%s' (frame %d)"), gimp_filename_to_utf8 (filename), frame_number); gimp_progress_pulse (); /* If the colourmap is now different, we have to promote to RGB! */ if (! promote_to_rgb) { for (i = 0; i < ncols; i++) { if ((used_cmap[0][i] != cmap[0][i]) || (used_cmap[1][i] != cmap[1][i]) || (used_cmap[2][i] != cmap[2][i])) { /* Everything is RGB(A) from now on... sigh. */ promote_to_rgb = TRUE; /* Promote everything we have so far into RGB(A) */ #ifdef GIFDEBUG g_print ("GIF: Promoting image to RGB...\n"); #endif gimp_image_convert_rgb (image_ID); break; } } } if (Gif89.delayTime < 0) framename = g_strdup_printf (_("Frame %d"), frame_number); else framename = g_strdup_printf (_("Frame %d (%d%s)"), frame_number, 10 * Gif89.delayTime, "ms"); switch (previous_disposal) { case 0x00: break; /* 'don't care' */ case 0x01: framename_ptr = framename; framename = g_strconcat (framename, " (combine)", NULL); g_free (framename_ptr); break; case 0x02: framename_ptr = framename; framename = g_strconcat (framename, " (replace)", NULL); g_free (framename_ptr); break; case 0x03: /* Rarely-used, and unhandled by many loaders/players (including GIMP: we treat as 'combine' mode). */ framename_ptr = framename; framename = g_strconcat (framename, " (combine) (!)", NULL); g_free (framename_ptr); break; case 0x04: /* I've seen a composite of this type. stvo_online_banner2.gif */ case 0x05: case 0x06: /* I've seen a composite of this type. bn31.Gif */ case 0x07: framename_ptr = framename; framename = g_strconcat (framename, " (unknown disposal)", NULL); g_free (framename_ptr); g_message (_("GIF: Undocumented GIF composite type %d is " "not handled. Animation might not play or " "re-save perfectly."), previous_disposal); break; default: g_message ("Disposal word got corrupted. Bug."); break; } previous_disposal = Gif89.disposal; layer_ID = gimp_layer_new (image_ID, framename, len, height, promote_to_rgb ? GIMP_RGBA_IMAGE : GIMP_INDEXEDA_IMAGE, 100, GIMP_NORMAL_MODE); alpha_frame = TRUE; g_free (framename); } frame_number++; gimp_image_insert_layer (image_ID, layer_ID, -1, 0); gimp_layer_translate (layer_ID, (gint) leftpos, (gint) toppos); drawable = gimp_drawable_get (layer_ID); cur_progress = 0; max_progress = height; if (alpha_frame) dest = (guchar *) g_malloc (len * height * (promote_to_rgb ? 4 : 2)); else dest = (guchar *) g_malloc (len * height); #ifdef GIFDEBUG g_print ("GIF: reading %d by %d%s GIF image, ncols=%d\n", len, height, interlace ? " interlaced" : "", ncols); #endif if (! alpha_frame && promote_to_rgb) { /* I don't see how one would easily construct a GIF in which this could happen, but it's a mad mad world. */ g_message ("Ouch! Can't handle non-alpha RGB frames.\n" "Please file a bug report in GIMP's bugzilla."); gimp_quit (); } while ((v = LZWReadByte (fd, FALSE, c)) >= 0) { if (alpha_frame) { if (((guchar) v > highest_used_index) && !(v == Gif89.transparent)) highest_used_index = (guchar) v; if (promote_to_rgb) { temp = dest + ( (ypos * len) + xpos ) * 4; *(temp ) = (guchar) cmap[0][v]; *(temp+1) = (guchar) cmap[1][v]; *(temp+2) = (guchar) cmap[2][v]; *(temp+3) = (guchar) ((v == Gif89.transparent) ? 0 : 255); } else { temp = dest + ( (ypos * len) + xpos ) * 2; *temp = (guchar) v; *(temp+1) = (guchar) ((v == Gif89.transparent) ? 0 : 255); } } else { if ((guchar) v > highest_used_index) highest_used_index = (guchar) v; temp = dest + (ypos * len) + xpos; *temp = (guchar) v; } xpos++; if (xpos == len) { xpos = 0; if (interlace) { switch (pass) { case 0: case 1: ypos += 8; break; case 2: ypos += 4; break; case 3: ypos += 2; break; } if (ypos >= height) { pass++; switch (pass) { case 1: ypos = 4; break; case 2: ypos = 2; break; case 3: ypos = 1; break; default: goto fini; } } } else { ypos++; } if (frame_number == 1) { cur_progress++; if ((cur_progress % 16) == 0) gimp_progress_update ((gdouble) cur_progress / (gdouble) max_progress); } } if (ypos >= height) break; } fini: if (LZWReadByte (fd, FALSE, c) >= 0) g_print ("GIF: too much input data, ignoring extra...\n"); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE); gimp_pixel_rgn_set_rect (&pixel_rgn, dest, 0, 0, drawable->width, drawable->height); g_free (dest); gimp_drawable_flush (drawable); gimp_drawable_detach (drawable); return image_ID; }
/* 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 gint32 tile (gint32 image_id, gint32 drawable_id, gint32 *layer_id) { GimpPixelRgn src_rgn; GimpPixelRgn dest_rgn; GimpDrawable *drawable; GimpDrawable *new_layer; GimpImageBaseType image_type = GIMP_RGB; gint32 new_image_id = 0; gint old_width; gint old_height; gint i, j; gint progress; gint max_progress; gpointer pr; /* sanity check parameters */ if (tvals.new_width < 1 || tvals.new_height < 1) { *layer_id = -1; return -1; } /* initialize */ old_width = gimp_drawable_width (drawable_id); old_height = gimp_drawable_height (drawable_id); if (tvals.new_image) { /* create a new image */ switch (gimp_drawable_type (drawable_id)) { case GIMP_RGB_IMAGE: case GIMP_RGBA_IMAGE: image_type = GIMP_RGB; break; case GIMP_GRAY_IMAGE: case GIMP_GRAYA_IMAGE: image_type = GIMP_GRAY; break; case GIMP_INDEXED_IMAGE: case GIMP_INDEXEDA_IMAGE: image_type = GIMP_INDEXED; break; } new_image_id = gimp_image_new (tvals.new_width, tvals.new_height, image_type); gimp_image_undo_disable (new_image_id); *layer_id = gimp_layer_new (new_image_id, _("Background"), tvals.new_width, tvals.new_height, gimp_drawable_type (drawable_id), 100, GIMP_NORMAL_MODE); if (*layer_id == -1) return -1; gimp_image_insert_layer (new_image_id, *layer_id, -1, 0); new_layer = gimp_drawable_get (*layer_id); /* Get the source drawable */ drawable = gimp_drawable_get (drawable_id); } else { gimp_image_undo_group_start (image_id); gimp_image_resize (image_id, tvals.new_width, tvals.new_height, 0, 0); if (gimp_item_is_layer (drawable_id)) gimp_layer_resize (drawable_id, tvals.new_width, tvals.new_height, 0, 0); /* Get the source drawable */ drawable = gimp_drawable_get (drawable_id); new_layer = drawable; } /* progress */ progress = 0; max_progress = tvals.new_width * tvals.new_height; /* tile... */ for (i = 0; i < tvals.new_height; i += old_height) { gint height = old_height; if (height + i > tvals.new_height) height = tvals.new_height - i; for (j = 0; j < tvals.new_width; j += old_width) { gint width = old_width; gint c; if (width + j > tvals.new_width) width = tvals.new_width - j; gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&dest_rgn, new_layer, j, i, width, height, TRUE, FALSE); for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn), c = 0; pr != NULL; pr = gimp_pixel_rgns_process (pr), c++) { gint k; for (k = 0; k < src_rgn.h; k++) memcpy (dest_rgn.data + k * dest_rgn.rowstride, src_rgn.data + k * src_rgn.rowstride, src_rgn.w * src_rgn.bpp); progress += src_rgn.w * src_rgn.h; if (c % 16 == 0) gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } } } gimp_drawable_update (new_layer->drawable_id, 0, 0, new_layer->width, new_layer->height); gimp_drawable_detach (drawable); if (tvals.new_image) { gimp_drawable_detach (new_layer); /* copy the colormap, if necessary */ if (image_type == GIMP_INDEXED) { guchar *cmap; gint ncols; cmap = gimp_image_get_colormap (image_id, &ncols); gimp_image_set_colormap (new_image_id, cmap, ncols); g_free (cmap); } gimp_image_undo_enable (new_image_id); } else { gimp_image_undo_group_end (image_id); } return new_image_id; }
static void ico_dialog_update_icon_preview (GtkWidget *dialog, gint32 layer, gint bpp) { GtkWidget *preview = ico_dialog_get_layer_preview (dialog, layer); GdkPixbuf *pixbuf; gint w = gimp_drawable_width (layer); gint h = gimp_drawable_height (layer); if (! preview) return; if (bpp <= 8) { GimpDrawable *drawable; GimpDrawable *tmp; GimpPixelRgn src_pixel_rgn, dst_pixel_rgn; gint32 image; gint32 tmp_image; gint32 tmp_layer; guchar *buffer; guchar *cmap; gint num_colors; image = gimp_item_get_image (layer); tmp_image = gimp_image_new (w, h, gimp_image_base_type (image)); gimp_image_undo_disable (tmp_image); if (gimp_drawable_is_indexed (layer)) { cmap = gimp_image_get_colormap (image, &num_colors); gimp_image_set_colormap (tmp_image, cmap, num_colors); g_free (cmap); } tmp_layer = gimp_layer_new (tmp_image, "temporary", w, h, gimp_drawable_type (layer), 100, GIMP_NORMAL_MODE); gimp_image_insert_layer (tmp_image, tmp_layer, -1, 0); drawable = gimp_drawable_get (layer); tmp = gimp_drawable_get (tmp_layer); gimp_pixel_rgn_init (&src_pixel_rgn, drawable, 0, 0, w, h, FALSE, FALSE); gimp_pixel_rgn_init (&dst_pixel_rgn, tmp, 0, 0, w, h, TRUE, FALSE); buffer = g_malloc (w * h * 4); gimp_pixel_rgn_get_rect (&src_pixel_rgn, buffer, 0, 0, w, h); gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h); gimp_drawable_detach (tmp); gimp_drawable_detach (drawable); if (gimp_drawable_is_indexed (layer)) gimp_image_convert_rgb (tmp_image); gimp_image_convert_indexed (tmp_image, GIMP_FS_DITHER, GIMP_MAKE_PALETTE, 1 <<bpp, TRUE, FALSE, "dummy"); cmap = gimp_image_get_colormap (tmp_image, &num_colors); if ( num_colors == (1 << bpp) && !ico_cmap_contains_black (cmap, num_colors)) { /* Windows icons with color maps need the color black. * We need to eliminate one more color to make room for black. */ if (gimp_drawable_is_indexed (layer)) { g_free (cmap); cmap = gimp_image_get_colormap (image, &num_colors); gimp_image_set_colormap (tmp_image, cmap, num_colors); } else if (gimp_drawable_is_gray (layer)) { gimp_image_convert_grayscale (tmp_image); } else { gimp_image_convert_rgb (tmp_image); } tmp = gimp_drawable_get (tmp_layer); gimp_pixel_rgn_init (&dst_pixel_rgn, tmp, 0, 0, w, h, TRUE, FALSE); gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h); gimp_drawable_detach (tmp); if (!gimp_drawable_is_rgb (layer)) gimp_image_convert_rgb (tmp_image); gimp_image_convert_indexed (tmp_image, GIMP_FS_DITHER, GIMP_MAKE_PALETTE, (1<<bpp) - 1, TRUE, FALSE, "dummy"); } g_free (cmap); g_free (buffer); pixbuf = gimp_drawable_get_thumbnail (tmp_layer, MIN (w, 128), MIN (h, 128), GIMP_PIXBUF_SMALL_CHECKS); gimp_image_delete (tmp_image); } else if (bpp == 24) { GimpDrawable *drawable; GimpDrawable *tmp; GimpPixelRgn src_pixel_rgn, dst_pixel_rgn; gint32 image; gint32 tmp_image; gint32 tmp_layer; guchar *buffer; GimpParam *return_vals; gint n_return_vals; image = gimp_item_get_image (layer); tmp_image = gimp_image_new (w, h, gimp_image_base_type (image)); gimp_image_undo_disable (tmp_image); if (gimp_drawable_is_indexed (layer)) { guchar *cmap; gint num_colors; cmap = gimp_image_get_colormap (image, &num_colors); gimp_image_set_colormap (tmp_image, cmap, num_colors); g_free (cmap); } tmp_layer = gimp_layer_new (tmp_image, "temporary", w, h, gimp_drawable_type (layer), 100, GIMP_NORMAL_MODE); gimp_image_insert_layer (tmp_image, tmp_layer, -1, 0); drawable = gimp_drawable_get (layer); tmp = gimp_drawable_get (tmp_layer); gimp_pixel_rgn_init (&src_pixel_rgn, drawable, 0, 0, w, h, FALSE, FALSE); gimp_pixel_rgn_init (&dst_pixel_rgn, tmp, 0, 0, w, h, TRUE, FALSE); buffer = g_malloc (w * h * 4); gimp_pixel_rgn_get_rect (&src_pixel_rgn, buffer, 0, 0, w, h); gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h); g_free (buffer); gimp_drawable_detach (tmp); gimp_drawable_detach (drawable); if (gimp_drawable_is_indexed (layer)) gimp_image_convert_rgb (tmp_image); return_vals = gimp_run_procedure ("plug-in-threshold-alpha", &n_return_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, tmp_image, GIMP_PDB_DRAWABLE, tmp_layer, GIMP_PDB_INT32, ICO_ALPHA_THRESHOLD, GIMP_PDB_END); gimp_destroy_params (return_vals, n_return_vals); pixbuf = gimp_drawable_get_thumbnail (tmp_layer, MIN (w, 128), MIN (h, 128), GIMP_PIXBUF_SMALL_CHECKS); gimp_image_delete (tmp_image); } else { pixbuf = gimp_drawable_get_thumbnail (layer, MIN (w, 128), MIN (h, 128), GIMP_PIXBUF_SMALL_CHECKS); } gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf); g_object_unref (pixbuf); }
gint32 load_image (const gchar *filename, GimpRunMode runmode, gboolean preview, gboolean *resolution_loaded, GError **error) { gint32 volatile image_ID; gint32 layer_ID; struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; jpeg_saved_marker_ptr marker; FILE *infile; guchar *buf; guchar **rowbuf; GimpImageBaseType image_type; GimpImageType layer_type; GeglBuffer *buffer = NULL; const Babl *format; gint tile_height; gint scanlines; gint i, start, end; cmsHTRANSFORM cmyk_transform = NULL; /* We set up the normal JPEG error routines. */ cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; if (!preview) { jerr.pub.output_message = my_output_message; gimp_progress_init_printf (_("Opening '%s'"), gimp_filename_to_utf8 (filename)); } if ((infile = g_fopen (filename, "rb")) == NULL) { g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), _("Could not open '%s' for reading: %s"), gimp_filename_to_utf8 (filename), g_strerror (errno)); return -1; } image_ID = -1; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp (jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ jpeg_destroy_decompress (&cinfo); if (infile) fclose (infile); if (image_ID != -1 && !preview) gimp_image_delete (image_ID); if (preview) destroy_preview (); if (buffer) g_object_unref (buffer); return -1; } /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress (&cinfo); /* Step 2: specify data source (eg, a file) */ jpeg_stdio_src (&cinfo, infile); if (! preview) { /* - step 2.1: tell the lib to save the comments */ jpeg_save_markers (&cinfo, JPEG_COM, 0xffff); /* - step 2.2: tell the lib to save APP1 data (Exif or XMP) */ jpeg_save_markers (&cinfo, JPEG_APP0 + 1, 0xffff); /* - step 2.3: tell the lib to save APP2 data (ICC profiles) */ jpeg_save_markers (&cinfo, JPEG_APP0 + 2, 0xffff); } /* Step 3: read file parameters with jpeg_read_header() */ jpeg_read_header (&cinfo, TRUE); /* We can ignore the return value from jpeg_read_header since * (a) suspension is not possible with the stdio data source, and * (b) we passed TRUE to reject a tables-only JPEG file as an error. * See libjpeg.doc for more info. */ /* Step 4: set parameters for decompression */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Step 5: Start decompressor */ jpeg_start_decompress (&cinfo); /* We may need to do some setup of our own at this point before reading * the data. After jpeg_start_decompress() we have the correct scaled * output image dimensions available, as well as the output colormap * if we asked for color quantization. */ /* temporary buffer */ tile_height = gimp_tile_height (); buf = g_new (guchar, tile_height * cinfo.output_width * cinfo.output_components); rowbuf = g_new (guchar *, tile_height); for (i = 0; i < tile_height; i++) rowbuf[i] = buf + cinfo.output_width * cinfo.output_components * i; switch (cinfo.output_components) { case 1: image_type = GIMP_GRAY; layer_type = GIMP_GRAY_IMAGE; break; case 3: image_type = GIMP_RGB; layer_type = GIMP_RGB_IMAGE; break; case 4: if (cinfo.out_color_space == JCS_CMYK) { image_type = GIMP_RGB; layer_type = GIMP_RGB_IMAGE; break; } /*fallthrough*/ default: g_message ("Don't know how to load JPEG images " "with %d color channels, using colorspace %d (%d).", cinfo.output_components, cinfo.out_color_space, cinfo.jpeg_color_space); return -1; break; } if (preview) { image_ID = preview_image_ID; } else { image_ID = gimp_image_new_with_precision (cinfo.output_width, cinfo.output_height, image_type, GIMP_PRECISION_U8_GAMMA); gimp_image_undo_disable (image_ID); gimp_image_set_filename (image_ID, filename); } if (preview) { preview_layer_ID = gimp_layer_new (preview_image_ID, _("JPEG preview"), cinfo.output_width, cinfo.output_height, layer_type, 100, GIMP_NORMAL_MODE); layer_ID = preview_layer_ID; } else { layer_ID = gimp_layer_new (image_ID, _("Background"), cinfo.output_width, cinfo.output_height, layer_type, 100, GIMP_NORMAL_MODE); } if (! preview) { GString *comment_buffer = NULL; guint8 *profile = NULL; guint profile_size = 0; /* Step 5.0: save the original JPEG settings in a parasite */ jpeg_detect_original_settings (&cinfo, image_ID); /* Step 5.1: check for comments, or Exif metadata in APP1 markers */ for (marker = cinfo.marker_list; marker; marker = marker->next) { const gchar *data = (const gchar *) marker->data; gsize len = marker->data_length; if (marker->marker == JPEG_COM) { #ifdef GIMP_UNSTABLE g_print ("jpeg-load: found image comment (%d bytes)\n", marker->data_length); #endif if (! comment_buffer) { comment_buffer = g_string_new_len (data, len); } else { /* concatenate multiple comments, separate them with LF */ g_string_append_c (comment_buffer, '\n'); g_string_append_len (comment_buffer, data, len); } } else if ((marker->marker == JPEG_APP0 + 1) && (len > sizeof (JPEG_APP_HEADER_EXIF) + 8) && ! strcmp (JPEG_APP_HEADER_EXIF, data)) { #ifdef GIMP_UNSTABLE g_print ("jpeg-load: found Exif block (%d bytes)\n", (gint) (len - sizeof (JPEG_APP_HEADER_EXIF))); #endif } } if (jpeg_load_resolution (image_ID, &cinfo)) { if (resolution_loaded) *resolution_loaded = TRUE; } /* if we found any comments, then make a parasite for them */ if (comment_buffer && comment_buffer->len) { GimpParasite *parasite; jpeg_load_sanitize_comment (comment_buffer->str); parasite = gimp_parasite_new ("gimp-comment", GIMP_PARASITE_PERSISTENT, strlen (comment_buffer->str) + 1, comment_buffer->str); gimp_image_attach_parasite (image_ID, parasite); gimp_parasite_free (parasite); g_string_free (comment_buffer, TRUE); } /* Step 5.3: check for an embedded ICC profile in APP2 markers */ jpeg_icc_read_profile (&cinfo, &profile, &profile_size); if (cinfo.out_color_space == JCS_CMYK) { cmyk_transform = jpeg_load_cmyk_transform (profile, profile_size); } else if (profile) /* don't attach the profile if we are transforming */ { GimpParasite *parasite; parasite = gimp_parasite_new ("icc-profile", GIMP_PARASITE_PERSISTENT | GIMP_PARASITE_UNDOABLE, profile_size, profile); gimp_image_attach_parasite (image_ID, parasite); gimp_parasite_free (parasite); } g_free (profile); /* Do not attach the "jpeg-save-options" parasite to the image * because this conflicts with the global defaults (bug #75398). */ } /* Step 6: while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ /* Here we use the library's state variable cinfo.output_scanline as the * loop counter, so that we don't have to keep track ourselves. */ buffer = gimp_drawable_get_buffer (layer_ID); format = babl_format (image_type == GIMP_RGB ? "R'G'B' u8" : "Y' u8"); while (cinfo.output_scanline < cinfo.output_height) { start = cinfo.output_scanline; end = cinfo.output_scanline + tile_height; end = MIN (end, cinfo.output_height); scanlines = end - start; for (i = 0; i < scanlines; i++) jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &rowbuf[i], 1); if (cinfo.out_color_space == JCS_CMYK) jpeg_load_cmyk_to_rgb (buf, cinfo.output_width * scanlines, cmyk_transform); gegl_buffer_set (buffer, GEGL_RECTANGLE (0, start, cinfo.output_width, scanlines), 0, format, buf, GEGL_AUTO_ROWSTRIDE); if (! preview && (cinfo.output_scanline % 32) == 0) gimp_progress_update ((gdouble) cinfo.output_scanline / (gdouble) cinfo.output_height); } /* Step 7: Finish decompression */ jpeg_finish_decompress (&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ if (cmyk_transform) cmsDeleteTransform (cmyk_transform); /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress (&cinfo); g_object_unref (buffer); /* free up the temporary buffers */ g_free (rowbuf); g_free (buf); /* After finish_decompress, we can close the input file. * Here we postpone it until after no more JPEG errors are possible, * so as to simplify the setjmp error logic above. (Actually, I don't * think that jpeg_destroy can do an error exit, but why assume anything...) */ fclose (infile); /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.num_warnings is nonzero). */ /* Detach from the drawable and add it to the image. */ if (! preview) { gimp_progress_update (1.0); } gimp_image_insert_layer (image_ID, layer_ID, -1, 0); return image_ID; }