Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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;
}