static gpointer iterator_buf_pool_get (gint size) { gint i; g_static_mutex_lock (&pool_mutex); if (G_UNLIKELY (!buf_pool)) { buf_pool = g_array_new (TRUE, TRUE, sizeof (BufInfo)); } for (i=0; i<buf_pool->len; i++) { BufInfo *info = &g_array_index (buf_pool, BufInfo, i); if (info->size >= size && info->used == 0) { info->used ++; g_static_mutex_unlock (&pool_mutex); return info->buf; } } { BufInfo info = {0, 1, NULL}; info.size = size; info.buf = gegl_malloc (size); g_array_append_val (buf_pool, info); g_static_mutex_unlock (&pool_mutex); return info.buf; } }
static gpointer gegl_memdup (gpointer src, gsize size) { gpointer ret; ret = gegl_malloc (size); memcpy (ret, src, size); return ret; }
GeglTile * gegl_tile_new (gint size) { GeglTile *tile = gegl_tile_new_bare (); tile->data = gegl_malloc (size); tile->size = size; return tile; }
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); }
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 void gegl_random_init (void) { if (random_data_inited) return; else { GRand *gr = g_rand_new_with_seed (42); gint i; /* Ensure alignment, needed with the use of CL_MEM_USE_HOST_PTR */ gegl_random_data = gegl_malloc (RANDOM_DATA_SIZE * sizeof (guint32)); for (i = 0; i < RANDOM_DATA_SIZE; i++) gegl_random_data[i] = g_rand_int (gr); g_rand_free (gr); random_data_inited = TRUE; } }
static void get_indirect (GeglBufferIterator *iter, int index) { GeglBufferIteratorPriv *priv = iter->priv; SubIterState *sub = &priv->sub_iter[index]; sub->real_data = gegl_malloc (sub->format_bpp * sub->real_roi.width * sub->real_roi.height); if (sub->access_mode & GEGL_ACCESS_READ) { gegl_buffer_get_unlocked (sub->buffer, sub->level?1.0/(1<<sub->level):1.0, &sub->real_roi, sub->format, sub->real_data, GEGL_AUTO_ROWSTRIDE, sub->abyss_policy); } sub->row_stride = sub->real_roi.width * sub->format_bpp; iter->data[index] = sub->real_data; sub->current_tile_mode = GeglIteratorTileMode_GetBuffer; }
static gint fir_gen_convolve_matrix (gfloat sigma, gfloat **cmatrix) { gint clen; gfloat *cmatrix_p; clen = fir_calc_convolve_matrix_length (sigma); *cmatrix = gegl_malloc (sizeof (gfloat) * clen); cmatrix_p = *cmatrix; if (clen == 1) { cmatrix_p [0] = 1; } else { gint i; gdouble sum = 0; gint half_clen = clen / 2; for (i = 0; i < clen; i++) { cmatrix_p [i] = gaussian_func_1d (i - half_clen, sigma); sum += cmatrix_p [i]; } for (i = 0; i < clen; i++) { cmatrix_p [i] /= sum; } } return clen; }
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; }
void * alloc_for_format(const Babl *format, int pixels) { const size_t bytes = babl_format_get_bytes_per_pixel(format)*pixels; return gegl_malloc(bytes); }
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; }
void gimp_display_shell_render (GimpDisplayShell *shell, cairo_t *cr, gint x, gint y, gint w, gint h) { GimpImage *image; GeglBuffer *buffer; #ifdef USE_NODE_BLIT GeglNode *node; #endif gdouble scale_x = 1.0; gdouble scale_y = 1.0; gdouble buffer_scale = 1.0; gint viewport_offset_x; gint viewport_offset_y; gint viewport_width; gint viewport_height; gint scaled_x; gint scaled_y; gint scaled_width; gint scaled_height; cairo_surface_t *xfer; gint xfer_src_x; gint xfer_src_y; gint mask_src_x = 0; gint mask_src_y = 0; gint cairo_stride; guchar *cairo_data; GeglBuffer *cairo_buffer; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_return_if_fail (cr != NULL); g_return_if_fail (w > 0 && h > 0); image = gimp_display_get_image (shell->display); buffer = gimp_pickable_get_buffer (GIMP_PICKABLE (image)); #ifdef USE_NODE_BLIT node = gimp_projectable_get_graph (GIMP_PROJECTABLE (image)); #endif #ifdef GIMP_DISPLAY_RENDER_ENABLE_SCALING /* if we had this future API, things would look pretty on hires (retina) */ scale_x = gdk_window_get_scale_factor (gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (shell)))); #endif scale_x = MIN (scale_x, GIMP_DISPLAY_RENDER_MAX_SCALE); scale_y = scale_x; if (shell->scale_x > shell->scale_y) { scale_y *= (shell->scale_x / shell->scale_y); buffer_scale = shell->scale_y * scale_y; } else if (shell->scale_y > shell->scale_x) { scale_x *= (shell->scale_y / shell->scale_x); buffer_scale = shell->scale_x * scale_x; } else { buffer_scale = shell->scale_x * scale_x; } gimp_display_shell_scroll_get_scaled_viewport (shell, &viewport_offset_x, &viewport_offset_y, &viewport_width, &viewport_height); scaled_x = floor ((x + viewport_offset_x) * scale_x); scaled_y = floor ((y + viewport_offset_y) * scale_y); scaled_width = ceil (w * scale_x); scaled_height = ceil (h * scale_y); if (shell->rotate_transform) { xfer = cairo_surface_create_similar_image (cairo_get_target (cr), CAIRO_FORMAT_ARGB32, scaled_width, scaled_height); cairo_surface_mark_dirty (xfer); xfer_src_x = 0; xfer_src_y = 0; } else { xfer = gimp_display_xfer_get_surface (shell->xfer, scaled_width, scaled_height, &xfer_src_x, &xfer_src_y); } cairo_stride = cairo_image_surface_get_stride (xfer); cairo_data = cairo_image_surface_get_data (xfer) + xfer_src_y * cairo_stride + xfer_src_x * 4; cairo_buffer = gegl_buffer_linear_new_from_data (cairo_data, babl_format ("cairo-ARGB32"), GEGL_RECTANGLE (0, 0, scaled_width, scaled_height), cairo_stride, NULL, NULL); if (shell->profile_transform || gimp_display_shell_has_filter (shell)) { gboolean can_convert_to_u8; /* if there is a profile transform or a display filter, we need * to use temp buffers */ can_convert_to_u8 = gimp_display_shell_profile_can_convert_to_u8 (shell); /* create the filter buffer if we have filters */ if ((gimp_display_shell_has_filter (shell) || ! can_convert_to_u8) && ! shell->filter_buffer) { gint w = GIMP_DISPLAY_RENDER_BUF_WIDTH * GIMP_DISPLAY_RENDER_MAX_SCALE; gint h = GIMP_DISPLAY_RENDER_BUF_HEIGHT * GIMP_DISPLAY_RENDER_MAX_SCALE; shell->filter_data = gegl_malloc (w * h * babl_format_get_bytes_per_pixel (shell->filter_format)); shell->filter_stride = w * babl_format_get_bytes_per_pixel (shell->filter_format); shell->filter_buffer = gegl_buffer_linear_new_from_data (shell->filter_data, shell->filter_format, GEGL_RECTANGLE (0, 0, w, h), GEGL_AUTO_ROWSTRIDE, (GDestroyNotify) gegl_free, shell->filter_data); } if (shell->profile_transform) { /* if there is a profile transform, load the projection * pixels into the profile_buffer */ #ifndef USE_NODE_BLIT gegl_buffer_get (buffer, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), buffer_scale, gimp_projectable_get_format (GIMP_PROJECTABLE (image)), shell->profile_data, shell->profile_stride, GEGL_ABYSS_CLAMP); #else gegl_node_blit (node, buffer_scale, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), gimp_projectable_get_format (GIMP_PROJECTABLE (image)), shell->profile_data, shell->profile_stride, GEGL_BLIT_CACHE); #endif if (gimp_display_shell_has_filter (shell) || ! can_convert_to_u8) { /* if there are filters, convert the pixels from the * profile_buffer to the filter_buffer */ gimp_display_shell_profile_convert_buffer (shell, shell->profile_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height), shell->filter_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height)); } else { /* otherwise, convert the profile_buffer directly into * the cairo_buffer */ gimp_display_shell_profile_convert_buffer (shell, shell->profile_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height), cairo_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height)); } } else { /* otherwise, load the projection pixels directly into the * filter_buffer */ #ifndef USE_NODE_BLIT gegl_buffer_get (buffer, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), buffer_scale, shell->filter_format, shell->filter_data, shell->filter_stride, GEGL_ABYSS_CLAMP); #else gegl_node_blit (node, buffer_scale, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), shell->filter_format, shell->filter_data, shell->filter_stride, GEGL_BLIT_CACHE); #endif } if (gimp_display_shell_has_filter (shell)) { /* convert the filter_buffer in place */ gimp_color_display_stack_convert_buffer (shell->filter_stack, shell->filter_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height)); } if (gimp_display_shell_has_filter (shell) || ! can_convert_to_u8) { /* finally, copy the filter buffer to the cairo-ARGB32 buffer */ gegl_buffer_get (shell->filter_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height), 1.0, babl_format ("cairo-ARGB32"), cairo_data, cairo_stride, GEGL_ABYSS_CLAMP); } } else { /* otherwise we can copy the projection pixels straight to the * cairo-ARGB32 buffer */ #ifndef USE_NODE_BLIT gegl_buffer_get (buffer, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), buffer_scale, babl_format ("cairo-ARGB32"), cairo_data, cairo_stride, GEGL_ABYSS_CLAMP); #else gegl_node_blit (node, buffer_scale, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), babl_format ("cairo-ARGB32"), cairo_data, cairo_stride, GEGL_BLIT_CACHE); #endif } g_object_unref (cairo_buffer); if (shell->mask) { if (! shell->mask_surface) { shell->mask_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, GIMP_DISPLAY_RENDER_BUF_WIDTH * GIMP_DISPLAY_RENDER_MAX_SCALE, GIMP_DISPLAY_RENDER_BUF_HEIGHT * GIMP_DISPLAY_RENDER_MAX_SCALE); } cairo_surface_mark_dirty (shell->mask_surface); cairo_stride = cairo_image_surface_get_stride (shell->mask_surface); cairo_data = cairo_image_surface_get_data (shell->mask_surface) + mask_src_y * cairo_stride + mask_src_x * 4; gegl_buffer_get (shell->mask, GEGL_RECTANGLE (scaled_x - shell->mask_offset_x, scaled_y - shell->mask_offset_y, scaled_width, scaled_height), buffer_scale, babl_format ("Y u8"), cairo_data, cairo_stride, GEGL_ABYSS_NONE); if (shell->mask_inverted) { gint mask_height = scaled_height; while (mask_height--) { gint mask_width = scaled_width; guchar *d = cairo_data; while (mask_width--) { guchar inv = 255 - *d; *d++ = inv; } cairo_data += cairo_stride; } } } /* put it to the screen */ cairo_save (cr); cairo_rectangle (cr, x, y, w, h); cairo_scale (cr, 1.0 / scale_x, 1.0 / scale_y); cairo_set_source_surface (cr, xfer, x * scale_x - xfer_src_x, y * scale_y - xfer_src_y); if (shell->rotate_transform) { cairo_pattern_t *pattern; pattern = cairo_get_source (cr); cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); cairo_set_line_width (cr, 1.0); cairo_stroke_preserve (cr); cairo_surface_destroy (xfer); } cairo_clip (cr); cairo_paint (cr); if (shell->mask) { gimp_cairo_set_source_rgba (cr, &shell->mask_color); cairo_mask_surface (cr, shell->mask_surface, (x - mask_src_x) * scale_x, (y - mask_src_y) * scale_y); } cairo_restore (cr); }
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; }
/* FIXME: make this use direct data access in more cases than the * case of the base buffer. */ gpointer * gegl_buffer_linear_open (GeglBuffer *buffer, const GeglRectangle *extent, /* if NULL, use buf */ gint *rowstride,/* returns rowstride */ const Babl *format) /* if NULL, from buf */ { if (!format) format = buffer->soft_format; if (extent == NULL) extent=&buffer->extent; /*gegl_buffer_lock (buffer);*/ g_rec_mutex_lock (&buffer->tile_storage->mutex); if (extent->x == buffer->extent.x && extent->y == buffer->extent.y && extent->width == buffer->tile_width && extent->height <= buffer->tile_height && buffer->soft_format == format) { GeglTile *tile; g_assert (buffer->tile_width <= buffer->tile_storage->tile_width); g_assert (buffer->tile_height == buffer->tile_storage->tile_height); tile = g_object_get_data (G_OBJECT (buffer), "linear-tile"); g_assert (tile == NULL); /* We need to reference count returned direct * linear buffers to allow multiple open like * the copying case. */ tile = gegl_tile_source_get_tile ((GeglTileSource*) (buffer), 0,0,0); g_assert (tile); gegl_tile_lock (tile); g_object_set_data (G_OBJECT (buffer), "linear-tile", tile); if(rowstride)*rowstride = buffer->tile_storage->tile_width * babl_format_get_bytes_per_pixel (format); return (gpointer)gegl_tile_get_data (tile); } /* first check if there is a linear buffer, share the existing buffer if one * exists. */ { GList *linear_buffers; GList *iter; BufferInfo *info = NULL; linear_buffers = g_object_get_data (G_OBJECT (buffer), "linear-buffers"); for (iter = linear_buffers; iter; iter=iter->next) { info = iter->data; if (info->format == format && info->extent.x == buffer->extent.x && info->extent.y == buffer->extent.y && info->extent.width == buffer->extent.width && info->extent.height == buffer->extent.height ) { info->refs++; g_print ("!!!!!! sharing a linear buffer!!!!!\n"); return info->buf; } } } { BufferInfo *info = g_new0 (BufferInfo, 1); GList *linear_buffers; gint rs; linear_buffers = g_object_get_data (G_OBJECT (buffer), "linear-buffers"); linear_buffers = g_list_append (linear_buffers, info); g_object_set_data (G_OBJECT (buffer), "linear-buffers", linear_buffers); info->extent = *extent; info->format = format; rs = info->extent.width * babl_format_get_bytes_per_pixel (format); if(rowstride)*rowstride = rs; info->buf = gegl_malloc (rs * info->extent.height); gegl_buffer_get_unlocked (buffer, 1.0, &info->extent, format, info->buf, rs, GEGL_ABYSS_NONE); return info->buf; } return NULL; }
/** * 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; }
void gimp_display_shell_render (GimpDisplayShell *shell, cairo_t *cr, gint x, gint y, gint w, gint h) { GimpImage *image; GimpProjection *projection; GeglBuffer *buffer; gdouble scale_x = 1.0; gdouble scale_y = 1.0; gdouble buffer_scale = 1.0; gint viewport_offset_x; gint viewport_offset_y; gint viewport_width; gint viewport_height; gint scaled_x; gint scaled_y; gint scaled_width; gint scaled_height; cairo_surface_t *xfer; gint xfer_src_x; gint xfer_src_y; gint mask_src_x = 0; gint mask_src_y = 0; gint stride; guchar *data; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_return_if_fail (cr != NULL); g_return_if_fail (w > 0 && h > 0); image = gimp_display_get_image (shell->display); projection = gimp_image_get_projection (image); buffer = gimp_pickable_get_buffer (GIMP_PICKABLE (projection)); #ifdef GIMP_DISPLAY_RENDER_ENABLE_SCALING /* if we had this future API, things would look pretty on hires (retina) */ scale_x = gdk_window_get_scale_factor (gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (shell)))); #endif scale_x = MIN (scale_x, GIMP_DISPLAY_RENDER_MAX_SCALE); scale_y = scale_x; if (shell->scale_x > shell->scale_y) { scale_y *= (shell->scale_x / shell->scale_y); buffer_scale = shell->scale_y * scale_y; } else if (shell->scale_y > shell->scale_x) { scale_x *= (shell->scale_y / shell->scale_x); buffer_scale = shell->scale_x * scale_x; } else { buffer_scale = shell->scale_x * scale_x; } gimp_display_shell_scroll_get_scaled_viewport (shell, &viewport_offset_x, &viewport_offset_y, &viewport_width, &viewport_height); scaled_x = floor ((x + viewport_offset_x) * scale_x); scaled_y = floor ((y + viewport_offset_y) * scale_y); scaled_width = ceil (w * scale_x); scaled_height = ceil (h * scale_y); if (shell->rotate_transform) { xfer = cairo_surface_create_similar_image (cairo_get_target (cr), CAIRO_FORMAT_ARGB32, scaled_width, scaled_height); cairo_surface_mark_dirty (xfer); xfer_src_x = 0; xfer_src_y = 0; } else { xfer = gimp_display_xfer_get_surface (shell->xfer, scaled_width, scaled_height, &xfer_src_x, &xfer_src_y); } stride = cairo_image_surface_get_stride (xfer); data = cairo_image_surface_get_data (xfer); data += xfer_src_y * stride + xfer_src_x * 4; /* apply filters to the rendered projection */ if (shell->filter_stack) { const Babl *filter_format = babl_format ("R'G'B'A float"); if (! shell->filter_buffer) { gint w = GIMP_DISPLAY_RENDER_BUF_WIDTH * GIMP_DISPLAY_RENDER_MAX_SCALE; gint h = GIMP_DISPLAY_RENDER_BUF_HEIGHT * GIMP_DISPLAY_RENDER_MAX_SCALE; shell->filter_data = gegl_malloc (w * h * babl_format_get_bytes_per_pixel (filter_format)); shell->filter_stride = w * babl_format_get_bytes_per_pixel (filter_format); shell->filter_buffer = gegl_buffer_linear_new_from_data (shell->filter_data, filter_format, GEGL_RECTANGLE (0, 0, w, h), GEGL_AUTO_ROWSTRIDE, (GDestroyNotify) gegl_free, shell->filter_data); } gegl_buffer_get (buffer, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), buffer_scale, filter_format, shell->filter_data, shell->filter_stride, GEGL_ABYSS_CLAMP); gimp_color_display_stack_convert_buffer (shell->filter_stack, shell->filter_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height)); gegl_buffer_get (shell->filter_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height), 1.0, babl_format ("cairo-ARGB32"), data, stride, GEGL_ABYSS_CLAMP); } else { gegl_buffer_get (buffer, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), buffer_scale, babl_format ("cairo-ARGB32"), data, stride, GEGL_ABYSS_CLAMP); } if (shell->mask) { gint mask_height; if (! shell->mask_surface) { shell->mask_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, GIMP_DISPLAY_RENDER_BUF_WIDTH * GIMP_DISPLAY_RENDER_MAX_SCALE, GIMP_DISPLAY_RENDER_BUF_HEIGHT * GIMP_DISPLAY_RENDER_MAX_SCALE); } cairo_surface_mark_dirty (shell->mask_surface); stride = cairo_image_surface_get_stride (shell->mask_surface); data = cairo_image_surface_get_data (shell->mask_surface); data += mask_src_y * stride + mask_src_x * 4; gegl_buffer_get (shell->mask, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), buffer_scale, babl_format ("Y u8"), data, stride, GEGL_ABYSS_CLAMP); /* invert the mask so what is *not* the foreground object is masked */ mask_height = scaled_height; while (mask_height--) { gint mask_width = scaled_width; guchar *d = data; while (mask_width--) { guchar inv = 255 - *d; *d++ = inv; } data += stride; } } /* put it to the screen */ cairo_save (cr); cairo_rectangle (cr, x, y, w, h); cairo_scale (cr, 1.0 / scale_x, 1.0 / scale_y); cairo_set_source_surface (cr, xfer, x * scale_x - xfer_src_x, y * scale_y - xfer_src_y); if (shell->rotate_transform) { cairo_pattern_t *pattern; pattern = cairo_get_source (cr); cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); cairo_set_line_width (cr, 1.0); cairo_stroke_preserve (cr); cairo_surface_destroy (xfer); } cairo_clip (cr); cairo_paint (cr); if (shell->mask) { gimp_cairo_set_source_rgba (cr, &shell->mask_color); cairo_mask_surface (cr, shell->mask_surface, (x - mask_src_x) * scale_x, (y - mask_src_y) * scale_y); } cairo_restore (cr); }