Ejemplo n.º 1
0
static gpointer
negative_exec (GthAsyncTask *task,
	       gpointer      user_data)
{
	NegativeData    *negative_data = user_data;
	cairo_format_t   format;
	int              width;
	int              height;
	int              source_stride;
	int              destination_stride;
	unsigned char   *p_source_line;
	unsigned char   *p_destination_line;
	unsigned char   *p_source;
	unsigned char   *p_destination;
	gboolean         cancelled;
	double           progress;
	gboolean         terminated;
	int              x, y;
	unsigned char    red, green, blue, alpha;

	format = cairo_image_surface_get_format (negative_data->source);
	width = cairo_image_surface_get_width (negative_data->source);
	height = cairo_image_surface_get_height (negative_data->source);
	source_stride = cairo_image_surface_get_stride (negative_data->source);

	negative_data->destination = cairo_image_surface_create (format, width, height);
	destination_stride = cairo_image_surface_get_stride (negative_data->destination);
	p_source_line = _cairo_image_surface_flush_and_get_data (negative_data->source);
	p_destination_line = _cairo_image_surface_flush_and_get_data (negative_data->destination);
	for (y = 0; y < height; y++) {
		gth_async_task_get_data (task, NULL, &cancelled, NULL);
		if (cancelled)
			return NULL;

		progress = (double) y / height;
		gth_async_task_set_data (task, NULL, NULL, &progress);

		p_source = p_source_line;
		p_destination = p_destination_line;
		for (x = 0; x < width; x++) {
			CAIRO_GET_RGBA (p_source, red, green, blue, alpha);
			CAIRO_SET_RGBA (p_destination,
					255 - red,
					255 - green,
					255 - blue,
					alpha);

			p_source += 4;
			p_destination += 4;
		}
		p_source_line += source_stride;
		p_destination_line += destination_stride;
	}

	cairo_surface_mark_dirty (negative_data->destination);
	terminated = TRUE;
	gth_async_task_set_data (task, &terminated, NULL, NULL);

	return NULL;
}
Ejemplo n.º 2
0
static gpointer
adjust_contrast_exec (GthAsyncTask *task,
		      gpointer      user_data)
{
	AdjustContrastData *adjust_data = user_data;
	cairo_format_t      format;
	int                 width;
	int                 height;
	int                 source_stride;
	cairo_surface_t    *destination;
	int                 destination_stride;
	unsigned char      *p_source_line;
	unsigned char      *p_destination_line;
	unsigned char      *p_source;
	unsigned char      *p_destination;
	gboolean            cancelled;
	double              progress;
	int                 x, y;
	unsigned char       red, green, blue, alpha;
	GthImage          *destination_image;

	/* initialize some extra data */

	adjust_contrast_setup (adjust_data);

	/* convert the image */

	format = cairo_image_surface_get_format (adjust_data->source);
	width = cairo_image_surface_get_width (adjust_data->source);
	height = cairo_image_surface_get_height (adjust_data->source);
	source_stride = cairo_image_surface_get_stride (adjust_data->source);

	destination = cairo_image_surface_create (format, width, height);
	destination_stride = cairo_image_surface_get_stride (destination);
	p_source_line = _cairo_image_surface_flush_and_get_data (adjust_data->source);
	p_destination_line = _cairo_image_surface_flush_and_get_data (destination);
	for (y = 0; y < height; y++) {
		gth_async_task_get_data (task, NULL, &cancelled, NULL);
		if (cancelled)
			return NULL;

		progress = (double) y / height;
		gth_async_task_set_data (task, NULL, NULL, &progress);

		p_source = p_source_line;
		p_destination = p_destination_line;
		for (x = 0; x < width; x++) {
			CAIRO_GET_RGBA (p_source, red, green, blue, alpha);
			red   = adjust_contrast_func (adjust_data, GTH_HISTOGRAM_CHANNEL_RED, red);
			green = adjust_contrast_func (adjust_data, GTH_HISTOGRAM_CHANNEL_GREEN, green);
			blue  = adjust_contrast_func (adjust_data, GTH_HISTOGRAM_CHANNEL_BLUE, blue);
			CAIRO_SET_RGBA (p_destination, red, green, blue, alpha);

			p_source += 4;
			p_destination += 4;
		}
		p_source_line += source_stride;
		p_destination_line += destination_stride;
	}

	cairo_surface_mark_dirty (destination);

	destination_image = gth_image_new_for_surface (destination);
	gth_image_task_set_destination (GTH_IMAGE_TASK (task), destination_image);

	_g_object_unref (destination_image);
	cairo_surface_destroy (destination);

	return NULL;
}
Ejemplo n.º 3
0
static void
horizontal_scale_transpose (cairo_surface_t *image,
			    cairo_surface_t *scaled,
			    ScaleReal        scale_factor,
			    resize_filter_t *resize_filter)
{
	ScaleReal  scale;
	ScaleReal  support;
	int        y;
	int        image_width;
	int        scaled_width;
	int        scaled_height;
	guchar    *p_src;
        guchar    *p_dest;
        int        src_rowstride;
        int        dest_rowstride;
        ScaleReal *weights;

	if (resize_filter->cancelled)
		return;

	scale = MAX ((ScaleReal) 1.0 / scale_factor + EPSILON, 1.0);
	support = scale * resize_filter_get_support (resize_filter);
	if (support < 0.5) {
		support = 0.5;
		scale = 1.0;
	}

	image_width = cairo_image_surface_get_width (image);
	scaled_width = cairo_image_surface_get_width (scaled);
	scaled_height = cairo_image_surface_get_height (scaled);
	p_src = _cairo_image_surface_flush_and_get_data (image);
	p_dest = _cairo_image_surface_flush_and_get_data (scaled);
	src_rowstride = cairo_image_surface_get_stride (image);
	dest_rowstride = cairo_image_surface_get_stride (scaled);
	weights = g_new (ScaleReal, 2.0 * support + 3.0);

	scale = reciprocal (scale);
	for (y = 0; y < scaled_height; y++) {
	        guchar    *p_src_row;
	        guchar    *p_dest_pixel;
		ScaleReal  bisect;
		int        start;
		int        stop;
		ScaleReal  density;
		int        n;
		int        x;
		int        i;
#ifdef HAVE_VECTOR_OPERATIONS
		r4vector   v_pixel, v_rgba;
#endif /* HAVE_VECTOR_OPERATIONS */

		if (resize_filter->task != NULL) {
			double progress;

			gth_async_task_get_data (resize_filter->task, NULL, &resize_filter->cancelled, NULL);
			if (resize_filter->cancelled)
				goto out;

			progress = (double) resize_filter->processed_lines++ / resize_filter->total_lines;
			gth_async_task_set_data (resize_filter->task, NULL, NULL, &progress);
		}

		bisect = ((ScaleReal) y + 0.5) / scale_factor + EPSILON;
		start = MAX (bisect - support + 0.5, 0);
		stop = MIN (bisect + support + 0.5, (ScaleReal) image_width);

		density = 0.0;
		for (n = 0; n < stop - start; n++) {
			weights[n] = resize_filter_get_weight (resize_filter, scale * ((ScaleReal) (start + n) - bisect + 0.5));
			density += weights[n];
		}

		/*
		g_assert (n == stop - start);
		g_assert (stop - start <= (2.0 * support) + 3);
		*/

		if ((density != 0.0) && (density != 1.0)) {
			density = reciprocal (density);
			for (i = 0; i < n; i++)
				weights[i] *= density;
		}

		p_src_row = p_src + (start * 4);
		p_dest_pixel = p_dest;
		for (x = 0; x < scaled_width; x++) {
			guchar *p_src_pixel;

			p_src_pixel = p_src_row;

#ifdef HAVE_VECTOR_OPERATIONS

			v_rgba.v = (v4r) { 0.0, 0.0, 0.0, 0.0 };
			for (i = 0; i < n; i++) {
				v_pixel.v = (v4r) { p_src_pixel[0], p_src_pixel[1], p_src_pixel[2], p_src_pixel[3] };
				v_rgba.v = v_rgba.v + (v_pixel.v * weights[i]);

				p_src_pixel += 4;
			}
			v_rgba.v = v_rgba.v + 0.5;

			p_dest_pixel[0] = CLAMP_PIXEL (v_rgba.r[0]);
			p_dest_pixel[1] = CLAMP_PIXEL (v_rgba.r[1]);
			p_dest_pixel[2] = CLAMP_PIXEL (v_rgba.r[2]);
			p_dest_pixel[3] = CLAMP_PIXEL (v_rgba.r[3]);

#else /* ! HAVE_VECTOR_OPERATIONS */

			ScaleReal r, g, b, a, w;

			r = g = b = a = 0.0;
			for (i = 0; i < n; i++) {
				w = weights[i];

				r += w * p_src_pixel[CAIRO_RED];
				g += w * p_src_pixel[CAIRO_GREEN];
				b += w * p_src_pixel[CAIRO_BLUE];
				a += w * p_src_pixel[CAIRO_ALPHA];

				p_src_pixel += 4;
			}

			p_dest_pixel[CAIRO_RED] = CLAMP_PIXEL (r + 0.5);
			p_dest_pixel[CAIRO_GREEN] = CLAMP_PIXEL (g + 0.5);
			p_dest_pixel[CAIRO_BLUE] = CLAMP_PIXEL (b + 0.5);
			p_dest_pixel[CAIRO_ALPHA] = CLAMP_PIXEL (a + 0.5);

#endif /* HAVE_VECTOR_OPERATIONS */

			p_dest_pixel += 4;
			p_src_row += src_rowstride;
		}

		p_dest += dest_rowstride;
	}

	out:

	cairo_surface_mark_dirty (scaled);

	g_free (weights);
}
Ejemplo n.º 4
0
static gpointer
grayscale_exec (GthAsyncTask *task,
	        gpointer      user_data)
{
	GrayscaleData   *grayscale_data = user_data;
	cairo_surface_t *source;
	cairo_format_t   format;
	int              width;
	int              height;
	int              source_stride;
	cairo_surface_t *destination;
	int              destination_stride;
	unsigned char   *p_source_line;
	unsigned char   *p_destination_line;
	unsigned char   *p_source;
	unsigned char   *p_destination;
	gboolean         cancelled;
	double           progress;
	int              x, y;
	unsigned char    red, green, blue, alpha;
	unsigned char    min, max, value;

	source = gth_image_task_get_source_surface (GTH_IMAGE_TASK (task));
	format = cairo_image_surface_get_format (source);
	width = cairo_image_surface_get_width (source);
	height = cairo_image_surface_get_height (source);
	source_stride = cairo_image_surface_get_stride (source);

	destination = cairo_image_surface_create (format, width, height);
	destination_stride = cairo_image_surface_get_stride (destination);
	p_source_line = _cairo_image_surface_flush_and_get_data (source);
	p_destination_line = _cairo_image_surface_flush_and_get_data (destination);
	for (y = 0; y < height; y++) {
		gth_async_task_get_data (task, NULL, &cancelled, NULL);
		if (cancelled)
			return NULL;

		progress = (double) y / height;
		gth_async_task_set_data (task, NULL, NULL, &progress);

		p_source = p_source_line;
		p_destination = p_destination_line;
		for (x = 0; x < width; x++) {
			CAIRO_GET_RGBA (p_source, red, green, blue, alpha);

			switch (grayscale_data->method) {
			case METHOD_BRIGHTNESS:
				value = (0.2125 * red + 0.7154 * green + 0.072 * blue);
				break;

			case METHOD_SATURATION:
				max = MAX (MAX (red, green), blue);
				min = MIN (MIN (red, green), blue);
				value = (max + min) / 2;
				break;

			case METHOD_AVARAGE:
				value = (0.3333 * red + 0.3333 * green + 0.3333 * blue);
				break;

			default:
				g_assert_not_reached ();
			}

			CAIRO_SET_RGBA (p_destination,
					value,
					value,
					value,
					alpha);

			p_source += 4;
			p_destination += 4;
		}
		p_source_line += source_stride;
		p_destination_line += destination_stride;
	}

	cairo_surface_mark_dirty (destination);
	gth_image_task_set_destination_surface (GTH_IMAGE_TASK (task), destination);

	cairo_surface_destroy (destination);
	cairo_surface_destroy (source);

	return NULL;
}
Ejemplo n.º 5
0
static cairo_surface_t*
rotate (cairo_surface_t *image,
	double           angle,
	gboolean         high_quality,
	guchar           r0,
	guchar           g0,
	guchar           b0,
	guchar           a0,
	GthAsyncTask    *task)
{
	cairo_surface_t *image_with_background;
	cairo_surface_t *rotated;
	double           angle_rad;
	double           cos_angle, sin_angle;
	double           src_width, src_height;
	int              new_width, new_height;
	int              src_rowstride, new_rowstride;
	int              xi, yi;
	double           x, y;
	double           x2, y2;
	int              x2min, y2min;
	int              x2max, y2max;
	double           fx, fy;
	guchar          *p_src, *p_new;
	guchar          *p_src2, *p_new2;
	guchar           r00, r01, r10, r11;
	guchar           g00, g01, g10, g11;
	guchar           b00, b01, b10, b11;
	guchar           a00, a01, a10, a11;
	double           half_new_width;
	double           half_new_height;
	double           half_src_width;
	double           half_src_height;
	int              tmp;
	guchar           r, g, b, a;
	guint32          pixel;

	angle = CLAMP (angle, -90.0, 90.0);
	angle_rad = angle / 180.0 * G_PI;
	cos_angle = cos (angle_rad);
	sin_angle = sin (angle_rad);
	src_width  = cairo_image_surface_get_width  (image);
	src_height = cairo_image_surface_get_height (image);
	new_width  = GDOUBLE_ROUND_TO_INT (      cos_angle  * src_width + fabs(sin_angle) * src_height);
	new_height = GDOUBLE_ROUND_TO_INT (fabs (sin_angle) * src_width +      cos_angle  * src_height);

	if (a0 == 0xff) {
		/* pre-multiply the background color */

		image_with_background = _cairo_image_surface_copy (image);
		p_src = _cairo_image_surface_flush_and_get_data (image);
		p_new = _cairo_image_surface_flush_and_get_data (image_with_background);
		src_rowstride = cairo_image_surface_get_stride (image);
		new_rowstride = cairo_image_surface_get_stride (image_with_background);

		cairo_surface_flush (image_with_background);
		for (yi = 0; yi < src_height; yi++) {
			p_src2 = p_src;
			p_new2 = p_new;
			for (xi = 0; xi < src_width; xi++) {
				a = p_src2[CAIRO_ALPHA];
				r = p_src2[CAIRO_RED] + _cairo_multiply_alpha (r0, 0xff - a);
				g = p_src2[CAIRO_GREEN] + _cairo_multiply_alpha (g0, 0xff - a);
				b = p_src2[CAIRO_BLUE] + _cairo_multiply_alpha (b0, 0xff - a);
				pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
				memcpy (p_new2, &pixel, sizeof (guint32));

				p_new2 += 4;
				p_src2 += 4;
			}
			p_src += src_rowstride;
			p_new += new_rowstride;
		}
		cairo_surface_mark_dirty (image_with_background);
	}
	else
		image_with_background = cairo_surface_reference (image);

	/* create the rotated image */

	rotated = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, new_width, new_height);

	p_src = _cairo_image_surface_flush_and_get_data (image_with_background);
	p_new = _cairo_image_surface_flush_and_get_data (rotated);
	src_rowstride = cairo_image_surface_get_stride (image_with_background);
	new_rowstride = cairo_image_surface_get_stride (rotated);

