/* * blend_pixels patched 8-24-05 to fix bug #163721. Note that this change * causes the function to treat src1 and src2 asymmetrically. This gives the * right behavior for the smudge tool, which is the only user of this function * at the time of patching. If you want to use the function for something * else, caveat emptor. */ void gimp_gegl_smudge_blend (GeglBuffer *top_buffer, const GeglRectangle *top_rect, GeglBuffer *bottom_buffer, const GeglRectangle *bottom_rect, GeglBuffer *dest_buffer, const GeglRectangle *dest_rect, gdouble blend) { GeglBufferIterator *iter; iter = gegl_buffer_iterator_new (top_buffer, top_rect, 0, babl_format ("RGBA float"), GEGL_BUFFER_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, bottom_buffer, bottom_rect, 0, babl_format ("RGBA float"), GEGL_BUFFER_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0, babl_format ("RGBA float"), GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { const gfloat *top = iter->data[0]; const gfloat *bottom = iter->data[1]; gfloat *dest = iter->data[2]; gint count = iter->length; const gfloat blend1 = 1.0 - blend; const gfloat blend2 = blend; while (count--) { const gfloat a1 = blend1 * bottom[3]; const gfloat a2 = blend2 * top[3]; const gfloat a = a1 + a2; gint b; if (a == 0) { for (b = 0; b < 4; b++) dest[b] = 0; } else { for (b = 0; b < 3; b++) dest[b] = bottom[b] + (bottom[b] * a1 + top[b] * a2 - a * bottom[b]); dest[3] = a; } top += 4; bottom += 4; dest += 4; } } }
void mask_components_onto (GeglBuffer *src_buffer, GeglBuffer *aux_buffer, GeglBuffer *dst_buffer, GeglRectangle *roi, GimpComponentMask mask, gboolean linear_mode) { GeglBufferIterator *iter; const Babl *iterator_format; if (linear_mode) iterator_format = babl_format ("RGBA float"); else iterator_format = babl_format ("R'G'B'A float"); iter = gegl_buffer_iterator_new (dst_buffer, roi, 0, iterator_format, GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, src_buffer, roi, 0, iterator_format, GEGL_ACCESS_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, aux_buffer, roi, 0, iterator_format, GEGL_ACCESS_READ, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { gfloat *dest = (gfloat *)iter->data[0]; gfloat *src = (gfloat *)iter->data[1]; gfloat *aux = (gfloat *)iter->data[2]; glong samples = iter->length; while (samples--) { dest[RED] = (mask & GIMP_COMPONENT_MASK_RED) ? aux[RED] : src[RED]; dest[GREEN] = (mask & GIMP_COMPONENT_MASK_GREEN) ? aux[GREEN] : src[GREEN]; dest[BLUE] = (mask & GIMP_COMPONENT_MASK_BLUE) ? aux[BLUE] : src[BLUE]; dest[ALPHA] = (mask & GIMP_COMPONENT_MASK_ALPHA) ? aux[ALPHA] : src[ALPHA]; src += 4; aux += 4; dest += 4; } } }
void gimp_gegl_combine_mask (GeglBuffer *mask_buffer, const GeglRectangle *mask_rect, GeglBuffer *dest_buffer, const GeglRectangle *dest_rect, gdouble opacity) { GeglBufferIterator *iter; iter = gegl_buffer_iterator_new (mask_buffer, mask_rect, 0, babl_format ("Y float"), GEGL_BUFFER_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0, babl_format ("Y float"), GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { const gfloat *mask = iter->data[0]; gfloat *dest = iter->data[1]; gint count = iter->length; while (count--) { *dest *= *mask * opacity; mask += 1; dest += 1; } } }
static gboolean gegl_operation_point_filter_process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result) { const Babl *in_format = gegl_operation_get_format (operation, "input"); const Babl *out_format = gegl_operation_get_format (operation, "output"); GeglOperationPointFilterClass *point_filter_class; point_filter_class = GEGL_OPERATION_POINT_FILTER_GET_CLASS (operation); if ((result->width > 0) && (result->height > 0)) { { GeglBufferIterator *i = gegl_buffer_iterator_new (output, result, out_format, GEGL_BUFFER_WRITE); gint read = /*output == input ? 0 :*/ gegl_buffer_iterator_add (i, input, result, in_format, GEGL_BUFFER_READ); /* using separate read and write iterators for in-place ideally a single * readwrite indice would be sufficient */ while (gegl_buffer_iterator_next (i)) point_filter_class->process (operation, i->data[read], i->data[0], i->length, &i->roi[0]); } } return TRUE; }
static void transfer_registration_color (GeglBuffer *src, GeglBuffer **dst, gint count) { GimpRGB color, test; GeglBufferIterator *gi; const Babl *src_format, *dst_format; gint i, src_bpp, dst_bpp; gdouble white; gimp_context_get_foreground (&color); white = 1.0; src_format = gegl_buffer_get_format (src); src_bpp = babl_format_get_bytes_per_pixel (src_format); dst_format = gegl_buffer_get_format (dst[0]); dst_bpp = babl_format_get_bytes_per_pixel (dst_format); gi = gegl_buffer_iterator_new (src, NULL, 0, NULL, GEGL_BUFFER_READ, GEGL_ABYSS_NONE); for (i = 0; i < count; i++) { gegl_buffer_iterator_add (gi, dst[i], NULL, 0, NULL, GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE); } while (gegl_buffer_iterator_next (gi)) { guint j, k; gpointer src_data, dst_data[MAX_EXTRACT_IMAGES]; src_data = gi->data[0]; for (j = 0; j < count; j++) dst_data[j] = gi->data[j+1]; for (k = 0; k < gi->length; k++) { gulong pos; pos = k * src_bpp; gimp_rgba_set_pixel (&test, src_format, ((guchar *)src_data) + pos); if (gimp_rgb_distance (&test, &color) < 1e-6) { for (j = 0; j < count; j++) { gpointer data; data = dst_data[j]; babl_process (babl_fish (babl_format ("Y double"), dst_format), &white, (guchar *)data + (k * dst_bpp), 1); } } } } }
GeglBufferIterator *gegl_buffer_iterator_new (GeglBuffer *buffer, const GeglRectangle *roi, const Babl *format, guint flags) { GeglBufferIterator *i = (gpointer)g_slice_new0 (GeglBufferIterators); /* Because the iterator is nulled above, we can forgo explicitly setting * i->is_finished to FALSE. */ gegl_buffer_iterator_add (i, buffer, roi, format, flags); return i; }
static void process_standard (GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, guint *channel_bits, GeglRandom *rand, GeglDitherStrategy dither_strategy) { GeglBufferIterator *gi; guint channel_mask [4]; generate_channel_masks (channel_bits, channel_mask); gi = gegl_buffer_iterator_new (input, result, 0, babl_format ("R'G'B'A u16"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (gi, output, result, 0, babl_format ("R'G'B'A u16"), GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (gi)) { guint y; for (y = 0; y < gi->roi->height; y++) { switch (dither_strategy) { case GEGL_DITHER_NONE: process_row_no_dither (gi, channel_mask, channel_bits, y); break; case GEGL_DITHER_RANDOM: process_row_random (gi, channel_mask, channel_bits, y, rand); break; case GEGL_DITHER_RESILIENT: process_row_resilient (gi, channel_mask, channel_bits, y, rand); break; case GEGL_DITHER_RANDOM_COVARIANT: process_row_random_covariant (gi, channel_mask, channel_bits, y, rand); break; case GEGL_DITHER_BAYER: process_row_bayer (gi, channel_mask, channel_bits, y); break; case GEGL_DITHER_FLOYD_STEINBERG: /* Done separately */ break; default: process_row_no_dither (gi, channel_mask, channel_bits, y); } } } }
GeglBufferIterator * gegl_buffer_iterator_new (GeglBuffer *buf, const GeglRectangle *roi, gint level, const Babl *format, unsigned int flags, GeglAbyssPolicy abyss_policy) { GeglBufferIterator *iter = gegl_buffer_iterator_empty_new (); gegl_buffer_iterator_add (iter, buf, roi, level, format, flags, abyss_policy); return iter; }
GeglBufferIterator * gegl_buffer_iterator_new (GeglBuffer *buffer, const GeglRectangle *roi, gint level, const Babl *format, guint flags, GeglAbyssPolicy abyss_policy) { GeglBufferIterator *i = (gpointer)g_slice_new0 (GeglBufferIterators); /* Because the iterator is nulled above, we can forgo explicitly setting * i->is_finished to FALSE. */ i->level = level; gegl_buffer_iterator_add (i, buffer, roi, level, format, flags, abyss_policy); return i; }
GeglBufferIterator * gegl_buffer_iterator_new (GeglBuffer *buf, const GeglRectangle *roi, gint level, const Babl *format, GeglAccessMode access_mode, GeglAbyssPolicy abyss_policy) { GeglBufferIterator *iter = gegl_buffer_iterator_empty_new (); gegl_buffer_iterator_add (iter, buf, roi, level, format, access_mode, abyss_policy); return iter; }
void gimp_gegl_combine_mask_weird (GeglBuffer *mask_buffer, const GeglRectangle *mask_rect, GeglBuffer *dest_buffer, const GeglRectangle *dest_rect, gdouble opacity, gboolean stipple) { GeglBufferIterator *iter; iter = gegl_buffer_iterator_new (mask_buffer, mask_rect, 0, babl_format ("Y float"), GEGL_BUFFER_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0, babl_format ("Y float"), GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { const gfloat *mask = iter->data[0]; gfloat *dest = iter->data[1]; gint count = iter->length; if (stipple) { while (count--) { dest[0] += (1.0 - dest[0]) * *mask * opacity; mask += 1; dest += 1; } } else { while (count--) { if (opacity > dest[0]) dest[0] += (opacity - dest[0]) * *mask * opacity; mask += 1; dest += 1; } } } }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { AutostretchData data; GeglBufferIterator *gi; buffer_get_auto_strech_data (input, &data); clean_autostretch_data (&data); gi = gegl_buffer_iterator_new (input, result, 0, babl_format ("HSVA float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (gi, output, result, 0, babl_format ("HSVA float"), GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (gi)) { gfloat *in = gi->data[0]; gfloat *out = gi->data[1]; gint i; for (i = 0; i < gi->length; i++) { out[0] = in[0]; /* Keep hue */ out[1] = (in[1] - data.slo) / data.sdiff; out[2] = (in[2] - data.vlo) / data.vdiff; out[3] = in[3]; /* Keep alpha */ in += 4; out += 4; } } return TRUE; }
void gimp_gegl_index_to_mask (GeglBuffer *indexed_buffer, const GeglRectangle *indexed_rect, const Babl *indexed_format, GeglBuffer *mask_buffer, const GeglRectangle *mask_rect, gint index) { GeglBufferIterator *iter; iter = gegl_buffer_iterator_new (indexed_buffer, indexed_rect, 0, indexed_format, GEGL_ACCESS_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, mask_buffer, mask_rect, 0, babl_format ("Y float"), GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { const guchar *indexed = iter->data[0]; gfloat *mask = iter->data[1]; gint count = iter->length; while (count--) { if (*indexed == index) *mask = 1.0; else *mask = 0.0; indexed++; mask++; } } }
static int gimp_mypaint_surface_draw_dab (MyPaintSurface *base_surface, float x, float y, float radius, float color_r, float color_g, float color_b, float opaque, float hardness, float color_a, float aspect_ratio, float angle, float lock_alpha, float colorize) { GimpMybrushSurface *surface = (GimpMybrushSurface *)base_surface; GeglBufferIterator *iter; GeglRectangle dabRect; GimpComponentMask component_mask = surface->component_mask; const float one_over_radius2 = 1.0f / (radius * radius); const double angle_rad = angle / 360 * 2 * M_PI; const float cs = cos(angle_rad); const float sn = sin(angle_rad); float normal_mode; float segment1_slope; float segment2_slope; float r_aa_start; hardness = CLAMP (hardness, 0.0f, 1.0f); segment1_slope = -(1.0f / hardness - 1.0f); segment2_slope = -hardness / (1.0f - hardness); aspect_ratio = MAX (1.0f, aspect_ratio); r_aa_start = radius - 1.0f; r_aa_start = MAX (r_aa_start, 0); r_aa_start = (r_aa_start * r_aa_start) / aspect_ratio; normal_mode = opaque * (1.0f - colorize); colorize = opaque * colorize; /* FIXME: This should use the real matrix values to trim aspect_ratio dabs */ dabRect = calculate_dab_roi (x, y, radius); gegl_rectangle_intersect (&dabRect, &dabRect, gegl_buffer_get_extent (surface->buffer)); if (dabRect.width <= 0 || dabRect.height <= 0) return 0; gegl_rectangle_bounding_box (&surface->dirty, &surface->dirty, &dabRect); iter = gegl_buffer_iterator_new (surface->buffer, &dabRect, 0, babl_format ("R'G'B'A float"), GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE); if (surface->paint_mask) { GeglRectangle mask_roi = dabRect; mask_roi.x -= surface->paint_mask_x; mask_roi.y -= surface->paint_mask_y; gegl_buffer_iterator_add (iter, surface->paint_mask, &mask_roi, 0, babl_format ("Y float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); } while (gegl_buffer_iterator_next (iter)) { float *pixel = (float *)iter->data[0]; float *mask; int iy, ix; if (surface->paint_mask) mask = iter->data[1]; else mask = NULL; for (iy = iter->roi[0].y; iy < iter->roi[0].y + iter->roi[0].height; iy++) { for (ix = iter->roi[0].x; ix < iter->roi[0].x + iter->roi[0].width; ix++) { float rr, base_alpha, alpha, dst_alpha, r, g, b, a; if (radius < 3.0f) rr = calculate_rr_antialiased (ix, iy, x, y, aspect_ratio, sn, cs, one_over_radius2, r_aa_start); else rr = calculate_rr (ix, iy, x, y, aspect_ratio, sn, cs, one_over_radius2); base_alpha = calculate_alpha_for_rr (rr, hardness, segment1_slope, segment2_slope); alpha = base_alpha * normal_mode; if (mask) alpha *= *mask; dst_alpha = pixel[ALPHA]; /* a = alpha * color_a + dst_alpha * (1.0f - alpha); * which converts to: */ a = alpha * (color_a - dst_alpha) + dst_alpha; r = pixel[RED]; g = pixel[GREEN]; b = pixel[BLUE]; if (a > 0.0f) { /* By definition the ratio between each color[] and pixel[] component in a non-pre-multipled blend always sums to 1.0f. * Originaly this would have been "(color[n] * alpha * color_a + pixel[n] * dst_alpha * (1.0f - alpha)) / a", * instead we only calculate the cheaper term. */ float src_term = (alpha * color_a) / a; float dst_term = 1.0f - src_term; r = color_r * src_term + r * dst_term; g = color_g * src_term + g * dst_term; b = color_b * src_term + b * dst_term; } if (colorize > 0.0f && base_alpha > 0.0f) { alpha = base_alpha * colorize; a = alpha + dst_alpha - alpha * dst_alpha; if (a > 0.0f) { GimpHSL pixel_hsl, out_hsl; GimpRGB pixel_rgb = {color_r, color_g, color_b}; GimpRGB out_rgb = {r, g, b}; float src_term = alpha / a; float dst_term = 1.0f - src_term; gimp_rgb_to_hsl (&pixel_rgb, &pixel_hsl); gimp_rgb_to_hsl (&out_rgb, &out_hsl); out_hsl.h = pixel_hsl.h; out_hsl.s = pixel_hsl.s; gimp_hsl_to_rgb (&out_hsl, &out_rgb); r = (float)out_rgb.r * src_term + r * dst_term; g = (float)out_rgb.g * src_term + g * dst_term; b = (float)out_rgb.b * src_term + b * dst_term; } } if (component_mask != GIMP_COMPONENT_MASK_ALL) { if (component_mask & GIMP_COMPONENT_MASK_RED) pixel[RED] = r; if (component_mask & GIMP_COMPONENT_MASK_GREEN) pixel[GREEN] = g; if (component_mask & GIMP_COMPONENT_MASK_BLUE) pixel[BLUE] = b; if (component_mask & GIMP_COMPONENT_MASK_ALPHA) pixel[ALPHA] = a; } else { pixel[RED] = r; pixel[GREEN] = g; pixel[BLUE] = b; pixel[ALPHA] = a; } pixel += 4; if (mask) mask += 1; } } } return 1; }
static void gimp_mypaint_surface_get_color (MyPaintSurface *base_surface, float x, float y, float radius, float *color_r, float *color_g, float *color_b, float *color_a) { GimpMybrushSurface *surface = (GimpMybrushSurface *)base_surface; GeglRectangle dabRect; if (radius < 1.0f) radius = 1.0f; dabRect = calculate_dab_roi (x, y, radius); *color_r = 0.0f; *color_g = 0.0f; *color_b = 0.0f; *color_a = 0.0f; if (dabRect.width > 0 || dabRect.height > 0) { const float one_over_radius2 = 1.0f / (radius * radius); float sum_weight = 0.0f; float sum_r = 0.0f; float sum_g = 0.0f; float sum_b = 0.0f; float sum_a = 0.0f; /* Read in clamp mode to avoid transparency bleeding in at the edges */ GeglBufferIterator *iter = gegl_buffer_iterator_new (surface->buffer, &dabRect, 0, babl_format ("R'aG'aB'aA float"), GEGL_BUFFER_READ, GEGL_ABYSS_CLAMP); if (surface->paint_mask) { GeglRectangle mask_roi = dabRect; mask_roi.x -= surface->paint_mask_x; mask_roi.y -= surface->paint_mask_y; gegl_buffer_iterator_add (iter, surface->paint_mask, &mask_roi, 0, babl_format ("Y float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); } while (gegl_buffer_iterator_next (iter)) { float *pixel = (float *)iter->data[0]; float *mask; int iy, ix; if (surface->paint_mask) mask = iter->data[1]; else mask = NULL; for (iy = iter->roi[0].y; iy < iter->roi[0].y + iter->roi[0].height; iy++) { float yy = (iy + 0.5f - y); for (ix = iter->roi[0].x; ix < iter->roi[0].x + iter->roi[0].width; ix++) { /* pixel_weight == a standard dab with hardness = 0.5, aspect_ratio = 1.0, and angle = 0.0 */ float xx = (ix + 0.5f - x); float rr = (yy * yy + xx * xx) * one_over_radius2; float pixel_weight = 0.0f; if (rr <= 1.0f) pixel_weight = 1.0f - rr; if (mask) pixel_weight *= *mask; sum_r += pixel_weight * pixel[RED]; sum_g += pixel_weight * pixel[GREEN]; sum_b += pixel_weight * pixel[BLUE]; sum_a += pixel_weight * pixel[ALPHA]; sum_weight += pixel_weight; pixel += 4; if (mask) mask += 1; } } } if (sum_a > 0.0f && sum_weight > 0.0f) { sum_r /= sum_weight; sum_g /= sum_weight; sum_b /= sum_weight; sum_a /= sum_weight; sum_r /= sum_a; sum_g /= sum_a; sum_b /= sum_a; /* FIXME: Clamping is wrong because GEGL allows alpha > 1, this should probably re-multipy things */ *color_r = CLAMP(sum_r, 0.0f, 1.0f); *color_g = CLAMP(sum_g, 0.0f, 1.0f); *color_b = CLAMP(sum_b, 0.0f, 1.0f); *color_a = CLAMP(sum_a, 0.0f, 1.0f); } } }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); cmsHTRANSFORM transform; const Babl *in_format, *out_format; gboolean alpha; gint bpp; in_format = babl_format_n (babl_type ("float"), babl_format_get_n_components (gegl_buffer_get_format (input))); bpp = babl_format_get_bytes_per_pixel (in_format); /* create the transformation */ { cmsHPROFILE in_profile, out_profile; cmsUInt32Number format; in_profile = o->src_profile; format = determine_lcms_format (in_format, in_profile); if (format == 0) return FALSE; if (format & EXTRA_SH (1)) alpha = TRUE; else alpha = FALSE; out_profile = create_lcms_linear_rgb_profile (); transform = cmsCreateTransform (in_profile, format, out_profile, alpha ? TYPE_RGBA_FLT : TYPE_RGB_FLT, o->intent, o->black_point_compensation ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0); cmsCloseProfile (out_profile); } out_format = alpha ? babl_format ("RGBA float") : babl_format ("RGB float"); /* iterate over the pixels */ { GeglBufferIterator *gi; gi = gegl_buffer_iterator_new (input, result, 0, in_format, GEGL_BUFFER_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (gi, output, result, 0, out_format, GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (gi)) { if (alpha) memcpy (gi->data[1], gi->data[0], bpp * gi->length); cmsDoTransform (transform, gi->data[0], gi->data[1], gi->length); } } cmsDeleteTransform (transform); return TRUE; }
static void lcms_layers_transform_rgb (gint *layers, gint num_layers, cmsHPROFILE src_profile, cmsHPROFILE dest_profile, GimpColorRenderingIntent intent, gboolean bpc) { gint i; for (i = 0; i < num_layers; i++) { gint32 layer_id = layers[i]; const Babl *layer_format; gboolean has_alpha; const Babl *type; const Babl *iter_format = NULL; cmsUInt32Number lcms_format = 0; cmsHTRANSFORM transform = NULL; gint *children; gint num_children; children = gimp_item_get_children (layer_id, &num_children); if (children) { lcms_layers_transform_rgb (children, num_children, src_profile, dest_profile, intent, bpc); g_free (children); continue; } layer_format = gimp_drawable_get_format (layer_id); has_alpha = babl_format_has_alpha (layer_format); type = babl_format_get_type (layer_format, 0); if (type == babl_type ("u8")) { if (has_alpha) { lcms_format = TYPE_RGBA_8; iter_format = babl_format ("R'G'B'A u8"); } else { lcms_format = TYPE_RGB_8; iter_format = babl_format ("R'G'B' u8"); } } else if (type == babl_type ("u16")) { if (has_alpha) { lcms_format = TYPE_RGBA_16; iter_format = babl_format ("R'G'B'A u16"); } else { lcms_format = TYPE_RGB_16; iter_format = babl_format ("R'G'B' u16"); } } else if (type == babl_type ("half")) /* 16-bit floating point (half) */ { #ifdef TYPE_RGB_HALF_FLT /* half float types are only in lcms 2.4 and newer */ if (has_alpha) { lcms_format = TYPE_RGBA_HALF_FLT; iter_format = babl_format ("R'G'B'A half"); } else { lcms_format = TYPE_RGB_HALF_FLT; iter_format = babl_format ("R'G'B' float"); } #endif /* TYPE_RGB_HALF_FLT */ } else if (type == babl_type ("float")) { if (has_alpha) { lcms_format = TYPE_RGBA_FLT; iter_format = babl_format ("R'G'B'A float"); } else { lcms_format = TYPE_RGB_FLT; iter_format = babl_format ("R'G'B' float"); } } else if (type == babl_type ("double")) { if (has_alpha) { #ifdef TYPE_RGBA_DBL /* RGBA double not implemented in lcms */ lcms_format = TYPE_RGBA_DBL; iter_format = babl_format ("R'G'B'A double"); #endif /* TYPE_RGBA_DBL */ } else { lcms_format = TYPE_RGB_DBL; iter_format = babl_format ("R'G'B' double"); } } if (lcms_format == 0) { g_printerr ("lcms: layer format %s not supported, " "falling back to float\n", babl_get_name (layer_format)); if (has_alpha) { lcms_format = TYPE_RGBA_FLT; iter_format = babl_format ("R'G'B'A float"); } else { lcms_format = TYPE_RGB_FLT; iter_format = babl_format ("R'G'B' float"); } } transform = cmsCreateTransform (src_profile, lcms_format, dest_profile, lcms_format, intent, cmsFLAGS_NOOPTIMIZE | (bpc ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0)); if (transform) { GeglBuffer *src_buffer; GeglBuffer *dest_buffer; GeglBufferIterator *iter; gint layer_width; gint layer_height; gint layer_bpp; gboolean layer_alpha; gdouble progress_start = (gdouble) i / num_layers; gdouble progress_end = (gdouble) (i + 1) / num_layers; gdouble range = progress_end - progress_start; gint count = 0; gint done = 0; src_buffer = gimp_drawable_get_buffer (layer_id); dest_buffer = gimp_drawable_get_shadow_buffer (layer_id); layer_width = gegl_buffer_get_width (src_buffer); layer_height = gegl_buffer_get_height (src_buffer); layer_bpp = babl_format_get_bytes_per_pixel (iter_format); layer_alpha = babl_format_has_alpha (iter_format); iter = gegl_buffer_iterator_new (src_buffer, NULL, 0, iter_format, GEGL_ACCESS_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, dest_buffer, NULL, 0, iter_format, GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { /* lcms doesn't touch the alpha channel, simply * copy everything to dest before the transform */ if (layer_alpha) memcpy (iter->data[1], iter->data[0], iter->length * layer_bpp); cmsDoTransform (transform, iter->data[0], iter->data[1], iter->length); } g_object_unref (src_buffer); g_object_unref (dest_buffer); gimp_drawable_merge_shadow (layer_id, TRUE); gimp_drawable_update (layer_id, 0, 0, layer_width, layer_height); if (count++ % 32 == 0) { gimp_progress_update (progress_start + (gdouble) done / (layer_width * layer_height) * range); } cmsDeleteTransform (transform); } } }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *roi, gint level) { GeglProperties *o = GEGL_PROPERTIES (operation); const Babl *format = babl_format ("RGBA float"); GeglSampler *sampler; GeglBufferIterator *iter; const GeglRectangle *in_extent; gdouble cx, cy; gdouble dx = 0.0, dy = 0.0; gdouble coangle_of_view_2; gdouble focal_length; gdouble curvature_sign; gdouble cap_angle_2; gdouble cap_radius; gdouble cap_depth; gdouble factor; gdouble f, f2, r, r_inv, r2, p, f_p, f_p2, f_pf, a, a_inv, sgn; gboolean perspective; gboolean inverse; gint i, j; sampler = gegl_buffer_sampler_new_at_level (input, format, o->sampler_type, level); iter = gegl_buffer_iterator_new (output, roi, level, format, GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, input, roi, level, format, GEGL_ACCESS_READ, GEGL_ABYSS_NONE); in_extent = gegl_operation_source_get_bounding_box (operation, "input"); cx = in_extent->x + in_extent->width / 2.0; cy = in_extent->y + in_extent->height / 2.0; if (o->mode == GEGL_SPHERIZE_MODE_RADIAL || o->mode == GEGL_SPHERIZE_MODE_HORIZONTAL) { dx = 2.0 / (in_extent->width - 1); } if (o->mode == GEGL_SPHERIZE_MODE_RADIAL || o->mode == GEGL_SPHERIZE_MODE_VERTICAL) { dy = 2.0 / (in_extent->height - 1); } coangle_of_view_2 = MAX (180.0 - o->angle_of_view, 0.01) * G_PI / 360.0; focal_length = tan (coangle_of_view_2); curvature_sign = o->curvature > 0.0 ? +1.0 : -1.0; cap_angle_2 = fabs (o->curvature) * coangle_of_view_2; cap_radius = 1.0 / sin (cap_angle_2); cap_depth = curvature_sign * cap_radius * cos (cap_angle_2); factor = fabs (o->amount); f = focal_length; f2 = f * f; r = cap_radius; r_inv = 1 / r; r2 = r * r; p = cap_depth; f_p = f + p; f_p2 = f_p * f_p; f_pf = f_p * f; a = cap_angle_2; a_inv = 1 / a; sgn = curvature_sign; perspective = o->angle_of_view > EPSILON; inverse = o->amount < 0.0; while (gegl_buffer_iterator_next (iter)) { gfloat *out_pixel = iter->data[0]; const gfloat *in_pixel = iter->data[1]; gfloat x, y; y = dy * (iter->roi->y + 0.5 - cy); for (j = iter->roi->y; j < iter->roi->y + iter->roi->height; j++, y += dy) { x = dx * (iter->roi->x + 0.5 - cx); for (i = iter->roi->x; i < iter->roi->x + iter->roi->width; i++, x += dx) { gfloat d2; d2 = x * x + y * y; if (d2 > EPSILON && d2 < 1.0 - EPSILON) { gdouble d = sqrt (d2); gdouble src_d = d; gdouble src_x, src_y; if (! inverse) { gdouble d2_f2 = d2 + f2; if (perspective) src_d = (f_pf - sgn * sqrt (d2_f2 * r2 - f_p2 * d2)) * d / d2_f2; src_d = (G_PI_2 - acos (src_d * r_inv)) * a_inv; } else { src_d = r * cos (G_PI_2 - src_d * a); if (perspective) src_d = f * src_d / (f_p - sgn * sqrt (r2 - src_d * src_d)); } if (factor < 1.0) src_d = d + (src_d - d) * factor; src_x = dx ? cx + src_d * x / (dx * d) : i + 0.5; src_y = dy ? cy + src_d * y / (dy * d) : j + 0.5; gegl_sampler_get (sampler, src_x, src_y, NULL, out_pixel, GEGL_ABYSS_NONE); } else { memcpy (out_pixel, in_pixel, sizeof (gfloat) * 4); } out_pixel += 4; in_pixel += 4; } } } g_object_unref (sampler); return TRUE; }
static void set_background (GeglProperties *o, const GeglRectangle *rect, GeglBuffer *input, GeglBuffer *output, gint division_x, gint division_y, gint offset_x, gint offset_y) { const Babl *format = babl_format ("RGBA float"); if (o->background_type == GEGL_BACKGROUND_TYPE_TRANSPARENT) { GeglColor *color = gegl_color_new ("rgba(0.0,0.0,0.0,0.0)"); gegl_buffer_set_color (output, rect, color); g_object_unref (color); } else if (o->background_type == GEGL_BACKGROUND_TYPE_COLOR) { gegl_buffer_set_color (output, rect, o->bg_color); } else if (o->background_type == GEGL_BACKGROUND_TYPE_IMAGE) { gegl_buffer_copy (input, NULL, GEGL_ABYSS_NONE, output, NULL); } else { /* GEGL_BACKGROUND_TYPE_INVERT */ GeglBufferIterator *iter; GeglRectangle clear = *rect; if (o->fractional_type == GEGL_FRACTIONAL_TYPE_IGNORE) { clear.x = offset_x; clear.y = offset_y; clear.width = o->tile_width * (rect->width / o->tile_width); clear.height = o->tile_height * (rect->height / o->tile_height); } iter = gegl_buffer_iterator_new (input, &clear, 0, format, GEGL_ACCESS_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, output, &clear, 0, format, GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { gfloat *src = iter->data[0]; gfloat *dst = iter->data[1]; glong n_pixels = iter->length; while (n_pixels--) { *dst++ = 1.f - *src++; *dst++ = 1.f - *src++; *dst++ = 1.f - *src++; *dst++ = *src++; } } } }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { gfloat min[3], max[3], diff[3]; GeglBufferIterator *gi; GeglProperties *o; gint c; if (gegl_cl_is_accelerated ()) if (cl_process (operation, input, output, result)) return TRUE; o = GEGL_PROPERTIES (operation); buffer_get_min_max (input, min, max); if (o->keep_colors) reduce_min_max_global (min, max); for (c = 0; c < 3; c++) { diff[c] = max[c] - min[c]; /* Avoid a divide by zero error if the image is a solid color */ if (diff[c] < 1e-3) { min[c] = 0.0; diff[c] = 1.0; } } gi = gegl_buffer_iterator_new (input, result, 0, babl_format ("RGBA float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (gi, output, result, 0, babl_format ("RGBA float"), GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (gi)) { gfloat *in = gi->data[0]; gfloat *out = gi->data[1]; gint o; for (o = 0; o < gi->length; o++) { for (c = 0; c < 3; c++) out[c] = (in[c] - min[c]) / diff[c]; out[3] = in[3]; in += 4; out += 4; } } return TRUE; }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { const GeglRectangle *whole_region; GeglRectangle shift_region; GeglBufferIterator *gi; gint half_width; gint half_height; gint index_iter; gint index_iter2; whole_region = gegl_operation_source_get_bounding_box (operation, "input"); half_width = whole_region->width / 2; half_height = whole_region->height / 2; shift_region.x = whole_region->x + half_width; shift_region.y = whole_region->y + half_height; shift_region.width = whole_region->width; shift_region.height = whole_region->height; gi = gegl_buffer_iterator_new (output, whole_region, 0, babl_format ("R'G'B'A float"), GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); index_iter = gegl_buffer_iterator_add (gi, input, whole_region, 0, babl_format ("R'G'B'A float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); index_iter2 = gegl_buffer_iterator_add (gi, input, &shift_region, 0, babl_format ("R'G'B'A float"), GEGL_ACCESS_READ, GEGL_ABYSS_LOOP); while (gegl_buffer_iterator_next (gi)) { guint k; gfloat *data_out; gfloat *data_in1; gfloat *data_in2; data_out = (gfloat*) gi->data[0]; data_in1 = (gfloat*) gi->data[index_iter]; data_in2 = (gfloat*) gi->data[index_iter2]; for (k = 0; k < gi->length; k++) { gint x, y, b; gfloat alpha; gfloat val_x, val_y; gfloat w, w1, w2; const gfloat eps = 1e-4; x = gi->roi[0].x + k % gi->roi[0].width; y = gi->roi[0].y + k / gi->roi[0].width; val_x = (half_width - x) / (gfloat) half_width; val_y = (half_height - y) / (gfloat) half_height; val_x = ABS (CLAMP (val_x, -1.0, 1.0)); val_y = ABS (CLAMP (val_y, -1.0, 1.0)); /* ambiguous position */ if (ABS (val_x - val_y) >= 1.0 - eps) w = 0.0; else w = val_x * val_y / (val_x * val_y + (1.0 - val_x) * (1.0 - val_y)); alpha = data_in1[3] * (1.0 - w) + data_in2[3] * w; w1 = (1.0 - w) * data_in1[3] / alpha; w2 = w * data_in2[3] / alpha; for (b = 0; b < 3; b++) data_out[b] = data_in1[b] * w1 + data_in2[b] * w2; data_out[3] = alpha; data_out += 4; data_in1 += 4; data_in2 += 4; } } return TRUE; }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *aux, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglProperties *o = GEGL_PROPERTIES (operation); const Babl *format_io, *format_coords; GeglSampler *sampler; GeglBufferIterator *it; gint index_in, index_out, index_coords; format_io = babl_format ("RGBA float"); format_coords = babl_format_n (babl_type ("float"), 2); sampler = gegl_buffer_sampler_new_at_level (input, format_io, o->sampler_type, level); if (aux != NULL) { it = gegl_buffer_iterator_new (output, result, level, format_io, GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); index_out = 0; index_coords = gegl_buffer_iterator_add (it, aux, result, level, format_coords, GEGL_ACCESS_READ, GEGL_ABYSS_NONE); index_in = gegl_buffer_iterator_add (it, input, result, level, format_io, GEGL_ACCESS_READ, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (it)) { gint i; gint n_pixels = it->length; gint x = it->roi->x; /* initial x */ gint y = it->roi->y; /* and y coordinates */ gdouble scaling = GEGL_PROPERTIES (operation)->scaling; gfloat *in = it->data[index_in]; gfloat *out = it->data[index_out]; gfloat *coords = it->data[index_coords]; for (i=0; i<n_pixels; i++) { /* if the coordinate asked is an exact pixel, we fetch it * directly, to avoid the blur of sampling */ if (coords[0] == 0 && coords[1] == 0) { out[0] = in[0]; out[1] = in[1]; out[2] = in[2]; out[3] = in[3]; } else { gegl_sampler_get (sampler, x+coords[0] * scaling, y+coords[1] * scaling, NULL, out, GEGL_ABYSS_NONE); } coords += 2; in += 4; out += 4; /* update x and y coordinates */ x++; if (x >= (it->roi->x + it->roi->width)) { x = it->roi->x; y++; } } } } else { gegl_buffer_copy (input, result, GEGL_ABYSS_NONE, output, result); } g_object_unref (sampler); return TRUE; }
void gimp_gegl_dodgeburn (GeglBuffer *src_buffer, const GeglRectangle *src_rect, GeglBuffer *dest_buffer, const GeglRectangle *dest_rect, gdouble exposure, GimpDodgeBurnType type, GimpTransferMode mode) { GeglBufferIterator *iter; if (type == GIMP_DODGE_BURN_TYPE_BURN) exposure = -exposure; iter = gegl_buffer_iterator_new (src_buffer, src_rect, 0, babl_format ("R'G'B'A float"), GEGL_BUFFER_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0, babl_format ("R'G'B'A float"), GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE); switch (mode) { gfloat factor; case GIMP_TRANSFER_HIGHLIGHTS: factor = 1.0 + exposure * (0.333333); while (gegl_buffer_iterator_next (iter)) { gfloat *src = iter->data[0]; gfloat *dest = iter->data[1]; gint count = iter->length; while (count--) { *dest++ = *src++ * factor; *dest++ = *src++ * factor; *dest++ = *src++ * factor; *dest++ = *src++; } } break; case GIMP_TRANSFER_MIDTONES: if (exposure < 0) factor = 1.0 - exposure * (0.333333); else factor = 1.0 / (1.0 + exposure); while (gegl_buffer_iterator_next (iter)) { gfloat *src = iter->data[0]; gfloat *dest = iter->data[1]; gint count = iter->length; while (count--) { *dest++ = pow (*src++, factor); *dest++ = pow (*src++, factor); *dest++ = pow (*src++, factor); *dest++ = *src++; } } break; case GIMP_TRANSFER_SHADOWS: if (exposure >= 0) factor = 0.333333 * exposure; else factor = -0.333333 * exposure; while (gegl_buffer_iterator_next (iter)) { gfloat *src = iter->data[0]; gfloat *dest = iter->data[1]; gint count = iter->length; while (count--) { if (exposure >= 0) { gfloat s; s = *src++; *dest++ = factor + s - factor * s; s = *src++; *dest++ = factor + s - factor * s; s = *src++; *dest++ = factor + s - factor * s; } else { gfloat s; s = *src++; if (s < factor) *dest++ = 0; else /* factor <= value <=1 */ *dest++ = (s - factor) / (1.0 - factor); s = *src++; if (s < factor) *dest++ = 0; else /* factor <= value <=1 */ *dest++ = (s - factor) / (1.0 - factor); s = *src++; if (s < factor) *dest++ = 0; else /* factor <= value <=1 */ *dest++ = (s - factor) / (1.0 - factor); } *dest++ = *src++; } } break; } }
void gimp_gegl_convolve (GeglBuffer *src_buffer, const GeglRectangle *src_rect, GeglBuffer *dest_buffer, const GeglRectangle *dest_rect, const gfloat *kernel, gint kernel_size, gdouble divisor, GimpConvolutionType mode, gboolean alpha_weighting) { GeglBufferIterator *iter; GeglRectangle *src_roi; GeglRectangle *dest_roi; const Babl *src_format; const Babl *dest_format; gint src_components; gint dest_components; src_format = gegl_buffer_get_format (src_buffer); if (babl_format_is_palette (src_format)) src_format = gimp_babl_format (GIMP_RGB, GIMP_PRECISION_FLOAT_LINEAR, babl_format_has_alpha (src_format)); else src_format = gimp_babl_format (gimp_babl_format_get_base_type (src_format), GIMP_PRECISION_FLOAT_LINEAR, babl_format_has_alpha (src_format)); dest_format = gegl_buffer_get_format (dest_buffer); if (babl_format_is_palette (dest_format)) dest_format = gimp_babl_format (GIMP_RGB, GIMP_PRECISION_FLOAT_LINEAR, babl_format_has_alpha (dest_format)); else dest_format = gimp_babl_format (gimp_babl_format_get_base_type (dest_format), GIMP_PRECISION_FLOAT_LINEAR, babl_format_has_alpha (dest_format)); src_components = babl_format_get_n_components (src_format); dest_components = babl_format_get_n_components (dest_format); iter = gegl_buffer_iterator_new (src_buffer, src_rect, 0, src_format, GEGL_BUFFER_READ, GEGL_ABYSS_NONE); src_roi = &iter->roi[0]; gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0, dest_format, GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE); dest_roi = &iter->roi[1]; while (gegl_buffer_iterator_next (iter)) { /* Convolve the src image using the convolution kernel, writing * to dest Convolve is not tile-enabled--use accordingly */ const gfloat *src = iter->data[0]; gfloat *dest = iter->data[1]; const gint components = src_components; const gint a_component = components - 1; const gint rowstride = src_components * src_roi->width; const gint margin = kernel_size / 2; const gint x1 = src_roi->x; const gint y1 = src_roi->y; const gint x2 = src_roi->x + src_roi->width - 1; const gint y2 = src_roi->y + src_roi->height - 1; gint x, y; gfloat offset; /* If the mode is NEGATIVE_CONVOL, the offset should be 128 */ if (mode == GIMP_NEGATIVE_CONVOL) { offset = 0.5; mode = GIMP_NORMAL_CONVOL; } else { offset = 0.0; } for (y = 0; y < dest_roi->height; y++) { gfloat *d = dest; if (alpha_weighting) { for (x = 0; x < dest_roi->width; x++) { const gfloat *m = kernel; gdouble total[4] = { 0.0, 0.0, 0.0, 0.0 }; gdouble weighted_divisor = 0.0; gint i, j, b; for (j = y - margin; j <= y + margin; j++) { for (i = x - margin; i <= x + margin; i++, m++) { gint xx = CLAMP (i, x1, x2); gint yy = CLAMP (j, y1, y2); const gfloat *s = src + yy * rowstride + xx * components; const gfloat a = s[a_component]; if (a) { gdouble mult_alpha = *m * a; weighted_divisor += mult_alpha; for (b = 0; b < a_component; b++) total[b] += mult_alpha * s[b]; total[a_component] += mult_alpha; } } } if (weighted_divisor == 0.0) weighted_divisor = divisor; for (b = 0; b < a_component; b++) total[b] /= weighted_divisor; total[a_component] /= divisor; for (b = 0; b < components; b++) { total[b] += offset; if (mode != GIMP_NORMAL_CONVOL && total[b] < 0.0) total[b] = - total[b]; *d++ = CLAMP (total[b], 0.0, 1.0); } } } else { for (x = 0; x < dest_roi->width; x++) { const gfloat *m = kernel; gdouble total[4] = { 0.0, 0.0, 0.0, 0.0 }; gint i, j, b; for (j = y - margin; j <= y + margin; j++) { for (i = x - margin; i <= x + margin; i++, m++) { gint xx = CLAMP (i, x1, x2); gint yy = CLAMP (j, y1, y2); const gfloat *s = src + yy * rowstride + xx * components; for (b = 0; b < components; b++) total[b] += *m * s[b]; } } for (b = 0; b < components; b++) { total[b] = total[b] / divisor + offset; if (mode != GIMP_NORMAL_CONVOL && total[b] < 0.0) total[b] = - total[b]; total[b] = CLAMP (total[b], 0.0, 1.0); } } } dest += dest_roi->width * dest_components; } } }
static void record_pix_stats (GeglBuffer *buffer, GeglBuffer *previous_buffer, uint8_t *info_rgb_hist, uint8_t *rgb_square_diff) { int rgb_hist[NEGL_RGB_HIST_DIM * NEGL_RGB_HIST_DIM * NEGL_RGB_HIST_DIM]={0,}; int sum = 0; int second_max_hist = 0; int max_hist = 0; int slot; long r_square_diff = 0; long g_square_diff = 0; long b_square_diff = 0; GeglBufferIterator *it = gegl_buffer_iterator_new (buffer, NULL, 0, babl_format ("RGBA u8"), GEGL_BUFFER_READ, GEGL_ABYSS_NONE); if (previous_video_frame) gegl_buffer_iterator_add (it, previous_buffer, NULL, 0, babl_format ("RGBA u8"), GEGL_BUFFER_READ, GEGL_ABYSS_NONE); for (slot = 0; slot < NEGL_RGB_HIST_SLOTS; slot ++) rgb_hist[slot] = 0; while (gegl_buffer_iterator_next (it)) { uint8_t *data = (void*)it->data[0]; int i; if (strstr (format, "histogram")) { for (i = 0; i < it->length; i++) { int r = data[i * 3 + 0] / 256.0 * NEGL_RGB_HIST_DIM; int g = data[i * 3 + 1] / 256.0 * NEGL_RGB_HIST_DIM; int b = data[i * 3 + 2] / 256.0 * NEGL_RGB_HIST_DIM; int slot = r * NEGL_RGB_HIST_DIM * NEGL_RGB_HIST_DIM + g * NEGL_RGB_HIST_DIM + b; if (slot < 0) slot = 0; if (slot >= NEGL_RGB_HIST_SLOTS) slot = NEGL_RGB_HIST_SLOTS; rgb_hist[slot]++; if (rgb_hist[slot] > max_hist) { second_max_hist = max_hist; max_hist = rgb_hist[slot]; } sum++; } } if (previous_buffer) { uint8_t *data_prev = (void*)it->data[1]; int i; for (i = 0; i < it->length; i++) { #define square(a) ((a)*(a)) r_square_diff += square(data[i * 3 + 0] -data_prev [i * 3 + 0]); g_square_diff += square(data[i * 3 + 1] -data_prev [i * 3 + 1]); b_square_diff += square(data[i * 3 + 2] -data_prev [i * 3 + 2]); } } } if (strstr(format, "histogram")) { int slot; for (slot = 0; slot < NEGL_RGB_HIST_SLOTS; slot ++) { int val = (sqrtf(rgb_hist[slot]) / (sqrtf(second_max_hist) * 0.9 + sqrtf(max_hist) * 0.1)) * 255; if (val > 255) val = 255; info_rgb_hist[rgb_hist_shuffle (slot)] = val; } } if (previous_buffer) { rgb_square_diff[0] = sqrt(r_square_diff) * 255 / sum; rgb_square_diff[1] = sqrt(g_square_diff) * 255 / sum; rgb_square_diff[2] = sqrt(b_square_diff) * 255 / sum; } }
void gimp_gegl_replace (GeglBuffer *top_buffer, const GeglRectangle *top_rect, GeglBuffer *bottom_buffer, const GeglRectangle *bottom_rect, GeglBuffer *mask_buffer, const GeglRectangle *mask_rect, GeglBuffer *dest_buffer, const GeglRectangle *dest_rect, gdouble opacity, const gboolean *affect) { GeglBufferIterator *iter; iter = gegl_buffer_iterator_new (top_buffer, top_rect, 0, babl_format ("RGBA float"), GEGL_BUFFER_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, bottom_buffer, bottom_rect, 0, babl_format ("RGBA float"), GEGL_BUFFER_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, mask_buffer, mask_rect, 0, babl_format ("Y float"), GEGL_BUFFER_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0, babl_format ("RGBA float"), GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { const gfloat *top = iter->data[0]; const gfloat *bottom = iter->data[1]; const gfloat *mask = iter->data[2]; gfloat *dest = iter->data[3]; gint count = iter->length; while (count--) { gint b; gdouble mask_val = *mask * opacity; /* calculate new alpha first. */ gfloat s1_a = bottom[3]; gfloat s2_a = top[3]; gdouble a_val = s1_a + mask_val * (s2_a - s1_a); if (a_val == 0.0) { /* In any case, write out versions of the blending * function that result when combinations of s1_a, s2_a, * and mask_val --> 0 (or mask_val -->1) */ /* 1: s1_a, s2_a, AND mask_val all approach 0+: */ /* 2: s1_a AND s2_a both approach 0+, regardless of mask_val: */ if (s1_a + s2_a == 0.0) { for (b = 0; b < 3; b++) { gfloat new_val; new_val = bottom[b] + mask_val * (top[b] - bottom[b]); dest[b] = affect[b] ? MIN (new_val, 1.0) : bottom[b]; } } /* 3: mask_val AND s1_a both approach 0+, regardless of s2_a */ else if (s1_a + mask_val == 0.0) { for (b = 0; b < 3; b++) dest[b] = bottom[b]; } /* 4: mask_val -->1 AND s2_a -->0, regardless of s1_a */ else if (1.0 - mask_val + s2_a == 0.0) { for (b = 0; b < 3; b++) dest[b] = affect[b] ? top[b] : bottom[b]; } } else { gdouble a_recip = 1.0 / a_val; /* possible optimization: fold a_recip into s1_a and s2_a */ for (b = 0; b < 3; b++) { gfloat new_val = a_recip * (bottom[b] * s1_a + mask_val * (top[b] * s2_a - bottom[b] * s1_a)); dest[b] = affect[b] ? MIN (new_val, 1.0) : bottom[b]; } } dest[3] = affect[3] ? a_val : s1_a; top += 4; bottom += 4; mask += 1; dest += 4; } } }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglOperationAreaFilter *area = GEGL_OPERATION_AREA_FILTER (operation); GeglProperties *o = GEGL_PROPERTIES (operation); GeglBuffer *dest, *dest_tmp; GeglRectangle working_region; GeglRectangle *whole_region; GeglBufferIterator *iter; whole_region = gegl_operation_source_get_bounding_box (operation, "input"); working_region.x = result->x - area->left; working_region.width = result->width + area->left + area->right; working_region.y = result->y - area->top; working_region.height = result->height + area->top + area->bottom; gegl_rectangle_intersect (&working_region, &working_region, whole_region); dest_tmp = gegl_buffer_new (&working_region, babl_format ("Y' float")); iter = gegl_buffer_iterator_new (dest_tmp, &working_region, 0, babl_format ("Y' float"), GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, input, &working_region, 0, babl_format ("Y' float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { gint i; gfloat *data_out = iter->data[0]; gfloat *data_in = iter->data[1]; for (i = 0; i < iter->length; i++) { /* compute sigmoidal transfer */ gfloat val = *data_in; val = 1.0 / (1.0 + exp (-(SIGMOIDAL_BASE + (o->sharpness * SIGMOIDAL_RANGE)) * (val - 0.5))); val = val * o->brightness; *data_out = CLAMP (val, 0.0, 1.0); data_out +=1; data_in +=1; } } dest = grey_blur_buffer (dest_tmp, o->glow_radius, result); iter = gegl_buffer_iterator_new (output, result, 0, babl_format ("RGBA float"), GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, input, result, 0, babl_format ("RGBA float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, dest, result, 0, babl_format ("Y' float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { gint i; gfloat *data_out = iter->data[0]; gfloat *data_in = iter->data[1]; gfloat *data_blur = iter->data[2]; for (i = 0; i < iter->length; i++) { gint c; for (c = 0; c < 3; c++) { gfloat tmp = (1.0 - data_in[c]) * (1.0 - *data_blur); data_out[c] = CLAMP (1.0 - tmp, 0.0, 1.0); } data_out[3] = data_in[3]; data_out += 4; data_in += 4; data_blur+= 1; } } g_object_unref (dest); g_object_unref (dest_tmp); return TRUE; }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *roi, gint level) { GeglProperties *o = GEGL_PROPERTIES (operation); AlParamsType *params = (AlParamsType *) o->user_data; const Babl *format = babl_format ("RGBA float"); GeglSampler *sampler; GeglBufferIterator *iter; gint x, y; sampler = gegl_buffer_sampler_new_at_level (input, format, GEGL_SAMPLER_CUBIC, level); iter = gegl_buffer_iterator_new (output, roi, level, format, GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, input, roi, level, format, GEGL_ACCESS_READ, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { gfloat *out_pixel = iter->data[0]; gfloat *in_pixel = iter->data[1]; for (y = iter->roi->y; y < iter->roi->y + iter->roi->height; y++) { gdouble dy, dysqr; dy = -((gdouble) y - params->b + 0.5); dysqr = dy * dy; for (x = iter->roi->x; x < iter->roi->x + iter->roi->width; x++) { gdouble dx, dxsqr; dx = (gdouble) x - params->a + 0.5; dxsqr = dx * dx; if (dysqr < (params->bsqr - (params->bsqr * dxsqr) / params->asqr)) { /** * If (x, y) is inside the affected region, we can find its original * position and fetch the pixel with the sampler */ gdouble ox, oy; find_undistorted_pos (dx, dy, o->refraction_index, params, &ox, &oy); gegl_sampler_get (sampler, ox + params->a, params->b - oy, NULL, out_pixel, GEGL_ABYSS_NONE); } else { /** * Otherwise (that is for pixels outside the lens), we could either leave * the image data unchanged, or set it to a specified 'background_color', * depending on the user input. */ if (o->keep_surroundings) memcpy (out_pixel, in_pixel, sizeof (gfloat) * 4); else memcpy (out_pixel, params->bg_color, sizeof (gfloat) * 4); } out_pixel += 4; in_pixel += 4; } } } g_object_unref (sampler); return TRUE; }
/** * gimp_color_transform_process_buffer: * @transform: * @src_format: * @src_rect: * @dest_format: * @dest_rect: * * This function transforms buffer into another buffer. * * Since: 2.10 **/ void gimp_color_transform_process_buffer (GimpColorTransform *transform, GeglBuffer *src_buffer, const GeglRectangle *src_rect, GeglBuffer *dest_buffer, const GeglRectangle *dest_rect) { GimpColorTransformPrivate *priv; GeglBufferIterator *iter; gint total_pixels; gint done_pixels = 0; g_return_if_fail (GIMP_IS_COLOR_TRANSFORM (transform)); g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); priv = transform->priv; if (src_rect) { total_pixels = src_rect->width * src_rect->height; } else { total_pixels = (gegl_buffer_get_width (src_buffer) * gegl_buffer_get_height (src_buffer)); } if (src_buffer != dest_buffer) { const Babl *fish = NULL; if (babl_format_has_alpha (priv->dest_format)) fish = babl_fish (priv->src_format, priv->dest_format); iter = gegl_buffer_iterator_new (src_buffer, src_rect, 0, priv->src_format, GEGL_ACCESS_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0, priv->dest_format, GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { /* make sure the alpha channel is copied too, lcms doesn't copy it */ if (fish) babl_process (fish, iter->data[0], iter->data[1], iter->length); cmsDoTransform (priv->transform, iter->data[0], iter->data[1], iter->length); done_pixels += iter->roi[0].width * iter->roi[0].height; g_signal_emit (transform, gimp_color_transform_signals[PROGRESS], 0, (gdouble) done_pixels / (gdouble) total_pixels); } } else { iter = gegl_buffer_iterator_new (src_buffer, src_rect, 0, priv->src_format, GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { cmsDoTransform (priv->transform, iter->data[0], iter->data[0], iter->length); done_pixels += iter->roi[0].width * iter->roi[0].height; g_signal_emit (transform, gimp_color_transform_signals[PROGRESS], 0, (gdouble) done_pixels / (gdouble) total_pixels); } } g_signal_emit (transform, gimp_color_transform_signals[PROGRESS], 0, 1.0); }
GeglBuffer * gimp_image_contiguous_region_by_color (GimpImage *image, GimpDrawable *drawable, gboolean sample_merged, gboolean antialias, gfloat threshold, gboolean select_transparent, GimpSelectCriterion select_criterion, const GimpRGB *color) { /* Scan over the image's active layer, finding pixels within the * specified threshold from the given R, G, & B values. If * antialiasing is on, use the same antialiasing scheme as in * fuzzy_select. Modify the image's mask to reflect the * additional selection */ GeglBufferIterator *iter; GimpPickable *pickable; GeglBuffer *src_buffer; GeglBuffer *mask_buffer; const Babl *format; gint n_components; gboolean has_alpha; gfloat start_col[MAX_CHANNELS]; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (color != NULL, NULL); if (sample_merged) pickable = GIMP_PICKABLE (image); else pickable = GIMP_PICKABLE (drawable); gimp_pickable_flush (pickable); src_buffer = gimp_pickable_get_buffer (pickable); format = choose_format (src_buffer, select_criterion, &n_components, &has_alpha); gimp_rgba_get_pixel (color, format, start_col); if (has_alpha) { if (select_transparent) { /* don't select transparancy if "color" isn't fully transparent */ if (start_col[n_components - 1] > 0.0) select_transparent = FALSE; } } else { select_transparent = FALSE; } mask_buffer = gegl_buffer_new (gegl_buffer_get_extent (src_buffer), babl_format ("Y float")); iter = gegl_buffer_iterator_new (src_buffer, NULL, 0, format, GEGL_BUFFER_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, mask_buffer, NULL, 0, babl_format ("Y float"), GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { const gfloat *src = iter->data[0]; gfloat *dest = iter->data[1]; gint count = iter->length; while (count--) { /* Find how closely the colors match */ *dest = pixel_difference (start_col, src, antialias, threshold, n_components, has_alpha, select_transparent, select_criterion); src += n_components; dest += 1; } } return mask_buffer; }