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; }
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; }
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); }
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; }
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; }