/*
 * bilinear interpolation
 *            fx
 *    v00------------v01
 *    |        |      |
 * fy |--------v      |
 *    |               |
 *    |               |
 *    |               |
 *    v10------------v11
 */
#define INTERPOLATE(v, v00, v01, v10, v11, fx, fy) \
	tmp = (1.0 - (fy)) * \
	      ((1.0 - (fx)) * (v00) + (fx) * (v01)) \
              + \
              (fy) * \
              ((1.0 - (fx)) * (v10) + (fx) * (v11)); \
	v = CLAMP (tmp, 0, 255);

#define GET_VALUES(r, g, b, a, x, y) \
	if (x >= 0 && x < src_width && y >= 0 && y < src_height) { \
		p_src2 = p_src + src_rowstride * y + 4 * x; \
		r = p_src2[CAIRO_RED]; \
		g = p_src2[CAIRO_GREEN]; \
		b = p_src2[CAIRO_BLUE]; \
		a = p_src2[CAIRO_ALPHA]; \
	} \
	else { \
		r = r0; \
		g = g0; \
		b = b0; \
		a = a0; \
	}

	half_new_width = new_width / 2.0;
	half_new_height = new_height / 2.0;
	half_src_width = src_width / 2.0;
	half_src_height = src_height / 2.0;

	cairo_surface_flush (rotated);

	y = - half_new_height;
	for (yi = 0; yi < new_height; yi++) {
		if (task != NULL) {
			gboolean cancelled;
			double   progress;

			gth_async_task_get_data (task, NULL, &cancelled, NULL);
			if (cancelled)
				goto out;

			progress = (double) yi / new_height;
			gth_async_task_set_data (task, NULL, NULL, &progress);
		}

		p_new2 = p_new;

		x = - half_new_width;
		for (xi = 0; xi < new_width; xi++) {
			x2 = cos_angle * x - sin_angle * y + half_src_width;
			y2 = sin_angle * x + cos_angle * y + half_src_height;

			if (high_quality) {
				/* Bilinear interpolation. */

				x2min = (int) x2;
				y2min = (int) y2;
				x2max = x2min + 1;
				y2max = y2min + 1;

				GET_VALUES (r00, g00, b00, a00, x2min, y2min);
				GET_VALUES (r01, g01, b01, a01, x2max, y2min);
				GET_VALUES (r10, g10, b10, a10, x2min, y2max);
				GET_VALUES (r11, g11, b11, a11, x2max, y2max);

				fx = x2 - x2min;
				fy = y2 - y2min;

				INTERPOLATE (r, r00, r01, r10, r11, fx, fy);
				INTERPOLATE (g, g00, g01, g10, g11, fx, fy);
				INTERPOLATE (b, b00, b01, b10, b11, fx, fy);
				INTERPOLATE (a, a00, a01, a10, a11, fx, fy);

				pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, a);
				memcpy (p_new2, &pixel, sizeof (guint32));
			}
			else {
				/* Nearest neighbor */

				x2min = GDOUBLE_ROUND_TO_INT (x2);
				y2min = GDOUBLE_ROUND_TO_INT (y2);

				GET_VALUES (p_new2[CAIRO_RED],
					    p_new2[CAIRO_GREEN],
					    p_new2[CAIRO_BLUE],
					    p_new2[CAIRO_ALPHA],
					    x2min,
					    y2min);
			}

			p_new2 += 4;
			x += 1.0;
		}

		p_new += new_rowstride;
		y += 1.0;
	}

	out:

	cairo_surface_mark_dirty (rotated);
	cairo_surface_destroy (image_with_background);

#undef INTERPOLATE
#undef GET_VALUES

	return rotated;
}