Commit fa0b423c authored by Daniel Sabo's avatar Daniel Sabo

photocopy: Don't linearize, implement get_cached_region

parent bda0ab61
......@@ -48,15 +48,6 @@ gegl_chant_double (white, _("Percent White"),
#define THRESHOLD 0.75
typedef struct {
gdouble black;
gdouble white;
gdouble prev_mask_radius;
gdouble prev_sharpness;
gdouble prev_black;
gdouble prev_white;
} Ramps;
static void
grey_blur_buffer (GeglBuffer *input,
gdouble sharpness,
......@@ -137,83 +128,66 @@ calculate_threshold (gint *hist,
}
static void
compute_ramp (GeglBuffer *input,
GeglOperation *operation,
gdouble pct_black,
gdouble pct_white,
gint under_threshold,
gdouble *threshold_black,
gdouble *threshold_white)
compute_ramp (GeglBuffer *dest1,
GeglBuffer *dest2,
const GeglRectangle *roi,
gdouble pct_black,
gdouble pct_white,
gboolean under_threshold,
gdouble *threshold_black,
gdouble *threshold_white)
{
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
GeglBufferIterator *iter;
GeglRectangle *whole_region;
gint n_pixels;
gint hist1[2000];
gint hist2[2000];
gdouble diff;
gint count;
GeglBuffer *dest1, *dest2;
gfloat *src1_buf;
gfloat *src2_buf;
gfloat *dst_buf;
gint total_pixels;
gfloat* ptr1;
gfloat* ptr2;
whole_region = gegl_operation_source_get_bounding_box (operation, "input");
grey_blur_buffer (input, o->sharpness, o->mask_radius, &dest1, &dest2);
total_pixels = whole_region->width * whole_region->height;
src1_buf = g_slice_alloc (total_pixels * sizeof (gfloat));
src2_buf = g_slice_alloc (total_pixels * sizeof (gfloat));
dst_buf = g_slice_alloc (total_pixels * sizeof (gfloat));
gegl_buffer_get (dest1, whole_region, 1.0, babl_format ("Y float"),
src1_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
gegl_buffer_get (dest2, whole_region, 1.0, babl_format ("Y float"),
src2_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
n_pixels = whole_region->width * whole_region->height;
iter = gegl_buffer_iterator_new (dest1, roi, 0,
babl_format ("Y float"),
GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
gegl_buffer_iterator_add (iter, dest2, roi, 0,
babl_format ("Y float"),
GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
memset (hist1, 0, sizeof (int) * 2000);
memset (hist2, 0, sizeof (int) * 2000);
count = 0;
ptr1 = src1_buf;
ptr2 = src2_buf;
while (n_pixels--)
{
diff = *ptr1 / *ptr2;
ptr1++;
ptr2++;
if (under_threshold)
{
if (diff < THRESHOLD)
{
hist2[(int) (diff * 1000)] ++;
count ++;
}
}
else
{
if (diff >= THRESHOLD && diff < 2.0)
{
hist1[(int) (diff * 1000)] ++;
count ++;
}
}
}
g_object_unref (dest1);
g_object_unref (dest2);
g_slice_free1 (total_pixels * sizeof (gfloat), src1_buf);
g_slice_free1 (total_pixels * sizeof (gfloat), src2_buf);
g_slice_free1 (total_pixels * sizeof (gfloat), dst_buf);
while (gegl_buffer_iterator_next (iter))
{
gint n_pixels = iter->length;
gfloat *ptr1 = iter->data[0];
gfloat *ptr2 = iter->data[1];
while (n_pixels--)
{
diff = *ptr1 / *ptr2;
ptr1++;
ptr2++;
if (under_threshold)
{
if (diff < THRESHOLD && diff >= 0.0f)
{
hist2[(int) (diff * 1000)] ++;
count ++;
}
}
else
{
if (diff >= THRESHOLD && diff < 2.0)
{
hist1[(int) (diff * 1000)] ++;
count ++;
}
}
}
}
*threshold_black = calculate_threshold (hist1, pct_black, count, 0);
*threshold_white = calculate_threshold (hist2, pct_white, count, 1);
......@@ -222,26 +196,36 @@ compute_ramp (GeglBuffer *input,
static void
prepare (GeglOperation *operation)
{
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
gegl_operation_set_format (operation, "input",
babl_format ("Y float"));
gegl_operation_set_format (operation, "output",
babl_format ("Y float"));
if (o->chant_data)
{
Ramps* ramps = (Ramps*) o->chant_data;
}
/* hack so that thresholds are only calculated once */
if (ramps->prev_mask_radius != o->mask_radius ||
ramps->prev_sharpness != o->sharpness ||
ramps->prev_black != o->black ||
ramps->prev_white != o->white)
{
g_slice_free (Ramps, o->chant_data);
o->chant_data = NULL;
}
}
static GeglRectangle
get_required_for_output (GeglOperation *operation,
const gchar *input_pad,
const GeglRectangle *roi)
{
GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, "input");
/* Don't request an infinite plane */
if (gegl_rectangle_is_infinite_plane (&result))
return *roi;
return result;
}
static GeglRectangle
get_cached_region (GeglOperation *operation,
const GeglRectangle *roi)
{
GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, "input");
if (gegl_rectangle_is_infinite_plane (&result))
return *roi;
return result;
}
static gboolean
......@@ -253,144 +237,92 @@ process (GeglOperation *operation,
{
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
GeglBufferIterator *iter;
GeglBuffer *dest1;
GeglBuffer *dest2;
Ramps* ramps;
gint n_pixels;
gfloat *out_pixel;
gint total_pixels;
gdouble diff;
Ramps *get_ramps;
gdouble ramp_down;
gdouble ramp_up;
gdouble mult;
gfloat *src1_buf;
gfloat *src2_buf;
gfloat *dst_buf;
gfloat* ptr1;
gfloat* ptr2;
static GMutex mutex = { 0, };
total_pixels = result->width * result->height;
dst_buf = g_slice_alloc (total_pixels * sizeof (gfloat));
g_mutex_lock (&mutex);
if (o->chant_data == NULL)
{
o->chant_data = g_slice_new (Ramps);
ramps = (Ramps*) o->chant_data;
compute_ramp (input,
operation,
o->black,
o->white,1,
&ramps->black,
&ramps->white);
ramps->prev_mask_radius = o->mask_radius;
ramps->prev_sharpness = o->sharpness;
ramps->prev_black = o->black;
ramps->prev_white = o->white;
}
g_mutex_unlock (&mutex);
grey_blur_buffer (input, o->sharpness, o->mask_radius, &dest1, &dest2);
total_pixels = result->width * result->height;
src1_buf = g_slice_alloc (total_pixels * sizeof (gfloat));
src2_buf = g_slice_alloc (total_pixels * sizeof (gfloat));
gegl_buffer_get (dest1, result, 1.0, babl_format ("Y float"),
src1_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
gegl_buffer_get (dest2, result, 1.0, babl_format ("Y float"),
src2_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
g_object_unref (dest1);
g_object_unref (dest2);
out_pixel = dst_buf;
n_pixels = result->width * result->height;
get_ramps = (Ramps*) o->chant_data;
ramp_down = get_ramps->black;
ramp_up = get_ramps->white;
ptr1 = src1_buf;
ptr2 = src2_buf;
while (n_pixels--)
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_BUFFER_READ,
GEGL_ABYSS_NONE);
gegl_buffer_iterator_add (iter, dest2, result, 0,
babl_format ("Y float"),
GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
gegl_buffer_iterator_add (iter, output, result, 0,
babl_format ("Y float"),
GEGL_BUFFER_WRITE,
GEGL_ABYSS_NONE);
while (gegl_buffer_iterator_next (iter))
{
diff = *ptr1 / *ptr2;
if (diff < THRESHOLD)
gint n_pixels = iter->length;
gfloat *ptr1 = iter->data[0];
gfloat *ptr2 = iter->data[1];
gfloat *out_pixel = iter->data[2];
while (n_pixels--)
{
if (ramp_down == 0.0)
*out_pixel = 0.0;
else
diff = *ptr1 / *ptr2;
if (diff < THRESHOLD)
{
mult = (ramp_down - MIN (ramp_down,
(THRESHOLD - diff))) / ramp_down;
*out_pixel = *ptr1 * mult;
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;
{
if (ramp_up == 0.0)
mult = 1.0;
else
mult = MIN (ramp_up,
(diff - THRESHOLD)) / ramp_up;
*out_pixel = mult + *ptr1 - mult * *ptr1;
*out_pixel = mult + *ptr1 - mult * *ptr1;
}
ptr1++;
ptr2++;
out_pixel++;
}
ptr1++;
ptr2++;
out_pixel ++;
}
gegl_buffer_set (output,
result,
0,
babl_format ("Y float"),
dst_buf, GEGL_AUTO_ROWSTRIDE);
g_slice_free1 (total_pixels * sizeof (gfloat), src1_buf);
g_slice_free1 (total_pixels * sizeof (gfloat), src2_buf);
g_slice_free1 (total_pixels * sizeof (gfloat), dst_buf);
return TRUE;
}
static void
finalize (GObject *object)
{
GeglChantO *o = GEGL_CHANT_PROPERTIES (object);
if (o->chant_data)
{
g_slice_free (Ramps, o->chant_data);
o->chant_data = NULL;
}
g_object_unref (dest1);
g_object_unref (dest2);
G_OBJECT_CLASS (gegl_chant_parent_class)->finalize (object);
return TRUE;
}
static void
gegl_chant_class_init (GeglChantClass *klass)
{
GObjectClass *object_class;
GeglOperationClass *operation_class;
GeglOperationFilterClass *filter_class;
object_class = G_OBJECT_CLASS (klass);
operation_class = GEGL_OPERATION_CLASS (klass);
filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
object_class->finalize = finalize;
operation_class->prepare = prepare;
filter_class->process = process;
operation_class->prepare = prepare;
operation_class->get_required_for_output = get_required_for_output;
operation_class->get_cached_region = get_cached_region;
filter_class->process = process;
gegl_operation_class_set_keys (operation_class,
"name", "gegl:photocopy",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment