static gdouble gimp_levels_config_input_from_color (GimpHistogramChannel channel, const GimpRGB *color) { switch (channel) { case GIMP_HISTOGRAM_VALUE: return MAX (MAX (color->r, color->g), color->b); case GIMP_HISTOGRAM_RED: return color->r; case GIMP_HISTOGRAM_GREEN: return color->g; case GIMP_HISTOGRAM_BLUE: return color->b; case GIMP_HISTOGRAM_ALPHA: return color->a; case GIMP_HISTOGRAM_RGB: return MIN (MIN (color->r, color->g), color->b); case GIMP_HISTOGRAM_LUMINANCE: return GIMP_RGB_LUMINANCE (color->r, color->g, color->b); } return 0.0; }
static gboolean gimp_operation_colorize_process (GeglOperation *operation, void *in_buf, void *out_buf, glong samples, const GeglRectangle *roi, gint level) { GimpOperationPointFilter *point = GIMP_OPERATION_POINT_FILTER (operation); GimpColorizeConfig *config = GIMP_COLORIZE_CONFIG (point->config); gfloat *src = in_buf; gfloat *dest = out_buf; GimpHSL hsl; if (! config) return FALSE; hsl.h = config->hue; hsl.s = config->saturation; hsl.a = src[ALPHA]; while (samples--) { GimpRGB rgb; gfloat lum = GIMP_RGB_LUMINANCE (src[RED], src[GREEN], src[BLUE]); if (config->lightness > 0) { lum = lum * (1.0 - config->lightness); lum += 1.0 - (1.0 - config->lightness); } else if (config->lightness < 0) { lum = lum * (config->lightness + 1.0); } hsl.l = lum; gimp_hsl_to_rgb (&hsl, &rgb); /* the code in base/colorize.c would multiply r,b,g with lum, * but this is a bug since it should multiply with 255. We * don't repeat this bug here (this is the reason why the gegl * colorize is brighter than the legacy one). */ dest[RED] = rgb.r; /* * lum; */ dest[GREEN] = rgb.g; /* * lum; */ dest[BLUE] = rgb.b; /* * lum */; dest[ALPHA] = rgb.a; src += 4; dest += 4; } return TRUE; }
/** * gimp_rgb_luminance: * @rgb: * * Return value: the luminous intensity of the range from 0.0 to 1.0. * * Since: GIMP 2.4 **/ gdouble gimp_rgb_luminance (const GimpRGB *rgb) { gdouble luminance; g_return_val_if_fail (rgb != NULL, 0.0); luminance = GIMP_RGB_LUMINANCE (rgb->r, rgb->g, rgb->b); return CLAMP (luminance, 0.0, 1.0); }
static VALUE rb_GIMP_RGB_LUMINANCE (VALUE self, VALUE r, VALUE g, VALUE b) { gdouble result; result = GIMP_RGB_LUMINANCE((gdouble)NUM2DBL(r), (gdouble)NUM2DBL(g), (gdouble)NUM2DBL(b)); return rb_float_new(result); }
void gimp_operation_layer_mode_blend_luma_lighten_only (const gfloat *in, const gfloat *layer, gfloat *comp, gint samples) { while (samples--) { if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) { gfloat dest_luminance; gfloat src_luminance; gint c; dest_luminance = GIMP_RGB_LUMINANCE (in[0], in[1], in[2]); src_luminance = GIMP_RGB_LUMINANCE (layer[0], layer[1], layer[2]); if (dest_luminance >= src_luminance) { for (c = 0; c < 3; c++) comp[c] = in[c]; } else { for (c = 0; c < 3; c++) comp[c] = layer[c]; } } comp[ALPHA] = layer[ALPHA]; comp += 4; layer += 4; in += 4; } }
static inline guchar pixel_luminance (const guchar *p, gint bpp) { switch (bpp) { case 1: case 2: return p[0]; case 3: case 4: return GIMP_RGB_LUMINANCE (p[0], p[1], p[2]); default: return 0; /* should not be reached */ } }
/* Returns NGRADSAMPLES samples of active gradient. Each sample has (gimp_drawable_bpp (drawable_id)) bytes. "ripped" from gradmap.c. */ static guchar * get_gradient_samples (gint32 drawable_id, gboolean reverse) { gchar *gradient_name; gint n_f_samples; gdouble *f_samples, *f_samp; /* float samples */ guchar *b_samples, *b_samp; /* byte samples */ gint bpp, color, has_alpha, alpha; gint i, j; gradient_name = gimp_context_get_gradient (); gimp_gradient_get_uniform_samples (gradient_name, NGRADSAMPLES, reverse, &n_f_samples, &f_samples); g_free (gradient_name); bpp = gimp_drawable_bpp (drawable_id); color = gimp_drawable_is_rgb (drawable_id); has_alpha = gimp_drawable_has_alpha (drawable_id); alpha = (has_alpha ? bpp - 1 : bpp); b_samples = g_new (guchar, NGRADSAMPLES * bpp); for (i = 0; i < NGRADSAMPLES; i++) { b_samp = &b_samples[i * bpp]; f_samp = &f_samples[i * 4]; if (color) for (j = 0; j < 3; j++) b_samp[j] = f_samp[j] * 255; else b_samp[0] = GIMP_RGB_LUMINANCE (f_samp[0], f_samp[1], f_samp[2]) * 255; if (has_alpha) b_samp[alpha] = f_samp[3] * 255; } g_free (f_samples); return b_samples; }
/* * Helper function to read a sample from a mask-size/exponent map */ static inline gfloat get_map_value (const guchar *src, gint bpp) { gfloat value; if (bpp >= 3) value = GIMP_RGB_LUMINANCE (src[0], src[1], src[2]); else value = *src; if (value < 1.0) value = 1.0; /* value should be in [0,1] */ value /= 255.0; return value; }
static gdouble displace_map_give_value (guchar *pt, gint alpha, gint bytes) { gdouble ret, val_alpha; if (bytes >= 3) ret = GIMP_RGB_LUMINANCE (pt[0], pt[1], pt[2]); else ret = (gdouble) *pt; if (alpha) { val_alpha = pt[bytes - 1]; ret = ((ret - 127.5) * val_alpha / 255.0) + 127.5; } return ret; }
static void desaturate_region_luminosity (PixelRegion *srcPR, PixelRegion *destPR, const gboolean has_alpha) { const guchar *src = srcPR->data; guchar *dest = destPR->data; gint h = srcPR->h; while (h--) { const guchar *s = src; guchar *d = dest; gint j; for (j = 0; j < srcPR->w; j++) { gint luminosity = GIMP_RGB_LUMINANCE (s[RED_PIX], s[GREEN_PIX], s[BLUE_PIX]) + 0.5; d[RED_PIX] = luminosity; d[GREEN_PIX] = luminosity; d[BLUE_PIX] = luminosity; if (has_alpha) d[ALPHA_PIX] = s[ALPHA_PIX]; d += destPR->bytes; s += srcPR->bytes; } src += srcPR->rowstride; dest += destPR->rowstride; } }
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); }
void gimp_levels_config_adjust_by_colors (GimpLevelsConfig *config, GimpHistogramChannel channel, const GimpRGB *black, const GimpRGB *gray, const GimpRGB *white) { g_return_if_fail (GIMP_IS_LEVELS_CONFIG (config)); g_object_freeze_notify (G_OBJECT (config)); if (black) { config->low_input[channel] = gimp_levels_config_input_from_color (channel, black); g_object_notify (G_OBJECT (config), "low-input"); } if (white) { config->high_input[channel] = gimp_levels_config_input_from_color (channel, white); g_object_notify (G_OBJECT (config), "high-input"); } if (gray) { gdouble input; gdouble range; gdouble inten; gdouble out_light; gdouble lightness; /* Calculate lightness value */ lightness = GIMP_RGB_LUMINANCE (gray->r, gray->g, gray->b); input = gimp_levels_config_input_from_color (channel, gray); range = config->high_input[channel] - config->low_input[channel]; if (range <= 0) return; input -= config->low_input[channel]; if (input < 0) return; /* Normalize input and lightness */ inten = input / range; out_light = lightness/ range; if (out_light <= 0) return; /* Map selected color to corresponding lightness */ config->gamma[channel] = log (inten) / log (out_light); g_object_notify (G_OBJECT (config), "gamma"); } g_object_thaw_notify (G_OBJECT (config)); }
static gboolean gimp_operation_desaturate_process (GeglOperation *operation, void *in_buf, void *out_buf, glong samples, const GeglRectangle *roi, gint level) { GimpOperationPointFilter *point = GIMP_OPERATION_POINT_FILTER (operation); GimpDesaturateConfig *config = GIMP_DESATURATE_CONFIG (point->config); gfloat *src = in_buf; gfloat *dest = out_buf; if (! config) return FALSE; switch (config->mode) { case GIMP_DESATURATE_LIGHTNESS: while (samples--) { gfloat min, max, value; max = MAX (src[0], src[1]); max = MAX (max, src[2]); min = MIN (src[0], src[1]); min = MIN (min, src[2]); value = (max + min) / 2; dest[0] = value; dest[1] = value; dest[2] = value; dest[3] = src[3]; src += 4; dest += 4; } break; case GIMP_DESATURATE_LUMINOSITY: while (samples--) { gfloat value = GIMP_RGB_LUMINANCE (src[0], src[1], src[2]); dest[0] = value; dest[1] = value; dest[2] = value; dest[3] = src[3]; src += 4; dest += 4; } break; case GIMP_DESATURATE_AVERAGE: while (samples--) { gfloat value = (src[0] + src[1] + src[2]) / 3; dest[0] = value; dest[1] = value; dest[2] = value; dest[3] = src[3]; src += 4; dest += 4; } break; } return TRUE; }
static gint32 do_curl_effect (gint32 drawable_id) { gint x = 0; gint y = 0; gboolean color_image; gint x1, y1, k; guint alpha_pos, progress, max_progress; gdouble intensity, alpha; GimpVector2 v, dl, dr; gdouble dl_mag, dr_mag, angle, factor; guchar *pp, *dest, fore_grayval, back_grayval; guchar *gradsamp; GimpPixelRgn dest_rgn; gpointer pr; gint32 curl_layer_id; guchar *grad_samples = NULL; color_image = gimp_drawable_is_rgb (drawable_id); curl_layer = gimp_drawable_get (gimp_layer_new (image_id, _("Curl Layer"), true_sel_width, true_sel_height, color_image ? GIMP_RGBA_IMAGE : GIMP_GRAYA_IMAGE, 100, GIMP_NORMAL_MODE)); curl_layer_id = curl_layer->drawable_id; gimp_image_insert_layer (image_id, curl_layer->drawable_id, gimp_item_get_parent (drawable_id), drawable_position); gimp_drawable_fill (curl_layer->drawable_id, GIMP_FILL_TRANSPARENT); gimp_drawable_offsets (drawable_id, &x1, &y1); gimp_layer_set_offsets (curl_layer->drawable_id, sel_x + x1, sel_y + y1); gimp_tile_cache_ntiles (2 * (curl_layer->width / gimp_tile_width () + 1)); gimp_pixel_rgn_init (&dest_rgn, curl_layer, 0, 0, true_sel_width, true_sel_height, TRUE, TRUE); /* Init shade_under */ gimp_vector2_set (&dl, -sel_width, -sel_height); dl_mag = gimp_vector2_length (&dl); gimp_vector2_set (&dr, -(sel_width - right_tangent.x), -(sel_height - right_tangent.y)); dr_mag = gimp_vector2_length (&dr); alpha = acos (gimp_vector2_inner_product (&dl, &dr) / (dl_mag * dr_mag)); /* Init shade_curl */ fore_grayval = GIMP_RGB_LUMINANCE (fore_color[0], fore_color[1], fore_color[2]) + 0.5; back_grayval = GIMP_RGB_LUMINANCE (back_color[0], back_color[1], back_color[2]) + 0.5; /* Gradient Samples */ switch (curl.colors) { case CURL_COLORS_FG_BG: break; case CURL_COLORS_GRADIENT: grad_samples = get_gradient_samples (curl_layer->drawable_id, FALSE); break; case CURL_COLORS_GRADIENT_REVERSE: grad_samples = get_gradient_samples (curl_layer->drawable_id, TRUE); break; } max_progress = 2 * sel_width * sel_height; progress = 0; alpha_pos = dest_rgn.bpp - 1; /* Main loop */ for (pr = gimp_pixel_rgns_register (1, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { dest = dest_rgn.data; for (y1 = dest_rgn.y; y1 < dest_rgn.y + dest_rgn.h; y1++) { pp = dest; for (x1 = dest_rgn.x; x1 < dest_rgn.x + dest_rgn.w; x1++) { /* Map coordinates to get the curl correct... */ switch (curl.orientation) { case CURL_ORIENTATION_VERTICAL: x = CURL_EDGE_RIGHT (curl.edge) ? x1 : sel_width - 1 - x1; y = CURL_EDGE_UPPER (curl.edge) ? y1 : sel_height - 1 - y1; break; case CURL_ORIENTATION_HORIZONTAL: x = CURL_EDGE_LOWER (curl.edge) ? y1 : sel_width - 1 - y1; y = CURL_EDGE_LEFT (curl.edge) ? x1 : sel_height - 1 - x1; break; } if (left_of_diagl (x, y)) { /* uncurled region */ for (k = 0; k <= alpha_pos; k++) pp[k] = 0; } else if (right_of_diagr (x, y) || (right_of_diagm (x, y) && below_diagb (x, y) && !inside_circle (x, y))) { /* curled region */ for (k = 0; k <= alpha_pos; k++) pp[k] = 0; } else { v.x = -(sel_width - x); v.y = -(sel_height - y); angle = acos (gimp_vector2_inner_product (&v, &dl) / (gimp_vector2_length (&v) * dl_mag)); if (inside_circle (x, y) || below_diagb (x, y)) { /* Below the curl. */ factor = angle / alpha; for (k = 0; k < alpha_pos; k++) pp[k] = 0; pp[alpha_pos] = (curl.shade ? (guchar) ((float) 255 * (float) factor) : 0); } else { /* On the curl */ switch (curl.colors) { case CURL_COLORS_FG_BG: intensity = pow (sin (G_PI * angle / alpha), 1.5); if (color_image) { pp[0] = (intensity * back_color[0] + (1.0 - intensity) * fore_color[0]); pp[1] = (intensity * back_color[1] + (1.0 - intensity) * fore_color[1]); pp[2] = (intensity * back_color[2] + (1.0 - intensity) * fore_color[2]); } else pp[0] = (intensity * back_grayval + (1 - intensity) * fore_grayval); pp[alpha_pos] = (guchar) ((double) 255.99 * (1.0 - intensity * (1.0 - curl.opacity))); break; case CURL_COLORS_GRADIENT: case CURL_COLORS_GRADIENT_REVERSE: /* Calculate position in Gradient */ intensity = (angle/alpha) + sin (G_PI*2 * angle/alpha) * 0.075; /* Check boundaries */ intensity = CLAMP (intensity, 0.0, 1.0); gradsamp = (grad_samples + ((guint) (intensity * NGRADSAMPLES)) * dest_rgn.bpp); if (color_image) { pp[0] = gradsamp[0]; pp[1] = gradsamp[1]; pp[2] = gradsamp[2]; } else pp[0] = gradsamp[0]; pp[alpha_pos] = (guchar) ((double) gradsamp[alpha_pos] * (1.0 - intensity * (1.0 - curl.opacity))); break; } } } pp += dest_rgn.bpp; } dest += dest_rgn.rowstride; } progress += dest_rgn.w * dest_rgn.h; gimp_progress_update ((double) progress / (double) max_progress); } gimp_progress_update (1.0); gimp_drawable_flush (curl_layer); gimp_drawable_merge_shadow (curl_layer->drawable_id, FALSE); gimp_drawable_update (curl_layer->drawable_id, 0, 0, curl_layer->width, curl_layer->height); gimp_drawable_detach (curl_layer); g_free (grad_samples); return curl_layer_id; }
/* * For all x and y as requested, replace the pixel at (x,y) * with a weighted average of the most frequently occurring * values in a circle of mask_size diameter centered at (x,y). */ static void oilify (GimpDrawable *drawable, GimpPreview *preview) { gboolean use_inten; gboolean use_msmap = FALSE; gboolean use_emap = FALSE; GimpDrawable *mask_size_map_drawable = NULL; GimpDrawable *exponent_map_drawable = NULL; GimpPixelRgn mask_size_map_rgn; GimpPixelRgn exponent_map_rgn; gint msmap_bpp = 0; gint emap_bpp = 0; GimpPixelRgn dest_rgn; GimpPixelRgn *regions[3]; gint n_regions; gint bpp; gint *sqr_lut; gint x1, y1, x2, y2; gint width, height; gint Hist[HISTSIZE]; gint Hist_rgb[4][HISTSIZE]; gpointer pr; gint progress, max_progress; guchar *src_buf; guchar *src_inten_buf = NULL; gint i; use_inten = (ovals.mode == MODE_INTEN); /* Get the selection bounds */ if (preview) { gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); x2 = x1 + width; y2 = y1 + height; } else { gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); width = x2 - x1; height = y2 - y1; } progress = 0; max_progress = width * height; bpp = drawable->bpp; /* * Look-up-table implementation of the square function, for use in the * VERY TIGHT inner loops */ { gint lut_size = (gint) ovals.mask_size / 2 + 1; sqr_lut = g_new (gint, lut_size); for (i = 0; i < lut_size; i++) sqr_lut[i] = SQR (i); } /* Get the map drawables, if applicable */ if (ovals.use_mask_size_map && ovals.mask_size_map >= 0) { use_msmap = TRUE; mask_size_map_drawable = gimp_drawable_get (ovals.mask_size_map); gimp_pixel_rgn_init (&mask_size_map_rgn, mask_size_map_drawable, x1, y1, width, height, FALSE, FALSE); msmap_bpp = mask_size_map_drawable->bpp; } if (ovals.use_exponent_map && ovals.exponent_map >= 0) { use_emap = TRUE; exponent_map_drawable = gimp_drawable_get (ovals.exponent_map); gimp_pixel_rgn_init (&exponent_map_rgn, exponent_map_drawable, x1, y1, width, height, FALSE, FALSE); emap_bpp = exponent_map_drawable->bpp; } gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, width, height, (preview == NULL), TRUE); { GimpPixelRgn src_rgn; gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE); src_buf = g_new (guchar, width * height * bpp); gimp_pixel_rgn_get_rect (&src_rgn, src_buf, x1, y1, width, height); } /* * If we're working in intensity mode, then generate a separate intensity * map of the source image. This way, we can avoid calculating the * intensity of any given source pixel more than once. */ if (use_inten) { guchar *src; guchar *dest; src_inten_buf = g_new (guchar, width * height); for (i = 0, src = src_buf, dest = src_inten_buf ; i < (width * height) ; i++, src += bpp, dest++) { *dest = (guchar) GIMP_RGB_LUMINANCE (src[0], src[1], src[2]); } } n_regions = 0; regions[n_regions++] = &dest_rgn; if (use_msmap) regions[n_regions++] = &mask_size_map_rgn; if (use_emap) regions[n_regions++] = &exponent_map_rgn; for (pr = gimp_pixel_rgns_register2 (n_regions, regions); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { gint y; guchar *dest_row; guchar *src_msmap_row = NULL; guchar *src_emap_row = NULL; for (y = dest_rgn.y, dest_row = dest_rgn.data, src_msmap_row = mask_size_map_rgn.data, /* valid iff use_msmap */ src_emap_row = exponent_map_rgn.data /* valid iff use_emap */ ; y < (gint) (dest_rgn.y + dest_rgn.h) ; y++, dest_row += dest_rgn.rowstride, src_msmap_row += mask_size_map_rgn.rowstride, /* valid iff use_msmap */ src_emap_row += exponent_map_rgn.rowstride) /* valid iff use_emap */ { gint x; guchar *dest; guchar *src_msmap = NULL; guchar *src_emap = NULL; for (x = dest_rgn.x, dest = dest_row, src_msmap = src_msmap_row, /* valid iff use_msmap */ src_emap = src_emap_row /* valid iff use_emap */ ; x < (gint) (dest_rgn.x + dest_rgn.w) ; x++, dest += bpp, src_msmap += msmap_bpp, /* valid iff use_msmap */ src_emap += emap_bpp) /* valid iff use_emap */ { gint radius, radius_squared; gfloat exponent; gint mask_x1, mask_y1; gint mask_x2, mask_y2; gint mask_y; gint src_offset; guchar *src_row; guchar *src_inten_row = NULL; if (use_msmap) { gfloat factor = get_map_value (src_msmap, msmap_bpp); radius = ROUND (factor * (0.5 * ovals.mask_size)); } else { radius = (gint) ovals.mask_size / 2; } radius_squared = SQR (radius); exponent = ovals.exponent; if (use_emap) exponent *= get_map_value (src_emap, emap_bpp); if (use_inten) memset (Hist, 0, sizeof (Hist)); memset (Hist_rgb, 0, sizeof (Hist_rgb)); mask_x1 = CLAMP ((x - radius), x1, x2); mask_y1 = CLAMP ((y - radius), y1, y2); mask_x2 = CLAMP ((x + radius + 1), x1, x2); mask_y2 = CLAMP ((y + radius + 1), y1, y2); src_offset = (mask_y1 - y1) * width + (mask_x1 - x1); for (mask_y = mask_y1, src_row = src_buf + src_offset * bpp, src_inten_row = src_inten_buf + src_offset /* valid iff use_inten */ ; mask_y < mask_y2 ; mask_y++, src_row += width * bpp, src_inten_row += width) /* valid iff use_inten */ { guchar *src; guchar *src_inten = NULL; gint dy_squared = sqr_lut[ABS (mask_y - y)]; gint mask_x; for (mask_x = mask_x1, src = src_row, src_inten = src_inten_row /* valid iff use_inten */ ; mask_x < mask_x2 ; mask_x++, src += bpp, src_inten++) /* valid iff use_inten */ { gint dx_squared = sqr_lut[ABS (mask_x - x)]; gint b; /* Stay inside a circular mask area */ if ((dx_squared + dy_squared) > radius_squared) continue; if (use_inten) { gint inten = *src_inten; ++Hist[inten]; for (b = 0; b < bpp; b++) Hist_rgb[b][inten] += src[b]; } else { for (b = 0; b < bpp; b++) ++Hist_rgb[b][src[b]]; } } /* for mask_x */ } /* for mask_y */ if (use_inten) { weighted_average_color (Hist, Hist_rgb, exponent, dest, bpp); } else { gint b; for (b = 0; b < bpp; b++) dest[b] = weighted_average_value (Hist_rgb[b], exponent); } } /* for x */ } /* for y */ if (preview) { gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), &dest_rgn); } else { progress += dest_rgn.w * dest_rgn.h; gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } } /* for pr */ /* Detach from the map drawables */ if (mask_size_map_drawable) gimp_drawable_detach (mask_size_map_drawable); if (exponent_map_drawable) gimp_drawable_detach (exponent_map_drawable); if (src_inten_buf) g_free (src_inten_buf); g_free (src_buf); g_free (sqr_lut); if (!preview) { /* Update the oil-painted region */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, width, height); } }
/* This function chooses a gray value for the text color, based on * the average luminance of the text area of the splash image. */ static gboolean splash_average_text_area (GimpSplash *splash, GdkPixbuf *pixbuf, GdkColor *color) { const guchar *pixels; gint rowstride; gint channels; gint luminance = 0; guint sum[3] = { 0, 0, 0 }; GdkRectangle image = { 0, 0, 0, 0 }; GdkRectangle area = { 0, 0, 0, 0 }; g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE); g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8, FALSE); image.width = gdk_pixbuf_get_width (pixbuf); image.height = gdk_pixbuf_get_height (pixbuf); rowstride = gdk_pixbuf_get_rowstride (pixbuf); channels = gdk_pixbuf_get_n_channels (pixbuf); pixels = gdk_pixbuf_get_pixels (pixbuf); splash_position_layouts (splash, "Short text", "Somewhat longer text", &area); splash_position_layouts (splash, "", "", NULL); if (gdk_rectangle_intersect (&image, &area, &area)) { const gint count = area.width * area.height; gint x, y; pixels += area.x * channels; pixels += area.y * rowstride; for (y = 0; y < area.height; y++) { const guchar *src = pixels; for (x = 0; x < area.width; x++) { sum[0] += src[0]; sum[1] += src[1]; sum[2] += src[2]; src += channels; } pixels += rowstride; } luminance = GIMP_RGB_LUMINANCE (sum[0] / count, sum[1] / count, sum[2] / count); luminance = CLAMP0255 (luminance > 127 ? luminance - 223 : luminance + 223); } color->red = color->green = color->blue = (luminance << 8 | luminance); return gdk_colormap_alloc_color (gtk_widget_get_colormap (splash->area), color, FALSE, TRUE); }
void gimp_levels_config_adjust_by_colors (GimpLevelsConfig *config, GimpHistogramChannel channel, const GimpRGB *black, const GimpRGB *gray, const GimpRGB *white) { g_return_if_fail (GIMP_IS_LEVELS_CONFIG (config)); g_object_freeze_notify (G_OBJECT (config)); if (black) { config->low_input[channel] = gimp_levels_config_input_from_color (channel, black); g_object_notify (G_OBJECT (config), "low-input"); } if (white) { config->high_input[channel] = gimp_levels_config_input_from_color (channel, white); g_object_notify (G_OBJECT (config), "high-input"); } if (gray) { gdouble input; gdouble range; gdouble inten; gdouble out_light; gdouble lightness; /* Calculate lightness value */ lightness = GIMP_RGB_LUMINANCE (gray->r, gray->g, gray->b); input = gimp_levels_config_input_from_color (channel, gray); range = config->high_input[channel] - config->low_input[channel]; if (range <= 0) goto out; input -= config->low_input[channel]; if (input < 0) goto out; /* Normalize input and lightness */ inten = input / range; out_light = lightness / range; /* See bug 622054: picking pure black or white as gamma doesn't * work. But we cannot compare to 0.0 or 1.0 because cpus and * compilers are shit. If you try to check out_light using * printf() it will give exact 0.0 or 1.0 anyway, probably * because the generated code is different and out_light doesn't * live in a register. That must be why the cpu/compiler mafia * invented epsilon and defined this shit to be the programmer's * responsibility. */ if (out_light <= 0.0001 || out_light >= 0.9999) goto out; /* Map selected color to corresponding lightness */ config->gamma[channel] = log (inten) / log (out_light); config->gamma[channel] = CLAMP (config->gamma[channel], 0.1, 10.0); g_object_notify (G_OBJECT (config), "gamma"); } out: g_object_thaw_notify (G_OBJECT (config)); }
static gboolean gimp_operation_desaturate_process (GeglOperation *operation, void *in_buf, void *out_buf, glong samples, const GeglRectangle *roi, gint level) { GimpOperationDesaturate *desaturate = GIMP_OPERATION_DESATURATE (operation); gfloat *src = in_buf; gfloat *dest = out_buf; switch (desaturate->mode) { case GIMP_DESATURATE_LIGHTNESS: while (samples--) { gfloat min, max, value; max = MAX (src[0], src[1]); max = MAX (max, src[2]); min = MIN (src[0], src[1]); min = MIN (min, src[2]); value = (max + min) / 2; dest[0] = value; dest[1] = value; dest[2] = value; dest[3] = src[3]; src += 4; dest += 4; } break; case GIMP_DESATURATE_LUMA: case GIMP_DESATURATE_LUMINANCE: while (samples--) { gfloat value = GIMP_RGB_LUMINANCE (src[0], src[1], src[2]); dest[0] = value; dest[1] = value; dest[2] = value; dest[3] = src[3]; src += 4; dest += 4; } break; case GIMP_DESATURATE_AVERAGE: while (samples--) { gfloat value = (src[0] + src[1] + src[2]) / 3; dest[0] = value; dest[1] = value; dest[2] = value; dest[3] = src[3]; src += 4; dest += 4; } break; } return TRUE; }