static inline void randomize_prepare_row (GimpPixelRgn *pixel_rgn, guchar *data, int x, int y, int w) { gint b; if (y <= 0) { gimp_pixel_rgn_get_row(pixel_rgn, data, x, (y + 1), w); } else if (y >= pixel_rgn->h) { gimp_pixel_rgn_get_row(pixel_rgn, data, x, (y - 1), w); } else { gimp_pixel_rgn_get_row(pixel_rgn, data, x, y, w); } /* * Fill in edge pixels */ for (b = 0; b < pixel_rgn->bpp; b++) { data[-(gint)pixel_rgn->bpp + b] = data[b]; data[w * pixel_rgn->bpp + b] = data[(w - 1) * pixel_rgn->bpp + b]; } }
static void getrange (GimpDrawable *drawable, guchar *mintab, guchar *maxtab, gint x1, gint y1, gint x2, gint y2) { gint i, j, k, channels; GimpPixelRgn rgn_in; guchar *inrow; channels = gimp_drawable_bpp (drawable->drawable_id); gimp_pixel_rgn_init (&rgn_in, drawable, x1, y1, x2 - x1, y2 - y1, FALSE, FALSE); inrow = g_new (guchar, channels * (x2 - x1)); for (j = 0; j < 4; j++){ mintab[j]=255; maxtab[j]=0; } for (i = y1; i < y2; i++) { /* Get row i */ gimp_pixel_rgn_get_row (&rgn_in, inrow, x1, i, x2 - x1); for (j = x1; j < x2; j++) { for (k = 0; k < channels; k++){ mintab[k]=MIN ( inrow[channels * (j - x1) + k], mintab[k] ) ; maxtab[k]=MAX ( inrow[channels * (j - x1) + k], maxtab[k] ) ; } } } g_free (inrow); }
static void color_rotate (GimpDrawable *drawable) { GimpPixelRgn srcPR, destPR; gint width, height; gint bytes; guchar *src_row, *dest_row; gint row; gint x, y; if (! gimp_drawable_mask_intersect (drawable->drawable_id, &x, &y, &width, &height)) { return; } bytes = drawable->bpp; src_row = g_new (guchar, width * bytes); dest_row = g_new (guchar, width * bytes); gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); gimp_pixel_rgn_init (&destPR, drawable, 0, 0, drawable->width, drawable->height, TRUE, TRUE); for (row = y; row < (y + height); row++) { gimp_pixel_rgn_get_row (&srcPR, src_row, x, row, width); color_rotate_row (src_row, dest_row, row, width, bytes); gimp_pixel_rgn_set_row (&destPR, dest_row, x, row, width); if ((row % 10) == 0) gimp_progress_update ((double) row / (double) height); } /* update the processed region */ gimp_progress_update (1.0); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x, y, width, height); g_free (src_row); g_free (dest_row); }
static void prepare_row (GimpPixelRgn *pixel_rgn, guchar *data, gint x, gint y, gint w) { gint b; if (y <= 0) gimp_pixel_rgn_get_row (pixel_rgn, data, x, (y + 1), w); else if (y >= pixel_rgn->h) gimp_pixel_rgn_get_row (pixel_rgn, data, x, (y - 1), w); else gimp_pixel_rgn_get_row (pixel_rgn, data, x, y, w); /* Fill in edge pixels */ for (b = 0; b < pixel_rgn->bpp; b++) { data[-(gint)pixel_rgn->bpp + b] = data[b]; data[w * pixel_rgn->bpp + b] = data[(w - 1) * pixel_rgn->bpp + b]; } }
static void render_gray_image(Preview_t *preview_base, GimpPixelRgn *srcrgn) { guchar *src_row, *dest_buffer, *src, *dest; gint row, col; gint bpp, dwidth, dheight, pwidth, pheight; gint *src_col; GtkWidget *preview = preview_base->preview; dwidth = srcrgn->w; dheight = srcrgn->h; pwidth = preview_base->widget_width; pheight = preview_base->widget_height; bpp = srcrgn->bpp; src_row = g_new(guchar, dwidth * bpp); dest_buffer = g_new(guchar, pwidth * pheight); src_col = g_new(gint, pwidth); for (col = 0; col < pwidth; col++) src_col[col] = (col * dwidth / pwidth) * bpp; dest = dest_buffer; for (row = 0; row < pheight; row++) { gimp_pixel_rgn_get_row(srcrgn, src_row, 0, row * dheight / pheight, dwidth); src = src_row; for (col = 0; col < pwidth; col++) { src = &src_row[src_col[col]]; *dest++ = *src; } } gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview), 0, 0, pwidth, pheight, GIMP_GRAY_IMAGE, dest_buffer, pwidth); g_free(src_col); g_free(src_row); g_free(dest_buffer); }
static void blur (GimpDrawable *drawable) { gint i, j, k, channels; gint x1, y1, x2, y2; GimpPixelRgn rgn_in, rgn_out; guchar *row1, *row2, *row3; guchar *outrow; gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); channels = gimp_drawable_bpp (drawable->drawable_id); 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 row1, row2, row3, outrow */ row1 = g_new (guchar, channels * (x2 - x1)); outrow = g_new (guchar, channels * (x2 - x1)); for (i = y1; i < y2; i++) { /* Get row i-1, i, i+1 */ gimp_pixel_rgn_get_row (&rgn_in, row1, x1, MAX (y1, i - 1), x2 - x1); for (j = x1; j < x2; j++) { /* For each layer, compute the average of the nine pixels */ for (k = 0; k < channels; k++) { int in = row1[channels * (j - x1) + k]; int a = (1.0 - (in / 255.0)) * 100.0; int r = rand() % 100; outrow[channels * (j - x1) + k] = r < a ? 0 : 255; } } gimp_pixel_rgn_set_row (&rgn_out, outrow, x1, i, x2 - x1); if (i % 10 == 0) gimp_progress_update ((gdouble) (i - y1) / (gdouble) (y2 - y1)); } g_free (row1); g_free (outrow); 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 sobel_prepare_row (GimpPixelRgn *pixel_rgn, guchar *data, gint x, gint y, gint w) { gint b; y = CLAMP (y, 0, pixel_rgn->h - 1); gimp_pixel_rgn_get_row (pixel_rgn, data, x, y, w); /* Fill in edge pixels */ for (b = 0; b < pixel_rgn->bpp; b++) { data[-(int)pixel_rgn->bpp + b] = data[b]; data[w * pixel_rgn->bpp + b] = data[(w - 1) * pixel_rgn->bpp + b]; } }
static void shuffle (GimpPixelRgn *rgn_in, guchar **row, gint x1, gint y1, gint width, gint height, gint ypos) { gint i; guchar *tmp_row; /* Get tile row (i + radius + 1) into row[0] */ gimp_pixel_rgn_get_row (rgn_in, row[0], x1, MIN (ypos + radius + y1, y1 + height - 1), width); /* Permute row[i] with row[i-1] and row[0] with row[2r] */ tmp_row = row[0]; for (i = 1; i < 2 * radius + 1; i++) row[i - 1] = row[i]; row[2 * radius] = tmp_row; }
/* do the analyzing */ static void analyze (GimpDrawable *drawable) { GimpPixelRgn srcPR; guchar *src_row, *cmap; gint x, y, numcol; gint x1, y1, x2, y2, w, h; 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")); if (! gimp_drawable_mask_intersect (drawable->drawable_id, &x1, &y1, &w, &h)) return; x2 = x1 + w; y2 = y1 + h; /* * 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 < w; 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 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, x2, y2; 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); gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); bpp = gimp_drawable_bpp (drawable->drawable_id); ppm_kill (&brushppm); ppm_new (&brushppm, x2 - x1, y2 - y1); p = &brushppm; rowstride = p->width * 3; src_row = g_new (guchar, (x2 - x1) * bpp); gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, x2 - x1, y2 - y1, FALSE, FALSE); if (bpp == 3) { /* RGB */ int bpr = (x2 - x1) * 3; for (row = 0, y = y1; y < y2; row++, y++) { gimp_pixel_rgn_get_row (&src_rgn, src_row, x1, y, (x2 - x1)); memcpy (p->col + row*rowstride, src_row, bpr); } } else { /* RGBA (bpp > 3) GrayA (bpp == 2) or Gray */ gboolean is_gray = ((bpp > 3) ? TRUE : FALSE); for (row = 0, y = y1; y < y2; row++, y++) { guchar *tmprow = p->col + row * rowstride; guchar *tmprow_ptr; gimp_pixel_rgn_get_row (&src_rgn, src_row, x1, y, (x2 - x1)); src = src_row; tmprow_ptr = tmprow; /* Possible micro-optimization here: * src_end = src + src_rgn.bpp * (x2-x1); * 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 void c2g_region (GimpPixelRgn *srcPR, GimpPixelRgn *destPR, gint bytes, /* Bytes per pixel */ gdouble radius, gdouble amount_p, gdouble gamma_p, gint x1, /* Corners of subregion */ gint x2, gint y1, gint y2, gboolean show_progress) { guchar *src; guchar *dest; guchar *bigsrc; guchar *bigdest; guchar *tmpdest; gint width = x2 - x1; gint height = y2 - y1; gdouble *cmatrix = NULL; gint cmatrix_length; gdouble *ctable; gint row, col, idx; gint w = c2g_params.radius+10; gdouble amount = c2g_params.amount; gdouble gamma = c2g_params.gamma; if (show_progress) gimp_progress_init (_("Blurring...")); iir_init(c2g_params.radius); /* allocate buffers */ src = g_new (guchar, MAX (width, height) * bytes); dest = g_new (guchar, MAX (width, height) * bytes); iir.p = g_new(gdouble, MAX (width, height)+2*w); bigsrc = g_new(guchar, width * height * bytes); bigdest = g_new(guchar, width * height * bytes); tmpdest = g_new(guchar, width * height * bytes); if (show_progress) gimp_progress_init (_("Colour converting...")); // 1. Calculate Nayatani Grey and Blur in LAB gimp_pixel_rgn_get_rect (srcPR, bigsrc, x1, y1, width, height); extract_lab(bigsrc, bytes, width * height, bigdest); nayatani(bigdest,bytes,width * height, bigdest); gimp_pixel_rgn_set_rect (destPR, bigdest, x1, y1, width, height); // 2. Make a blur of Grey LAB for (row = 0, idx=0; row < height; row++, idx+=width) { gimp_pixel_rgn_get_row (destPR, src, x1, y1 + row, width); blur_line (ctable, cmatrix, cmatrix_length, src, dest, width, bytes); gimp_pixel_rgn_set_row (destPR, dest, x1, y1 + row, width); } for (col = 0; col < width; col++) { gimp_pixel_rgn_get_col (destPR, src, x1 + col, y1, height); blur_line (ctable, cmatrix, cmatrix_length, src, dest, height, bytes); gimp_pixel_rgn_set_col (destPR, dest, x1 + col, y1, height); if (show_progress && col % 8 == 0) gimp_progress_update ((gdouble) col / (3 * width) + 0.33); } // 3. Convert grey and blur back to RGB. compose_lab(bigdest, width * height, bytes, bigdest); // bigdest=greyRGB gimp_pixel_rgn_get_rect (destPR, bigsrc, x1, y1, width, height); compose_lab(bigsrc, width * height, bytes, bigsrc); // bigsrc= blurgreyRGB // 4. Blur Colour RGB and write into destPR gimp_pixel_rgn_get_rect (srcPR, tmpdest, x1, y1, width, height); gimp_pixel_rgn_set_rect (destPR, tmpdest, x1, y1, width, height); for (row = 0, idx=0; row < height; row++, idx+=width) { gimp_pixel_rgn_get_row (destPR, src, x1, y1 + row, width); blur_line (ctable, cmatrix, cmatrix_length, src, dest, width, bytes); gimp_pixel_rgn_set_row (destPR, dest, x1, y1 + row, width); } for (col = 0; col < width; col++) { gimp_pixel_rgn_get_col (destPR, src, x1 + col, y1, height); blur_line (ctable, cmatrix, cmatrix_length, src, dest, height, bytes); gimp_pixel_rgn_set_col (destPR, dest, x1 + col, y1, height); if (show_progress && col % 8 == 0) gimp_progress_update ((gdouble) col / (3 * width) + 0.33); } // destPR = blur colour RGB chromaunsharp( srcPR, destPR, bigdest, bigsrc, bytes, x1, y1, width, height, amount, gamma, tmpdest ); compose_lab(tmpdest, width * height, bytes, tmpdest); // tmpdest has unsharp gimp_pixel_rgn_set_rect (destPR, tmpdest, x1, y1, width, height); if (show_progress) gimp_progress_update (0.0); g_free (bigsrc); g_free (bigdest); g_free (tmpdest); g_free (iir.p); g_free (dest); g_free (src); }
void precompute_normals (gint x1, gint x2, gint y) { GimpVector3 *tmpv, p1, p2, p3, normal; gdouble *tmpd; gint n, i, nv; guchar *map = NULL; gint bpp = 1; guchar mapval; /* First, compute the heights */ /* ========================== */ tmpv = triangle_normals[0]; triangle_normals[0] = triangle_normals[1]; triangle_normals[1] = tmpv; tmpv = vertex_normals[0]; vertex_normals[0] = vertex_normals[1]; vertex_normals[1] = vertex_normals[2]; vertex_normals[2] = tmpv; tmpd = heights[0]; heights[0] = heights[1]; heights[1] = heights[2]; heights[2] = tmpd; if (mapvals.bumpmap_id != -1) { bpp = gimp_drawable_bpp(mapvals.bumpmap_id); } gimp_pixel_rgn_get_row (&bump_region, bumprow, x1, y, x2 - x1); if (mapvals.bumpmaptype > 0) { switch (mapvals.bumpmaptype) { case 1: map = logmap; break; case 2: map = sinemap; break; default: map = spheremap; break; } for (n = 0; n < (x2 - x1); n++) { if (bpp>1) { mapval = (guchar)((float)((bumprow[n * bpp] +bumprow[n * bpp +1] + bumprow[n * bpp + 2])/3.0 )) ; } else { mapval = bumprow[n * bpp]; } heights[2][n] = (gdouble) mapvals.bumpmax * (gdouble) map[mapval] / 255.0; } } else { for (n = 0; n < (x2 - x1); n++) { if (bpp>1) { mapval = (guchar)((float)((bumprow[n * bpp] +bumprow[n * bpp +1] + bumprow[n * bpp + 2])/3.0 )) ; } else { mapval = bumprow[n * bpp]; } heights[2][n] = (gdouble) mapvals.bumpmax * (gdouble) mapval / 255.0; } } /* Compute triangle normals */ /* ======================== */ i = 0; for (n = 0; n < (x2 - x1 - 1); n++) { p1.x = 0.0; p1.y = ystep; p1.z = heights[2][n] - heights[1][n]; p2.x = xstep; p2.y = ystep; p2.z = heights[2][n+1] - heights[1][n]; p3.x = xstep; p3.y = 0.0; p3.z = heights[1][n+1] - heights[1][n]; triangle_normals[1][i] = gimp_vector3_cross_product (&p2, &p1); triangle_normals[1][i+1] = gimp_vector3_cross_product (&p3, &p2); gimp_vector3_normalize (&triangle_normals[1][i]); gimp_vector3_normalize (&triangle_normals[1][i+1]); i += 2; } /* Compute vertex normals */ /* ====================== */ i = 0; gimp_vector3_set (&normal, 0.0, 0.0, 0.0); for (n = 0; n < (x2 - x1 - 1); n++) { nv = 0; if (n > 0) { if (y > 0) { gimp_vector3_add (&normal, &normal, &triangle_normals[0][i-1]); gimp_vector3_add (&normal, &normal, &triangle_normals[0][i-2]); nv += 2; } if (y < pre_h) { gimp_vector3_add (&normal, &normal, &triangle_normals[1][i-1]); nv++; } } if (n <pre_w) { if (y > 0) { gimp_vector3_add (&normal, &normal, &triangle_normals[0][i]); gimp_vector3_add (&normal, &normal, &triangle_normals[0][i+1]); nv += 2; } if (y < pre_h) { gimp_vector3_add (&normal, &normal, &triangle_normals[1][i]); gimp_vector3_add (&normal, &normal, &triangle_normals[1][i+1]); nv += 2; } } gimp_vector3_mul (&normal, 1.0 / (gdouble) nv); gimp_vector3_normalize (&normal); vertex_normals[1][n] = normal; i += 2; } }
gboolean draw_page_cairo (GtkPrintContext *context, PrintData *data) { GimpDrawable *drawable = gimp_drawable_get (data->drawable_id); GimpPixelRgn region; cairo_t *cr; cairo_surface_t *surface; guchar *pixels; gdouble cr_width; gdouble cr_height; gdouble cr_dpi_x; gdouble cr_dpi_y; gint width; gint height; gint stride; gint y; gdouble scale_x; gdouble scale_y; width = drawable->width; height = drawable->height; gimp_tile_cache_ntiles (width / gimp_tile_width () + 1); cr = gtk_print_context_get_cairo_context (context); cr_width = gtk_print_context_get_width (context); cr_height = gtk_print_context_get_height (context); cr_dpi_x = gtk_print_context_get_dpi_x (context); cr_dpi_y = gtk_print_context_get_dpi_y (context); scale_x = cr_dpi_x / data->xres; scale_y = cr_dpi_y / data->yres; #if 0 /* print header if it is requested */ if (data->show_info_header) { draw_info_header (context, cr, data); /* In points */ #define HEADER_HEIGHT (20 * 72.0 / 25.4) cairo_translate (cr, 0, HEADER_HEIGHT); cr_height -= HEADER_HEIGHT; } #endif cairo_translate (cr, data->offset_x / cr_dpi_x * 72.0, data->offset_y / cr_dpi_y * 72.0); cairo_scale (cr, scale_x, scale_y); gimp_pixel_rgn_init (®ion, drawable, 0, 0, width, height, FALSE, FALSE); surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); pixels = cairo_image_surface_get_data (surface); stride = cairo_image_surface_get_stride (surface); for (y = 0; y < height; y++, pixels += stride) { gimp_pixel_rgn_get_row (®ion, pixels, 0, y, width); switch (drawable->bpp) { case 3: convert_from_rgb (pixels, width); break; case 4: convert_from_rgba (pixels, width); break; } if (y % 16 == 0) gimp_progress_update ((gdouble) y / (gdouble) height); } cairo_set_source_surface (cr, surface, 0, 0); cairo_rectangle (cr, 0, 0, width, height); cairo_fill (cr); cairo_surface_destroy (surface); gimp_progress_update (1.0); gimp_drawable_detach (drawable); return TRUE; }
/* Interpol linearly height[2] and triangle_normals[1] * using the next row */ void interpol_row (gint x1, gint x2, gint y) { GimpVector3 p1, p2, p3; gint n, i; guchar *map = NULL; gint bpp = 1; guchar* bumprow1 = NULL; guchar* bumprow2 = NULL; if (mapvals.bumpmap_id != -1) { bpp = gimp_drawable_bpp(mapvals.bumpmap_id); } bumprow1 = g_new (guchar, pre_w * bpp); bumprow2 = g_new (guchar, pre_w * bpp); gimp_pixel_rgn_get_row (&bump_region, bumprow1, x1, y, x2 - x1); gimp_pixel_rgn_get_row (&bump_region, bumprow2, x1, y+1, x2 - x1); if (mapvals.bumpmaptype > 0) { switch (mapvals.bumpmaptype) { case 1: map = logmap; break; case 2: map = sinemap; break; default: map = spheremap; break; } } for (n = 0; n < (x2 - x1); n++) { gdouble diff; guchar mapval; guchar mapval1, mapval2; if (bpp>1) { mapval1 = (guchar)((float)((bumprow1[n * bpp] +bumprow1[n * bpp +1] + bumprow1[n * bpp + 2])/3.0 )) ; mapval2 = (guchar)((float)((bumprow2[n * bpp] +bumprow2[n * bpp +1] + bumprow2[n * bpp + 2])/3.0 )) ; } else { mapval1 = bumprow1[n * bpp]; mapval2 = bumprow2[n * bpp]; } diff = mapval1 - mapval2; mapval = (guchar) CLAMP (mapval1 + diff, 0.0, 255.0); if (mapvals.bumpmaptype > 0) { heights[1][n] = (gdouble) mapvals.bumpmax * (gdouble) map[mapval1] / 255.0; heights[2][n] = (gdouble) mapvals.bumpmax * (gdouble) map[mapval] / 255.0; } else { heights[1][n] = (gdouble) mapvals.bumpmax * (gdouble) mapval1 / 255.0; heights[2][n] = (gdouble) mapvals.bumpmax * (gdouble) mapval / 255.0; } } i = 0; for (n = 0; n < (x2 - x1 - 1); n++) { /* heights rows 1 and 2 are inverted */ p1.x = 0.0; p1.y = ystep; p1.z = heights[1][n] - heights[2][n]; p2.x = xstep; p2.y = ystep; p2.z = heights[1][n+1] - heights[2][n]; p3.x = xstep; p3.y = 0.0; p3.z = heights[2][n+1] - heights[2][n]; triangle_normals[1][i] = gimp_vector3_cross_product (&p2, &p1); triangle_normals[1][i+1] = gimp_vector3_cross_product (&p3, &p2); gimp_vector3_normalize (&triangle_normals[1][i]); gimp_vector3_normalize (&triangle_normals[1][i+1]); i += 2; } g_free (bumprow1); g_free (bumprow2); }
static void render_rgb_image(Preview_t *preview_base, GimpPixelRgn *srcrgn) { guchar *src_row, *dest_buffer, *src, *dest; gint row, col; gint dwidth, dheight, pwidth, pheight; gint *src_col; gint bpp, alpha, has_alpha, b; guchar check; gboolean gray = get_map_info()->show_gray; GtkWidget *preview = preview_base->preview; dwidth = srcrgn->w; dheight = srcrgn->h; pwidth = preview_base->widget_width; pheight = preview_base->widget_height; bpp = srcrgn->bpp; alpha = bpp; has_alpha = gimp_drawable_has_alpha(srcrgn->drawable->drawable_id); if (has_alpha) alpha--; src_row = g_new(guchar, dwidth * bpp); dest_buffer = g_new(guchar, pwidth * pheight * bpp); src_col = g_new(gint, pwidth); for (col = 0; col < pwidth; col++) src_col[col] = (col * dwidth / pwidth) * bpp; dest = dest_buffer; for (row = 0; row < pheight; row++) { gimp_pixel_rgn_get_row(srcrgn, src_row, 0, row * dheight / pheight, dwidth); for (col = 0; col < pwidth; col++) { src = &src_row[src_col[col]]; if(!has_alpha || src[alpha] == OPAQUE) { /* no alpha channel or opaque -- simple way */ for (b = 0; b < alpha; b++) dest[b] = src[b]; } else { /* more or less transparent */ if( ( col % (CHECKWIDTH*2) < CHECKWIDTH ) ^ ( row % (CHECKWIDTH*2) < CHECKWIDTH ) ) check = LIGHTCHECK; else check = DARKCHECK; if (src[alpha] == 0) { /* full transparent -- check */ for (b = 0; b < alpha; b++) dest[b] = check; } else { /* middlemost transparent -- mix check and src */ for (b = 0; b < alpha; b++) dest[b] = (src[b] * src[alpha] + check * (OPAQUE - src[alpha])) / OPAQUE; } } if (gray) { guchar avg; avg = (299 * dest[0] + 587 * dest[1] + 114 * dest[2]) / 1000; for (b = 0; b < alpha; b++) dest[b] = avg; } dest += alpha; } } gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview), 0, 0, pwidth, pheight, GIMP_RGB_IMAGE, dest_buffer, pwidth * 3); g_free(src_col); g_free(src_row); g_free(dest_buffer); }
static void do_acrop (GimpDrawable *drawable, gint32 image_id) { GimpPixelRgn srcPR; gint iwidth, iheight; gint x, y, l; guchar *buffer; gint xmin, xmax, ymin, ymax; gint *layers = NULL; gint numlayers; iwidth = gimp_image_width(image_id); iheight = gimp_image_height(image_id); /* Set each edge to the opposite side -- i.e. xmin (the left edge * of the final cropped image) starts at the right edge. */ xmin = iwidth - 1; xmax = 1; ymin = iheight - 1; ymax = 1; buffer = g_malloc ((iwidth > iheight ? iwidth : iheight) * drawable->bpp); layers = gimp_image_get_layers (image_id, &numlayers); for (l=0; l<numlayers; ++l) { gint dwidth, dheight; gint layerOffsetX, layerOffsetY; gint bytes; gint start; drawable = gimp_drawable_get(layers[l]); dwidth = drawable->width; dheight = drawable->height; bytes = drawable->bpp; /* Relate the layer coordinates to the image coordinates */ gimp_drawable_offsets (layers[l], &layerOffsetX, &layerOffsetY); /* initialize the pixel region to this layer */ gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, dwidth, dheight, FALSE, FALSE); /* Update ymin. If the layer offset is greater than ymin, * then the region to be cropped already contains the whole layer * and we don't have to look any farther. */ start = 0; if (layerOffsetY < 0) start = -layerOffsetY; for (y = start; y < dheight && layerOffsetY + y < ymin; y++) { gimp_pixel_rgn_get_row (&srcPR, buffer, 0, y, dwidth); for (x = 0; x < dwidth * bytes; x += bytes) { if (!colours_equal (buffer, &buffer[x], bytes)) { /* convert this layer coordinate back to image coord */ ymin = y + layerOffsetY; break; } } } /* Update ymax. If the layer's offset plus height is less than * ymax, then the region to be cropped already contains the * whole layer and we don't have to look any farther. */ start = dheight - 1; if (layerOffsetY + dheight > iheight) start = iheight - layerOffsetY - 1; for (y = start; y > 0 && layerOffsetY + y > ymax; y--) { gimp_pixel_rgn_get_row (&srcPR, buffer, 0, y, dwidth); for (x = 0; x < dwidth * bytes; x += bytes) { if (!colours_equal (buffer, &buffer[x], bytes)) { /* convert this layer coordinate back to image coord */ ymax = y + layerOffsetY + 1; break; } } } /* Update xmin. If the layer offset is greater than ymin, * then the region to be cropped already contains the whole layer * and we don't have to look any farther. */ start = 0; if (layerOffsetX < 0) start = -layerOffsetX; for (x = start; x < dwidth && layerOffsetX + x < xmin; x++) { gimp_pixel_rgn_get_col (&srcPR, buffer, x, 0, dheight); for (y = 0; y < dheight * bytes; y += bytes) { if (!colours_equal (buffer, &buffer[y], bytes)) { /* convert this layer coordinate back to image coord */ xmin = x + layerOffsetX; break; } } } /* Update xmax. If the layer's offset plus width is less than * xmax, then the region to be cropped already contains the * whole layer and we don't have to look any farther. */ start = dwidth - 1; if (layerOffsetX + dwidth > iwidth) start = iwidth - layerOffsetX - 1; for (x = start; x > 0 && layerOffsetX + x > xmax; x--) { gimp_pixel_rgn_get_col (&srcPR, buffer, x, 0, dheight); for (y = 0; y < dheight * bytes; y += bytes) { if (!colours_equal (buffer, &buffer[y], bytes)) { /* convert this layer coordinate back to image coord */ xmax = x + layerOffsetX + 1; break; } } } gimp_progress_update ((gdouble)l / numlayers); } if (xmin == 0 && xmax == iwidth && ymin == 0 && ymax == iheight) { g_message ("Nothing to crop."); return; } gimp_image_undo_group_start (image_id); gimp_image_crop(image_id, xmax - xmin, ymax - ymin, xmin, ymin); g_free (layers); g_free (buffer); gimp_progress_update (1.00); gimp_image_undo_group_end (image_id); }
static void grid (gint32 image_ID, GimpDrawable *drawable, GimpPreview *preview) { GimpPixelRgn srcPR, destPR; gint bytes; gint x_offset, y_offset; guchar *dest, *buffer = NULL; gint x, y; gboolean alpha; gboolean blend; guchar hcolor[4]; guchar vcolor[4]; guchar icolor[4]; guchar *cmap; gint ncolors; gimp_rgba_get_uchar (&grid_cfg.hcolor, hcolor, hcolor + 1, hcolor + 2, hcolor + 3); gimp_rgba_get_uchar (&grid_cfg.vcolor, vcolor, vcolor + 1, vcolor + 2, vcolor + 3); gimp_rgba_get_uchar (&grid_cfg.icolor, icolor, icolor + 1, icolor + 2, icolor + 3); switch (gimp_image_base_type (image_ID)) { case GIMP_RGB: blend = TRUE; break; case GIMP_GRAY: hcolor[0] = gimp_rgb_luminance_uchar (&grid_cfg.hcolor); vcolor[0] = gimp_rgb_luminance_uchar (&grid_cfg.vcolor); icolor[0] = gimp_rgb_luminance_uchar (&grid_cfg.icolor); blend = TRUE; break; case GIMP_INDEXED: cmap = gimp_image_get_colormap (image_ID, &ncolors); hcolor[0] = best_cmap_match (cmap, ncolors, &grid_cfg.hcolor); vcolor[0] = best_cmap_match (cmap, ncolors, &grid_cfg.vcolor); icolor[0] = best_cmap_match (cmap, ncolors, &grid_cfg.icolor); g_free (cmap); blend = FALSE; break; default: g_assert_not_reached (); blend = FALSE; } bytes = drawable->bpp; alpha = gimp_drawable_has_alpha (drawable->drawable_id); if (preview) { gimp_preview_get_position (preview, &sx1, &sy1); gimp_preview_get_size (preview, &sx2, &sy2); buffer = g_new (guchar, bytes * sx2 * sy2); sx2 += sx1; sy2 += sy1; } else { gimp_drawable_mask_bounds (drawable->drawable_id, &sx1, &sy1, &sx2, &sy2); gimp_pixel_rgn_init (&destPR, drawable, 0, 0, sx2 - sx1, sy2 - sy1, TRUE, TRUE); } gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, sx2 - sx1, sy2 - sy1, FALSE, FALSE); dest = g_new (guchar, (sx2 - sx1) * bytes); for (y = sy1; y < sy2; y++) { gimp_pixel_rgn_get_row (&srcPR, dest, sx1, y, (sx2 - sx1)); y_offset = y - grid_cfg.hoffset; while (y_offset < 0) y_offset += grid_cfg.hspace; if ((y_offset + (grid_cfg.hwidth / 2)) % grid_cfg.hspace < grid_cfg.hwidth) { for (x = sx1; x < sx2; x++) { pix_composite (&dest[(x-sx1) * bytes], hcolor, bytes, blend, alpha); } } for (x = sx1; x < sx2; x++) { x_offset = grid_cfg.vspace + x - grid_cfg.voffset; while (x_offset < 0) x_offset += grid_cfg.vspace; if ((x_offset + (grid_cfg.vwidth / 2)) % grid_cfg.vspace < grid_cfg.vwidth) { pix_composite (&dest[(x-sx1) * bytes], vcolor, bytes, blend, alpha); } if ((x_offset + (grid_cfg.iwidth / 2)) % grid_cfg.vspace < grid_cfg.iwidth && ((y_offset % grid_cfg.hspace >= grid_cfg.ispace && y_offset % grid_cfg.hspace < grid_cfg.ioffset) || (grid_cfg.hspace - (y_offset % grid_cfg.hspace) >= grid_cfg.ispace && grid_cfg.hspace - (y_offset % grid_cfg.hspace) < grid_cfg.ioffset))) { pix_composite (&dest[(x-sx1) * bytes], icolor, bytes, blend, alpha); } } if ((y_offset + (grid_cfg.iwidth / 2)) % grid_cfg.hspace < grid_cfg.iwidth) { for (x = sx1; x < sx2; x++) { x_offset = grid_cfg.vspace + x - grid_cfg.voffset; while (x_offset < 0) x_offset += grid_cfg.vspace; if ((x_offset % grid_cfg.vspace >= grid_cfg.ispace && x_offset % grid_cfg.vspace < grid_cfg.ioffset) || (grid_cfg.vspace - (x_offset % grid_cfg.vspace) >= grid_cfg.ispace && grid_cfg.vspace - (x_offset % grid_cfg.vspace) < grid_cfg.ioffset)) { pix_composite (&dest[(x-sx1) * bytes], icolor, bytes, blend, alpha); } } } if (preview) { memcpy (buffer + (y - sy1) * (sx2 - sx1) * bytes, dest, (sx2 - sx1) * bytes); } else { gimp_pixel_rgn_set_row (&destPR, dest, sx1, y, (sx2 - sx1)); if (y % 16 == 0) gimp_progress_update ((gdouble) y / (gdouble) (sy2 - sy1)); } } g_free (dest); if (preview) { gimp_preview_draw_buffer (preview, buffer, bytes * (sx2 - sx1)); g_free (buffer); } else { gimp_progress_update (1.0); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, sx1, sy1, sx2 - sx1, sy2 - sy1); } }
gint guess_new_size (GtkWidget * button, PreviewData * p_data, GuessDir direction) { gint32 disc_layer_ID; GimpDrawable *drawable; gint z1, z2, k; gint z1min, z1max, z2max; gint width, height; gint lw, lh; gint x_off, y_off; gint bpp, c_bpp; GimpPixelRgn rgn_in; guchar *line; gboolean has_alpha; gdouble sum; gint mask_size; gint max_mask_size = 0; gint old_size; gint new_size; disc_layer_ID = p_data->vals->disc_layer_ID; switch (direction) { case GUESS_DIR_HOR: old_size = p_data->old_width; break; case GUESS_DIR_VERT: old_size = p_data->old_height; break; default: g_message("You just found a bug"); return 0; } LAYER_CHECK_ACTION(disc_layer_ID, gtk_dialog_response (GTK_DIALOG (dlg), RESPONSE_REFRESH), old_size); width = gimp_drawable_width (disc_layer_ID); height = gimp_drawable_height (disc_layer_ID); has_alpha = gimp_drawable_has_alpha (disc_layer_ID); bpp = gimp_drawable_bpp (disc_layer_ID); c_bpp = bpp - (has_alpha ? 1 : 0); drawable = gimp_drawable_get (disc_layer_ID); gimp_pixel_rgn_init (&rgn_in, drawable, 0, 0, width, height, FALSE, FALSE); gimp_drawable_offsets (disc_layer_ID, &x_off, &y_off); x_off -= p_data->x_off; y_off -= p_data->y_off; lw = (MIN (p_data->old_width, width + x_off) - MAX (0, x_off)); lh = (MIN (p_data->old_height, height + y_off) - MAX (0, y_off)); switch (direction) { case GUESS_DIR_HOR: z1min = MAX (0, y_off); z1max = MIN (p_data->old_height, height + y_off); z2max = lw; break; case GUESS_DIR_VERT: z1min = MAX (0, x_off); z1max = MIN (p_data->old_width, width + x_off); z2max = lh; break; default: g_message("You just found a bug"); return 0; } line = g_try_new (guchar, bpp * z2max); for (z1 = z1min; z1 < z1max; z1++) { switch (direction) { case GUESS_DIR_HOR: gimp_pixel_rgn_get_row (&rgn_in, line, MAX (0, -x_off), z1 - y_off, z2max); break; case GUESS_DIR_VERT: gimp_pixel_rgn_get_col (&rgn_in, line, z1 - x_off, MAX (0, -y_off), z2max); break; } mask_size = 0; for (z2 = 0; z2 < z2max; z2++) { sum = 0; for (k = 0; k < c_bpp; k++) { sum += line[bpp * z2 + k]; } sum /= (255 * c_bpp); if (has_alpha) { sum *= (gdouble) line[bpp * (z2 + 1) - 1] / 255; } if (sum >= (0.5 / c_bpp)) { mask_size++; } } if (mask_size > max_mask_size) { max_mask_size = mask_size; } } new_size = old_size - max_mask_size; g_free (line); gimp_drawable_detach (drawable); return new_size; }
static void blur (GimpDrawable *drawable) { gint i, ii, channels; gint x1, y1, x2, y2; GimpPixelRgn rgn_in, rgn_out; guchar **row; guchar *outrow; gint width, height; gimp_progress_init ("My Blur..."); /* Gets upper left and lower right coordinates, * and layers number in the image */ gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); width = x2 - x1; height = y2 - y1; channels = gimp_drawable_bpp (drawable->drawable_id); /* Allocate a big enough tile cache */ gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1)); /* 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, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&rgn_out, drawable, x1, y1, width, height, TRUE, TRUE); /* Allocate memory for input and output tile rows */ init_mem (&row, &outrow, width * channels); for (ii = -radius; ii <= radius; ii++) { gimp_pixel_rgn_get_row (&rgn_in, row[radius + ii], x1, y1 + CLAMP (ii, 0, height - 1), width); } for (i = 0; i < height; i++) { /* To be done for each tile row */ process_row (row, outrow, x1, y1, width, height, channels, i); gimp_pixel_rgn_set_row (&rgn_out, outrow, x1, i + y1, width); /* shift tile rows to insert the new one at the end */ shuffle (&rgn_in, row, x1, y1, width, height, i); if (i % 10 == 0) gimp_progress_update ((gdouble) i / (gdouble) height); } /* We could also put that in a separate function but it's * rather simple */ for (ii = 0; ii < 2 * radius + 1; ii++) g_free (row[ii]); g_free (row); 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, width, height); }
static void sinusrow (GimpDrawable *drawable) { gint i, j, k, channels; gint x1, y1, x2, y2; GimpPixelRgn rgn_in, rgn_out; guchar *inrow; guchar *outrow; /* 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); /* Initialise enough memory for inrow, outrow */ inrow = g_new (guchar, channels * (x2 - x1)); outrow = g_new (guchar, channels * (x2 - x1)); guchar minp[4],maxp[4]; getrange(drawable, minp, maxp, x1, x2, y1, y2); for (i = y1; i < y2; i++) { /* Get row i */ gimp_pixel_rgn_get_row (&rgn_in, inrow, x1, i, x2 - x1); for (j = x1; j < x2; j++) { /* For each layer, compute the average of the nine * pixels */ for (k = 0; k < channels; k++) { double angle = inrow[channels * (j - x1) + k], max=255; angle = M_2_PI * (angle / max ) ; outrow[channels * (j - x1) + k] = (guchar)(255*(1+sin(angle))/2); } } /*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 void sharpen (GimpDrawable *drawable) { GimpPixelRgn src_rgn; /* Source image region */ GimpPixelRgn dst_rgn; /* Destination image region */ guchar *src_rows[4]; /* Source pixel rows */ guchar *src_ptr; /* Current source pixel */ guchar *dst_row; /* Destination pixel row */ intneg *neg_rows[4]; /* Negative coefficient rows */ intneg *neg_ptr; /* Current negative coefficient */ gint i; /* Looping vars */ gint y; /* Current location in image */ gint row; /* Current row in src_rows */ gint count; /* Current number of filled src_rows */ gint width; /* Byte width of the image */ gint x1; /* Selection bounds */ gint y1; gint y2; gint sel_width; /* Selection width */ gint sel_height; /* Selection height */ gint img_bpp; /* Bytes-per-pixel in image */ void (*filter)(int, guchar *, guchar *, intneg *, intneg *, intneg *); filter = NULL; if (! gimp_drawable_mask_intersect (drawable->drawable_id, &x1, &y1, &sel_width, &sel_height)) return; y2 = y1 + sel_height; img_bpp = gimp_drawable_bpp (drawable->drawable_id); /* * Let the user know what we're doing... */ gimp_progress_init (_("Sharpening")); /* * Setup for filter... */ gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, sel_width, sel_height, FALSE, FALSE); gimp_pixel_rgn_init (&dst_rgn, drawable, x1, y1, sel_width, sel_height, TRUE, TRUE); compute_luts (); width = sel_width * img_bpp; for (row = 0; row < 4; row ++) { src_rows[row] = g_new (guchar, width); neg_rows[row] = g_new (intneg, width); } dst_row = g_new (guchar, width); /* * Pre-load the first row for the filter... */ gimp_pixel_rgn_get_row (&src_rgn, src_rows[0], x1, y1, sel_width); for (i = width, src_ptr = src_rows[0], neg_ptr = neg_rows[0]; i > 0; i --, src_ptr ++, neg_ptr ++) *neg_ptr = neg_lut[*src_ptr]; row = 1; count = 1; /* * Select the filter... */ switch (img_bpp) { case 1 : filter = gray_filter; break; case 2 : filter = graya_filter; break; case 3 : filter = rgb_filter; break; case 4 : filter = rgba_filter; break; }; /* * Sharpen... */ for (y = y1; y < y2; y ++) { /* * Load the next pixel row... */ if ((y + 1) < y2) { /* * Check to see if our src_rows[] array is overflowing yet... */ if (count >= 3) count --; /* * Grab the next row... */ gimp_pixel_rgn_get_row (&src_rgn, src_rows[row], x1, y + 1, sel_width); for (i = width, src_ptr = src_rows[row], neg_ptr = neg_rows[row]; i > 0; i --, src_ptr ++, neg_ptr ++) *neg_ptr = neg_lut[*src_ptr]; count ++; row = (row + 1) & 3; } else { /* * No more pixels at the bottom... Drop the oldest samples... */ count --; } /* * Now sharpen pixels and save the results... */ if (count == 3) { (* filter) (sel_width, src_rows[(row + 2) & 3], dst_row, neg_rows[(row + 1) & 3] + img_bpp, neg_rows[(row + 2) & 3] + img_bpp, neg_rows[(row + 3) & 3] + img_bpp); /* * Set the row... */ gimp_pixel_rgn_set_row (&dst_rgn, dst_row, x1, y, sel_width); } else if (count == 2) { if (y == y1) /* first row */ gimp_pixel_rgn_set_row (&dst_rgn, src_rows[0], x1, y, sel_width); else /* last row */ gimp_pixel_rgn_set_row (&dst_rgn, src_rows[(sel_height - 1) & 3], x1, y, sel_width); } if ((y & 15) == 0) gimp_progress_update ((gdouble) (y - y1) / (gdouble) sel_height); } /* * OK, we're done. Free all memory used... */ for (row = 0; row < 4; row ++) { g_free (src_rows[row]); g_free (neg_rows[row]); } g_free (dst_row); /* * Update the screen... */ gimp_progress_update (1.0); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, sel_width, sel_height); }
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*/ /* EXAMPLE OF CODE : */ float h,s,b; RGBtoHSB (rgb,&h,&s,&b); h=180.0f*(1.0f + cos(h * M_2_PI / 360.0f)); HSBtoRGB(h,s,b,rgb); /* 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 void render_indexed_image(Preview_t *preview_base, GimpPixelRgn *srcrgn) { guchar *src_row, *dest_buffer, *src, *dest; gint row, col; gint dwidth, dheight, pwidth, pheight; gint *src_col; gint bpp, alpha, has_alpha; guchar *cmap, *colour; gint ncols; gboolean gray = get_map_info()->show_gray; GtkWidget *preview = preview_base->preview; dwidth = srcrgn->w; dheight = srcrgn->h; pwidth = preview_base->widget_width; pheight = preview_base->widget_height; bpp = srcrgn->bpp; alpha = bpp; has_alpha = gimp_drawable_has_alpha(srcrgn->drawable->drawable_id); if (has_alpha) alpha--; cmap = gimp_image_get_colormap (gimp_item_get_image (srcrgn->drawable->drawable_id), &ncols); src_row = g_new(guchar, dwidth * bpp); dest_buffer = g_new(guchar, pwidth * pheight * 3); src_col = g_new(gint, pwidth); for (col = 0; col < pwidth; col++) src_col[col] = (col * dwidth / pwidth) * bpp; dest = dest_buffer; for (row = 0; row < pheight; row++) { gimp_pixel_rgn_get_row(srcrgn, src_row, 0, row * dheight / pheight, dwidth); for (col = 0; col < pwidth; col++) { src = &src_row[src_col[col]]; colour = cmap + 3 * (int)(*src); if (gray) { guchar avg = (299 * colour[0] + 587 * colour[1] + 114 * colour[2]) / 1000; *dest++ = avg; *dest++ = avg; *dest++ = avg; } else { *dest++ = colour[0]; *dest++ = colour[1]; *dest++ = colour[2]; } } } gimp_preview_area_draw(GIMP_PREVIEW_AREA(preview), 0, 0, pwidth, pheight, GIMP_RGB_IMAGE, dest_buffer, pwidth * 3); g_free(src_col); g_free(src_row); g_free(dest_buffer); }
static void neon (GimpDrawable *drawable, gdouble radius, gdouble amount, GimpPreview *preview) { GimpPixelRgn src_rgn, dest_rgn; gint width, height; gint bytes, bpp; gboolean has_alpha; guchar *dest; guchar *src, *src2, *sp_p, *sp_m; gdouble n_p[5], n_m[5]; gdouble d_p[5], d_m[5]; gdouble bd_p[5], bd_m[5]; gdouble *val_p, *val_m, *vp, *vm; gint x1, y1, x2, y2; gint i, j; gint row, col, b; gint terms; gint progress = 0, max_progress = 1; gint initial_p[4]; gint initial_m[4]; gdouble std_dev; guchar *preview_buffer1 = NULL; guchar *preview_buffer2 = NULL; 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); } if (radius < 1.0) return; bytes = drawable->bpp; bpp = bytes; has_alpha = gimp_drawable_has_alpha(drawable->drawable_id); if (has_alpha) bpp--; val_p = g_new (gdouble, MAX (width, height) * bytes); val_m = g_new (gdouble, MAX (width, height) * bytes); src = g_new (guchar, MAX (width, height) * bytes); src2 = 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); if (preview) { preview_buffer1 = g_new (guchar, width * height * bytes); preview_buffer2 = g_new (guchar, width * height * bytes); } else { gimp_pixel_rgn_init (&dest_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, TRUE); progress = 0; max_progress = (radius < 1.0 ) ? 0 : width * height * radius * 2; } /* First the vertical pass */ radius = fabs (radius) + 1.0; std_dev = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0))); /* derive the constants for calculating the gaussian from the std dev */ find_constants (n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev); for (col = 0; col < width; col++) { memset (val_p, 0, height * bytes * sizeof (gdouble)); memset (val_m, 0, height * bytes * sizeof (gdouble)); gimp_pixel_rgn_get_col (&src_rgn, src, col + x1, y1, (y2 - y1)); sp_p = src; sp_m = src + (height - 1) * bytes; vp = val_p; vm = val_m + (height - 1) * bytes; /* Set up the first vals */ for (i = 0; i < bytes; i++) { initial_p[i] = sp_p[i]; initial_m[i] = sp_m[i]; } for (row = 0; row < height; row++) { gdouble *vpptr, *vmptr; terms = (row < 4) ? row : 4; for (b = 0; b < bpp; b++) { vpptr = vp + b; vmptr = vm + b; for (i = 0; i <= terms; i++) { *vpptr += n_p[i] * sp_p[(-i * bytes) + b] - d_p[i] * vp[(-i * bytes) + b]; *vmptr += n_m[i] * sp_m[(i * bytes) + b] - d_m[i] * vm[(i * bytes) + b]; } for (j = i; j <= 4; j++) { *vpptr += (n_p[j] - bd_p[j]) * initial_p[b]; *vmptr += (n_m[j] - bd_m[j]) * initial_m[b]; } } if (has_alpha) { vp[bpp] = sp_p[bpp]; vm[bpp] = sp_m[bpp]; } sp_p += bytes; sp_m -= bytes; vp += bytes; vm -= bytes; } transfer_pixels (val_p, val_m, dest, bytes, height); if (preview) { for (row = 0 ; row < height ; row++) memcpy (preview_buffer1 + (row * width + col) * bytes, dest + bytes * row, bytes); } else { gimp_pixel_rgn_set_col (&dest_rgn, dest, col + x1, y1, (y2 - y1)); progress += height * radius; if ((col % 20) == 0) gimp_progress_update ((double) progress / (double) max_progress); } } /* Now the horizontal pass */ gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); for (row = 0; row < height; row++) { memset (val_p, 0, width * bytes * sizeof (gdouble)); memset (val_m, 0, width * bytes * sizeof (gdouble)); gimp_pixel_rgn_get_row (&src_rgn, src, x1, row + y1, (x2 - x1)); if (preview) { memcpy (src2, preview_buffer1 + row * width * bytes, width * bytes); } else { gimp_pixel_rgn_get_row (&dest_rgn, src2, x1, row + y1, (x2 - x1)); } sp_p = src; sp_m = src + (width - 1) * bytes; vp = val_p; vm = val_m + (width - 1) * bytes; /* Set up the first vals */ for (i = 0; i < bytes; i++) { initial_p[i] = sp_p[i]; initial_m[i] = sp_m[i]; } for (col = 0; col < width; col++) { gdouble *vpptr, *vmptr; terms = (col < 4) ? col : 4; for (b = 0; b < bpp; b++) { vpptr = vp + b; vmptr = vm + b; for (i = 0; i <= terms; i++) { *vpptr += n_p[i] * sp_p[(-i * bytes) + b] - d_p[i] * vp[(-i * bytes) + b]; *vmptr += n_m[i] * sp_m[(i * bytes) + b] - d_m[i] * vm[(i * bytes) + b]; } for (j = i; j <= 4; j++) { *vpptr += (n_p[j] - bd_p[j]) * initial_p[b]; *vmptr += (n_m[j] - bd_m[j]) * initial_m[b]; } } if (has_alpha) { vp[bpp] = sp_p[bpp]; vm[bpp] = sp_m[bpp]; } sp_p += bytes; sp_m -= bytes; vp += bytes; vm -= bytes; } transfer_pixels (val_p, val_m, dest, bytes, width); combine_to_gradient (dest, src2, bytes, width, amount); if (preview) { memcpy (preview_buffer2 + row * width * bytes, dest, width * bytes); } else { gimp_pixel_rgn_set_row (&dest_rgn, dest, x1, row + y1, (x2 - x1)); progress += width * radius; if ((row % 20) == 0) gimp_progress_update ((double) progress / (double) max_progress); } } if (preview) { gimp_preview_draw_buffer (preview, preview_buffer2, width * bytes); g_free (preview_buffer1); g_free (preview_buffer2); } else { gimp_progress_update (1.0); /* now, merge horizontal and vertical into a magnitude */ gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, TRUE); /* 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 up buffers */ g_free (val_p); g_free (val_m); g_free (src); g_free (src2); g_free (dest); }
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); }
/* do the exchanging */ static void exchange (GimpDrawable *drawable, GimpPreview *preview) { GimpPixelRgn srcPR, destPR; guchar min_red, min_green, min_blue; guchar max_red, max_green, max_blue; guchar from_red, from_green, from_blue; guchar to_red, to_green, to_blue; guchar *src_row, *dest_row; gint x, y, bpp = drawable->bpp; gboolean has_alpha; gint x1, y1, y2; gint width, height; GimpRGB min; GimpRGB max; if (preview) { gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); } else if (! gimp_drawable_mask_intersect (drawable->drawable_id, &x1, &y1, &width, &height)) { return; } y2 = y1 + height; has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); /* allocate memory */ src_row = g_new (guchar, drawable->width * bpp); gimp_rgb_get_uchar (&xargs.from, &from_red, &from_green, &from_blue); gimp_rgb_get_uchar (&xargs.to, &to_red, &to_green, &to_blue); /* get boundary values */ min = xargs.from; gimp_rgb_subtract (&min, &xargs.threshold); gimp_rgb_clamp (&min); gimp_rgb_get_uchar (&min, &min_red, &min_green, &min_blue); max = xargs.from; gimp_rgb_add (&max, &xargs.threshold); gimp_rgb_clamp (&max); gimp_rgb_get_uchar (&max, &max_red, &max_green, &max_blue); dest_row = g_new (guchar, drawable->width * bpp); gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&destPR, drawable, x1, y1, width, height, (preview == NULL), TRUE); for (y = y1; y < y2; y++) { gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y, width); for (x = 0; x < width; x++) { guchar pixel_red, pixel_green, pixel_blue; guchar new_red, new_green, new_blue; guint idx; /* get current pixel-values */ pixel_red = src_row[x * bpp]; pixel_green = src_row[x * bpp + 1]; pixel_blue = src_row[x * bpp + 2]; idx = x * bpp; /* want this pixel? */ if (pixel_red >= min_red && pixel_red <= max_red && pixel_green >= min_green && pixel_green <= max_green && pixel_blue >= min_blue && pixel_blue <= max_blue) { guchar red_delta, green_delta, blue_delta; red_delta = pixel_red > from_red ? pixel_red - from_red : from_red - pixel_red; green_delta = pixel_green > from_green ? pixel_green - from_green : from_green - pixel_green; blue_delta = pixel_blue > from_blue ? pixel_blue - from_blue : from_blue - pixel_blue; new_red = CLAMP (to_red + red_delta, 0, 255); new_green = CLAMP (to_green + green_delta, 0, 255); new_blue = CLAMP (to_blue + blue_delta, 0, 255); } else { new_red = pixel_red; new_green = pixel_green; new_blue = pixel_blue; } /* fill buffer */ dest_row[idx + 0] = new_red; dest_row[idx + 1] = new_green; dest_row[idx + 2] = new_blue; /* copy alpha-channel */ if (has_alpha) dest_row[idx + 3] = src_row[x * bpp + 3]; } /* store the dest */ gimp_pixel_rgn_set_row (&destPR, dest_row, x1, y, width); /* and tell the user what we're doing */ if (!preview && (y % 10) == 0) gimp_progress_update ((gdouble) y / (gdouble) height); } g_free (src_row); g_free (dest_row); if (preview) { gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), &destPR); } else { gimp_progress_update (1.0); /* update the processed region */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, width, height); } }
/* - Filter function - I wish all filter functions had a pmode :) */ static void glasstile (GimpDrawable *drawable, GimpPreview *preview) { GimpPixelRgn srcPR, destPR; gint width, height; gint bytes; guchar *dest, *d; guchar *cur_row; gint row, col, i; gint x1, y1, x2, y2; /* Translations of variable names from Maswan * rutbredd = grid width * ruthojd = grid height * ymitt = y middle * xmitt = x middle */ gint rutbredd, xpixel1, xpixel2; gint ruthojd , ypixel2; gint xhalv, xoffs, xmitt, xplus; gint yhalv, yoffs, ymitt, yplus; 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; } bytes = drawable->bpp; cur_row = g_new (guchar, width * bytes); dest = g_new (guchar, width * bytes); /* initialize the pixel regions, set grid height/width */ gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&destPR, drawable, x1, y1, width, height, preview == NULL, TRUE); rutbredd = gtvals.xblock; ruthojd = gtvals.yblock; xhalv = rutbredd / 2; yhalv = ruthojd / 2; xplus = rutbredd % 2; yplus = ruthojd % 2; ymitt = y1; yoffs = 0; /* Loop through the rows */ for (row = y1; row < y2; row++) { d = dest; ypixel2 = ymitt + yoffs * 2; ypixel2 = CLAMP (ypixel2, 0, y2 - 1); gimp_pixel_rgn_get_row (&srcPR, cur_row, x1, ypixel2, width); yoffs++; /* if current offset = half, do a displacement next time around */ if (yoffs == yhalv) { ymitt += ruthojd; yoffs = - (yhalv + yplus); } xmitt = 0; xoffs = 0; for (col = 0; col < x2 - x1; col++) /* one pixel */ { xpixel1 = (xmitt + xoffs) * bytes; xpixel2 = (xmitt + xoffs * 2) * bytes; if (xpixel2 < (x2 - x1) * bytes) { if (xpixel2 < 0) xpixel2 = 0; for (i = 0; i < bytes; i++) d[xpixel1 + i] = cur_row[xpixel2 + i]; } else { for (i = 0; i < bytes; i++) d[xpixel1 + i] = cur_row[xpixel1 + i]; } xoffs++; if (xoffs == xhalv) { xmitt += rutbredd; xoffs = - (xhalv + xplus); } } /* Store the dest */ gimp_pixel_rgn_set_row (&destPR, dest, x1, row, width); if (!preview && ((row % 5) == 0)) { gimp_progress_update ((gdouble) row / (gdouble) height); } } /* Update region */ if (preview) { gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), &destPR); } else { gimp_progress_update (1.0); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, width, height); } g_free (cur_row); g_free (dest); }
static void rotate_drawable (GimpDrawable *drawable) { GimpPixelRgn srcPR, destPR; gint width, height; gint longside; gint bytes; gint row, col; gint offsetx, offsety; gboolean was_lock_alpha = FALSE; guchar *buffer; guchar *src_row, *dest_row; /* initialize */ row = 0; /* Get the size of the input drawable. */ width = drawable->width; height = drawable->height; bytes = drawable->bpp; if (gimp_layer_get_lock_alpha (drawable->drawable_id)) { was_lock_alpha = TRUE; gimp_layer_set_lock_alpha (drawable->drawable_id, FALSE); } if (rotvals.angle == 2) /* we're rotating by 180° */ { gimp_tile_cache_ntiles (2 * (width / gimp_tile_width() + 1)); gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height, TRUE, TRUE); src_row = (guchar *) g_malloc (width * bytes); dest_row = (guchar *) g_malloc (width * bytes); for (row = 0; row < height; row++) { gimp_pixel_rgn_get_row (&srcPR, src_row, 0, row, width); for (col = 0; col < width; col++) { memcpy (dest_row + col * bytes, src_row + (width - 1 - col) * bytes, bytes); } gimp_pixel_rgn_set_row (&destPR, dest_row, 0, (height - row - 1), width); if ((row % 5) == 0) gimp_progress_update ((double) row / (double) height); } g_free (src_row); g_free (dest_row); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, 0, 0, width, height); } else /* we're rotating by 90° or 270° */ { (width > height) ? (longside = width) : (longside = height); gimp_layer_resize (drawable->drawable_id, longside, longside, 0, 0); drawable = gimp_drawable_get (drawable->drawable_id); gimp_drawable_flush (drawable); gimp_tile_cache_ntiles ((longside / gimp_tile_width () + 1) + (longside / gimp_tile_height () + 1)); gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, longside, longside, FALSE, FALSE); gimp_pixel_rgn_init (&destPR, drawable, 0, 0, longside, longside, TRUE, TRUE); buffer = g_malloc (longside * bytes); if (rotvals.angle == 1) /* we're rotating by 90° */ { for (row = 0; row < height; row++) { gimp_pixel_rgn_get_row (&srcPR, buffer, 0, row, width); gimp_pixel_rgn_set_col (&destPR, buffer, (height - row - 1), 0, width); if ((row % 5) == 0) gimp_progress_update ((double) row / (double) height); } } else /* we're rotating by 270° */ { for (col = 0; col < width; col++) { gimp_pixel_rgn_get_col (&srcPR, buffer, col, 0, height); gimp_pixel_rgn_set_row (&destPR, buffer, 0, (width - col - 1), height); if ((col % 5) == 0) gimp_progress_update ((double) col / (double) width); } } g_free (buffer); gimp_progress_update (1.0); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, 0, 0, height, width); gimp_layer_resize (drawable->drawable_id, height, width, 0, 0); drawable = gimp_drawable_get (drawable->drawable_id); gimp_drawable_flush (drawable); gimp_drawable_update (drawable->drawable_id, 0, 0, height, width); } gimp_drawable_offsets (drawable->drawable_id, &offsetx, &offsety); rotate_compute_offsets (&offsetx, &offsety, gimp_image_width (image_ID), gimp_image_height (image_ID), width, height); gimp_layer_set_offsets (drawable->drawable_id, offsetx, offsety); if (was_lock_alpha) gimp_layer_set_lock_alpha (drawable->drawable_id, TRUE); return; }
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 void do_zcrop (GimpDrawable *drawable, gint32 image_id) { GimpPixelRgn srcPR, destPR; gint width, height, x, y; gint bytes; guchar *buffer; gint8 *killrows; gint8 *killcols; gint32 livingrows, livingcols, destrow, destcol; gint total_area, area; gboolean has_alpha; width = drawable->width; height = drawable->height; bytes = drawable->bpp; total_area = width * height * 4; area = 0; killrows = g_new (gint8, height); killcols = g_new (gint8, width); buffer = g_malloc ((width > height ? width : height) * bytes); /* 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); has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); livingrows = 0; for (y = 0; y < height; y++) { gimp_pixel_rgn_get_row (&srcPR, buffer, 0, y, width); killrows[y] = TRUE; for (x = 0; x < width * bytes; x += bytes) { if (! colors_equal (buffer, &buffer[x], bytes, has_alpha)) { livingrows++; killrows[y] = FALSE; break; } } area += width; if (y % 20 == 0) gimp_progress_update ((double) area / (double) total_area); } livingcols = 0; for (x = 0; x < width; x++) { gimp_pixel_rgn_get_col (&srcPR, buffer, x, 0, height); killcols[x] = TRUE; for (y = 0; y < height * bytes; y += bytes) { if (! colors_equal (buffer, &buffer[y], bytes, has_alpha)) { livingcols++; killcols[x] = FALSE; break; } } area += height; if (x % 20 == 0) gimp_progress_update ((double) area / (double) total_area); } if ((livingcols == 0 || livingrows==0) || (livingcols == width && livingrows == height)) { g_message (_("Nothing to crop.")); g_free (killrows); g_free (killcols); return; } destrow = 0; for (y = 0; y < height; y++) { if (!killrows[y]) { gimp_pixel_rgn_get_row (&srcPR, buffer, 0, y, width); gimp_pixel_rgn_set_row (&destPR, buffer, 0, destrow, width); destrow++; } area += width; if (y % 20 == 0) gimp_progress_update ((double) area / (double) total_area); } destcol = 0; gimp_pixel_rgn_init(&srcPR, drawable, 0, 0, width, height, FALSE, TRUE); for (x = 0; x < width; x++) { if (!killcols[x]) { gimp_pixel_rgn_get_col (&srcPR, buffer, x, 0, height); gimp_pixel_rgn_set_col (&destPR, buffer, destcol, 0, height); destcol++; } area += height; if (x % 20 == 0) gimp_progress_update ((double) area / (double) total_area); } g_free (buffer); g_free (killrows); g_free (killcols); gimp_progress_update (1.00); gimp_image_undo_group_start (image_id); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_image_crop (image_id, livingcols, livingrows, 0, 0); gimp_image_undo_group_end (image_id); }