static cairo_surface_t * _cairo_surface_create_from_ppm (int width, int height, int colors, int bits, guchar *buffer, gsize buffer_size) { cairo_surface_t *surface; int stride; guchar *buffer_p; int r, c; guchar *row; guchar *column; guint32 pixel; if (bits != 8) return NULL; surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); stride = cairo_image_surface_get_stride (surface); buffer_p = buffer; row = _cairo_image_surface_flush_and_get_data (surface); for (r = 0; r < height; r++) { column = row; for (c = 0; c < width; c++) { switch (colors) { case 4: pixel = CAIRO_RGBA_TO_UINT32 (buffer_p[0], buffer_p[1], buffer_p[2], buffer_p[3]); break; case 3: pixel = CAIRO_RGBA_TO_UINT32 (buffer_p[0], buffer_p[1], buffer_p[2], 0xff); break; case 1: pixel = CAIRO_RGBA_TO_UINT32 (buffer_p[0], buffer_p[0], buffer_p[0], 0xff); break; } memcpy (column, &pixel, sizeof (guint32)); column += 4; buffer_p += colors; } row += stride; } cairo_surface_mark_dirty (surface); return surface; }
static void _cairo_surface_reduce_row (guchar *dest_data, guchar *src_row0, guchar *src_row1, guchar *src_row2, int src_width) { int x, b; ScaleReal sum; int col0, col1, col2; guchar c[4]; guint32 pixel; /* Pre calculated gausian matrix * Standard deviation = 0.71 12 32 12 32 86 32 12 32 12 Matrix sum is = 262 Normalize by dividing with 273 */ for (x = 0; x < src_width - (src_width % 2); x += 2) { for (b = 0; b < 4; b++) { col0 = MAX (x - 1, 0) * 4 + b; col1 = x * 4 + b; col2 = MIN (x + 1, src_width - 1) * 4 + b; sum = 0.0; sum += src_row0[col0] * 12; sum += src_row0[col1] * 32; sum += src_row0[col2] * 12; sum += src_row1[col0] * 32; sum += src_row1[col1] * 86; sum += src_row1[col2] * 32; sum += src_row2[col0] * 12; sum += src_row2[col1] * 32; sum += src_row2[col2] * 12; sum /= 262.0; c[b] = CLAMP (sum, 0, 255); } pixel = CAIRO_RGBA_TO_UINT32 (c[CAIRO_RED], c[CAIRO_GREEN], c[CAIRO_BLUE], c[CAIRO_ALPHA]); memcpy (dest_data, &pixel, 4); dest_data += 4; } }
cairo_surface_t * _cairo_image_surface_create_from_pixbuf (GdkPixbuf *pixbuf) { cairo_surface_t *surface; cairo_surface_metadata_t *metadata; int width; int height; int p_stride; int p_n_channels; guchar *p_pixels; int s_stride; unsigned char *s_pixels; int h, w; guint32 pixel; guchar r, g, b, a; if (pixbuf == NULL) return NULL; g_object_get (G_OBJECT (pixbuf), "width", &width, "height", &height, "rowstride", &p_stride, "n-channels", &p_n_channels, "pixels", &p_pixels, NULL ); surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); s_stride = cairo_image_surface_get_stride (surface); s_pixels = _cairo_image_surface_flush_and_get_data (surface); metadata = _cairo_image_surface_get_metadata (surface); _cairo_metadata_set_has_alpha (metadata, (p_n_channels == 4)); if (p_n_channels == 4) { guchar *s_iter; guchar *p_iter; for (h = 0; h < height; h++) { s_iter = s_pixels; p_iter = p_pixels; for (w = 0; w < width; w++) { a = p_iter[3]; if (a == 0xff) { pixel = CAIRO_RGBA_TO_UINT32 (p_iter[0], p_iter[1], p_iter[2], 0xff); } else if (a == 0) { pixel = 0; } else { r = _cairo_multiply_alpha (p_iter[0], a); g = _cairo_multiply_alpha (p_iter[1], a); b = _cairo_multiply_alpha (p_iter[2], a); pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, a); } memcpy (s_iter, &pixel, sizeof (guint32)); s_iter += 4; p_iter += p_n_channels; } s_pixels += s_stride; p_pixels += p_stride; } } else { guchar *s_iter; guchar *p_iter; for (h = 0; h < height; h++) { s_iter = s_pixels; p_iter = p_pixels; for (w = 0; w < width; w++) { pixel = CAIRO_RGBA_TO_UINT32 (p_iter[0], p_iter[1], p_iter[2], 0xff); memcpy (s_iter, &pixel, sizeof (guint32)); s_iter += 4; p_iter += p_n_channels; } s_pixels += s_stride; p_pixels += p_stride; } } cairo_surface_mark_dirty (surface); return surface; }
cairo_surface_t * _cairo_image_surface_scale_bilinear_2x2 (cairo_surface_t *image, int new_width, int new_height) { cairo_surface_t *scaled; int src_width; int src_height; guchar *p_src; guchar *p_dest; int src_rowstride; int dest_rowstride; ScaleReal step_x, step_y; guchar *p_dest_row; guchar *p_src_row; guchar *p_src_col; guchar *p_dest_col; ScaleReal x_src, y_src; int x, y; guchar r00, r01, r10, r11; guchar g00, g01, g10, g11; guchar b00, b01, b10, b11; guchar a00, a01, a10, a11; guchar r, g, b, a; guint32 pixel; ScaleReal tmp; ScaleReal x_fract, y_fract; int col, row; scaled = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, new_width, new_height); src_width = cairo_image_surface_get_width (image); src_height = cairo_image_surface_get_height (image); 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); cairo_surface_flush (scaled); step_x = (ScaleReal) src_width / new_width; step_y = (ScaleReal) src_height / new_height; p_dest_row = p_dest; p_src_row = p_src; y_src = 0; for (y = 0; y < new_height; y++) { row = floor (y_src); y_fract = y_src - row; p_src_row = p_src + (row * src_rowstride); p_dest_col = p_dest_row; p_src_col = p_src_row; x_src = 0; for (x = 0; x < new_width; x++) { col = floor (x_src); x_fract = x_src - col; p_src_col = p_src_row + (col * 4); /* x00 */ CAIRO_COPY_RGBA (p_src_col, r00, g00, b00, a00); /* x01 */ if (col + 1 < src_width - 1) { p_src_col += 4; CAIRO_COPY_RGBA (p_src_col, r01, g01, b01, a01); } else { r01 = r00; g01 = g00; b01 = b00; a01 = a00; } /* x10 */ if (row + 1 < src_height - 1) { p_src_col = p_src_row + src_rowstride + (col * 4); CAIRO_COPY_RGBA (p_src_col, r10, g10, b10, a10); } else { r10 = r00; g10 = g00; b10 = b00; a10 = a00; } /* x11 */ if ((row + 1 < src_height - 1) && (col + 1 < src_width - 1)) { p_src_col += 4; CAIRO_COPY_RGBA (p_src_col, r11, g11, b11, a11); } else { r11 = r00; g11 = g00; b11 = b00; a11 = a00; } BILINEAR_INTERPOLATE (r, r00, r01, r10, r11, x_fract, y_fract); BILINEAR_INTERPOLATE (g, g00, g01, g10, g11, x_fract, y_fract); BILINEAR_INTERPOLATE (b, b00, b01, b10, b11, x_fract, y_fract); BILINEAR_INTERPOLATE (a, a00, a01, a10, a11, x_fract, y_fract); pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, a); memcpy (p_dest_col, &pixel, 4); p_dest_col += 4; x_src += step_x; } p_dest_row += dest_rowstride; y_src += step_y; } cairo_surface_mark_dirty (scaled); return scaled; }
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; }