/* ------------------------------ * gap_pview_render_f_from_image * ------------------------------ * render preview widget from image. * IMPORTANT: the image is scaled to preview size * and the visible layers in the image are merged together ! * If the supplied image shall stay unchanged, * you may use gap_pview_render_f_from_image_duplicate * * hint: call gtk_widget_queue_draw(pv_ptr->da_widget); * after this procedure to make the changes appear on screen. */ void gap_pview_render_f_from_image (GapPView *pv_ptr , gint32 image_id , gint32 flip_request , gint32 flip_status ) { gint32 layer_id; guchar *frame_data; GimpPixelRgn pixel_rgn; GimpDrawable *drawable; if(image_id < 0) { if(gap_debug) { printf("gap_pview_render_f_from_image: have no image, cant render image_id:%d\n" ,(int)image_id ); } return; } p_free_desaturated_area_data(pv_ptr); if((gimp_image_width(image_id) != pv_ptr->pv_width) || ( gimp_image_height(image_id) != pv_ptr->pv_height)) { gimp_image_scale(image_id, pv_ptr->pv_width, pv_ptr->pv_height); } /* workaround: gimp_image_merge_visible_layers * needs at least 2 layers to work without complaining * therefore add 2 full transparent dummy layers */ { gint32 l_layer_id; GimpImageBaseType l_type; l_type = gimp_image_base_type(image_id); l_type = (l_type * 2); /* convert from GimpImageBaseType to GimpImageType */ l_layer_id = gimp_layer_new(image_id, "dummy_01" , 4, 4 , l_type , 0.0 /* Opacity full transparent */ , 0 /* NORMAL */ ); gimp_image_add_layer(image_id, l_layer_id, 0); l_layer_id = gimp_layer_new(image_id, "dummy_02" , 4, 4 , l_type , 0.0 /* Opacity full transparent */ , 0 /* NORMAL */ ); gimp_image_add_layer(image_id, l_layer_id, 0); gimp_layer_resize_to_image_size(l_layer_id); } layer_id = gimp_image_merge_visible_layers (image_id, GIMP_CLIP_TO_IMAGE); drawable = gimp_drawable_get (layer_id); frame_data = g_malloc(drawable->width * drawable->height * drawable->bpp); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0 , drawable->width, drawable->height , FALSE /* dirty */ , FALSE /* shadow */ ); gimp_pixel_rgn_get_rect (&pixel_rgn, frame_data , 0 , 0 , drawable->width , drawable->height); { gboolean frame_data_was_grabbed; frame_data_was_grabbed = gap_pview_render_f_from_buf (pv_ptr , frame_data , drawable->width , drawable->height , drawable->bpp , TRUE /* allow_grab_src_data */ , flip_request , flip_status ); if(!frame_data_was_grabbed) g_free(frame_data); gimp_drawable_detach (drawable); } } /* end gap_pview_render_f_from_image */
static void explorer (GimpDrawable * drawable) { GimpPixelRgn srcPR; GimpPixelRgn destPR; gint width; gint height; gint bpp; gint row; gint x1; gint y1; gint x2; gint y2; guchar *src_row; guchar *dest_row; /* Get the input area. This is the bounding box of the selection in * the image (or the entire image if there is no selection). Only * operating on the input area is simply an optimization. It doesn't * need to be done for correct operation. (It simply makes it go * faster, since fewer pixels need to be operated on). */ gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); /* Get the size of the input image. (This will/must be the same * as the size of the output image. */ width = drawable->width; height = drawable->height; bpp = drawable->bpp; /* allocate row buffers */ src_row = g_new (guchar, bpp * (x2 - x1)); dest_row = g_new (guchar, bpp * (x2 - x1)); /* initialize the pixel regions */ gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height, TRUE, TRUE); xbild = width; ybild = height; xdiff = (xmax - xmin) / xbild; ydiff = (ymax - ymin) / ybild; /* for grayscale drawables */ if (bpp < 3) { gint i; for (i = 0; i < MAXNCOLORS; i++) valuemap[i] = GIMP_RGB_LUMINANCE (colormap[i].r, colormap[i].g, colormap[i].b); } for (row = y1; row < y2; row++) { gimp_pixel_rgn_get_row (&srcPR, src_row, x1, row, (x2 - x1)); explorer_render_row (src_row, dest_row, row, (x2 - x1), bpp); /* store the dest */ gimp_pixel_rgn_set_row (&destPR, dest_row, x1, row, (x2 - x1)); if ((row % 10) == 0) gimp_progress_update ((double) row / (double) (y2 - y1)); } /* update the processed region */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, (x2 - x1), (y2 - y1)); g_free (src_row); g_free (dest_row); }
static gint save_image (char *filename, gint32 image_ID, gint32 drawable_ID) { GPixelRgn pixel_rgn; TileDrawable *drawable; GDrawableType drawable_type; struct jpeg_compress_struct cinfo; struct my_error_mgr jerr; FILE *outfile; guchar *temp, *t; guchar *data; guchar *src, *s; char *name; int has_alpha; GimpExportReturnType export = GIMP_EXPORT_CANCEL; gint32 e_image_ID = -1; gint32 e_drawable_ID = -1; GPrecisionType precision; int rowstride, yend; int i, j; drawable = gimp_drawable_get (drawable_ID); drawable_type = gimp_drawable_type (drawable_ID); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); name = malloc (strlen (filename) + 11); sprintf (name, "%s %s:",_("Saving"), filename); gimp_progress_init (name); free (name); /* Step 1: allocate and initialize JPEG compression object */ /* We have to set up the error handler first, in case the initialization * step fails. (Unlikely, but it could happen if you are out of memory.) * This routine fills in the contents of struct jerr, and returns jerr's * address which we place into the link field in cinfo. */ cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; outfile = NULL; /* 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_compress (&cinfo); if (outfile) fclose (outfile); if (drawable) gimp_drawable_detach (drawable); return FALSE; } /* Now we can initialize the JPEG compression object. */ jpeg_create_compress (&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ /* Here we use the library-supplied code to send compressed data to a * stdio stream. You can also write your own code to do something else. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to write binary files. */ if ((outfile = fopen (filename, "wb")) == NULL) { fprintf (stderr, "can't open %s\n", filename); return FALSE; } jpeg_stdio_dest (&cinfo, outfile); /* Get the input image and a pointer to its data. */ cinfo.input_components = gimp_drawable_num_channels(drawable_ID); has_alpha = gimp_drawable_has_alpha(drawable_ID); if(has_alpha) --cinfo.input_components; /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ /* image width and height, in pixels */ cinfo.image_width = drawable->width; cinfo.image_height = drawable->height; /* colorspace of input image */ cinfo.in_color_space = gimp_drawable_color(drawable_ID) ? JCS_RGB : JCS_GRAYSCALE; /* Now use the library's routine to set default compression parameters. * (You must set at least cinfo.in_color_space before calling this, * since the defaults depend on the source color space.) */ jpeg_set_defaults (&cinfo); /* Now you can set any non-default parameters you wish to. * Here we just illustrate the use of quality (quantization table) scaling: */ jpeg_set_quality (&cinfo, (int) (jsvals.quality * 100), TRUE /* limit to baseline-JPEG values */); cinfo.smoothing_factor = (int) (jsvals.smoothing * 100); cinfo.optimize_coding = jsvals.optimize; /* Step 4: Start compressor */ /* TRUE ensures that we will write a complete interchange-JPEG file. * Pass TRUE unless you are very sure of what you're doing. */ jpeg_start_compress (&cinfo, TRUE); // Step 4a: write icc profile { char *buffer = NULL; int size = 0; if (gimp_image_has_icc_profile (image_ID, ICC_IMAGE_PROFILE)) { buffer = gimp_image_get_icc_profile_by_mem (image_ID, &size, ICC_IMAGE_PROFILE); if (buffer) { write_icc_profile (&cinfo, buffer, size); printf ("%s:%d %s() embedded icc profile\n",__FILE__,__LINE__,__func__); } } } /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ /* Here we use the library's state variable cinfo.next_scanline as the * loop counter, so that we don't have to keep track ourselves. * To keep things simple, we pass one scanline per call; you can pass * more if you wish, though. */ /* JSAMPLEs per row in image_buffer */ rowstride = drawable->bpp * drawable->width; temp = (guchar *) malloc (cinfo.image_width * cinfo.input_components * 4); data = (guchar *) malloc (rowstride * gimp_tile_height ()); export = gimp_export_image (&image_ID, &drawable_ID, "Jpeg",
static void brushdmenuselect (GtkWidget *widget, gpointer data) { GimpPixelRgn src_rgn; guchar *src_row; guchar *src; gint id; gint bpp; gint x, y; ppm_t *p; gint x1, y1, w, h; gint row; GimpDrawable *drawable; gint rowstride; gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &id); if (id == -1) return; if (brush_from_file == 2) return; /* Not finished GUI-building yet */ if (brush_from_file) { #if 0 unselectall (brush_list); #endif preset_save_button_set_sensitive (FALSE); } gtk_adjustment_set_value (brush_gamma_adjust, 1.0); gtk_adjustment_set_value (brush_aspect_adjust, 0.0); drawable = gimp_drawable_get (id); if (! gimp_drawable_mask_intersect (drawable->drawable_id, &x1, &y1, &w, &h)) return; bpp = gimp_drawable_bpp (drawable->drawable_id); ppm_kill (&brushppm); ppm_new (&brushppm, w, h); p = &brushppm; rowstride = p->width * 3; src_row = g_new (guchar, w * bpp); gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, w, h, FALSE, FALSE); if (bpp == 3) { /* RGB */ gint bpr = w * 3; gint y2 = y1 + h; for (row = 0, y = y1; y < y2; row++, y++) { gimp_pixel_rgn_get_row (&src_rgn, src_row, x1, y, w); memcpy (p->col + row*rowstride, src_row, bpr); } } else { /* RGBA (bpp > 3) GrayA (bpp == 2) or Gray */ gboolean is_gray = ((bpp > 3) ? TRUE : FALSE); gint y2 = y1 + h; for (row = 0, y = y1; y < y2; row++, y++) { guchar *tmprow = p->col + row * rowstride; guchar *tmprow_ptr; gint x2 = x1 + w; gimp_pixel_rgn_get_row (&src_rgn, src_row, x1, y, w); src = src_row; tmprow_ptr = tmprow; /* Possible micro-optimization here: * src_end = src + src_rgn.bpp * w); * for ( ; src < src_end ; src += src_rgn.bpp) */ for (x = x1; x < x2; x++) { *(tmprow_ptr++) = src[0]; *(tmprow_ptr++) = src[is_gray ? 1 : 0]; *(tmprow_ptr++) = src[is_gray ? 2 : 0]; src += src_rgn.bpp; } } } g_free (src_row); if (bpp >= 3) pcvals.color_brushes = 1; else pcvals.color_brushes = 0; brush_from_file = 0; update_brush_preview (NULL); }
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_progress_update (1.0); 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; }
/* Save a layer from an image */ gboolean save_layer(gint32 drawable_ID, WebPWriterFunction writer, void *custom_ptr, #ifdef WEBP_0_5 gboolean animation, WebPAnimEncoder *enc, int frame_timestamp, #endif WebPSaveParams *params, GError **error) { gboolean status = FALSE; gint bpp; gint width; gint height; GimpImageType drawable_type; WebPConfig config; WebPPicture picture; guchar *buffer = NULL; #ifdef GIMP_2_9 GeglBuffer *geglbuffer; GeglRectangle extent; #else GimpDrawable *drawable = NULL; GimpPixelRgn region; #endif /* Retrieve the image data */ bpp = gimp_drawable_bpp(drawable_ID); width = gimp_drawable_width(drawable_ID); height = gimp_drawable_height(drawable_ID); drawable_type = gimp_drawable_type(drawable_ID); /* Initialize the WebP configuration with a preset and fill in the * remaining values */ WebPConfigPreset(&config, webp_preset_by_name(params->preset), params->quality); config.lossless = params->lossless; config.method = 6; /* better quality */ config.alpha_quality = params->alpha_quality; /* Prepare the WebP structure */ WebPPictureInit(&picture); picture.use_argb = 1; picture.width = width; picture.height = height; picture.writer = writer; picture.custom_ptr = custom_ptr; picture.progress_hook = webp_file_progress; do { /* Attempt to allocate a buffer of the appropriate size */ buffer = (guchar *)g_malloc(bpp * width * height); if(!buffer) { g_set_error(error, G_FILE_ERROR, 0, "Unable to allocate buffer for layer"); break; } #ifdef GIMP_2_9 /* Obtain the buffer and get its extent */ geglbuffer = gimp_drawable_get_buffer(drawable_ID); extent = *gegl_buffer_get_extent(geglbuffer); /* Read the layer buffer into our buffer */ gegl_buffer_get(geglbuffer, &extent, 1.0, NULL, buffer, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); g_object_unref(geglbuffer); #else /* Get the drawable */ drawable = gimp_drawable_get(drawable_ID); /* Obtain the pixel region for the drawable */ gimp_pixel_rgn_init(®ion, drawable, 0, 0, width, height, FALSE, FALSE); /* Read the region into the buffer */ gimp_pixel_rgn_get_rect(®ion, buffer, 0, 0, width, height); gimp_drawable_detach(drawable); #endif /* Use the appropriate function to import the data from the buffer */ if(drawable_type == GIMP_RGB_IMAGE) { WebPPictureImportRGB(&picture, buffer, width * bpp); } else { WebPPictureImportRGBA(&picture, buffer, width * bpp); } #ifdef WEBP_0_5 if (animation == TRUE) { if (!WebPAnimEncoderAdd(enc, &picture, frame_timestamp, &config)) { g_set_error(error, G_FILE_ERROR, picture.error_code, "WebP error: '%s'", webp_error_string(picture.error_code)); break; } } else { #endif if(!WebPEncode(&config, &picture)) { g_set_error(error, G_FILE_ERROR, picture.error_code, "WebP error: '%s'", webp_error_string(picture.error_code)); break; } #ifdef WEBP_0_5 } #endif /* Everything succeeded */ status = TRUE; } while(0); /* Free the buffer */ if (buffer) { free(buffer); } return status; }
static void blur (GimpDrawable *drawable) { gint i, j, k, channels; gint x1, y1, x2, y2; GimpPixelRgn rgn_in, rgn_out; guchar output[4]; /* Gets upper left and lower right coordinates, * and layers number in the image */ gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); channels = gimp_drawable_bpp (drawable->drawable_id); /* Initialises two PixelRgns, one to read original data, * and the other to write output data. That second one will * be merged at the end by the call to * gimp_drawable_merge_shadow() */ gimp_pixel_rgn_init (&rgn_in, drawable, x1, y1, x2 - x1, y2 - y1, FALSE, FALSE); gimp_pixel_rgn_init (&rgn_out, drawable, x1, y1, x2 - x1, y2 - y1, TRUE, TRUE); for (i = x1; i < x2; i++) { for (j = y1; j < y2; j++) { guchar pixel[9][4]; /* Get nine pixels */ gimp_pixel_rgn_get_pixel (&rgn_in, pixel[0], MAX (i - 1, x1), MAX (j - 1, y1)); gimp_pixel_rgn_get_pixel (&rgn_in, pixel[1], MAX (i - 1, x1), j); gimp_pixel_rgn_get_pixel (&rgn_in, pixel[2], MAX (i - 1, x1), MIN (j + 1, y2 - 1)); gimp_pixel_rgn_get_pixel (&rgn_in, pixel[3], i, MAX (j - 1, y1)); gimp_pixel_rgn_get_pixel (&rgn_in, pixel[4], i, j); gimp_pixel_rgn_get_pixel (&rgn_in, pixel[5], i, MIN (j + 1, y2 - 1)); gimp_pixel_rgn_get_pixel (&rgn_in, pixel[6], MIN (i + 1, x2 - 1), MAX (j - 1, y1)); gimp_pixel_rgn_get_pixel (&rgn_in, pixel[7], MIN (i + 1, x2 - 1), j); gimp_pixel_rgn_get_pixel (&rgn_in, pixel[8], MIN (i + 1, x2 - 1), MIN (j + 1, y2 - 1)); /* For each layer, compute the average of the * nine */ for (k = 0; k < channels; k++) { int tmp, sum = 0; for (tmp = 0; tmp < 9; tmp++) sum += pixel[tmp][k]; output[k] = sum / 9; } gimp_pixel_rgn_set_pixel (&rgn_out, output, i, j); } if (i % 10 == 0) gimp_progress_update ((gdouble) (i - x1) / (gdouble) (x2 - x1)); } /* Update the modified region */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, x2 - x1, y2 - y1); }
static void normalize_invert (GimpDrawable *drawable, gboolean normalize, guint maxval, gboolean invert) { GimpPixelRgn src_rgn, dest_rgn; gint bpp; gpointer pr; gint x, y, k; gint x1, y1, x2, y2; gboolean has_alpha; gdouble factor; if (normalize && maxval != 0) { factor = 255.0 / maxval; } else factor = 1.0; gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); bpp = drawable->bpp; has_alpha = gimp_drawable_has_alpha(drawable->drawable_id); gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); gimp_pixel_rgn_init (&dest_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, TRUE); for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { guchar *src = src_rgn.data; guchar *dest = dest_rgn.data; gint row = src_rgn.y - y1; for (y = 0; y < src_rgn.h; y++, row++) { guchar *s = src; guchar *d = dest; gint col = src_rgn.x - x1; for (x = 0; x < src_rgn.w; x++, col++) { if (has_alpha) { for (k = 0; k < bpp-1; k++) { d[k] = factor * s[k]; if (invert) d[k] = 255 - d[k]; } } else { for (k = 0; k < bpp; k++) { d[k] = factor * s[k]; if (invert) d[k] = 255 - d[k]; } } s += bpp; d += bpp; } src += src_rgn.rowstride; dest += dest_rgn.rowstride; } } }
static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[1]; gint sel_x1, sel_y1, sel_x2, sel_y2; gint img_height, img_width, img_bpp, img_has_alpha; GimpDrawable *drawable; GimpRunMode run_mode; GimpPDBStatusType status; *nreturn_vals = 1; *return_vals = values; status = GIMP_PDB_SUCCESS; if (param[0].type != GIMP_PDB_INT32) status = GIMP_PDB_CALLING_ERROR; run_mode = param[0].data.d_int32; INIT_I18N (); if (param[2].type != GIMP_PDB_DRAWABLE) status = GIMP_PDB_CALLING_ERROR; drawable = gimp_drawable_get (param[2].data.d_drawable); img_width = gimp_drawable_width (drawable->drawable_id); img_height = gimp_drawable_height (drawable->drawable_id); img_bpp = gimp_drawable_bpp (drawable->drawable_id); img_has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); gimp_drawable_mask_bounds (drawable->drawable_id, &sel_x1, &sel_y1, &sel_x2, &sel_y2); if (!gimp_drawable_is_rgb (drawable->drawable_id)) status = GIMP_PDB_CALLING_ERROR; if (status == GIMP_PDB_SUCCESS) { gr = g_rand_new (); memset (&qbist_info, 0, sizeof (qbist_info)); create_info (&qbist_info.info); qbist_info.oversampling = 4; switch (run_mode) { case GIMP_RUN_INTERACTIVE: /* Possibly retrieve data */ gimp_get_data (PLUG_IN_PROC, &qbist_info); /* Get information from the dialog */ if (dialog_run ()) { status = GIMP_PDB_SUCCESS; gimp_set_data (PLUG_IN_PROC, &qbist_info, sizeof (QbistInfo)); } else status = GIMP_PDB_EXECUTION_ERROR; break; case GIMP_RUN_NONINTERACTIVE: status = GIMP_PDB_CALLING_ERROR; break; case GIMP_RUN_WITH_LAST_VALS: /* Possibly retrieve data */ gimp_get_data (PLUG_IN_PROC, &qbist_info); status = GIMP_PDB_SUCCESS; break; default: status = GIMP_PDB_CALLING_ERROR; break; } if (status == GIMP_PDB_SUCCESS) { GimpPixelRgn imagePR; gpointer pr; gimp_tile_cache_ntiles ((drawable->width + gimp_tile_width () - 1) / gimp_tile_width ()); gimp_pixel_rgn_init (&imagePR, drawable, 0, 0, img_width, img_height, TRUE, TRUE); optimize (&qbist_info.info); gimp_progress_init (_("Qbist")); for (pr = gimp_pixel_rgns_register (1, &imagePR); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { gint row; for (row = 0; row < imagePR.h; row++) { qbist (&qbist_info.info, imagePR.data + row * imagePR.rowstride, imagePR.x, imagePR.y + row, imagePR.w, sel_x2 - sel_x1, sel_y2 - sel_y1, imagePR.bpp, qbist_info.oversampling); } gimp_progress_update ((gfloat) (imagePR.y - sel_y1) / (gfloat) (sel_y2 - sel_y1)); } gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, sel_x1, sel_y1, (sel_x2 - sel_x1), (sel_y2 - sel_y1)); gimp_displays_flush (); } g_rand_free (gr); } values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; gimp_drawable_detach (drawable); }
/* * For all x and y as requested, replace the pixel at (x,y) * with a weighted average of the most frequently occurring * values in a circle of mask_size diameter centered at (x,y). */ static void oilify (GimpDrawable *drawable, GimpPreview *preview) { gboolean use_inten; gboolean use_msmap = FALSE; gboolean use_emap = FALSE; GimpDrawable *mask_size_map_drawable = NULL; GimpDrawable *exponent_map_drawable = NULL; GimpPixelRgn mask_size_map_rgn; GimpPixelRgn exponent_map_rgn; gint msmap_bpp = 0; gint emap_bpp = 0; GimpPixelRgn dest_rgn; GimpPixelRgn *regions[3]; gint n_regions; gint bpp; gint *sqr_lut; gint x1, y1, x2, y2; gint width, height; gint Hist[HISTSIZE]; gint Hist_rgb[4][HISTSIZE]; gpointer pr; gint progress, max_progress; guchar *src_buf; guchar *src_inten_buf = NULL; gint i; use_inten = (ovals.mode == MODE_INTEN); /* Get the selection bounds */ if (preview) { gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); x2 = x1 + width; y2 = y1 + height; } else { gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); width = x2 - x1; height = y2 - y1; } progress = 0; max_progress = width * height; bpp = drawable->bpp; /* * Look-up-table implementation of the square function, for use in the * VERY TIGHT inner loops */ { gint lut_size = (gint) ovals.mask_size / 2 + 1; sqr_lut = g_new (gint, lut_size); for (i = 0; i < lut_size; i++) sqr_lut[i] = SQR (i); } /* Get the map drawables, if applicable */ if (ovals.use_mask_size_map && ovals.mask_size_map >= 0) { use_msmap = TRUE; mask_size_map_drawable = gimp_drawable_get (ovals.mask_size_map); gimp_pixel_rgn_init (&mask_size_map_rgn, mask_size_map_drawable, x1, y1, width, height, FALSE, FALSE); msmap_bpp = mask_size_map_drawable->bpp; } if (ovals.use_exponent_map && ovals.exponent_map >= 0) { use_emap = TRUE; exponent_map_drawable = gimp_drawable_get (ovals.exponent_map); gimp_pixel_rgn_init (&exponent_map_rgn, exponent_map_drawable, x1, y1, width, height, FALSE, FALSE); emap_bpp = exponent_map_drawable->bpp; } gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, width, height, (preview == NULL), TRUE); { GimpPixelRgn src_rgn; gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE); src_buf = g_new (guchar, width * height * bpp); gimp_pixel_rgn_get_rect (&src_rgn, src_buf, x1, y1, width, height); } /* * If we're working in intensity mode, then generate a separate intensity * map of the source image. This way, we can avoid calculating the * intensity of any given source pixel more than once. */ if (use_inten) { guchar *src; guchar *dest; src_inten_buf = g_new (guchar, width * height); for (i = 0, src = src_buf, dest = src_inten_buf ; i < (width * height) ; i++, src += bpp, dest++) { *dest = (guchar) GIMP_RGB_LUMINANCE (src[0], src[1], src[2]); } } n_regions = 0; regions[n_regions++] = &dest_rgn; if (use_msmap) regions[n_regions++] = &mask_size_map_rgn; if (use_emap) regions[n_regions++] = &exponent_map_rgn; for (pr = gimp_pixel_rgns_register2 (n_regions, regions); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { gint y; guchar *dest_row; guchar *src_msmap_row = NULL; guchar *src_emap_row = NULL; for (y = dest_rgn.y, dest_row = dest_rgn.data, src_msmap_row = mask_size_map_rgn.data, /* valid iff use_msmap */ src_emap_row = exponent_map_rgn.data /* valid iff use_emap */ ; y < (gint) (dest_rgn.y + dest_rgn.h) ; y++, dest_row += dest_rgn.rowstride, src_msmap_row += mask_size_map_rgn.rowstride, /* valid iff use_msmap */ src_emap_row += exponent_map_rgn.rowstride) /* valid iff use_emap */ { gint x; guchar *dest; guchar *src_msmap = NULL; guchar *src_emap = NULL; for (x = dest_rgn.x, dest = dest_row, src_msmap = src_msmap_row, /* valid iff use_msmap */ src_emap = src_emap_row /* valid iff use_emap */ ; x < (gint) (dest_rgn.x + dest_rgn.w) ; x++, dest += bpp, src_msmap += msmap_bpp, /* valid iff use_msmap */ src_emap += emap_bpp) /* valid iff use_emap */ { gint radius, radius_squared; gfloat exponent; gint mask_x1, mask_y1; gint mask_x2, mask_y2; gint mask_y; gint src_offset; guchar *src_row; guchar *src_inten_row = NULL; if (use_msmap) { gfloat factor = get_map_value (src_msmap, msmap_bpp); radius = ROUND (factor * (0.5 * ovals.mask_size)); } else { radius = (gint) ovals.mask_size / 2; } radius_squared = SQR (radius); exponent = ovals.exponent; if (use_emap) exponent *= get_map_value (src_emap, emap_bpp); if (use_inten) memset (Hist, 0, sizeof (Hist)); memset (Hist_rgb, 0, sizeof (Hist_rgb)); mask_x1 = CLAMP ((x - radius), x1, x2); mask_y1 = CLAMP ((y - radius), y1, y2); mask_x2 = CLAMP ((x + radius + 1), x1, x2); mask_y2 = CLAMP ((y + radius + 1), y1, y2); src_offset = (mask_y1 - y1) * width + (mask_x1 - x1); for (mask_y = mask_y1, src_row = src_buf + src_offset * bpp, src_inten_row = src_inten_buf + src_offset /* valid iff use_inten */ ; mask_y < mask_y2 ; mask_y++, src_row += width * bpp, src_inten_row += width) /* valid iff use_inten */ { guchar *src; guchar *src_inten = NULL; gint dy_squared = sqr_lut[ABS (mask_y - y)]; gint mask_x; for (mask_x = mask_x1, src = src_row, src_inten = src_inten_row /* valid iff use_inten */ ; mask_x < mask_x2 ; mask_x++, src += bpp, src_inten++) /* valid iff use_inten */ { gint dx_squared = sqr_lut[ABS (mask_x - x)]; gint b; /* Stay inside a circular mask area */ if ((dx_squared + dy_squared) > radius_squared) continue; if (use_inten) { gint inten = *src_inten; ++Hist[inten]; for (b = 0; b < bpp; b++) Hist_rgb[b][inten] += src[b]; } else { for (b = 0; b < bpp; b++) ++Hist_rgb[b][src[b]]; } } /* for mask_x */ } /* for mask_y */ if (use_inten) { weighted_average_color (Hist, Hist_rgb, exponent, dest, bpp); } else { gint b; for (b = 0; b < bpp; b++) dest[b] = weighted_average_value (Hist_rgb[b], exponent); } } /* for x */ } /* for y */ if (preview) { gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), &dest_rgn); } else { progress += dest_rgn.w * dest_rgn.h; gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } } /* for pr */ /* Detach from the map drawables */ if (mask_size_map_drawable) gimp_drawable_detach (mask_size_map_drawable); if (exponent_map_drawable) gimp_drawable_detach (exponent_map_drawable); if (src_inten_buf) g_free (src_inten_buf); g_free (src_buf); g_free (sqr_lut); if (!preview) { gimp_progress_update (1.0); /* Update the oil-painted region */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, width, height); } }
Preview_t * make_preview (GimpDrawable *drawable) { Preview_t *data = g_new(Preview_t, 1); GtkAdjustment *hadj; GtkAdjustment *vadj; GtkWidget *preview; GtkWidget *window; GtkWidget *button, *arrow; GtkWidget *ruler; GtkWidget *table; GtkWidget *scrollbar; gint width, height; data->drawable = drawable; data->preview = preview = gimp_preview_area_new (); g_object_set_data (G_OBJECT (preview), "preview", data); gtk_widget_set_events(GTK_WIDGET(preview), PREVIEW_MASK); g_signal_connect_after(preview, "expose-event", G_CALLBACK(preview_expose), data); g_signal_connect (preview, "size-allocate", G_CALLBACK (preview_size_allocate), (gpointer)data); /* Handle drop of links in preview widget */ gtk_drag_dest_set(preview, GTK_DEST_DEFAULT_ALL, target_table, 2, GDK_ACTION_COPY); g_signal_connect(preview, "drag-data-received", G_CALLBACK(handle_drop), NULL); data->widget_width = data->width = gimp_drawable_width(drawable->drawable_id); data->widget_height = data->height = gimp_drawable_height(drawable->drawable_id); gtk_widget_set_size_request (preview, data->widget_width, data->widget_height); /* The main table */ data->window = table = gtk_table_new(3, 3, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 1); gtk_table_set_row_spacings (GTK_TABLE (table), 1); /* Create button with arrow */ button = gtk_button_new(); gtk_widget_set_can_focus (button, FALSE); gtk_table_attach(GTK_TABLE(table), button, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_set_events(button, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); g_signal_connect(button, "button-press-event", G_CALLBACK(arrow_cb), NULL); gtk_widget_show(button); arrow = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_OUT); gtk_container_add(GTK_CONTAINER(button), arrow); gtk_widget_show(arrow); /* Create horizontal ruler */ data->hruler = ruler = gimp_ruler_new (GTK_ORIENTATION_HORIZONTAL); g_signal_connect_swapped(preview, "motion-notify-event", G_CALLBACK(GTK_WIDGET_GET_CLASS(ruler)->motion_notify_event), ruler); gtk_table_attach(GTK_TABLE(table), ruler, 1, 2, 0, 1, GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(ruler); /* Create vertical ruler */ data->vruler = ruler = gimp_ruler_new (GTK_ORIENTATION_VERTICAL); g_signal_connect_swapped(preview, "motion-notify-event", G_CALLBACK(GTK_WIDGET_GET_CLASS(ruler)->motion_notify_event), ruler); gtk_table_attach(GTK_TABLE(table), ruler, 0, 1, 1, 2, GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); gtk_widget_show(ruler); window = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(window), GTK_POLICY_NEVER, GTK_POLICY_NEVER); width = (data->width > 600) ? 600 : data->width; height = (data->height > 400) ? 400 : data->height; gtk_widget_set_size_request(window, width, height); gtk_table_attach(GTK_TABLE(table), window, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(window); hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (window)); g_signal_connect (hadj, "changed", G_CALLBACK (scroll_adj_changed), data->hruler); g_signal_connect (hadj, "value-changed", G_CALLBACK (scroll_adj_changed), data->hruler); vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (window)); g_signal_connect (vadj, "changed", G_CALLBACK (scroll_adj_changed), data->vruler); g_signal_connect (vadj, "value-changed", G_CALLBACK (scroll_adj_changed), data->vruler); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(window), preview); scrollbar = gtk_hscrollbar_new (hadj); gtk_table_attach(GTK_TABLE(table), scrollbar, 1, 2, 2, 3, GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0); gtk_widget_show (scrollbar); scrollbar = gtk_vscrollbar_new (vadj); gtk_table_attach(GTK_TABLE(table), scrollbar, 2, 3, 1, 2, GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0); gtk_widget_show (scrollbar); gtk_widget_show (preview); gimp_pixel_rgn_init(&data->src_rgn, drawable, 0, 0, data->width, data->height, FALSE, FALSE); render_preview(data, &data->src_rgn); gtk_widget_show(table); return data; }
static void dofilter (GimpDrawable *drawable) { gint i, j, k, channels; gint x1, y1, x2, y2; GimpPixelRgn rgn_in, rgn_out; guchar *inrow; guchar *outrow; /* Gets upper left and lower right coordinates, * and layers number in the image */ gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); channels = gimp_drawable_bpp (drawable->drawable_id); /* Initialises two PixelRgns, one to read original data, * and the other to write output data. That second one will * be merged at the end by the call to * gimp_drawable_merge_shadow() */ gimp_pixel_rgn_init (&rgn_in, drawable, x1, y1, x2 - x1, y2 - y1, FALSE, FALSE); gimp_pixel_rgn_init (&rgn_out, drawable, x1, y1, x2 - x1, y2 - y1, TRUE, TRUE); /* Initialise enough memory for inrow, outrow */ inrow = g_new (guchar, channels * (x2 - x1)); outrow = g_new (guchar, channels * (x2 - x1)); /* EXAMPLE USAGE of the functions to get the range */ // guchar minp[4],maxp[4]; // getrange(drawable, minp, maxp, x1, x2, y1, y2); for (i = y1; i < y2; i++) { /* Get row i into inrow array*/ gimp_pixel_rgn_get_row (&rgn_in, inrow, x1, i, x2 - x1); for (j = x1; j < x2; j++) { /* For each layer get the color * pixels */ guchar rgb[4]; for (k = 0; k < 4; k++) { if (k<channels) rgb[k] = inrow[channels * (j - x1) + k]; else rgb[k] = 0; } /* YOUR MAIN CODE HERE : should modify the values inside the rgb array*/ for (k = 0; k < channels; k++) { float l = 255.0f * log(1 + rgb[k])/log(256.0f); rgb[k] = (guchar) floor(l); } /* END OF YOUR MAIN CODE HERE */ /* write the new rgb values to the pixels of the outrow */ for (k = 0; k < channels; k++){ outrow[channels * (j - x1) + k] = rgb[k]; } } /*end for j each pixel of the row*/ gimp_pixel_rgn_set_row (&rgn_out, outrow, x1, i, x2 - x1); if (i % 10 == 0) gimp_progress_update ((gdouble) (i - x1) / (gdouble) (x2 - x1)); } /*end for i each row*/ g_free (inrow); g_free (outrow); /* Update the modified region */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, x2 - x1, y2 - y1); }
static gboolean focusblur_fft_buffer_update_source (FblurFftBuffer *fft, GimpDrawable *drawable, GimpPreview *preview) { GimpPixelRgn pr; gsize size; gint x1, x2, y1, y2; gint width, height; gint ntiles; fft->source.drawable = drawable; fft->source.preview = preview; gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); if (preview) { gint px1, px2, py1, py2; gint pw, ph; gimp_preview_get_position (GIMP_PREVIEW (preview), &px1, &py1); gimp_preview_get_size (GIMP_PREVIEW (preview), &pw, &ph); px2 = px1 + pw; py2 = py1 + ph; x1 = MAX (px1, x1); x2 = MIN (px2, x2); y1 = MAX (py1, y1); y2 = MIN (py2, y2); } g_assert (x1 < x2); g_assert (y1 < y2); width = x2 - x1; height = y2 - y1; ntiles = 1 + x2 / TILE_WIDTH - x1 / TILE_WIDTH; gimp_tile_cache_ntiles (ntiles); fft->source.has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); fft->source.bpp = drawable->bpp; fft->source.channels = drawable->bpp - (fft->source.has_alpha ? 1 : 0); fft->source.rowstride = drawable->bpp * width; size = fft->source.rowstride * height; if (fft->source.data_preview) { if (! preview) { g_free (fft->source.data_preview); fft->source.data_preview = NULL; } else if (size != fft->source.size) { g_free (fft->source.data_preview); goto allocate2; } } else { allocate2: if (preview) { fft->source.data_preview = g_malloc (size); if (! fft->source.data_preview) return FALSE; } } if (fft->source.data) { if (size != fft->source.size) { g_free (fft->source.data); goto allocate; } } else { allocate: fft->source.size = size; fft->source.data = g_malloc (size); if (! fft->source.data) return FALSE; goto reload; } if (x1 == fft->source.x1 && x2 == fft->source.x2 && y1 == fft->source.y1 && y2 == fft->source.y2) return TRUE; reload: fft->source.x1 = x1; fft->source.x2 = x2; fft->source.y1 = y1; fft->source.y2 = y2; fft->source.width = width; fft->source.height = height; /* need to recount */ fft->depth.count = 0; /* load */ gimp_pixel_rgn_init (&pr, drawable, x1, y1, width, height, FALSE, FALSE); gimp_pixel_rgn_get_rect (&pr, fft->source.data, fft->source.x1, fft->source.y1, fft->source.width, fft->source.height); return TRUE; }
/* do the analyzing */ static void analyze (GimpDrawable *drawable) { GimpPixelRgn srcPR; guchar *src_row, *cmap; gint x, y, numcol; gint x1, y1, x2, y2; guchar r, g, b; gint a; guchar idx; gboolean gray; gboolean has_alpha; gboolean has_sel; guchar *sel; GimpPixelRgn selPR; gint ofsx, ofsy; GimpDrawable *selDrawable; gimp_progress_init (_("Colorcube Analysis")); gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); /* * Get the size of the input image (this will/must be the same * as the size of the output image). */ width = drawable->width; height = drawable->height; bpp = drawable->bpp; has_sel = !gimp_selection_is_empty (imageID); gimp_drawable_offsets (drawable->drawable_id, &ofsx, &ofsy); /* initialize the pixel region */ gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE); cmap = gimp_image_get_colormap (imageID, &numcol); gray = (gimp_drawable_is_gray (drawable->drawable_id) || gimp_item_is_channel (drawable->drawable_id)); has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); selDrawable = gimp_drawable_get (gimp_image_get_selection (imageID)); gimp_pixel_rgn_init (&selPR, selDrawable, 0, 0, width, height, FALSE, FALSE); /* allocate row buffer */ src_row = g_new (guchar, (x2 - x1) * bpp); sel = g_new (guchar, x2 - x1); for (y = y1; y < y2; y++) { gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y, (x2 - x1)); if (has_sel) gimp_pixel_rgn_get_row (&selPR, sel, x1 + ofsx, y + ofsy, (x2 - x1)); for (x = 0; x < x2 - x1; x++) { /* Start with full opacity. */ a = 255; /* * If the image is indexed, fetch RGB values * from colormap. */ if (cmap) { idx = src_row[x * bpp]; r = cmap[idx * 3]; g = cmap[idx * 3 + 1]; b = cmap[idx * 3 + 2]; if (has_alpha) a = src_row[x * bpp + 1]; } else if (gray) { r = g = b = src_row[x * bpp]; if (has_alpha) a = src_row[x * bpp + 1]; } else { r = src_row[x * bpp]; g = src_row[x * bpp + 1]; b = src_row[x * bpp + 2]; if (has_alpha) a = src_row[x * bpp + 3]; } if (has_sel) a *= sel[x]; else a *= 255; if (a != 0) insertcolor (r, g, b, (gdouble) a * (1.0 / (255.0 * 255.0))); } /* tell the user what we're doing */ if ((y % 10) == 0) gimp_progress_update ((gdouble) y / (gdouble) (y2 - y1)); } gimp_progress_update (1.0); /* clean up */ gimp_drawable_detach (selDrawable); g_free (src_row); g_free (sel); }
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, beta; 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_TRANSPARENT_FILL); gimp_drawable_offsets (drawable_id, &x1, &y1); gimp_layer_set_offsets (curl_layer->drawable_id, sel_x1 + x1, sel_y1 + 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)); beta = alpha / 2; /* 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_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; }
static void compute_difference (GimpDrawable *drawable, GimpDrawable *drawable1, GimpDrawable *drawable2, guchar *maxval) { GimpPixelRgn src1_rgn, src2_rgn, dest_rgn; gint width, height; gint bpp; gpointer pr; gint x, y, k; gint x1, y1, x2, y2; gboolean has_alpha; *maxval = 0; gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); width = (x2 - x1); height = (y2 - y1); if (width < 1 || height < 1) return; bpp = drawable->bpp; has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); gimp_pixel_rgn_init (&src1_rgn, drawable1, 0, 0, drawable1->width, drawable1->height, FALSE, FALSE); gimp_pixel_rgn_init (&src2_rgn, drawable2, 0, 0, drawable1->width, drawable1->height, FALSE, FALSE); gimp_pixel_rgn_init (&dest_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, TRUE); for (pr = gimp_pixel_rgns_register (3, &src1_rgn, &src2_rgn, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { guchar *src1 = src1_rgn.data; guchar *src2 = src2_rgn.data; guchar *dest = dest_rgn.data; gint row = src1_rgn.y - y1; for (y = 0; y < src1_rgn.h; y++, row++) { guchar *s1 = src1; guchar *s2 = src2; guchar *d = dest; gint col = src1_rgn.x - x1; for (x = 0; x < src1_rgn.w; x++, col++) { if (has_alpha) { for (k = 0; k < bpp-1; k++) { d[k] = CLAMP0255 (s1[k] - s2[k]); *maxval = MAX (d[k], *maxval); } } else { for (k = 0; k < bpp; k++) { d[k] = CLAMP0255 (s1[k] - s2[k]); *maxval = MAX (d[k], *maxval); } } s1 += bpp; s2 += bpp; d += bpp; } src1 += src1_rgn.rowstride; src2 += src2_rgn.rowstride; dest += dest_rgn.rowstride; } } }
static void clear_curled_region (gint32 drawable_id) { GimpPixelRgn src_rgn, dest_rgn; gpointer pr; gint x = 0; gint y = 0; guint x1, y1, i; guchar *dest, *src, *pp, *sp; guint alpha_pos, progress, max_progress; GimpDrawable *drawable; max_progress = 2 * sel_width * sel_height; progress = max_progress / 2; drawable = gimp_drawable_get (drawable_id); gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1)); gimp_pixel_rgn_init (&src_rgn, drawable, sel_x1, sel_y1, true_sel_width, true_sel_height, FALSE, FALSE); gimp_pixel_rgn_init (&dest_rgn, drawable, sel_x1, sel_y1, true_sel_width, true_sel_height, TRUE, TRUE); alpha_pos = dest_rgn.bpp - 1; for (pr = gimp_pixel_rgns_register (2, &dest_rgn, &src_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { dest = dest_rgn.data; src = src_rgn.data; for (y1 = dest_rgn.y; y1 < dest_rgn.y + dest_rgn.h; y1++) { sp = src; 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_x1 : sel_width - 1 - (x1 - sel_x1)); y = (CURL_EDGE_UPPER (curl.edge) ? y1 - sel_y1 : sel_height - 1 - (y1 - sel_y1)); break; case CURL_ORIENTATION_HORIZONTAL: x = (CURL_EDGE_LOWER (curl.edge) ? y1 - sel_y1 : sel_width - 1 - (y1 - sel_y1)); y = (CURL_EDGE_LEFT (curl.edge) ? x1 - sel_x1 : sel_height - 1 - (x1 - sel_x1)); break; } for (i = 0; i < alpha_pos; i++) pp[i] = sp[i]; if (right_of_diagr (x, y) || (right_of_diagm (x, y) && below_diagb (x, y) && !inside_circle (x, y))) { /* Right of the curl */ pp[alpha_pos] = 0; } else { pp[alpha_pos] = sp[alpha_pos]; } pp += dest_rgn.bpp; sp += src_rgn.bpp; } src += src_rgn.rowstride; dest += dest_rgn.rowstride; } progress += dest_rgn.w * dest_rgn.h; gimp_progress_update ((double) progress / (double) max_progress); } gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable_id, TRUE); gimp_drawable_update (drawable_id, sel_x1, sel_y1, true_sel_width, true_sel_height); gimp_drawable_detach (drawable); }
static void gauss_rle (GimpDrawable *drawable, gdouble radius, gint pass, gboolean show_progress) { GimpPixelRgn src_rgn, dest_rgn; gint width, height; gint bytes; gint has_alpha; guchar *dest, *dp; guchar *src, *sp; gint *buf, *bb; gint pixels; gint total = 1; gint x1, y1, x2, y2; gint i, row, col, b; gint start, end; gdouble progress, max_progress; gint *curve; gint *sum = NULL; gint val; gint length; gint initial_p, initial_m; gdouble std_dev; if (radius <= 0.0) return; gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); width = (x2 - x1); height = (y2 - y1); if (width < 1 || height < 1) return; bytes = drawable->bpp; has_alpha = gimp_drawable_has_alpha(drawable->drawable_id); buf = g_new (gint, MAX (width, height) * 2); /* allocate buffers for source and destination pixels */ src = g_new (guchar, MAX (width, height) * bytes); dest = g_new (guchar, MAX (width, height) * bytes); gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); gimp_pixel_rgn_init (&dest_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, TRUE); progress = 0.0; max_progress = 2 * width * height; /* First the vertical pass */ radius = fabs (radius) + 1.0; std_dev = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0))); curve = make_curve (std_dev, &length); sum = g_new (gint, 2 * length + 1); sum[0] = 0; for (i = 1; i <= length*2; i++) sum[i] = curve[i-length-1] + sum[i-1]; sum += length; total = sum[length] - sum[-length]; for (col = 0; col < width; col++) { gimp_pixel_rgn_get_col (&src_rgn, src, col + x1, y1, (y2 - y1)); if (has_alpha) multiply_alpha (src, height, bytes); sp = src; dp = dest; for (b = 0; b < bytes; b++) { initial_p = sp[b]; initial_m = sp[(height-1) * bytes + b]; /* Determine a run-length encoded version of the row */ run_length_encode (sp + b, buf, bytes, height); for (row = 0; row < height; row++) { start = (row < length) ? -row : -length; end = (height <= (row + length) ? (height - row - 1) : length); val = 0; i = start; bb = buf + (row + i) * 2; if (start != -length) val += initial_p * (sum[start] - sum[-length]); while (i < end) { pixels = bb[0]; i += pixels; if (i > end) i = end; val += bb[1] * (sum[i] - sum[start]); bb += (pixels * 2); start = i; } if (end != length) val += initial_m * (sum[length] - sum[end]); dp[row * bytes + b] = val / total; } } if (has_alpha) separate_alpha (dest, height, bytes); gimp_pixel_rgn_set_col (&dest_rgn, dest, col + x1, y1, (y2 - y1)); if (show_progress) { progress += height; if ((col % 32) == 0) gimp_progress_update (0.5 * (pass + (progress / max_progress))); } } /* prepare for the horizontal pass */ gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, TRUE); /* Now the horizontal pass */ for (row = 0; row < height; row++) { gimp_pixel_rgn_get_row (&src_rgn, src, x1, row + y1, (x2 - x1)); if (has_alpha) multiply_alpha (src, width, bytes); sp = src; dp = dest; for (b = 0; b < bytes; b++) { initial_p = sp[b]; initial_m = sp[(width-1) * bytes + b]; /* Determine a run-length encoded version of the row */ run_length_encode (sp + b, buf, bytes, width); for (col = 0; col < width; col++) { start = (col < length) ? -col : -length; end = (width <= (col + length)) ? (width - col - 1) : length; val = 0; i = start; bb = buf + (col + i) * 2; if (start != -length) val += initial_p * (sum[start] - sum[-length]); while (i < end) { pixels = bb[0]; i += pixels; if (i > end) i = end; val += bb[1] * (sum[i] - sum[start]); bb += (pixels * 2); start = i; } if (end != length) val += initial_m * (sum[length] - sum[end]); dp[col * bytes + b] = val / total; } } if (has_alpha) separate_alpha (dest, width, bytes); gimp_pixel_rgn_set_row (&dest_rgn, dest, x1, row + y1, (x2 - x1)); if (show_progress) { progress += width; if ((row % 32) == 0) gimp_progress_update (0.5 * (pass + (progress / max_progress))); } } /* merge the shadow, update the drawable */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, (x2 - x1), (y2 - y1)); /* free buffers */ g_free (buf); g_free (src); g_free (dest); }
static gint32 load_image (char *filename) { GPixelRgn pixel_rgn; TileDrawable *drawable; gint32 image_ID; gint32 layer_ID; struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; FILE *infile; guchar *buf; guchar **rowbuf; char *name; int image_type; int layer_type; int tile_height; int scanlines; int i, start, end; int m; int depth = 8; /* We set up the normal JPEG error routines. */ cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; if ((infile = fopen (filename, "rb")) == NULL) { g_warning ("can't open \"%s\"\n", filename); gimp_quit (); } if( strrchr(filename,'.') && strcmp( strrchr(filename, '.'), ".jp4") == 0 ) depth = 16; name = malloc (strlen (filename) + 12); sprintf (name, "%s %s:", _("Loading"), filename); gimp_progress_init (name); free (name); 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) gimp_image_delete (image_ID); gimp_quit (); } /* 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); setup_read_icc_profile(&cinfo); for (m = 0; m < 16; m++) jpeg_save_markers(&cinfo, JPEG_APP0 + m, 0xFFFF); /* Step 3: read file parameters with jpeg_read_header() */ (void) 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. */ prepareColour( &cinfo ); /* 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. * In this example, we need to make an output work buffer of the right size. */ /* 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; /* Create a new image of the proper size and associate the filename with it. */ if(depth == 8) { switch (cinfo.output_components) { case 1: image_type = GRAY; layer_type = GRAY_IMAGE; break; case 3: image_type = RGB; layer_type = RGB_IMAGE; break; case 4: image_type = RGB; layer_type = RGBA_IMAGE; break; default: gimp_quit (); } } else { switch (cinfo.output_components) { case 1: image_type = U16_GRAY; layer_type = U16_GRAY_IMAGE; break; case 3: image_type = U16_RGB; layer_type = U16_RGB_IMAGE; break; case 4: image_type = U16_RGB; layer_type = U16_RGBA_IMAGE; break; default: gimp_quit (); } } image_ID = gimp_image_new (cinfo.output_width / (depth/8), cinfo.output_height, image_type); gimp_image_set_filename (image_ID, filename); layer_ID = gimp_layer_new (image_ID, _("Background"), cinfo.output_width / (depth/8), cinfo.output_height, layer_type, 100, NORMAL_MODE); gimp_image_add_layer (image_ID, layer_ID, 0); drawable = gimp_drawable_get (layer_ID); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE); /* 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. */ while (cinfo.output_scanline < cinfo.output_height) { start = cinfo.output_scanline; end = cinfo.output_scanline + tile_height; end = MIN (end,CAST(int) cinfo.output_height); scanlines = end - start; for (i = 0; i < scanlines; i++) jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &rowbuf[i], 1); /* for (i = start; i < end; i++) gimp_pixel_rgn_set_row (&pixel_rgn, tilerow[i - start], 0, i, drawable->width); */ if(cinfo.out_color_space == JCS_CMYK) for(i = 0; i < scanlines*drawable->width*cinfo.output_components; ++i) buf[i] = 255 - buf[i]; if(depth == 16 && 0) for(i = 0; i < scanlines*drawable->width*cinfo.output_components; ++i) { unsigned char c = buf[2*i]; buf[2*i] = buf[2*i+1]; buf[2*i+1] = c; } gimp_pixel_rgn_set_rect (&pixel_rgn, buf, 0, start, drawable->width, scanlines); gimp_progress_update ((double) cinfo.output_scanline / (double) cinfo.output_height); } // Step 6a: read icc profile { LPBYTE Buffer = NULL; size_t Len = 0; cmsHPROFILE hProfile=NULL; if (read_icc_profile(&cinfo, &Buffer, &Len)) { printf ("%s:%d %s() embedded profile found\n",__FILE__,__LINE__,__func__); } else if (read_icc_profile2(&cinfo, &Buffer, &Len)) { printf ("%s:%d %s() default profile selected\n",__FILE__,__LINE__,__func__); } if(Buffer && Len) { hProfile = cmsOpenProfileFromMem(Buffer, Len); if (hProfile) { gimp_image_set_icc_profile_by_mem (image_ID, Len, Buffer, ICC_IMAGE_PROFILE); cmsCloseProfile (hProfile); free(Buffer); printf ("%s:%d %s() set profile\n",__FILE__,__LINE__,__func__); } } } /* Step 7: Finish decompression */ jpeg_finish_decompress (&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress (&cinfo); /* 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). */ /* Tell the GIMP to display the image. */ gimp_drawable_flush (drawable); return image_ID; }
static void sobel (TileDrawable *drawable, gint do_horizontal, gint do_vertical, gint keep_sign) { GPixelRgn srcPR, destPR; gint width, height; gint num_channels; guchar *dest; guchar *prev_row; guchar *cur_row; guchar *next_row; guchar *pr; guchar *cr; guchar *nr; guchar *tmp; gint row, col; gint x1, y1, x2, y2; gint alpha; gint counter; GPrecisionType precision = gimp_drawable_precision (drawable->id); /* Get the input area. This is the bounding box of the selection in * the image (or the entire image if there is no selection). Only * operating on the input area is simply an optimization. It doesn't * need to be done for correct operation. (It simply makes it go * faster, since fewer pixels need to be operated on). */ gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2); gimp_progress_init (_("Sobel Edge Detect")); /* Get the size of the input image. (This will/must be the same * as the size of the output image. */ width = drawable->width; height = drawable->height; num_channels = drawable->num_channels; alpha = gimp_drawable_has_alpha (drawable -> id); /* allocate generic data row buffers */ prev_row = (guchar *) malloc ((x2 - x1 + 2) * drawable->bpp); cur_row = (guchar *) malloc ((x2 - x1 + 2) * drawable->bpp); next_row = (guchar *) malloc ((x2 - x1 + 2) * drawable->bpp); dest = (guchar *) malloc ((x2 - x1) * drawable->bpp); /* initialize the pixel regions */ gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height, TRUE, TRUE); /* generic data pointers to the three rows */ pr = prev_row + drawable->bpp; cr = cur_row + drawable->bpp; nr = next_row + drawable->bpp; sobel_prepare_row (&srcPR, pr, x1, y1 - 1, (x2 - x1)); sobel_prepare_row (&srcPR, cr, x1, y1, (x2 - x1)); counter = 0; /* loop through the rows, applying the sobel convolution */ for (row = y1; row < y2; row++) { /* prepare the next row */ sobel_prepare_row (&srcPR, nr, x1, row + 1, (x2 - x1)); switch(precision) { case PRECISION_U8: { guint8* d = (guint8*)dest; guint8* p = (guint8*)pr; guint8* c = (guint8*)cr; guint8* n = (guint8*)nr; gint gradient, hor_gradient, ver_gradient; for (col = 0; col < (x2 - x1) * num_channels; col++) { if (do_horizontal) hor_gradient = (p[col - num_channels] + 2 * p[col] + p[col + num_channels]) - (n[col - num_channels] + 2 * n[col] + n[col + num_channels]); else hor_gradient = 0; if (do_vertical) ver_gradient = (p[col - num_channels] + 2 * c[col - num_channels] + n[col - num_channels]) - (p[col + num_channels] + 2 * c[col + num_channels] + n[col + num_channels]); else ver_gradient = 0; if (do_vertical && do_horizontal) gradient = ROUND_TO_INT (RMS (hor_gradient, ver_gradient)) / 5.66; else { if (keep_sign) gradient = 127 + (ROUND_TO_INT ((hor_gradient + ver_gradient) / 8.0)); else gradient = ROUND_TO_INT (abs (hor_gradient + ver_gradient) / 4.0); } if (alpha && (((col + 1) % num_channels) == 0)) { *d++ = (counter == 0) ? 0 : 255; counter = 0; } else { *d++ = gradient; if (gradient > 10) counter ++; } } } break; case PRECISION_U16: { guint16* d = (guint16*)dest; guint16* p = (guint16*)pr; guint16* c = (guint16*)cr; guint16* n = (guint16*)nr; gint gradient, hor_gradient, ver_gradient; for (col = 0; col < (x2 - x1) * num_channels; col++) { if (do_horizontal) hor_gradient = (p[col - num_channels] + 2 * p[col] + p[col + num_channels]) - (n[col - num_channels] + 2 * n[col] + n[col + num_channels]); else hor_gradient = 0; if (do_vertical) ver_gradient = (p[col - num_channels] + 2 * c[col - num_channels] + n[col - num_channels]) - (p[col + num_channels] + 2 * c[col + num_channels] + n[col + num_channels]); else ver_gradient = 0; if (do_vertical && do_horizontal) gradient = ROUND_TO_INT (RMS (hor_gradient, ver_gradient)) / 5.66; else { if (keep_sign) gradient = 32767 + (ROUND_TO_INT ((hor_gradient + ver_gradient) / 8.0)); else gradient = ROUND_TO_INT (abs (hor_gradient + ver_gradient) / 4.0); } if (alpha && (((col + 1) % num_channels) == 0)) { *d++ = (counter == 0) ? 0 : 65535; counter = 0; } else { *d++ = gradient; if (gradient > (10/255.0) * 65535) counter ++; } } } break; case PRECISION_FLOAT: { gfloat* d = (gfloat*)dest; gfloat* p = (gfloat*)pr; gfloat* c = (gfloat*)cr; gfloat* n = (gfloat*)nr; gfloat gradient, hor_gradient, ver_gradient; for (col = 0; col < (x2 - x1) * num_channels; col++) { if (do_horizontal) hor_gradient = (p[col - num_channels] + 2 * p[col] + p[col + num_channels]) - (n[col - num_channels] + 2 * n[col] + n[col + num_channels]); else hor_gradient = 0; if (do_vertical) ver_gradient = (p[col - num_channels] + 2 * c[col - num_channels] + n[col - num_channels]) - (p[col + num_channels] + 2 * c[col + num_channels] + n[col + num_channels]); else ver_gradient = 0; if (do_vertical && do_horizontal) gradient = (RMS (hor_gradient, ver_gradient)) / 5.66; else { if (keep_sign) gradient = .5 + (hor_gradient + ver_gradient) / 8.0; else gradient = abs (hor_gradient + ver_gradient) / 4.0; } if (alpha && (((col + 1) % num_channels) == 0)) { *d++ = (counter == 0) ? 0.0 : 1.0; counter = 0; } else { *d++ = gradient; if (gradient > (10/255.0)) counter ++; } } } break; case PRECISION_FLOAT16: { guint16* d = (guint16*)dest; guint16* p = (guint16*)pr; guint16* c = (guint16*)cr; guint16* n = (guint16*)nr; gfloat gradient, hor_gradient, ver_gradient; ShortsFloat u,v,s, u1, v1, s1; for (col = 0; col < (x2 - x1) * num_channels; col++) { if (do_horizontal) hor_gradient = ( FLT(p[col - num_channels],u) + 2 * FLT(p[col], v) + FLT(p[col + num_channels], s) ) - ( FLT(n[col - num_channels],u1) + 2 * FLT(n[col], v1) + FLT(n[col + num_channels], s1) ); else hor_gradient = 0; if (do_vertical) ver_gradient = ( FLT(p[col - num_channels], u) + 2 * FLT (c[col - num_channels],v) + FLT(n[col - num_channels],s) ) - ( FLT(p[col + num_channels], u1) + 2 * FLT (c[col + num_channels],v1) + FLT(n[col + num_channels], s1) ); else ver_gradient = 0; if (do_vertical && do_horizontal) gradient = (RMS (hor_gradient, ver_gradient)) / 5.66; else { if (keep_sign) gradient = .5 + (hor_gradient + ver_gradient) / 8.0; else gradient = abs (hor_gradient + ver_gradient) / 4.0; } if (alpha && (((col + 1) % num_channels) == 0)) { *d++ = (counter == 0) ? 0.0 : 1.0; counter = 0; } else { *d++ = FLT16(gradient, u); if (gradient > (10/255.0)) counter ++; } } } break; } /* store the dest */ gimp_pixel_rgn_set_row (&destPR, dest, x1, row, (x2 - x1)); /* shuffle the row pointers */ tmp = pr; pr = cr; cr = nr; nr = tmp; if ((row % 5) == 0) gimp_progress_update ((double) row / (double) (y2 - y1)); } /* update the sobeled region */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->id, TRUE); gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1)); free (prev_row); free (cur_row); free (next_row); free (dest); }
ReducedImage* rcm_reduce_image (GimpDrawable *drawable, GimpDrawable *mask, gint LongerSize, gint Slctn) { guint32 image; GimpPixelRgn srcPR, srcMask; ReducedImage *temp; guchar *tempRGB, *src_row, *tempmask, *src_mask_row; gint i, j, x1, x2, y1, y2; gint RH, RW, width, height, bytes; gboolean NoSelectionMade; gint offx, offy; gdouble *tempHSV, H, S, V; bytes = drawable->bpp; temp = g_new0 (ReducedImage, 1); /* get bounds of image or selection */ gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); if (((x2-x1) != drawable->width) || ((y2-y1) != drawable->height)) NoSelectionMade = FALSE; else NoSelectionMade = TRUE; switch (Slctn) { case ENTIRE_IMAGE: x1 = 0; x2 = drawable->width; y1 = 0; y2 = drawable->height; break; case SELECTION_IN_CONTEXT: x1 = MAX (0, x1 - (x2-x1) / 2.0); x2 = MIN (drawable->width, x2 + (x2-x1) / 2.0); y1 = MAX (0, y1 - (y2-y1) / 2.0); y2 = MIN (drawable->height, y2 + (y2-y1) / 2.0); break; default: break; /* take selection dimensions */ } /* clamp to image size since this is the size of the mask */ gimp_drawable_offsets (drawable->drawable_id, &offx, &offy); image = gimp_item_get_image (drawable->drawable_id); x1 = CLAMP (x1, - offx, gimp_image_width (image) - offx); x2 = CLAMP (x2, - offx, gimp_image_width (image) - offx); y1 = CLAMP (y1, - offy, gimp_image_height (image) - offy); y2 = CLAMP (y2, - offy, gimp_image_height (image) - offy); /* calculate size of preview */ width = x2 - x1; height = y2 - y1; if (width < 1 || height < 1) return temp; if (width > height) { RW = LongerSize; RH = (float) height * (float) LongerSize / (float) width; } else { RH = LongerSize; RW = (float)width * (float) LongerSize / (float) height; } /* allocate memory */ tempRGB = g_new (guchar, RW * RH * bytes); tempHSV = g_new (gdouble, RW * RH * bytes); tempmask = g_new (guchar, RW * RH); gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&srcMask, mask, x1 + offx, y1 + offy, width, height, FALSE, FALSE); src_row = g_new (guchar, width * bytes); src_mask_row = g_new (guchar, width * bytes); /* reduce image */ for (i = 0; i < RH; i++) { gint whichcol, whichrow; whichrow = (float)i * (float)height / (float)RH; gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1 + whichrow, width); gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x1 + offx, y1 + offy + whichrow, width); for (j = 0; j < RW; j++) { whichcol = (float)j * (float)width / (float)RW; if (NoSelectionMade) tempmask[i*RW+j] = 255; else tempmask[i*RW+j] = src_mask_row[whichcol]; gimp_rgb_to_hsv4 (&src_row[whichcol*bytes], &H, &S, &V); tempRGB[i*RW*bytes+j*bytes+0] = src_row[whichcol*bytes+0]; tempRGB[i*RW*bytes+j*bytes+1] = src_row[whichcol*bytes+1]; tempRGB[i*RW*bytes+j*bytes+2] = src_row[whichcol*bytes+2]; tempHSV[i*RW*bytes+j*bytes+0] = H; tempHSV[i*RW*bytes+j*bytes+1] = S; tempHSV[i*RW*bytes+j*bytes+2] = V; if (bytes == 4) tempRGB[i*RW*bytes+j*bytes+3] = src_row[whichcol*bytes+3]; } } /* return values */ temp->width = RW; temp->height = RH; temp->rgb = tempRGB; temp->hsv = tempHSV; temp->mask = tempmask; return temp; }