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; }
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_webp (cairo_surface_t *image, char **buffer, gsize *buffer_size, char **keys, char **values, GError **error) { gboolean lossless; int quality; int method; WebPConfig config; CairoWebpData *cairo_webp_data; WebPPicture pic; lossless = TRUE; quality = 75; method = 4; if (keys && *keys) { char **kiter = keys; char **viter = values; while (*kiter) { if (strcmp (*kiter, "lossless") == 0) { if (*viter == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Must specify a value for the 'lossless' option"); return FALSE; } lossless = atoi (*viter); if (lossless < 0 || lossless > 1) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Invalid value set for the 'lossless' option of the WebP saver"); return FALSE; } } else if (strcmp (*kiter, "quality") == 0) { if (*viter == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Must specify a quality value to the WebP saver"); return FALSE; } quality = atoi (*viter); if (quality < 0 || quality > 100) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Unsupported quality value passed to the WebP saver"); return FALSE; } } else if (strcmp (*kiter, "method") == 0) { if (*viter == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Must specify a method value to the WebP saver"); return FALSE; } method = atoi (*viter); if (method < 0 || method > 6) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Unsupported method value passed to the WebP saver"); return FALSE; } } else { g_warning ("Bad option name '%s' passed to the WebP saver", *kiter); return FALSE; } ++kiter; ++viter; } } if (! WebPConfigInit (&config)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Version error"); return FALSE; } config.lossless = lossless; config.quality = quality; config.method = method; if (! WebPValidateConfig (&config)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Config error"); return FALSE; } cairo_webp_data = g_new0 (CairoWebpData, 1); cairo_webp_data->error = error; cairo_webp_data->buffer_data = gth_buffer_data_new (); cairo_webp_data->success = FALSE; WebPPictureInit (&pic); pic.width = cairo_image_surface_get_width (image); pic.height = cairo_image_surface_get_height (image); pic.writer = cairo_webp_writer_func; pic.custom_ptr = cairo_webp_data; pic.use_argb = TRUE; if (_WebPPictureImportCairoSurface (&pic, image)) { int ok = WebPEncode (&config, &pic); WebPPictureFree (&pic); if (cairo_webp_data->success && ! ok) { g_set_error (cairo_webp_data->error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Encoding error: %d", pic.error_code); cairo_webp_data->success = FALSE; } } else { g_set_error (cairo_webp_data->error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Memory error"); cairo_webp_data->success = FALSE; } if (cairo_webp_data->success) gth_buffer_data_get (cairo_webp_data->buffer_data, buffer, buffer_size); _cairo_webp_data_destroy (cairo_webp_data); return TRUE; }