/* Started from from http://www.gtkforums.com/about5204.html * Author: tadeboro */ GdkPixbuf * _gdk_pixbuf_new_from_cairo_surface (cairo_surface_t *surface) { int width; int height; int s_stride; unsigned char *s_pixels; GdkPixbuf *pixbuf; int p_stride; guchar *p_pixels; int p_n_channels; if (surface == NULL) return NULL; if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) return NULL; width = cairo_image_surface_get_width (surface); height = cairo_image_surface_get_height (surface); s_stride = cairo_image_surface_get_stride (surface); s_pixels = _cairo_image_surface_flush_and_get_data (surface); pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, _cairo_image_surface_get_has_alpha (surface), 8, width, height); p_stride = gdk_pixbuf_get_rowstride (pixbuf); p_pixels = gdk_pixbuf_get_pixels (pixbuf); p_n_channels = gdk_pixbuf_get_n_channels (pixbuf); while (height--) { guchar *s_iter = s_pixels; guchar *p_iter = p_pixels; int i; for (i = 0; i < width; i++) { gdouble alpha_factor = (gdouble) 0xff / s_iter[CAIRO_ALPHA]; p_iter[0] = (guchar) (alpha_factor * s_iter[CAIRO_RED] + .5); p_iter[1] = (guchar) (alpha_factor * s_iter[CAIRO_GREEN] + .5); p_iter[2] = (guchar) (alpha_factor * s_iter[CAIRO_BLUE] + .5); if (p_n_channels == 4) p_iter[3] = s_iter[CAIRO_ALPHA]; s_iter += 4; p_iter += p_n_channels; } s_pixels += s_stride; p_pixels += p_stride; } return pixbuf; }
static int _WebPPictureImportCairoSurface (WebPPicture *const picture, cairo_surface_t *image) { int stride; guchar *src_row; uint32_t *dest_row; int y, x, temp; guchar r, g, b, a; if (_cairo_image_surface_get_has_alpha (image)) picture->colorspace |= WEBP_CSP_ALPHA_BIT; else picture->colorspace &= ~WEBP_CSP_ALPHA_BIT; if (! WebPPictureAlloc (picture)) return 0; stride = cairo_image_surface_get_stride (image); src_row = _cairo_image_surface_flush_and_get_data (image); dest_row = picture->argb; for (y= 0; y < cairo_image_surface_get_height (image); y++) { guchar *pixel = src_row; for (x = 0; x < cairo_image_surface_get_width (image); x++) { CAIRO_GET_RGBA (pixel, r, g, b, a); dest_row[x] = ((a << 24) | (r << 16) | (g << 8) | b); pixel += 4; } src_row += stride; dest_row += picture->argb_stride; } return 1; }
static gboolean _cairo_surface_write_as_png (cairo_surface_t *image, char **buffer, gsize *buffer_size, char **keys, char **values, GError **error) { int compression_level; int width, height; gboolean alpha; guchar *pixels, *ptr, *buf; int rowstride; CairoPngData *cairo_png_data; png_color_8 sig_bit; int bpp; int row; compression_level = 6; if (keys && *keys) { char **kiter = keys; char **viter = values; while (*kiter) { if (strcmp (*kiter, "compression") == 0) { if (*viter == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Must specify a compression level"); return FALSE; } compression_level = atoi (*viter); if (compression_level < 0 || compression_level > 9) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Unsupported compression level passed to the PNG saver"); return FALSE; } } else { g_warning ("Bad option name '%s' passed to the PNG saver", *kiter); return FALSE; } ++kiter; ++viter; } } width = cairo_image_surface_get_width (image); height = cairo_image_surface_get_height (image); alpha = _cairo_image_surface_get_has_alpha (image); pixels = _cairo_image_surface_flush_and_get_data (image); rowstride = cairo_image_surface_get_stride (image); cairo_png_data = g_new0 (CairoPngData, 1); cairo_png_data->error = error; cairo_png_data->buffer_data = gth_buffer_data_new (); cairo_png_data->png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, &cairo_png_data->error, gerror_error_func, gerror_warning_func); if (cairo_png_data->png_ptr == NULL) { _cairo_png_data_destroy (cairo_png_data); return FALSE; } cairo_png_data->png_info_ptr = png_create_info_struct (cairo_png_data->png_ptr); if (cairo_png_data->png_info_ptr == NULL) { _cairo_png_data_destroy (cairo_png_data); return FALSE; } if (PNG_SETJMP (cairo_png_data->png_ptr)) { _cairo_png_data_destroy (cairo_png_data); return FALSE; } png_set_write_fn (cairo_png_data->png_ptr, cairo_png_data, cairo_png_write_data_func, cairo_png_flush_data_func); /* Set the image information here */ png_set_IHDR (cairo_png_data->png_ptr, cairo_png_data->png_info_ptr, width, height, 8, (alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB), PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* Options */ sig_bit.red = 8; sig_bit.green = 8; sig_bit.blue = 8; if (alpha) sig_bit.alpha = 8; png_set_sBIT (cairo_png_data->png_ptr, cairo_png_data->png_info_ptr, &sig_bit); png_set_compression_level (cairo_png_data->png_ptr, compression_level); /* Write the file header information. */ png_write_info (cairo_png_data->png_ptr, cairo_png_data->png_info_ptr); /* Write the image */ bpp = alpha ? 4 : 3; buf = g_new (guchar, width * bpp); ptr = pixels; for (row = 0; row < height; ++row) { _cairo_copy_line_as_rgba_big_endian (buf, ptr, width, alpha); png_write_rows (cairo_png_data->png_ptr, &buf, 1); ptr += rowstride; } g_free (buf); png_write_end (cairo_png_data->png_ptr, cairo_png_data->png_info_ptr); gth_buffer_data_get (cairo_png_data->buffer_data, buffer, buffer_size); _cairo_png_data_destroy (cairo_png_data); return TRUE; }
static gboolean _cairo_surface_write_as_tga (cairo_surface_t *image, char **buffer, gsize *buffer_size, char **keys, char **values, GError **error) { GthBufferData *buffer_data; int out_bpp = 0; int row; guchar header[18]; guchar footer[26]; gboolean rle_compression; gboolean alpha; guchar *pixels, *ptr, *buf; int width, height; int rowstride; rle_compression = TRUE; if (keys && *keys) { char **kiter = keys; char **viter = values; while (*kiter) { if (strcmp (*kiter, "compression") == 0) { if (*viter == NULL) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "Must specify a compression type"); return FALSE; } if (strcmp (*viter, "none") == 0) rle_compression = FALSE; else if (strcmp (*viter, "rle") == 0) rle_compression = TRUE; else { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "Unsupported compression type passed to the TGA saver"); return FALSE; } } else { g_warning ("Bad option name '%s' passed to the TGA saver", *kiter); return FALSE; } ++kiter; ++viter; } } width = cairo_image_surface_get_width (image); height = cairo_image_surface_get_height (image); alpha = _cairo_image_surface_get_has_alpha (image); pixels = _cairo_image_surface_flush_and_get_data (image); rowstride = cairo_image_surface_get_stride (image); buffer_data = gth_buffer_data_new (); /* write the header */ header[0] = 0; /* No image identifier / description */ header[1] = 0; header[2] = rle_compression ? 10 : 2; header[3] = header[4] = header[5] = header[6] = header[7] = 0; header[8] = header[9] = 0; /* xorigin */ header[10] = header[11] = 0; /* yorigin */ header[12] = width % 256; header[13] = width / 256; header[14] = height % 256; header[15] = height / 256; if (alpha) { out_bpp = 4; header[16] = 32; /* bpp */ header[17] = 0x28; /* alpha + orientation */ } else { out_bpp = 3; header[16] = 24; /* bpp */ header[17] = 0x20; /* alpha + orientation */ } gth_buffer_data_write (buffer_data, header, sizeof (header), error); /* allocate a small buffer to convert image data */ buf = g_try_malloc (width * out_bpp * sizeof (guchar)); if (! buf) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Insufficient memory")); return FALSE; } ptr = pixels; for (row = 0; row < height; ++row) { _cairo_copy_line_as_rgba_little_endian (buf, ptr, width, alpha); if (rle_compression) rle_write (buffer_data, buf, width, out_bpp, error); else gth_buffer_data_write (buffer_data, buf, width * out_bpp, error); ptr += rowstride; } g_free (buf); /* write the footer */ memset (footer, 0, 8); /* No extensions, no developer directory */ memcpy (footer + 8, magic, sizeof (magic)); /* magic signature */ gth_buffer_data_write (buffer_data, footer, sizeof (footer), error); gth_buffer_data_get (buffer_data, buffer, buffer_size); gth_buffer_data_free (buffer_data, FALSE); return TRUE; }