/* * Cartoon algorithm * ----------------- * Mask radius = radius of pixel neighborhood for intensity comparison * Threshold = relative intensity difference which will result in darkening * Ramp = amount of relative intensity difference before total black * Blur radius = mask radius / 3.0 * * Algorithm: * For each pixel, calculate pixel intensity value to be: avg (blur radius) * relative diff = pixel intensity / avg (mask radius) * If relative diff < Threshold * intensity mult = (Ramp - MIN (Ramp, (Threshold - relative diff))) / Ramp * pixel intensity *= intensity mult */ static void cartoon (GimpDrawable *drawable, GimpPreview *preview) { GimpPixelRgn src_rgn, dest_rgn; GimpPixelRgn *pr; gint width, height; gint bytes; gboolean has_alpha; guchar *dest1; guchar *dest2; guchar *src; guchar *src1, *sp_p1, *sp_m1; guchar *src2, *sp_p2, *sp_m2; gdouble n_p1[5], n_m1[5]; gdouble n_p2[5], n_m2[5]; gdouble d_p1[5], d_m1[5]; gdouble d_p2[5], d_m2[5]; gdouble bd_p1[5], bd_m1[5]; gdouble bd_p2[5], bd_m2[5]; gdouble *val_p1, *val_m1, *vp1, *vm1; gdouble *val_p2, *val_m2, *vp2, *vm2; gint x1, y1, x2, y2; gint i, j; gint row, col, b; gint terms; gint progress, max_progress; gint initial_p1[4]; gint initial_p2[4]; gint initial_m1[4]; gint initial_m2[4]; gdouble radius; gdouble std_dev1; gdouble std_dev2; gdouble ramp; guchar *preview_buffer = NULL; if (preview) { gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); } else { gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); width = (x2 - x1); height = (y2 - y1); } bytes = drawable->bpp; has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); val_p1 = g_new (gdouble, MAX (width, height) * bytes); val_p2 = g_new (gdouble, MAX (width, height) * bytes); val_m1 = g_new (gdouble, MAX (width, height) * bytes); val_m2 = g_new (gdouble, MAX (width, height) * bytes); src = g_new (guchar, MAX (width, height) * bytes); dest1 = g_new0 (guchar, width * height); dest2 = g_new0 (guchar, width * height); gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); progress = 0; max_progress = width * height * 2; /* Calculate the standard deviations */ radius = 1.0; /* blur radius */ radius = fabs (radius) + 1.0; std_dev1 = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0))); radius = cvals.mask_radius; radius = fabs (radius) + 1.0; std_dev2 = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0))); /* derive the constants for calculating the gaussian from the std dev */ find_constants (n_p1, n_m1, d_p1, d_m1, bd_p1, bd_m1, std_dev1); find_constants (n_p2, n_m2, d_p2, d_m2, bd_p2, bd_m2, std_dev2); /* First the vertical pass */ for (col = 0; col < width; col++) { memset (val_p1, 0, height * bytes * sizeof (gdouble)); memset (val_p2, 0, height * bytes * sizeof (gdouble)); memset (val_m1, 0, height * bytes * sizeof (gdouble)); memset (val_m2, 0, height * bytes * sizeof (gdouble)); gimp_pixel_rgn_get_col (&src_rgn, src, col + x1, y1, height); src1 = src; sp_p1 = src1; sp_m1 = src1 + (height - 1) * bytes; vp1 = val_p1; vp2 = val_p2; vm1 = val_m1 + (height - 1) * bytes; vm2 = val_m2 + (height - 1) * bytes; /* Set up the first vals */ for (i = 0; i < bytes; i++) { initial_p1[i] = sp_p1[i]; initial_m1[i] = sp_m1[i]; } for (row = 0; row < height; row++) { gdouble *vpptr1, *vmptr1; gdouble *vpptr2, *vmptr2; terms = (row < 4) ? row : 4; for (b = 0; b < bytes; b++) { vpptr1 = vp1 + b; vmptr1 = vm1 + b; vpptr2 = vp2 + b; vmptr2 = vm2 + b; for (i = 0; i <= terms; i++) { *vpptr1 += n_p1[i] * sp_p1[(-i * bytes) + b] - d_p1[i] * vp1[(-i * bytes) + b]; *vmptr1 += n_m1[i] * sp_m1[(i * bytes) + b] - d_m1[i] * vm1[(i * bytes) + b]; *vpptr2 += n_p2[i] * sp_p1[(-i * bytes) + b] - d_p2[i] * vp2[(-i * bytes) + b]; *vmptr2 += n_m2[i] * sp_m1[(i * bytes) + b] - d_m2[i] * vm2[(i * bytes) + b]; } for (j = i; j <= 4; j++) { *vpptr1 += (n_p1[j] - bd_p1[j]) * initial_p1[b]; *vmptr1 += (n_m1[j] - bd_m1[j]) * initial_m1[b]; *vpptr2 += (n_p2[j] - bd_p2[j]) * initial_p1[b]; *vmptr2 += (n_m2[j] - bd_m2[j]) * initial_m1[b]; } } sp_p1 += bytes; sp_m1 -= bytes; vp1 += bytes; vp2 += bytes; vm1 -= bytes; vm2 -= bytes; } transfer_pixels (val_p1, val_m1, dest1 + col, width, bytes, height); transfer_pixels (val_p2, val_m2, dest2 + col, width, bytes, height); if (!preview) { progress += height; if ((col % 5) == 0) gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } } for (row = 0; row < height; row++) { memset (val_p1, 0, width * sizeof (gdouble)); memset (val_p2, 0, width * sizeof (gdouble)); memset (val_m1, 0, width * sizeof (gdouble)); memset (val_m2, 0, width * sizeof (gdouble)); src1 = dest1 + row * width; src2 = dest2 + row * width; sp_p1 = src1; sp_p2 = src2; sp_m1 = src1 + width - 1; sp_m2 = src2 + width - 1; vp1 = val_p1; vp2 = val_p2; vm1 = val_m1 + width - 1; vm2 = val_m2 + width - 1; /* Set up the first vals */ initial_p1[0] = sp_p1[0]; initial_p2[0] = sp_p2[0]; initial_m1[0] = sp_m1[0]; initial_m2[0] = sp_m2[0]; for (col = 0; col < width; col++) { gdouble *vpptr1, *vmptr1; gdouble *vpptr2, *vmptr2; terms = (col < 4) ? col : 4; vpptr1 = vp1; vmptr1 = vm1; vpptr2 = vp2; vmptr2 = vm2; for (i = 0; i <= terms; i++) { *vpptr1 += n_p1[i] * sp_p1[-i] - d_p1[i] * vp1[-i]; *vmptr1 += n_m1[i] * sp_m1[i] - d_m1[i] * vm1[i]; *vpptr2 += n_p2[i] * sp_p2[-i] - d_p2[i] * vp2[-i]; *vmptr2 += n_m2[i] * sp_m2[i] - d_m2[i] * vm2[i]; } for (j = i; j <= 4; j++) { *vpptr1 += (n_p1[j] - bd_p1[j]) * initial_p1[0]; *vmptr1 += (n_m1[j] - bd_m1[j]) * initial_m1[0]; *vpptr2 += (n_p2[j] - bd_p2[j]) * initial_p2[0]; *vmptr2 += (n_m2[j] - bd_m2[j]) * initial_m2[0]; } sp_p1 ++; sp_p2 ++; sp_m1 --; sp_m2 --; vp1 ++; vp2 ++; vm1 --; vm2 --; } transfer_pixels (val_p1, val_m1, dest1 + row * width, 1, 1, width); transfer_pixels (val_p2, val_m2, dest2 + row * width, 1, 1, width); if (!preview) { progress += width; if ((row % 5) == 0) gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } } /* Compute the ramp value which sets 'pct_black' % of the darkened pixels black */ ramp = compute_ramp (dest1, dest2, width * height, cvals.pct_black); /* Initialize the pixel regions. */ gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE); if (preview) { pr = gimp_pixel_rgns_register (1, &src_rgn); preview_buffer = g_new (guchar, width * height * bytes); } else { gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, width, height, TRUE, TRUE); pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn); } while (pr) { guchar *src_ptr = src_rgn.data; guchar *dest_ptr; guchar *blur_ptr = dest1 + (src_rgn.y - y1) * width + (src_rgn.x - x1); guchar *avg_ptr = dest2 + (src_rgn.y - y1) * width + (src_rgn.x - x1); gdouble diff; gdouble mult = 0.0; gdouble lightness; if (preview) dest_ptr = preview_buffer + ((src_rgn.y - y1) * width + (src_rgn.x - x1)) * bytes; else dest_ptr = dest_rgn.data; for (row = 0; row < src_rgn.h; row++) { for (col = 0; col < src_rgn.w; col++) { if (avg_ptr[col] != 0) { diff = (gdouble) blur_ptr[col] / (gdouble) avg_ptr[col]; if (diff < cvals.threshold) { if (ramp == 0.0) mult = 0.0; else mult = (ramp - MIN (ramp, (cvals.threshold - diff))) / ramp; } else mult = 1.0; } lightness = CLAMP (blur_ptr[col] * mult, 0, 255); if (bytes < 3) { dest_ptr[col * bytes] = (guchar) lightness; if (has_alpha) dest_ptr[col * bytes + 1] = src_ptr[col * src_rgn.bpp + 1]; } else { /* Convert to HLS, set lightness and convert back */ gint r, g, b; r = src_ptr[col * src_rgn.bpp + 0]; g = src_ptr[col * src_rgn.bpp + 1]; b = src_ptr[col * src_rgn.bpp + 2]; gimp_rgb_to_hsl_int (&r, &g, &b); b = lightness; gimp_hsl_to_rgb_int (&r, &g, &b); dest_ptr[col * bytes + 0] = r; dest_ptr[col * bytes + 1] = g; dest_ptr[col * bytes + 2] = b; if (has_alpha) dest_ptr[col * bytes + 3] = src_ptr[col * src_rgn.bpp + 3]; } } src_ptr += src_rgn.rowstride; if (preview) dest_ptr += width * bytes; else dest_ptr += dest_rgn.rowstride; blur_ptr += width; avg_ptr += width; } if (!preview) { progress += src_rgn.w * src_rgn.h; gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } pr = gimp_pixel_rgns_process (pr); } if (preview) { gimp_preview_draw_buffer (preview, preview_buffer, width * bytes); g_free (preview_buffer); } else { /* 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, width, height); } /* free up buffers */ g_free (val_p1); g_free (val_p2); g_free (val_m1); g_free (val_m2); g_free (src); g_free (dest1); g_free (dest2); }
/* * Photocopy algorithm * ----------------- * Mask radius = radius of pixel neighborhood for intensity comparison * Threshold = relative intensity difference which will result in darkening * Ramp = amount of relative intensity difference before total black * Blur radius = mask radius / 3.0 * * Algorithm: * For each pixel, calculate pixel intensity value to be: avg (blur radius) * relative diff = pixel intensity / avg (mask radius) * If relative diff < Threshold * intensity mult = (Ramp - MIN (Ramp, (Threshold - relative diff))) / Ramp * pixel intensity *= intensity mult * Else * pixel intensity = white */ static void photocopy (GimpDrawable *drawable, GimpPreview *preview) { GimpPixelRgn src_rgn, dest_rgn; GimpPixelRgn *pr; gint width, height; gint bytes; gboolean has_alpha; guchar *dest1; guchar *dest2; guchar *src1, *sp_p1, *sp_m1; guchar *src2, *sp_p2, *sp_m2; gdouble n_p1[5], n_m1[5]; gdouble n_p2[5], n_m2[5]; gdouble d_p1[5], d_m1[5]; gdouble d_p2[5], d_m2[5]; gdouble bd_p1[5], bd_m1[5]; gdouble bd_p2[5], bd_m2[5]; gdouble *val_p1, *val_m1, *vp1, *vm1; gdouble *val_p2, *val_m2, *vp2, *vm2; gint x1, y1; gint i, j; gint row, col; gint terms; gint progress, max_progress; gint initial_p1[4]; gint initial_p2[4]; gint initial_m1[4]; gint initial_m2[4]; gdouble radius; gdouble val; gdouble std_dev1; gdouble std_dev2; gdouble ramp_down; gdouble ramp_up; if (preview) { gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); } else { gint x2, y2; gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); width = x2 - x1; height = y2 - y1; } bytes = drawable->bpp; has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); val_p1 = g_new (gdouble, MAX (width, height)); val_p2 = g_new (gdouble, MAX (width, height)); val_m1 = g_new (gdouble, MAX (width, height)); val_m2 = g_new (gdouble, MAX (width, height)); dest1 = g_new0 (guchar, width * height); dest2 = g_new0 (guchar, width * height); progress = 0; max_progress = width * height * 3; gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE); for (pr = gimp_pixel_rgns_register (1, &src_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { guchar *src_ptr = src_rgn.data; guchar *dest_ptr = dest1 + (src_rgn.y - y1) * width + (src_rgn.x - x1); for (row = 0; row < src_rgn.h; row++) { for (col = 0; col < src_rgn.w; col++) { /* desaturate */ if (bytes > 2) dest_ptr[col] = (guchar) gimp_rgb_to_l_int (src_ptr[col * bytes + 0], src_ptr[col * bytes + 1], src_ptr[col * bytes + 2]); else dest_ptr[col] = (guchar) src_ptr[col * bytes]; /* compute transfer */ val = pow (dest_ptr[col], (1.0 / GAMMA)); dest_ptr[col] = (guchar) CLAMP (val, 0, 255); } src_ptr += src_rgn.rowstride; dest_ptr += width; } if (!preview) { progress += src_rgn.w * src_rgn.h; gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } } /* Calculate the standard deviations */ radius = MAX (1.0, 10 * (1.0 - pvals.sharpness)); radius = fabs (radius) + 1.0; std_dev1 = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0))); radius = fabs (pvals.mask_radius) + 1.0; std_dev2 = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0))); /* derive the constants for calculating the gaussian from the std dev */ find_constants (n_p1, n_m1, d_p1, d_m1, bd_p1, bd_m1, std_dev1); find_constants (n_p2, n_m2, d_p2, d_m2, bd_p2, bd_m2, std_dev2); /* First the vertical pass */ for (col = 0; col < width; col++) { memset (val_p1, 0, height * sizeof (gdouble)); memset (val_p2, 0, height * sizeof (gdouble)); memset (val_m1, 0, height * sizeof (gdouble)); memset (val_m2, 0, height * sizeof (gdouble)); src1 = dest1 + col; sp_p1 = src1; sp_m1 = src1 + (height - 1) * width; vp1 = val_p1; vp2 = val_p2; vm1 = val_m1 + (height - 1); vm2 = val_m2 + (height - 1); /* Set up the first vals */ initial_p1[0] = sp_p1[0]; initial_m1[0] = sp_m1[0]; for (row = 0; row < height; row++) { gdouble *vpptr1, *vmptr1; gdouble *vpptr2, *vmptr2; terms = (row < 4) ? row : 4; vpptr1 = vp1; vmptr1 = vm1; vpptr2 = vp2; vmptr2 = vm2; for (i = 0; i <= terms; i++) { *vpptr1 += n_p1[i] * sp_p1[-i * width] - d_p1[i] * vp1[-i]; *vmptr1 += n_m1[i] * sp_m1[i * width] - d_m1[i] * vm1[i]; *vpptr2 += n_p2[i] * sp_p1[-i * width] - d_p2[i] * vp2[-i]; *vmptr2 += n_m2[i] * sp_m1[i * width] - d_m2[i] * vm2[i]; } for (j = i; j <= 4; j++) { *vpptr1 += (n_p1[j] - bd_p1[j]) * initial_p1[0]; *vmptr1 += (n_m1[j] - bd_m1[j]) * initial_m1[0]; *vpptr2 += (n_p2[j] - bd_p2[j]) * initial_p1[0]; *vmptr2 += (n_m2[j] - bd_m2[j]) * initial_m1[0]; } sp_p1 += width; sp_m1 -= width; vp1 += 1; vp2 += 1; vm1 -= 1; vm2 -= 1; } transfer_pixels (val_p1, val_m1, dest1 + col, width, height); transfer_pixels (val_p2, val_m2, dest2 + col, width, height); if (!preview) { progress += height; if ((col % 5) == 0) gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } } for (row = 0; row < height; row++) { memset (val_p1, 0, width * sizeof (gdouble)); memset (val_p2, 0, width * sizeof (gdouble)); memset (val_m1, 0, width * sizeof (gdouble)); memset (val_m2, 0, width * sizeof (gdouble)); src1 = dest1 + row * width; src2 = dest2 + row * width; sp_p1 = src1; sp_p2 = src2; sp_m1 = src1 + width - 1; sp_m2 = src2 + width - 1; vp1 = val_p1; vp2 = val_p2; vm1 = val_m1 + width - 1; vm2 = val_m2 + width - 1; /* Set up the first vals */ initial_p1[0] = sp_p1[0]; initial_p2[0] = sp_p2[0]; initial_m1[0] = sp_m1[0]; initial_m2[0] = sp_m2[0]; for (col = 0; col < width; col++) { gdouble *vpptr1, *vmptr1; gdouble *vpptr2, *vmptr2; terms = (col < 4) ? col : 4; vpptr1 = vp1; vmptr1 = vm1; vpptr2 = vp2; vmptr2 = vm2; for (i = 0; i <= terms; i++) { *vpptr1 += n_p1[i] * sp_p1[-i] - d_p1[i] * vp1[-i]; *vmptr1 += n_m1[i] * sp_m1[i] - d_m1[i] * vm1[i]; *vpptr2 += n_p2[i] * sp_p2[-i] - d_p2[i] * vp2[-i]; *vmptr2 += n_m2[i] * sp_m2[i] - d_m2[i] * vm2[i]; } for (j = i; j <= 4; j++) { *vpptr1 += (n_p1[j] - bd_p1[j]) * initial_p1[0]; *vmptr1 += (n_m1[j] - bd_m1[j]) * initial_m1[0]; *vpptr2 += (n_p2[j] - bd_p2[j]) * initial_p2[0]; *vmptr2 += (n_m2[j] - bd_m2[j]) * initial_m2[0]; } sp_p1 ++; sp_p2 ++; sp_m1 --; sp_m2 --; vp1 ++; vp2 ++; vm1 --; vm2 --; } transfer_pixels (val_p1, val_m1, dest1 + row * width, 1, width); transfer_pixels (val_p2, val_m2, dest2 + row * width, 1, width); if (!preview) { progress += width; if ((row % 5) == 0) gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } } /* Compute the ramp value which sets 'pct_black' % of the darkened pixels black */ ramp_down = compute_ramp (dest1, dest2, width * height, pvals.pct_black, 1); ramp_up = compute_ramp (dest1, dest2, width * height, 1.0 - pvals.pct_white, 0); /* Initialize the pixel regions. */ gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, width, height, (preview == NULL), TRUE); pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn); while (pr) { guchar *src_ptr = src_rgn.data; guchar *dest_ptr = dest_rgn.data; guchar *blur_ptr = dest1 + (src_rgn.y - y1) * width + (src_rgn.x - x1); guchar *avg_ptr = dest2 + (src_rgn.y - y1) * width + (src_rgn.x - x1); gdouble diff, mult; gdouble lightness = 0.0; for (row = 0; row < src_rgn.h; row++) { for (col = 0; col < src_rgn.w; col++) { if (avg_ptr[col] > EPSILON) { diff = (gdouble) blur_ptr[col] / (gdouble) avg_ptr[col]; if (diff < pvals.threshold) { if (ramp_down == 0.0) mult = 0.0; else mult = (ramp_down - MIN (ramp_down, (pvals.threshold - diff))) / ramp_down; lightness = CLAMP (blur_ptr[col] * mult, 0, 255); } else { if (ramp_up == 0.0) mult = 1.0; else mult = MIN (ramp_up, (diff - pvals.threshold)) / ramp_up; lightness = 255 - (1.0 - mult) * (255 - blur_ptr[col]); lightness = CLAMP (lightness, 0, 255); } } else { lightness = 0; } if (bytes < 3) { dest_ptr[col * bytes] = (guchar) lightness; if (has_alpha) dest_ptr[col * bytes + 1] = src_ptr[col * src_rgn.bpp + 1]; } else { dest_ptr[col * bytes + 0] = lightness; dest_ptr[col * bytes + 1] = lightness; dest_ptr[col * bytes + 2] = lightness; if (has_alpha) dest_ptr[col * bytes + 3] = src_ptr[col * src_rgn.bpp + 3]; } } src_ptr += src_rgn.rowstride; dest_ptr += dest_rgn.rowstride; blur_ptr += width; avg_ptr += width; } if (preview) { gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), &dest_rgn); } else { progress += src_rgn.w * src_rgn.h; gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } pr = gimp_pixel_rgns_process (pr); } if (! preview) { /* 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, width, height); } /* free up buffers */ g_free (val_p1); g_free (val_p2); g_free (val_m1); g_free (val_m2); g_free (dest1); g_free (dest2); }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglProperties *o = GEGL_PROPERTIES (operation); GeglBufferIterator *iter; GeglBuffer *dest1; GeglBuffer *dest2; gdouble diff; gdouble ramp_down; gdouble ramp_up; gdouble mult; grey_blur_buffer (input, o->sharpness, o->mask_radius, &dest1, &dest2); compute_ramp (dest1, dest2, result, o->black, o->white, TRUE, &ramp_down, &ramp_up); iter = gegl_buffer_iterator_new (dest1, result, 0, babl_format ("Y float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, dest2, result, 0, babl_format ("Y float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, output, result, 0, babl_format ("Y float"), GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { gint n_pixels = iter->length; gfloat *ptr1 = iter->data[0]; gfloat *ptr2 = iter->data[1]; gfloat *out_pixel = iter->data[2]; while (n_pixels--) { diff = *ptr1 / *ptr2; if (diff < THRESHOLD) { if (ramp_down == 0.0) *out_pixel = 0.0; else { mult = (ramp_down - MIN (ramp_down, (THRESHOLD - diff))) / ramp_down; *out_pixel = *ptr1 * mult; } } else { if (ramp_up == 0.0) mult = 1.0; else mult = MIN (ramp_up, (diff - THRESHOLD)) / ramp_up; *out_pixel = mult + *ptr1 - mult * *ptr1; } ptr1++; ptr2++; out_pixel++; } } g_object_unref (dest1); g_object_unref (dest2); return TRUE; }
/// \brief Computes a saw up wave /// \param wave /// the wave /// \return the wave output static midi_value_t compute_saw_up_wave(struct wave* wave) { return compute_ramp(wave); }
/// \brief Computes a saw down wave /// \param wave /// the wave /// \return the wave output static midi_value_t compute_saw_down_wave(struct wave* wave) { return MIDI_MAX_VALUE - compute_ramp(wave); }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglProperties *o = GEGL_PROPERTIES (operation); GeglBufferIterator *iter; GeglBuffer *dest1; GeglBuffer *dest2; GeglSampler *sampler1; GeglSampler *sampler2; gdouble ramp; gint x; gint y; gfloat tot_pixels = result->width * result->height; gfloat pixels = 0; grey_blur_buffer (input, o->mask_radius, &dest1, &dest2); sampler1 = gegl_buffer_sampler_new_at_level (dest1, babl_format ("Y' float"), GEGL_SAMPLER_LINEAR, level); sampler2 = gegl_buffer_sampler_new_at_level (dest2, babl_format ("Y' float"), GEGL_SAMPLER_LINEAR, level); ramp = compute_ramp (sampler1, sampler2, result, o->pct_black); iter = gegl_buffer_iterator_new (output, result, 0, babl_format ("Y'CbCrA float"), GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, input, result, 0, babl_format ("Y'CbCrA float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); gegl_operation_progress (operation, 0.0, ""); while (gegl_buffer_iterator_next (iter)) { gfloat *out_pixel = iter->data[0]; gfloat *in_pixel = iter->data[1]; for (y = iter->roi[0].y; y < iter->roi[0].y + iter->roi[0].height; ++y) { for (x = iter->roi[0].x; x < iter->roi[0].x + iter->roi[0].width; ++x) { gfloat pixel1; gfloat pixel2; gdouble mult = 0.0; gdouble diff; gegl_sampler_get (sampler1, x, y, NULL, &pixel1, GEGL_ABYSS_NONE); gegl_sampler_get (sampler2, x, y, NULL, &pixel2, GEGL_ABYSS_NONE); if (pixel2 != 0) { diff = (gdouble) pixel1 / (gdouble) pixel2; if (diff < THRESHOLD) { if (GEGL_FLOAT_EQUAL (ramp, 0.0)) mult = 0.0; else mult = (ramp - MIN (ramp, (THRESHOLD - diff))) / ramp; } else mult = 1.0; } out_pixel[0] = CLAMP (pixel1 * mult, 0.0, 1.0); out_pixel[1] = in_pixel[1]; out_pixel[2] = in_pixel[2]; out_pixel[3] = in_pixel[3]; out_pixel += 4; in_pixel += 4; } pixels += iter->roi[0].width; gegl_operation_progress (operation, pixels / tot_pixels, ""); } } gegl_operation_progress (operation, 1.0, ""); g_object_unref (sampler1); g_object_unref (sampler2); g_object_unref (dest1); g_object_unref (dest2); return TRUE; }