static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); gboolean need_fill = FALSE; gdouble r,g,b,a; if (input) { gegl_buffer_copy (input, result, output, result); } else { gegl_buffer_clear (output, result); } if (o->opacity > 0.0001 && o->color) { gegl_color_get_rgba (o->color, &r,&g,&b,&a); a *= o->opacity; if (a>0.001) need_fill=TRUE; } if (need_fill) { GStaticMutex mutex = G_STATIC_MUTEX_INIT; cairo_t *cr; cairo_surface_t *surface; guchar *data; g_static_mutex_lock (&mutex); data = (void*)gegl_buffer_linear_open (output, result, NULL, babl_format ("B'aG'aR'aA u8")); surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, result->width, result->height, result->width * 4); cr = cairo_create (surface); cairo_translate (cr, -result->x, -result->y); if (g_str_equal (o->fill_rule, "evenodd")) cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); gegl_path_cairo_play (o->d, cr); cairo_set_source_rgba (cr, r,g,b,a); cairo_fill (cr); cairo_destroy (cr); gegl_buffer_linear_close (output, data); g_static_mutex_unlock (&mutex); } return TRUE; }
TEST () { GeglBuffer *buffer; GeglRectangle extent = {0,0,40,20}; GeglRectangle roi = {1,1,30,10}; test_start(); buffer = gegl_buffer_new (&extent, babl_format ("Y float")); fill_rect (buffer, &roi, 0.5); roi.y+=3; roi.x+=20; { gint rowstride; gfloat *buf; gint x, y, i; buf = (gpointer)gegl_buffer_linear_open (buffer, &extent, &rowstride, NULL); g_assert (buf); i=0; for (y=0;y<extent.height;y++) for (x=0;x<extent.width;x++) { buf[i++]= ((x+y)*1.0) / extent.width; } gegl_buffer_linear_close (buffer, buf); } fill_rect (buffer, &roi, 0.2); print_buffer (buffer); gegl_buffer_destroy (buffer); test_end (); }
static void setup_helper_test(ViewHelperTest *test) { gpointer buf; GeglRectangle rect = {0, 0, 512, 512}; /* Create a buffer, fill it with white */ test->buffer = gegl_buffer_new(&rect, babl_format("R'G'B' u8")); buf = gegl_buffer_linear_open(test->buffer, NULL, NULL, babl_format("Y' u8")); memset(buf, 255, rect.width * rect.height); gegl_buffer_linear_close(test->buffer, buf); /* Setup a graph with two nodes, one sourcing the buffer and a no-op */ test->graph = gegl_node_new(); test->loadbuf = gegl_node_new_child(test->graph, "operation", "gegl:buffer-source", "buffer", test->buffer, NULL); test->out = gegl_node_new_child(test->graph, "operation", "gegl:nop", NULL); gegl_node_link_many(test->loadbuf, test->out, NULL); /* Setup the GeglView helper, hook up the output node to it */ test->helper = view_helper_new(); view_helper_set_node(test->helper, test->out); }
gint main (gint argc, gchar **argv) { g_thread_init (NULL); gtk_init (&argc, &argv); gegl_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "GEGL destructive painter"); if (argv[1] == NULL) { GeglRectangle rect = {0, 0, 512, 512}; gpointer buf; /* XXX: for best overall performance, this format should probably * be RaGaBaA float, overeager in-place processing code makes that fail though. */ buffer = gegl_buffer_new (&rect, babl_format("R'G'B' u8")); /* it would be useful to have a programmatic way of doing this, filling * with a given pixel value */ buf = gegl_buffer_linear_open (buffer, NULL, NULL, babl_format ("Y' u8")); memset (buf, 255, 512 * 512); gegl_buffer_linear_close (buffer, buf); } else { buffer = gegl_buffer_open (argv[1]); } gegl = gegl_node_new (); { GeglNode *loadbuf = gegl_node_new_child (gegl, "operation", "gegl:buffer-source", "buffer", buffer, NULL); out = gegl_node_new_child (gegl, "operation", "gegl:nop", NULL); gegl_node_link_many (loadbuf, out, NULL); view = g_object_new (GEGL_TYPE_VIEW, "node", out, NULL); top = loadbuf; } g_signal_connect (GTK_OBJECT (view), "motion-notify-event", (GCallback) paint_motion, NULL); g_signal_connect (GTK_OBJECT (view), "button-press-event", (GCallback) paint_press, NULL); g_signal_connect (GTK_OBJECT (view), "button-release-event", (GCallback) paint_release, NULL); gtk_widget_add_events (view, GDK_BUTTON_RELEASE_MASK); gtk_container_add (GTK_CONTAINER (window), view); gtk_widget_set_size_request (view, 512, 512); g_signal_connect (G_OBJECT (window), "delete-event", G_CALLBACK (gtk_main_quit), window); gtk_widget_show_all (window); gtk_main (); g_object_unref (gegl); gegl_buffer_destroy (buffer); gegl_exit (); return 0; }
gint main (gint argc, gchar **argv) { GeglBuffer *bufferA = NULL; GeglBuffer *bufferB = NULL; GeglBuffer *debug_buf = NULL; g_thread_init (NULL); gegl_init (&argc, &argv); if (argc != 3) { g_print ("This is simple image difference detection tool for use in regression testing" "return message is non zero if images are different, if they are equal" "the output will contain the string identical."); g_print ("Usage: %s <imageA> <imageB>\n", argv[0]); return 1; } { GeglNode *graph, *sink; graph = gegl_graph (sink=gegl_node ("gegl:buffer-sink", "buffer", &bufferA, NULL, gegl_node ("gegl:load", "path", argv[1], NULL))); gegl_node_process (sink); g_object_unref (graph); if (!bufferA) { g_printerr ("Failed to open %s\n", argv[1]); return 1; } graph = gegl_graph (sink=gegl_node ("gegl:buffer-sink", "buffer", &bufferB, NULL, gegl_node ("gegl:load", "path", argv[2], NULL))); gegl_node_process (sink); g_object_unref (graph); if (!bufferB) { g_printerr ("Failed to open %s\n", argv[2]); return 1; } } if (gegl_buffer_get_width (bufferA) != gegl_buffer_get_width (bufferB) || gegl_buffer_get_height (bufferA) != gegl_buffer_get_height (bufferB)) { g_printerr ("%s and %s differ in size\n", argv[1], argv[2]); g_printerr (" %ix%i vs %ix%i\n", gegl_buffer_get_width (bufferA), gegl_buffer_get_height (bufferA), gegl_buffer_get_width (bufferB), gegl_buffer_get_height (bufferB)); return 1; } debug_buf = gegl_buffer_new (gegl_buffer_get_extent (bufferA), babl_format ("R'G'B' u8")); { gfloat *bufA, *bufB; gfloat *a, *b; guchar *debug, *d; gint rowstrideA, rowstrideB, dRowstride; gint pixels; gint wrong_pixels=0; gint i; gdouble diffsum = 0.0; gdouble max_diff = 0.0; pixels = gegl_buffer_get_pixel_count (bufferA); bufA = (void*)gegl_buffer_linear_open (bufferA, NULL, &rowstrideA, babl_format ("CIE Lab float")); bufB = (void*)gegl_buffer_linear_open (bufferB, NULL, &rowstrideB, babl_format ("CIE Lab float")); debug = (void*)gegl_buffer_linear_open (debug_buf, NULL, &dRowstride, babl_format ("R'G'B' u8")); a = bufA; b = bufB; d = debug; for (i=0;i<pixels;i++) { gdouble diff = sqrt ( SQR(a[0]-b[0])+ SQR(a[1]-b[1])+ SQR(a[2]-b[2]) /*+SQR(a[3]-b[3])*/); if (diff>=0.01) { wrong_pixels++; diffsum += diff; if (diff > max_diff) max_diff = diff; d[0]=(diff/100.0 * 255); d[1]=0; d[2]=a[0]/100.0*255; } else { d[0]=a[0]/100.0*255; d[1]=a[0]/100.0*255; d[2]=a[0]/100.0*255; } a+=3; b+=3; d+=3; } a = bufA; b = bufB; d = debug; if (wrong_pixels) for (i=0;i<pixels;i++) { gdouble diff = sqrt ( SQR(a[0]-b[0])+ SQR(a[1]-b[1])+ SQR(a[2]-b[2]) /*+SQR(a[3]-b[3])*/); if (diff>=0.01) { d[0]=(100-a[0])/100.0*64+32; d[1]=(diff/max_diff * 255); d[2]=0; } else { d[0]=a[0]/100.0*255; d[1]=a[0]/100.0*255; d[2]=a[0]/100.0*255; } a+=3; b+=3; d+=3; } gegl_buffer_linear_close (bufferA, bufA); gegl_buffer_linear_close (bufferB, bufB); gegl_buffer_linear_close (debug_buf, debug); if (max_diff >= 0.1) { g_printerr ("%s and %s differ\n" " wrong pixels : %i/%i (%2.2f%%)\n" " max Δe : %2.3f\n" " avg Δe (wrong) : %2.3f(wrong) %2.3f(total)\n", argv[1], argv[2], wrong_pixels, pixels, (wrong_pixels*100.0/pixels), max_diff, diffsum/wrong_pixels, diffsum/pixels); if (max_diff > 1.5 && !strstr (argv[2], "broken")) { GeglNode *sink; gchar *debug_path = g_malloc (strlen (argv[2])+16); memcpy (debug_path, argv[2], strlen (argv[2])+1); memcpy (debug_path + strlen(argv[2])-4, "-diff.png", 11); gegl_graph (sink=gegl_node ("gegl:png-save", "path", debug_path, NULL, gegl_node ("gegl:buffer-source", "buffer", debug_buf, NULL))); gegl_node_process (sink); return 1; } if (strstr (argv[2], "broken")) g_print ("because the test is expected to fail "); else g_print ("because the error is small "); g_print ("we'll say "); } } g_print ("%s and %s are identical\n", argv[1], argv[2]); g_object_unref (debug_buf); g_object_unref (bufferA); g_object_unref (bufferB); gegl_exit (); return 0; }
static void stamp (GeglProperties *o, gdouble x, gdouble y) { WarpPrivate *priv = (WarpPrivate*) o->user_data; GeglBufferIterator *it; const Babl *format; gdouble stamp_force, influence; gdouble x_mean = 0.0; gdouble y_mean = 0.0; gint x_iter, y_iter; GeglRectangle area; const GeglRectangle *src_extent; gfloat *srcbuf, *stampbuf; gint buf_rowstride = 0; gfloat s = 0, c = 0; area.x = floor (x - o->size / 2.0); area.y = floor (y - o->size / 2.0); area.width = ceil (x + o->size / 2.0); area.height = ceil (y + o->size / 2.0); area.width -= area.x; area.height -= area.y; format = babl_format_n (babl_type ("float"), 2); /* If needed, compute the mean deformation */ if (o->behavior == GEGL_WARP_BEHAVIOR_SMOOTH) { gint pixel_count = 0; it = gegl_buffer_iterator_new (priv->buffer, &area, 0, format, GEGL_ACCESS_READ, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (it)) { gint n_pixels = it->length; gfloat *coords = it->data[0]; while (n_pixels--) { x_mean += coords[0]; y_mean += coords[1]; coords += 2; } pixel_count += it->roi->width * it->roi->height; } x_mean /= pixel_count; y_mean /= pixel_count; } else if (o->behavior == GEGL_WARP_BEHAVIOR_SWIRL_CW || o->behavior == GEGL_WARP_BEHAVIOR_SWIRL_CCW) { /* swirl by 5 degrees per stamp (for strength 100). * not exactly sin/cos factors, * since we calculate an off-center offset-vector */ /* note that this is fudged for stamp_force < 1.0 and * results in a slight upscaling there. It is a compromise * between exactness and calculation speed. */ s = sin (0.01 * o->strength * 5.0 / 180 * G_PI); c = cos (0.01 * o->strength * 5.0 / 180 * G_PI) - 1.0; } srcbuf = gegl_buffer_linear_open (priv->buffer, NULL, &buf_rowstride, NULL); buf_rowstride /= sizeof (gfloat); src_extent = gegl_buffer_get_extent (priv->buffer); stampbuf = g_new0 (gfloat, 2 * area.height * area.width); for (y_iter = 0; y_iter < area.height; y_iter++) { for (x_iter = 0; x_iter < area.width; x_iter++) { gfloat nvx, nvy; gfloat xi, yi; gfloat *vals; gint dx, dy; gfloat weight_x, weight_y; gfloat *srcptr; xi = area.x + x_iter; xi += -x + 0.5; yi = area.y + y_iter; yi += -y + 0.5; stamp_force = get_stamp_force (o, xi, yi); influence = 0.01 * o->strength * stamp_force; switch (o->behavior) { case GEGL_WARP_BEHAVIOR_MOVE: nvx = influence * (priv->last_x - x); nvy = influence * (priv->last_y - y); break; case GEGL_WARP_BEHAVIOR_GROW: nvx = influence * -0.1 * xi; nvy = influence * -0.1 * yi; break; case GEGL_WARP_BEHAVIOR_SHRINK: nvx = influence * 0.1 * xi; nvy = influence * 0.1 * yi; break; case GEGL_WARP_BEHAVIOR_SWIRL_CW: nvx = stamp_force * ( c * xi + s * yi); nvy = stamp_force * (-s * xi + c * yi); break; case GEGL_WARP_BEHAVIOR_SWIRL_CCW: nvx = stamp_force * ( c * xi - s * yi); nvy = stamp_force * ( s * xi + c * yi); break; case GEGL_WARP_BEHAVIOR_ERASE: case GEGL_WARP_BEHAVIOR_SMOOTH: default: nvx = 0.0; nvy = 0.0; break; } vals = stampbuf + (y_iter * area.width + x_iter) * 2; dx = floorf (nvx); dy = floorf (nvy); if (area.x + x_iter + dx < src_extent->x || area.x + x_iter + dx + 1 >= src_extent->x + src_extent->width || area.y + y_iter + dy < src_extent->y || area.y + y_iter + dy + 1 >= src_extent->y + src_extent->height) { continue; } srcptr = srcbuf + (area.y - src_extent->y + y_iter + dy) * buf_rowstride + (area.x - src_extent->x + x_iter + dx) * 2; if (o->behavior == GEGL_WARP_BEHAVIOR_ERASE) { vals[0] = srcptr[0] * (1.0 - MIN (influence, 1.0)); vals[1] = srcptr[1] * (1.0 - MIN (influence, 1.0)); } else if (o->behavior == GEGL_WARP_BEHAVIOR_SMOOTH) { vals[0] = (1.0 - influence) * srcptr[0] + influence * x_mean; vals[1] = (1.0 - influence) * srcptr[1] + influence * y_mean; } else { weight_x = nvx - dx; weight_y = nvy - dy; /* bilinear interpolation of the vectors */ vals[0] = srcptr[0] * (1.0 - weight_x) * (1.0 - weight_y); vals[1] = srcptr[1] * (1.0 - weight_x) * (1.0 - weight_y); vals[0] += srcptr[2] * weight_x * (1.0 - weight_y); vals[1] += srcptr[3] * weight_x * (1.0 - weight_y); vals[0] += srcptr[buf_rowstride + 0] * (1.0 - weight_x) * weight_y; vals[1] += srcptr[buf_rowstride + 1] * (1.0 - weight_x) * weight_y; vals[0] += srcptr[buf_rowstride + 2] * weight_x * weight_y; vals[1] += srcptr[buf_rowstride + 3] * weight_x * weight_y; vals[0] += nvx; vals[1] += nvy; } } } gegl_buffer_linear_close (priv->buffer, srcbuf); gegl_buffer_set (priv->buffer, &area, 0, format, stampbuf, GEGL_AUTO_ROWSTRIDE); g_free (stampbuf); /* Memorize the stamp location for movement dependant behavior like move */ priv->last_x = x; priv->last_y = y; }