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 gint32 load_raw( char* filename, FILE* file, enum pix_fmt fmt, struct raw_data* img_data, const gchar* plugin_name ) { gint nr_chls; gint x, y; gint32 img; gint32 layer; GimpDrawable* drawable; GimpPixelRgn pixel_rgn; guchar *pix_row; guint width = img_data->size[0]; guint height = img_data->size[1]; if (width <= 0 || height <= 0) { return ERROR; } img = create_new_image(filename, NULL, width, height, GIMP_RGB, &layer, &drawable, &pixel_rgn); nr_chls = gimp_drawable_bpp(drawable->drawable_id); pix_row = g_new(guchar, nr_chls * width); x = 0; y = 0; while (1) { guchar rgb[3]; if (read_rgb_pixel(file, fmt, rgb) == ERROR) return ERROR; pix_row[nr_chls * x] = rgb[IDX_RED]; pix_row[nr_chls * x + 1] = rgb[IDX_GREEN]; pix_row[nr_chls * x + 2] = rgb[IDX_BLUE]; x++; if (x == width) { gimp_pixel_rgn_set_row(&pixel_rgn, pix_row, 0, y, width); x = 0; y++; } if (y == height) break; } if (fgetc(file) != EOF) { printf("%s: warning: file contains more data\n", plugin_name); } return img; }
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); }
/* 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); } }
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 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); }
/* - 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 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 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 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); }
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 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 randomize (GimpDrawable *drawable, GimpPreview *preview) { GimpPixelRgn srcPR, destPR, destPR2, *sp, *dp, *tp; gint width, height; gint bytes; guchar *dest, *d; guchar *prev_row, *pr; guchar *cur_row, *cr; guchar *next_row, *nr; guchar *tmp; gint row, col; gint x, y; gint cnt; gint i, j, k; if (preview) { gimp_preview_get_position (preview, &x, &y); gimp_preview_get_size (preview, &width, &height); } else { if (! gimp_drawable_mask_intersect (drawable->drawable_id, &x, &y, &width, &height)) return; } bytes = drawable->bpp; /* * allocate row buffers */ prev_row = g_new (guchar, (width + 2) * bytes); cur_row = g_new (guchar, (width + 2) * bytes); next_row = g_new (guchar, (width + 2) * bytes); dest = g_new (guchar, width * bytes); /* * initialize the pixel regions */ gimp_pixel_rgn_init (&srcPR, drawable, x, y, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&destPR, drawable, x, y, width, height, TRUE, TRUE); gimp_pixel_rgn_init (&destPR2, drawable, x, y, width, height, TRUE, TRUE); sp = &srcPR; dp = &destPR; tp = NULL; pr = prev_row + bytes; cr = cur_row + bytes; nr = next_row + bytes; for (cnt = 1; cnt <= pivals.rndm_rcount; cnt++) { /* * prepare the first row and previous row */ randomize_prepare_row (sp, pr, x, y - 1, width); randomize_prepare_row (sp, cr, x, y, width); /* * loop through the rows, applying the selected convolution */ for (row = y; row < y + height; row++) { /* prepare the next row */ randomize_prepare_row (sp, nr, x, row + 1, width); d = dest; for (col = 0; col < width; col++) { if (g_rand_int_range (gr, 0, 100) <= (gint) pivals.rndm_pct) { switch (rndm_type) { /* * HURL * Just assign a random value. */ case RNDM_HURL: for (j = 0; j < bytes; j++) *d++ = g_rand_int_range (gr, 0, 256); break; /* * PICK * pick at random from a neighboring pixel. */ case RNDM_PICK: k = g_rand_int_range (gr, 0, 9); for (j = 0; j < bytes; j++) { i = col * bytes + j; switch (k) { case 0: *d++ = (gint) pr[i - bytes]; break; case 1: *d++ = (gint) pr[i]; break; case 2: *d++ = (gint) pr[i + bytes]; break; case 3: *d++ = (gint) cr[i - bytes]; break; case 4: *d++ = (gint) cr[i]; break; case 5: *d++ = (gint) cr[i + bytes]; break; case 6: *d++ = (gint) nr[i - bytes]; break; case 7: *d++ = (gint) nr[i]; break; case 8: *d++ = (gint) nr[i + bytes]; break; } } break; /* * SLUR * 80% chance it's from directly above, * 10% from above left, * 10% from above right. */ case RNDM_SLUR: k = g_rand_int_range (gr, 0, 10); for (j = 0; j < bytes; j++) { i = col*bytes + j; switch (k ) { case 0: *d++ = (gint) pr[i - bytes]; break; case 9: *d++ = (gint) pr[i + bytes]; break; default: *d++ = (gint) pr[i]; break; } } break; } /* * Otherwise, this pixel was not selected for randomization, * so use the current value. */ } else { for (j = 0; j < bytes; j++) *d++ = (gint) cr[col*bytes + j]; } } /* * Save the modified row, shuffle the row pointers, and every * so often, update the progress meter. */ gimp_pixel_rgn_set_row (dp, dest, x, row, width); tmp = pr; pr = cr; cr = nr; nr = tmp; if (! preview && PROG_UPDATE_TIME) { gdouble base = (gdouble) cnt / pivals.rndm_rcount; gdouble inc = (gdouble) row / (height * pivals.rndm_rcount); gimp_progress_update (base + inc); } } /* * if we have more cycles to perform, swap the src and dest Pixel Regions */ if (cnt < pivals.rndm_rcount) { if (tp != NULL) { tp = dp; dp = sp; sp = tp; } else { tp = &srcPR; sp = &destPR; dp = &destPR2; } } } if (! preview) gimp_progress_update (1.0); /* * update the randomized region */ if (preview) { gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), dp); } else { gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x, y, width, height); } /* * clean up after ourselves. */ g_free (prev_row); g_free (cur_row); g_free (next_row); g_free (dest); }
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); }
static void sobel (GimpDrawable *drawable, gboolean do_horizontal, gboolean do_vertical, gboolean keep_sign, GimpPreview *preview) { GimpPixelRgn srcPR, destPR; gint width, height; gint bytes; gint gradient, hor_gradient, ver_gradient; guchar *dest, *d; guchar *prev_row, *pr; guchar *cur_row, *cr; guchar *next_row, *nr; guchar *tmp; gint row, col; gint x1, y1, x2, y2; gboolean alpha; gint counter; guchar *preview_buffer = 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); gimp_progress_init (_("Sobel edge detecting")); width = x2 - x1; height = y2 - y1; } /* Get the size of the input image. (This will/must be the same * as the size of the output image. */ bytes = drawable->bpp; alpha = gimp_drawable_has_alpha (drawable->drawable_id); /* allocate row buffers */ prev_row = g_new (guchar, (width + 2) * bytes); cur_row = g_new (guchar, (width + 2) * bytes); next_row = g_new (guchar, (width + 2) * bytes); dest = g_new (guchar, width * bytes); /* initialize the pixel regions */ gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); if (preview) { preview_buffer = g_new (guchar, width * height * bytes); } else { gimp_pixel_rgn_init (&destPR, drawable, 0, 0, drawable->width, drawable->height, TRUE, TRUE); } pr = prev_row + bytes; cr = cur_row + bytes; nr = next_row + bytes; sobel_prepare_row (&srcPR, pr, x1, y1 - 1, width); sobel_prepare_row (&srcPR, cr, x1, y1, width); 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, width); d = dest; for (col = 0; col < width * bytes; col++) { hor_gradient = (do_horizontal ? ((pr[col - bytes] + 2 * pr[col] + pr[col + bytes]) - (nr[col - bytes] + 2 * nr[col] + nr[col + bytes])) : 0); ver_gradient = (do_vertical ? ((pr[col - bytes] + 2 * cr[col - bytes] + nr[col - bytes]) - (pr[col + bytes] + 2 * cr[col + bytes] + nr[col + bytes])) : 0); gradient = (do_vertical && do_horizontal) ? (ROUND (RMS (hor_gradient, ver_gradient)) / 5.66) /* always >0 */ : (keep_sign ? (127 + (ROUND ((hor_gradient + ver_gradient) / 8.0))) : (ROUND (abs (hor_gradient + ver_gradient) / 4.0))); if (alpha && (((col + 1) % bytes) == 0)) { /* the alpha channel */ *d++ = (counter == 0) ? 0 : 255; counter = 0; } else { *d++ = gradient; if (gradient > 10) counter ++; } } /* shuffle the row pointers */ tmp = pr; pr = cr; cr = nr; nr = tmp; /* store the dest */ if (preview) { memcpy (preview_buffer + width * (row - y1) * bytes, dest, width * bytes); } else { gimp_pixel_rgn_set_row (&destPR, dest, x1, row, width); if ((row % 20) == 0) gimp_progress_update ((double) row / (double) (y2 - y1)); } } if (preview) { gimp_preview_draw_buffer (preview, preview_buffer, width * bytes); g_free (preview_buffer); } else { gimp_progress_update (1.0); /* update the sobeled region */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, width, height); } g_free (prev_row); g_free (cur_row); g_free (next_row); g_free (dest); }
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 value_propagate_body (GimpDrawable *drawable, GimpPreview *preview) { GimpImageType dtype; ModeParam operation; GimpPixelRgn srcRgn, destRgn; guchar *here, *best, *dest; guchar *dest_row, *prev_row, *cur_row, *next_row; guchar *pr, *cr, *nr, *swap; gint width, height, bytes, index; gint begx, begy, endx, endy, x, y, dx; gint left_index, right_index, up_index, down_index; gpointer tmp; GimpRGB foreground; /* calculate neighbors' indexes */ left_index = (vpvals.direction_mask & (1 << Left2Right)) ? -1 : 0; right_index = (vpvals.direction_mask & (1 << Right2Left)) ? 1 : 0; up_index = (vpvals.direction_mask & (1 << Top2Bottom)) ? -1 : 0; down_index = (vpvals.direction_mask & (1 << Bottom2Top)) ? 1 : 0; operation = modes[vpvals.propagate_mode]; tmp = NULL; dtype = gimp_drawable_type (drawable->drawable_id); bytes = drawable->bpp; /* Here I use the algorithm of blur.c */ if (preview) { gimp_preview_get_position (preview, &begx, &begy); gimp_preview_get_size (preview, &width, &height); endx = begx + width; endy = begy + height; } else { if (! gimp_drawable_mask_intersect (drawable->drawable_id, &begx, &begy, &width, &height)) return; endx = begx + width; endy = begy + height; } gimp_tile_cache_ntiles (2 * ((width) / gimp_tile_width () + 1)); prev_row = g_new (guchar, (width + 2) * bytes); cur_row = g_new (guchar, (width + 2) * bytes); next_row = g_new (guchar, (width + 2) * bytes); dest_row = g_new (guchar, width * bytes); gimp_pixel_rgn_init (&srcRgn, drawable, begx, begy, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&destRgn, drawable, begx, begy, width, height, (preview == NULL), TRUE); pr = prev_row + bytes; cr = cur_row + bytes; nr = next_row + bytes; prepare_row (&srcRgn, pr, begx, (0 < begy) ? begy : begy - 1, endx-begx); prepare_row (&srcRgn, cr, begx, begy, endx-begx); best = g_new (guchar, bytes); if (!preview) gimp_progress_init (_("Value Propagate")); gimp_context_get_foreground (&foreground); gimp_rgb_get_uchar (&foreground, fore+0, fore+1, fore+2); /* start real job */ for (y = begy ; y < endy ; y++) { prepare_row (&srcRgn, nr, begx, ((y+1) < endy) ? y+1 : endy, endx-begx); for (index = 0; index < (endx - begx) * bytes; index++) dest_row[index] = cr[index]; for (x = 0 ; x < endx - begx; x++) { dest = dest_row + (x * bytes); here = cr + (x * bytes); /* *** copy source value to best value holder *** */ memcpy (best, here, bytes); if (operation.initializer) (* operation.initializer)(dtype, bytes, best, here, &tmp); /* *** gather neighbors' values: loop-unfolded version *** */ if (up_index == -1) for (dx = left_index ; dx <= right_index ; dx++) (* operation.updater)(dtype, bytes, here, pr+((x+dx)*bytes), best, tmp); for (dx = left_index ; dx <= right_index ; dx++) if (dx != 0) (* operation.updater)(dtype, bytes, here, cr+((x+dx)*bytes), best, tmp); if (down_index == 1) for (dx = left_index ; dx <= right_index ; dx++) (* operation.updater)(dtype, bytes, here, nr+((x+dx)*bytes), best, tmp); /* *** store it to dest_row*** */ (* operation.finalizer)(dtype, bytes, best, here, dest, tmp); } /* now store destline to destRgn */ gimp_pixel_rgn_set_row (&destRgn, dest_row, begx, y, endx - begx); /* shift the row pointers */ swap = pr; pr = cr; cr = nr; nr = swap; if (((y % 16) == 0) && !preview) gimp_progress_update ((gdouble) y / (gdouble) (endy - begy)); } if (preview) { gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), &destRgn); } else { /* update the region */ gimp_progress_update (1.0); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, begx, begy, endx-begx, endy-begy); } }
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); } }
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 int pr_ass_sub(PyGimpPixelRgn *self, PyObject *v, PyObject *w) { GimpPixelRgn *pr = &(self->pr); PyObject *x, *y; const guchar *buf; Py_ssize_t len, x1, x2, xs, y1, y2, ys; if (w == NULL) { PyErr_SetString(PyExc_TypeError, "can't delete subscripts"); return -1; } if (!PyString_Check(w)) { PyErr_SetString(PyExc_TypeError, "must assign string to subscript"); return -1; } if (!PyTuple_Check(v) || PyTuple_Size(v) != 2) { PyErr_SetString(PyExc_TypeError, "subscript must be a 2-tuple"); return -1; } if (!PyArg_ParseTuple(v, "OO", &x, &y)) return -1; buf = (const guchar *)PyString_AsString(w); len = PyString_Size(w); if (!buf || len > INT_MAX) { return -1; } if (PyInt_Check(x)) { x1 = PyInt_AsSsize_t(x); if (x1 < pr->x || x1 >= pr->x + pr->w) { PyErr_SetString(PyExc_IndexError, "x subscript out of range"); return -1; } if (PyInt_Check(y)) { y1 = PyInt_AsSsize_t(y); if (y1 < pr->y || y1 >= pr->y + pr->h) { PyErr_SetString(PyExc_IndexError, "y subscript out of range"); return -1; } if (len != pr->bpp) { PyErr_SetString(PyExc_TypeError, "string is wrong length"); return -1; } gimp_pixel_rgn_set_pixel(pr, buf, x1, y1); } else if (PySlice_Check(y)) { if (PySlice_GetIndices((PySliceObject *)y, pr->y + pr->h, &y1, &y2, &ys) || y1 >= y2 || ys != 1) { PyErr_SetString(PyExc_IndexError, "invalid y slice"); return -1; } if (y1 == 0) y1 = pr->y; if(y1 < pr->y || y2 < pr->y) { PyErr_SetString(PyExc_IndexError, "y subscript out of range"); return -1; } if (len != pr->bpp * (y2 - y1)) { PyErr_SetString(PyExc_TypeError, "string is wrong length"); return -1; } gimp_pixel_rgn_set_col(pr, buf, x1, y1, y2 - y1); } else { PyErr_SetString(PyExc_IndexError,"invalid y subscript"); return -1; } } else if (PySlice_Check(x)) { if (PySlice_GetIndices((PySliceObject *)x, pr->x + pr->w, &x1, &x2, &xs) || x1 >= x2 || xs != 1) { PyErr_SetString(PyExc_IndexError, "invalid x slice"); return -1; } if(x1 == 0) x1 = pr->x; if(x1 < pr->x || x2 < pr->x) { PyErr_SetString(PyExc_IndexError, "x subscript out of range"); return -1; } if (PyInt_Check(y)) { y1 = PyInt_AsSsize_t(y); if (y1 < pr->y || y1 >= pr->y + pr->h) { PyErr_SetString(PyExc_IndexError, "y subscript out of range"); return -1; } if (len != pr->bpp * (x2 - x1)) { PyErr_SetString(PyExc_TypeError, "string is wrong length"); return -1; } gimp_pixel_rgn_set_row(pr, buf, x1, y1, x2 - x1); } else if (PySlice_Check(y)) { if (PySlice_GetIndices((PySliceObject *)y, pr->y + pr->h, &y1, &y2, &ys) || y1 >= y2 || ys != 1) { PyErr_SetString(PyExc_IndexError, "invalid y slice"); return -1; } if (y1 == 0) y1 = pr->y; if(y1 < pr->y || y2 < pr->y) { PyErr_SetString(PyExc_IndexError, "y subscript out of range"); return -1; } if (len != pr->bpp * (x2 - x1) * (y2 - y1)) { PyErr_SetString(PyExc_TypeError, "string is wrong length"); return -1; } gimp_pixel_rgn_set_rect(pr, buf, x1, y1, x2 - x1, y2 - y1); } else { PyErr_SetString(PyExc_IndexError,"invalid y subscript"); return -1; } } else { PyErr_SetString(PyExc_TypeError, "invalid x subscript"); return -1; } return 0; }