static void tile_request_end(MyPaintTiledSurface *tiled_surface, MyPaintTileRequest *request) { MyPaintGeglTiledSurface *self = (MyPaintGeglTiledSurface *)tiled_surface; if (buffer_is_native(self)) { GeglBufferIterator *iterator = (GeglBufferIterator *)request->context; if (iterator) { gegl_buffer_iterator_next(iterator); request->context = NULL; } } else { // Push our linear buffer back into the GeglBuffer const int tile_size = tiled_surface->tile_size; GeglRectangle tile_bbox; g_assert(request->buffer); gegl_rectangle_set(&tile_bbox, request->tx*tile_size, request->ty*tile_size, tile_size, tile_size); gegl_buffer_set(self->buffer, &tile_bbox, 0, self->format, request->buffer, GEGL_AUTO_ROWSTRIDE); gegl_free(request->buffer); } }
void gegl_random_cleanup (void) { if (random_data_inited) { gegl_free (gegl_random_data); gegl_random_data = NULL; random_data_inited = FALSE; } }
int main(int argc, char **argv) { GeglTile *tile; GeglBuffer *buf_a, *buf_b, *buf_small_lin, *buf_big_lin; gpointer shared_data = NULL; gboolean result = TRUE; gpointer scratch_data; GeglRectangle buffer_rect = *GEGL_RECTANGLE(0, 0, 128, 128); gegl_init (&argc, &argv); buf_a = gegl_buffer_new (&buffer_rect, babl_format("RGBA u8")); buf_b = gegl_buffer_new (&buffer_rect, babl_format("RGBA u8")); buf_small_lin = gegl_buffer_linear_new (&buffer_rect, babl_format("RGBA float")); buf_big_lin = gegl_buffer_linear_new (GEGL_RECTANGLE(0, 0, 1024, 1024), babl_format("RGBA float")); tile = gegl_tile_source_get_tile (GEGL_TILE_SOURCE (buf_a), 0, 0, 0); shared_data = gegl_tile_get_data(tile); gegl_tile_unref (tile); if (!assert_is_empty (buf_a, 0, 0, shared_data)) result = FALSE; if (!assert_is_empty (buf_b, 0, 1, shared_data)) result = FALSE; if (!assert_is_empty (buf_a, 0, 0, shared_data)) result = FALSE; if (!assert_is_empty (buf_b, 0, 1, shared_data)) result = FALSE; if (!assert_is_empty (buf_small_lin, 0, 0, shared_data)) result = FALSE; if (!assert_is_unshared (buf_big_lin, 0, 0, shared_data)) result = FALSE; scratch_data = gegl_malloc(4 * buffer_rect.width * buffer_rect.height); gegl_buffer_get (buf_a, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE); gegl_buffer_get (buf_b, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE); gegl_buffer_get (buf_small_lin, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE); gegl_buffer_get (buf_big_lin, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE); gegl_free (scratch_data); g_object_unref(buf_a); g_object_unref(buf_b); g_object_unref(buf_small_lin); g_object_unref(buf_big_lin); gegl_exit(); if (result) return SUCCESS; return FAILURE; }
static void wav_hor_blur (GeglBuffer *src, GeglBuffer *dst, const GeglRectangle *dst_rect, gint radius, const Babl *format) { gint x, y; GeglRectangle write_rect = {dst_rect->x, dst_rect->y, dst_rect->width, 1}; GeglRectangle read_rect = {dst_rect->x - radius, dst_rect->y, dst_rect->width + 2 * radius, 1}; gfloat *src_buf = gegl_malloc (read_rect.width * sizeof (gfloat) * 3); gfloat *dst_buf = gegl_malloc (write_rect.width * sizeof (gfloat) * 3); for (y = 0; y < dst_rect->height; y++) { gint offset = 0; read_rect.y = dst_rect->y + y; write_rect.y = dst_rect->y + y; gegl_buffer_get (src, &read_rect, 1.0, format, src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP); for (x = 0; x < dst_rect->width; x++) { wav_get_mean_pixel_1D (src_buf + offset, dst_buf + offset, radius); offset += 3; } gegl_buffer_set (dst, &write_rect, 0, format, dst_buf, GEGL_AUTO_ROWSTRIDE); } gegl_free (src_buf); gegl_free (dst_buf); }
void gegl_buffer_linear_close (GeglBuffer *buffer, gpointer linear) { GeglTile *tile; tile = g_object_get_data (G_OBJECT (buffer), "linear-tile"); if (tile) { gegl_tile_unlock (tile); gegl_tile_unref (tile); g_object_set_data (G_OBJECT (buffer), "linear-tile", NULL); } else { GList *linear_buffers; GList *iter; linear_buffers = g_object_get_data (G_OBJECT (buffer), "linear-buffers"); for (iter = linear_buffers; iter; iter=iter->next) { BufferInfo *info = iter->data; if (info->buf == linear) { info->refs--; if (info->refs>0) { g_print ("EEeeek! %s\n", G_STRLOC); return; /* there are still others holding a reference to * this linear buffer */ } linear_buffers = g_list_remove (linear_buffers, info); g_object_set_data (G_OBJECT (buffer), "linear-buffers", linear_buffers); g_rec_mutex_unlock (&buffer->tile_storage->mutex); /* XXX: potential race */ gegl_buffer_set (buffer, &info->extent, 0, info->format, info->buf, 0); gegl_free (info->buf); g_free (info); g_rec_mutex_lock (&buffer->tile_storage->mutex); break; } } } /*gegl_buffer_unlock (buffer);*/ g_rec_mutex_unlock (&buffer->tile_storage->mutex); return; }
static void release_tile (GeglBufferIterator *iter, int index) { GeglBufferIteratorPriv *priv = iter->priv; SubIterState *sub = &priv->sub_iter[index]; if (sub->current_tile_mode == GeglIteratorTileMode_DirectTile) { if (sub->access_mode & GEGL_ACCESS_WRITE) gegl_tile_unlock (sub->current_tile); gegl_tile_unref (sub->current_tile); sub->current_tile = NULL; iter->data[index] = NULL; sub->current_tile_mode = GeglIteratorTileMode_Empty; } else if (sub->current_tile_mode == GeglIteratorTileMode_LinearTile) { sub->current_tile = NULL; iter->data[index] = NULL; sub->current_tile_mode = GeglIteratorTileMode_Empty; } else if (sub->current_tile_mode == GeglIteratorTileMode_GetBuffer) { if (sub->access_mode & GEGL_ACCESS_WRITE) { gegl_buffer_set_unlocked_no_notify (sub->buffer, &sub->real_roi, sub->level, sub->format, sub->real_data, GEGL_AUTO_ROWSTRIDE); } gegl_free (sub->real_data); sub->real_data = NULL; iter->data[index] = NULL; sub->current_tile_mode = GeglIteratorTileMode_Empty; } else if (sub->current_tile_mode == GeglIteratorTileMode_Empty) { return; } else { g_warn_if_reached (); } }
static void fir_ver_blur (GeglBuffer *src, const GeglRectangle *rect, GeglBuffer *dst, gfloat *cmatrix, gint clen, GeglAbyssPolicy policy, const Babl *format) { GeglRectangle cur_col = *rect; GeglRectangle in_col; const gint nc = babl_format_get_n_components (format); gfloat *col; gfloat *out; gint v; cur_col.width = 1; in_col = cur_col; in_col.height += clen - 1; in_col.y -= clen / 2; col = gegl_malloc (sizeof (gfloat) * in_col.height * nc); out = gegl_malloc (sizeof (gfloat) * cur_col.height * nc); for (v = 0; v < rect->width; v++) { cur_col.x = in_col.x = rect->x + v; gegl_buffer_get (src, &in_col, 1.0, format, col, GEGL_AUTO_ROWSTRIDE, policy); fir_blur_1D (col, out, cmatrix, clen, rect->height, nc); gegl_buffer_set (dst, &cur_col, 0, format, out, GEGL_AUTO_ROWSTRIDE); } gegl_free (out); gegl_free (col); }
static void fir_hor_blur (GeglBuffer *src, const GeglRectangle *rect, GeglBuffer *dst, gfloat *cmatrix, gint clen, GeglAbyssPolicy policy, const Babl *format) { GeglRectangle cur_row = *rect; GeglRectangle in_row; const gint nc = babl_format_get_n_components (format); gfloat *row; gfloat *out; gint v; cur_row.height = 1; in_row = cur_row; in_row.width += clen - 1; in_row.x -= clen / 2; row = gegl_malloc (sizeof (gfloat) * in_row.width * nc); out = gegl_malloc (sizeof (gfloat) * cur_row.width * nc); for (v = 0; v < rect->height; v++) { cur_row.y = in_row.y = rect->y + v; gegl_buffer_get (src, &in_row, 1.0, format, row, GEGL_AUTO_ROWSTRIDE, policy); fir_blur_1D (row, out, cmatrix, clen, rect->width, nc); gegl_buffer_set (dst, &cur_row, 0, format, out, GEGL_AUTO_ROWSTRIDE); } gegl_free (out); gegl_free (row); }
static gboolean gegl_gblur_1d_process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglProperties *o = GEGL_PROPERTIES (operation); const Babl *format = gegl_operation_get_format (operation, "output"); GeglGblur1dFilter filter; GeglAbyssPolicy abyss_policy = to_gegl_policy (o->abyss_policy); filter = filter_disambiguation (o->filter, o->std_dev); if (filter == GEGL_GBLUR_1D_IIR) { gdouble b[4], m[3][3]; iir_young_find_constants (o->std_dev, b, m); if (o->orientation == GEGL_ORIENTATION_HORIZONTAL) iir_young_hor_blur (input, result, output, b, m, abyss_policy, format); else iir_young_ver_blur (input, result, output, b, m, abyss_policy, format); } else { gfloat *cmatrix; gint clen; clen = fir_gen_convolve_matrix (o->std_dev, &cmatrix); /* FIXME: implement others format cases */ if (gegl_operation_use_opencl (operation) && format == babl_format ("RaGaBaA float")) if (fir_cl_process(input, output, result, format, cmatrix, clen, o->orientation, abyss_policy)) return TRUE; if (o->orientation == GEGL_ORIENTATION_HORIZONTAL) fir_hor_blur (input, result, output, cmatrix, clen, abyss_policy, format); else fir_ver_blur (input, result, output, cmatrix, clen, abyss_policy, format); gegl_free (cmatrix); } return TRUE; }
void gegl_tile_unref (GeglTile *tile) { if (!g_atomic_int_dec_and_test (&tile->ref_count)) return; /* In the case of a file store for example, we must make sure that * the in-memory tile is written to disk before we free the memory, * otherwise this data will be lost. */ if (!gegl_tile_is_stored (tile)) gegl_tile_store (tile); if (tile->data) { if (tile->next_shared == tile) { /* no clones */ if (tile->destroy_notify) { if (tile->destroy_notify == (void*)&free_data_directly) gegl_free (tile->data); else tile->destroy_notify (tile->destroy_notify_data); } tile->data = NULL; } else { tile->prev_shared->next_shared = tile->next_shared; tile->next_shared->prev_shared = tile->prev_shared; } } #ifdef GEGL_USE_TILE_MUTEX if (tile->mutex) { g_mutex_free (tile->mutex); tile->mutex = NULL; } #endif g_slice_free (GeglTile, tile); }
static gboolean test_scale (const gdouble scale, const gint x, const gint y, const Babl *format) { GeglNode *checkerboard; GeglBuffer *tmp_buffer; gboolean result = FALSE; const gint bpp = babl_format_get_bytes_per_pixel (format); const gint scaled_width = 32; const gint scaled_height = 32; gint pad = 32; guchar *output_buffer_scaled = gegl_malloc (scaled_width * scaled_height * bpp); guchar *output_node_scaled = gegl_malloc (scaled_width * scaled_height * bpp); if (2 / scale > pad) pad = 2 / scale + 2; tmp_buffer = gegl_buffer_new (GEGL_RECTANGLE ((x / scale) - pad, (y / scale) - pad, (scaled_width / scale) + (2 * pad), (scaled_height / scale) + (2 * pad)), babl_format ("RGBA float")); checkerboard = gegl_node_new_child(NULL, "operation", "gegl:checkerboard", "x", 16, "y", 16, NULL); gegl_node_blit_buffer (checkerboard, tmp_buffer, NULL, 0, GEGL_ABYSS_NONE); gegl_buffer_get (tmp_buffer, GEGL_RECTANGLE (x, y, scaled_width, scaled_height), scale, format, output_buffer_scaled, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); g_object_unref (checkerboard); g_object_unref (tmp_buffer); /* Re-create the node so we don't hit its cache */ checkerboard = gegl_node_new_child(NULL, "operation", "gegl:checkerboard", "x", 16, "y", 16, NULL); gegl_node_blit (checkerboard, scale, GEGL_RECTANGLE (x, y, scaled_width, scaled_height), format, output_node_scaled, GEGL_AUTO_ROWSTRIDE, 0); g_object_unref (checkerboard); if (0 == memcmp (output_buffer_scaled, output_node_scaled, scaled_width * scaled_height * bpp)) { printf ("."); fflush(stdout); result = TRUE; } else { printf ("\n scale=%.4f at %d, %d in \"%s\" ... FAIL\n", scale, x, y, babl_get_name (format)); result = FALSE; } gegl_free (output_buffer_scaled); gegl_free (output_node_scaled); return result; }
/** * Process the gegl filter * @param operation the given Gegl operation * @param input the input buffer. * @param output the output buffer. * @param result the region of interest. * @param level the level of detail * @return True, if the filter was successfull applied. */ static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglProperties *o = GEGL_PROPERTIES (operation); const Babl *input_format = gegl_buffer_get_format (input); const int bytes_per_pixel = babl_format_get_bytes_per_pixel (input_format); /** * src_buf, dst_buf: * Input- and output-buffers, containing the whole selection, * the filter should be applied on. * * src_pixel, dst_pixel: * pointers to the current source- and destination-pixel. * Using these pointers, the reading and writing can be delayed till the * end of the loop. Hence src_pixel can also point to background_color if * necessary. */ guint8 *src_buf, *dst_buf, *src_pixel, *dst_pixel, background_color[bytes_per_pixel]; /** * (x, y): Position of the pixel we compute at the moment. * (width, height): Dimensions of the lens * pixel_offset: For calculating the pixels position in src_buf / dst_buf. */ gint x, y, width, height, pixel_offset, projected_pixel_offset; /** * Further parameters that are needed to calculate the position of a projected * further pixel at (x, y). */ gfloat a, b, c, asqr, bsqr, csqr, dx, dy, dysqr, projected_x, projected_y, refraction_index; gboolean keep_surroundings; width = result->width; height = result->height; refraction_index = o->refraction_index; keep_surroundings = o->keep_surroundings; gegl_color_get_pixel (o->background_color, input_format, background_color); a = 0.5 * width; b = 0.5 * height; c = MIN (a, b); asqr = a * a; bsqr = b * b; csqr = c * c; /** * Todo: We might want to change the buffers sizes, as the memory consumption * could be rather large.However, due to the lens, it might happen, that one pixel from the * images center gets stretched to the whole image, so we will still need * at least a src_buf of size (width/2) * (height/2) * 4 to be able to * process one quarter of the image. */ src_buf = gegl_malloc (width * height * bytes_per_pixel); dst_buf = gegl_malloc (width * height * bytes_per_pixel); gegl_buffer_get (input, result, 1.0, input_format, src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); for (y = 0; y < height; y++) { /* dy is the current pixels distance (in y-direction) of the lenses center */ dy = -((gfloat)y - b + 0.5); /** * To determine, whether the pixel is within the elliptical region affected * by the lens, we furthermore need the squared distance. So we calculate it * once for each row. */ dysqr = dy * dy; for (x = 0; x < width; x++) { /* Again we need to calculate the pixels distance from the lens dx. */ dx = (gfloat)x - a + 0.5; /* Given x and y we can now determine the pixels offset in our buffer. */ pixel_offset = (x + y * width) * bytes_per_pixel; /* As described above, we only read and write image data once. */ dst_pixel = &dst_buf[pixel_offset]; if (dysqr < (bsqr - (bsqr * dx * dx) / asqr)) { /** * If (x, y) is inside the affected region, we can find its projected * position, calculate the projected_pixel_offset and set the src_pixel * to where we want to copy the pixel-data from. */ find_projected_pos (asqr, bsqr, csqr, dx, dy, refraction_index, &projected_x, &projected_y); projected_pixel_offset = ( (gint)(-projected_y + b) * width + (gint)( projected_x + a) ) * bytes_per_pixel; src_pixel = &src_buf[projected_pixel_offset]; } 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 (keep_surroundings) src_pixel = &src_buf[pixel_offset]; else src_pixel = background_color; } /** * At the end, we can copy the src_pixel (which was determined above), to * dst_pixel. */ memcpy (dst_pixel, src_pixel, bytes_per_pixel); } } gegl_buffer_set (output, result, 0, gegl_buffer_get_format (output), dst_buf, GEGL_AUTO_ROWSTRIDE); gegl_free (dst_buf); gegl_free (src_buf); return TRUE; }
static gboolean test_operation (const char *operation_name) { gboolean result = FALSE; const Babl *format = babl_format ("RGBA u8"); const gint bpp = babl_format_get_bytes_per_pixel (format); const gint out_width = 5 + 10; const gint out_height = 5 + 10; guchar *output_with_abyss = gegl_malloc (out_width * out_height * bpp); guchar *output_no_abyss = gegl_malloc (out_width * out_height * bpp); GeglColor *upper_color = gegl_color_new ("rgb(0.2, 0.8, 0.2)"); GeglColor *lower_color = gegl_color_new ("rgb(0.0, 0.0, 0.0)"); GeglColor *transparent = gegl_color_new ("rgba(0.0, 0.0, 0.0, 0.0)"); { /* Using abyss */ GeglNode *ptn = gegl_node_new(); GeglNode *test_op, *upper_rect, *lower_rect; test_op = gegl_node_new_child (ptn, "operation", operation_name, NULL); upper_rect = gegl_node_new_child (ptn, "operation", "gegl:rectangle", "color", upper_color, "x", 5.0, "y", 5.0, "width", 10.0, "height", 10.0, NULL); lower_rect = gegl_node_new_child (ptn, "operation", "gegl:rectangle", "color", lower_color, "x", 0.0, "y", 0.0, "width", 10.0, "height", 10.0, NULL); gegl_node_connect_to (lower_rect, "output", test_op, "input"); gegl_node_connect_to (upper_rect, "output", test_op, "aux"); { int i; guchar *out = output_with_abyss; for (i = 0; i < out_height; i++) { gegl_node_blit (test_op, 1.0, GEGL_RECTANGLE (0, i, out_width, 1), format, out, GEGL_AUTO_ROWSTRIDE, 0); out += out_width * bpp; } } g_object_unref (ptn); } { /* Explicit transparency */ GeglNode *ptn = gegl_node_new(); GeglNode *test_op, *upper_rect, *lower_rect; GeglNode *upper_over, *lower_over; GeglNode *background; test_op = gegl_node_new_child (ptn, "operation", operation_name, NULL); background = gegl_node_new_child (ptn, "operation", "gegl:rectangle", "color", transparent, "x", 0.0, "y", 0.0, "width", 10.0 + 5.0, "height", 10.0 + 5.0, NULL); upper_rect = gegl_node_new_child (ptn, "operation", "gegl:rectangle", "color", upper_color, "x", 5.0, "y", 5.0, "width", 10.0, "height", 10.0, NULL); upper_over = gegl_node_new_child (ptn, "operation", "gegl:over", NULL); lower_rect = gegl_node_new_child (ptn, "operation", "gegl:rectangle", "color", lower_color, "x", 0.0, "y", 0.0, "width", 10.0, "height", 10.0, NULL); lower_over = gegl_node_new_child (ptn, "operation", "gegl:over", NULL); gegl_node_connect_to (lower_rect, "output", lower_over, "aux"); gegl_node_connect_to (upper_rect, "output", upper_over, "aux"); gegl_node_connect_to (background, "output", lower_over, "input"); gegl_node_connect_to (background, "output", upper_over, "input"); gegl_node_connect_to (lower_over, "output", test_op, "input"); gegl_node_connect_to (upper_over, "output", test_op, "aux"); { int i; guchar *out = output_no_abyss; for (i = 0; i < out_height; i++) { gegl_node_blit (test_op, 1.0, GEGL_RECTANGLE (0, i, out_width, 1), format, out, GEGL_AUTO_ROWSTRIDE, 0); out += out_width * bpp; } } g_object_unref (ptn); } if (0 == memcmp (output_with_abyss, output_no_abyss, out_width * out_height * bpp)) { printf ("."); fflush(stdout); result = TRUE; } else { printf ("\n %s ... FAIL\n", operation_name); result = FALSE; } if (!result) { GeglBuffer *linear; gchar *filename; filename = g_strconcat (operation_name, " - with abyss.png", NULL); linear = gegl_buffer_linear_new_from_data (output_with_abyss, format, GEGL_RECTANGLE (0, 0, out_width, out_height), GEGL_AUTO_ROWSTRIDE, NULL, NULL); dump_to_png (filename, linear); g_free (filename); g_object_unref (linear); filename = g_strconcat (operation_name, " - no abyss.png", NULL); linear = gegl_buffer_linear_new_from_data (output_no_abyss, format, GEGL_RECTANGLE (0, 0, out_width, out_height), GEGL_AUTO_ROWSTRIDE, NULL, NULL); dump_to_png (filename, linear); g_free (filename); g_object_unref (linear); } gegl_free (output_with_abyss); gegl_free (output_no_abyss); return result; }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation); gfloat *src_buf; gfloat *dst_buf; gint n_pixels = result->width * result->height; GeglRectangle src_rect; gfloat *current_pix; gfloat *target_pix; gfloat *dst_pix; gint x, y; gint total_src_pixels; gint total_dst_pixels; gint bleed_max; gint bleed_index; gfloat blend_coefficient; GHashTable *bleed_table; static GMutex mutex = { 0, }; g_mutex_lock (&mutex); if (!o->chant_data) { o->chant_data = g_hash_table_new_full (tuple_hash, tuple_equal, g_free, g_free); calculate_bleed (operation, input); } g_mutex_unlock (&mutex); bleed_table = (GHashTable*) o->chant_data; src_rect.x = result->x - op_area->left; src_rect.width = result->width + op_area->left + op_area->right; src_rect.y = result->y - op_area->top; src_rect.height = result->height + op_area->top + op_area->bottom; total_src_pixels = src_rect.width * src_rect.height; total_dst_pixels = result->width * result->height; src_buf = gegl_malloc (4 * total_src_pixels * sizeof (gfloat)); dst_buf = gegl_malloc (4 * total_dst_pixels * sizeof (gfloat)); gegl_buffer_get (input, &src_rect, 1.0, babl_format ("RGBA float"), src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); current_pix = src_buf + 4*(o->strength + src_rect.width * o->strength); dst_pix = dst_buf; x = 0; y = 0; n_pixels = result->width * result->height; bleed_max = 0; bleed_index = 0; while (n_pixels--) { gint i; pair key = {x + result->x, y + result->y}; gint *bleed = g_hash_table_lookup (bleed_table, &key); if (x == 0) { for (i = 0; i < o->strength; i++) { pair key = {result->x - i, y + result->y}; gint *bleed = g_hash_table_lookup (bleed_table, &key); if (bleed) { bleed_max = *bleed; bleed_index = *bleed - i; break; } } } for (i = 0; i < 4; i++) dst_pix[i] = current_pix[i]; if (bleed) { gfloat blend_color[4]; gfloat blend_amount[4]; gfloat *blend_pix; bleed_max = *bleed; bleed_index = *bleed; target_pix = current_pix; blend_pix = current_pix - 12; for (i = 0; i < 4; i++) { blend_amount[i] = target_pix[i] - blend_pix[i]; blend_color[i] = blend_pix[i] + blend_amount[i]; dst_pix[i] = (2.0 * blend_color[i] + dst_pix[i])/3.0; } } else if (bleed_index > 0) { gfloat blend_color[4]; gfloat blend_amount[4]; gfloat *blend_pix; bleed_index--; blend_coefficient = 1.0 - ((gfloat) bleed_index)/(gfloat) bleed_max; blend_pix = current_pix - 4 * (bleed_max - bleed_index) - 12; target_pix = current_pix; for (i = 0; i < 4; i++) { blend_amount[i] = target_pix[i] - blend_pix[i]; blend_color[i] = blend_pix[i] + blend_amount[i] * blend_coefficient; dst_pix[i] = (2.0 * blend_color[i] + dst_pix[i])/3.0; } } x++; current_pix += 4; dst_pix += 4; if (x >= result->width) { bleed_max = 0; bleed_index = 0; x = 0; y++; current_pix += 8 * o->strength; } } gegl_buffer_set (output, result, 1, babl_format ("RGBA float"), dst_buf, GEGL_AUTO_ROWSTRIDE); gegl_free (src_buf); gegl_free (dst_buf); return TRUE; }
/** * Process the gegl filter * @param operation the given Gegl operation * @param input the input buffer. * @param output the output buffer. * @param result the region of interest. * @param level the level of detail * @return True, if the filter was successfull applied. */ static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglProperties *o = GEGL_PROPERTIES (operation); const Babl *input_format = babl_format ("Y float"); const int bytes_per_pixel = babl_format_get_bytes_per_pixel (input_format); GeglDTMetric metric; gint width, height, averaging, i; gfloat threshold_lo, threshold_hi, maxval, *src_buf, *dst_buf; gboolean normalize; width = result->width; height = result->height; threshold_lo = o->threshold_lo; threshold_hi = o->threshold_hi; normalize = o->normalize; metric = o->metric; averaging = o->averaging; src_buf = gegl_malloc (width * height * bytes_per_pixel); dst_buf = gegl_calloc (width * height, bytes_per_pixel); gegl_operation_progress (operation, 0.0, ""); gegl_buffer_get (input, result, 1.0, input_format, src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); if (!averaging) { binary_dt_1st_pass (operation, width, height, threshold_lo, src_buf, dst_buf); binary_dt_2nd_pass (operation, width, height, threshold_lo, metric, src_buf, dst_buf); } else { gfloat *tmp_buf; gint i, j; tmp_buf = gegl_malloc (width * height * bytes_per_pixel); for (i = 0; i < averaging; i++) { gfloat thres; thres = (i+1) * (threshold_hi - threshold_lo) / (averaging + 1); thres += threshold_lo; binary_dt_1st_pass (operation, width, height, thres, src_buf, tmp_buf); binary_dt_2nd_pass (operation, width, height, thres, metric, src_buf, tmp_buf); for (j = 0; j < width * height; j++) dst_buf[j] += tmp_buf[j]; } gegl_free (tmp_buf); } if (normalize) { maxval = EPSILON; for (i = 0; i < width * height; i++) maxval = MAX (dst_buf[i], maxval); } else { maxval = averaging; } if (averaging > 0 || normalize) { for (i = 0; i < width * height; i++) dst_buf[i] = dst_buf[i] * threshold_hi / maxval; } gegl_buffer_set (output, result, 0, input_format, dst_buf, GEGL_AUTO_ROWSTRIDE); gegl_operation_progress (operation, 1.0, ""); gegl_free (dst_buf); gegl_free (src_buf); return TRUE; }
static void binary_dt_2nd_pass (GeglOperation *operation, gint width, gint height, gfloat thres_lo, GeglDTMetric metric, gfloat *src, gfloat *dest) { gint u, y; gint q, w, *t, *s; gfloat *g, *row_copy; gfloat (*dt_f) (gfloat, gfloat, gfloat); gint (*dt_sep) (gint, gint, gfloat, gfloat); switch (metric) { case GEGL_DT_METRIC_CHESSBOARD: dt_f = cdt_f; dt_sep = cdt_sep; break; case GEGL_DT_METRIC_MANHATTAN: dt_f = mdt_f; dt_sep = mdt_sep; break; default: /* GEGL_DT_METRIC_EUCLIDEAN */ dt_f = edt_f; dt_sep = edt_sep; break; } /* sorry for the variable naming, they are taken from the paper */ s = gegl_calloc (sizeof (gint), width); t = gegl_calloc (sizeof (gint), width); row_copy = gegl_calloc (sizeof (gfloat), width); /* this could be parallelized */ for (y = 0; y < height; y++) { q = 0; s[0] = 0; t[0] = 0; g = dest + y * width; dest[0 + y * width] = MIN (dest[0 + y * width], 1.0); dest[width - 1 + y * width] = MIN (dest[width - 1 + y * width], 1.0); for (u = 1; u < width; u++) { while (q >= 0 && dt_f (t[q], s[q], g[s[q]]) >= dt_f (t[q], u, g[u]) + EPSILON) { q --; } if (q < 0) { q = 0; s[0] = u; } else { /* function Sep from paper */ w = dt_sep (s[q], u, g[s[q]], g[u]); w += 1; if (w < width) { q ++; s[q] = u; t[q] = w; } } } memcpy (row_copy, g, width * sizeof (gfloat)); for (u = width - 1; u >= 0; u--) { if (u == s[q]) g[u] = row_copy[u]; else g[u] = dt_f (u, s[q], row_copy[s[q]]); if (q > 0 && u == t[q]) { q--; } } gegl_operation_progress (operation, (gdouble) y / (gdouble) height / 2.0 + 0.5, ""); } gegl_free (t); gegl_free (s); gegl_free (row_copy); }