コード例 #1
0
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;
}
コード例 #2
0
ファイル: cairo-utils.c プロジェクト: cormac-w/gthumb
cairo_surface_t *
_cairo_image_surface_transform (cairo_surface_t *source,
				GthTransform     transform)
{
	cairo_surface_t *destination = NULL;
	cairo_format_t   format;
	int              width;
	int              height;
	int              source_stride;
	int              destination_width;
	int              destination_height;
	int              line_start;
	int              line_step;
	int              pixel_step;
	unsigned char   *p_source_line;
	unsigned char   *p_destination_line;
	unsigned char   *p_source;
	unsigned char   *p_destination;
	int              x;

	if (source == NULL)
		return NULL;

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

	_cairo_image_surface_transform_get_steps (format,
						  width,
						  height,
						  transform,
						  &destination_width,
						  &destination_height,
						  &line_start,
						  &line_step,
						  &pixel_step);

	destination = cairo_image_surface_create (format, destination_width, destination_height);
	p_source_line = _cairo_image_surface_flush_and_get_data (source);
	p_destination_line = _cairo_image_surface_flush_and_get_data (destination) + line_start;
	while (height-- > 0) {
		p_source = p_source_line;
		p_destination = p_destination_line;
		for (x = 0; x < width; x++) {
			memcpy (p_destination, p_source, 4);
			p_source += 4;
			p_destination += pixel_step;
		}
		p_source_line += source_stride;
		p_destination_line += line_step;
	}

	cairo_surface_mark_dirty (destination);

	return destination;
}
コード例 #3
0
ファイル: cairo-utils.c プロジェクト: cormac-w/gthumb
cairo_surface_t *
_cairo_image_surface_color_shift (cairo_surface_t *image,
				  int              shift)
{
	cairo_surface_t *shifted;
	int              i, j;
	int              width, height, src_stride, dest_stride;
	guchar          *src_pixels, *src_row, *src_pixel;
	guchar          *dest_pixels, *dest_row, *dest_pixel;
	int              val, temp;
	guchar           r, g, b, a;

	shifted = _cairo_image_surface_create_compatible (image);

	width       = cairo_image_surface_get_width (image);
	height      = cairo_image_surface_get_height (image);
	src_stride  = cairo_image_surface_get_stride (image);
	src_pixels  = _cairo_image_surface_flush_and_get_data (image);
	dest_stride = cairo_image_surface_get_stride (shifted);
	dest_pixels = _cairo_image_surface_flush_and_get_data (shifted);

	src_row = src_pixels;
	dest_row = dest_pixels;
	for (i = 0; i < height; i++) {
		src_pixel = src_row;
		dest_pixel  = dest_row;

		for (j = 0; j < width; j++) {
			CAIRO_GET_RGBA (src_pixel, r, g, b, a);

			val = r + shift;
			r = CLAMP (val, 0, 255);

			val = g + shift;
			g = CLAMP (val, 0, 255);

			val = b + shift;
			b = CLAMP (val, 0, 255);

			CAIRO_SET_RGBA (dest_pixel, r, g, b, a);

			src_pixel += 4;
			dest_pixel += 4;
		}

		src_row += src_stride;
		dest_row += dest_stride;
	}

	cairo_surface_mark_dirty (shifted);

	return shifted;
}
コード例 #4
0
ファイル: cairo-utils.c プロジェクト: cormac-w/gthumb
void
_cairo_paint_full_gradient (cairo_surface_t *surface,
			    GdkRGBA         *h_color1,
			    GdkRGBA         *h_color2,
			    GdkRGBA         *v_color1,
			    GdkRGBA         *v_color2)
{
	cairo_color_255_t  hcolor1;
	cairo_color_255_t  hcolor2;
	cairo_color_255_t  vcolor1;
	cairo_color_255_t  vcolor2;
	int                width;
	int                height;
	int                s_stride;
	unsigned char     *s_pixels;
	int                h, w;
	double             x, y;
	double             x_y, x_1_y, y_1_x, _1_x_1_y;
	guchar             red, green, blue;

	if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
		return;

	_gdk_rgba_to_cairo_color_255 (h_color1, &hcolor1);
	_gdk_rgba_to_cairo_color_255 (h_color2, &hcolor2);
	_gdk_rgba_to_cairo_color_255 (v_color1, &vcolor1);
	_gdk_rgba_to_cairo_color_255 (v_color2, &vcolor2);

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

	for (h = 0; h < height; h++) {
		guchar *s_iter = s_pixels;

	        x = (double) (height - h) / height;

	        for (w = 0; w < width; w++) {
	        	y        = (double) (width - w) / width;
			x_y      = x * y;
			x_1_y    = x * (1.0 - y);
			y_1_x    = y * (1.0 - x);
			_1_x_1_y = (1.0 - x) * (1.0 - y);

			red   = hcolor1.r * x_y + hcolor2.r * x_1_y + vcolor1.r * y_1_x + vcolor2.r * _1_x_1_y;
			green = hcolor1.g * x_y + hcolor2.g * x_1_y + vcolor1.g * y_1_x + vcolor2.g * _1_x_1_y;
			blue  = hcolor1.b * x_y + hcolor2.b * x_1_y + vcolor1.b * y_1_x + vcolor2.b * _1_x_1_y;

			CAIRO_SET_RGB (s_iter, red, green, blue);

			s_iter += 4;
		}

		s_pixels += s_stride;
	}

	cairo_surface_mark_dirty (surface);
}
コード例 #5
0
ファイル: cairo-utils.c プロジェクト: cormac-w/gthumb
cairo_surface_t *
_cairo_image_surface_copy_subsurface (cairo_surface_t *source,
				      int              src_x,
				      int              src_y,
				      int              width,
				      int              height)
{
	cairo_surface_t *destination;
	cairo_status_t   status;
	int              source_stride;
	int              destination_stride;
	unsigned char   *p_source;
	unsigned char   *p_destination;
	int              row_size;

	g_return_val_if_fail (source != NULL, NULL);
	g_return_val_if_fail (src_x + width <= cairo_image_surface_get_width (source), NULL);
	g_return_val_if_fail (src_y + height <= cairo_image_surface_get_height (source), NULL);

	destination = cairo_image_surface_create (cairo_image_surface_get_format (source), width, height);
	status = cairo_surface_status (destination);
	if (status != CAIRO_STATUS_SUCCESS) {
		g_warning ("_cairo_image_surface_copy_subsurface: could not create the surface: %s", cairo_status_to_string (status));
		cairo_surface_destroy (destination);
		return NULL;
	}

	source_stride = cairo_image_surface_get_stride (source);
	destination_stride = cairo_image_surface_get_stride (destination);
	p_source = _cairo_image_surface_flush_and_get_data (source) + (src_y * source_stride) + (src_x * 4);
	p_destination = _cairo_image_surface_flush_and_get_data (destination);
	row_size = width * 4;
	while (height-- > 0) {
		memcpy (p_destination, p_source, row_size);

		p_source += source_stride;
		p_destination += destination_stride;
	}

	cairo_surface_mark_dirty (destination);

	return destination;
}
コード例 #6
0
ファイル: cairo-scale.c プロジェクト: cristiklein/gthumb
static cairo_surface_t *
_cairo_surface_reduce_by_half (cairo_surface_t *src)
{
	int              src_width, src_height;
	cairo_surface_t *dest;
	int              src_rowstride, dest_rowstride;
	guchar          *row0, *row1, *row2;
	guchar          *src_data, *dest_data;
	int              y;

	src_width = cairo_image_surface_get_width (src);
	src_height = cairo_image_surface_get_height (src);
	dest = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
					   src_width / 2,
					   src_height / 2);

	dest_rowstride = cairo_image_surface_get_stride (dest);
	dest_data = _cairo_image_surface_flush_and_get_data (dest);

	src_rowstride = cairo_image_surface_get_stride (src);
	src_data = _cairo_image_surface_flush_and_get_data (src);

	for (y = 0; y < src_height - (src_height % 2); y += 2) {
		row0 = src_data + (MAX (y - 1, 0) * src_rowstride);
		row1 = src_data + (y * src_rowstride);
		row2 = src_data + (MIN (y + 1, src_height - 1) * src_rowstride);

		_cairo_surface_reduce_row (dest_data,
					   row0,
					   row1,
					   row2,
					   src_width);

		dest_data += dest_rowstride;
	}

	cairo_surface_mark_dirty (dest);

	return dest;
}
コード例 #7
0
ファイル: pixbuf-utils.c プロジェクト: KapTmaN/gthumb
/* 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;
}
コード例 #8
0
ファイル: main.c プロジェクト: KapTmaN/gthumb
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;
}
コード例 #9
0
ファイル: cairo-utils.c プロジェクト: cormac-w/gthumb
cairo_surface_t *
_cairo_image_surface_copy (cairo_surface_t *source)
{
	cairo_surface_t *result;
	unsigned char   *p_source;
	unsigned char   *p_destination;

	if (source == NULL)
		return NULL;

	result = _cairo_image_surface_create (cairo_image_surface_get_format (source),
					      cairo_image_surface_get_width (source),
					      cairo_image_surface_get_height (source));
	if (result == NULL)
		return NULL;

	p_source = _cairo_image_surface_flush_and_get_data (source);
	p_destination = _cairo_image_surface_flush_and_get_data (result);
	memcpy (p_destination, p_source, cairo_image_surface_get_stride (source) * cairo_image_surface_get_height (source));
	cairo_surface_mark_dirty (result);

	return result;
}
コード例 #10
0
ファイル: cairo-utils.c プロジェクト: GNOME/gthumb
gboolean
_cairo_image_surface_get_has_alpha (cairo_surface_t *surface)
{
	cairo_surface_metadata_t *metadata;
	gboolean                  has_alpha;
	int                       width;
	int                       height;
	int                       row_stride;
	guchar                   *row;
	int                       h, w;

	if (surface == NULL)
		return FALSE;

	metadata = _cairo_image_surface_get_metadata (surface);
	if ((metadata != NULL) && (metadata->valid_data & _CAIRO_METADATA_FLAG_HAS_ALPHA))
		return metadata->has_alpha;

	has_alpha = FALSE;
	if (cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32) {
		/* search an alpha value lower than 255 */

		width = cairo_image_surface_get_width (surface);
		height = cairo_image_surface_get_height (surface);
		row_stride = cairo_image_surface_get_stride (surface);
		row = _cairo_image_surface_flush_and_get_data (surface);

		for (h = 0; ! has_alpha && (h < height); h++) {
			guchar *pixel = row;
			for (w = 0; w < width; w++) {
				if (pixel[CAIRO_ALPHA] < 255) {
					has_alpha = TRUE;
					break;
				}
				pixel += 4;
			}
			row += row_stride;
		}
	}
	_cairo_metadata_set_has_alpha (metadata, has_alpha);

	return has_alpha;
}
コード例 #11
0
ファイル: cairo-utils.c プロジェクト: cormac-w/gthumb
gboolean
_cairo_image_surface_get_has_alpha (cairo_surface_t *surface)
{
	cairo_surface_metadata_t *metadata;
	int                       width;
	int                       height;
	int                       row_stride;
	guchar                   *row;
	int                       h, w;

	if (surface == NULL)
		return FALSE;

	metadata = cairo_surface_get_user_data (surface, &surface_metadata_key);
	if ((metadata != NULL) && (metadata->valid_data & _CAIRO_METADATA_FLAG_HAS_ALPHA))
		return metadata->has_alpha;

	if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_ARGB32)
		return FALSE;

	/* search an alpha value lower than 255 */

	width = cairo_image_surface_get_width (surface);
	height = cairo_image_surface_get_height (surface);
	row_stride = cairo_image_surface_get_stride (surface);
	row = _cairo_image_surface_flush_and_get_data (surface);

	for (h = 0; h < height; h++) {
		guchar *pixel = row;
		for (w = 0; w < width; w++) {
			if (pixel[CAIRO_ALPHA] < 255)
				return TRUE;
			pixel += 4;
		}
		row += row_stride;
	}

	return FALSE;
}
コード例 #12
0
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;
}
コード例 #13
0
ファイル: cairo-utils.c プロジェクト: cormac-w/gthumb
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;
}
コード例 #14
0
GthImage *
_cairo_image_surface_create_from_tiff (GInputStream  *istream,
				       GthFileData   *file_data,
				       int            requested_size,
				       int           *original_width_p,
				       int           *original_height_p,
				       gboolean      *loaded_original_p,
				       gpointer       user_data,
				       GCancellable  *cancellable,
				       GError       **error)
{
	GthImage		*image;
	Handle			 handle;
	TIFF			*tif;
	gboolean		 first_directory;
	int			 best_directory;
	int        		 max_width, max_height, min_diff;
	uint32			 image_width;
	uint32			 image_height;
	uint32			 spp;
	uint16			 extrasamples;
	uint16			*sampleinfo;
	uint16			 orientation;
	char			 emsg[1024];
	cairo_surface_t		*surface;
	cairo_surface_metadata_t*metadata;
	uint32			*raster;

	image = gth_image_new ();
	handle.cancellable = cancellable;
	handle.size = 0;

	if ((file_data != NULL) && (file_data->info != NULL)) {
		handle.istream = g_buffered_input_stream_new (istream);
		handle.size = g_file_info_get_size (file_data->info);
	}
	else {
		void  *data;
		gsize  size;

		/* read the whole stream to get the file size */

		if (! _g_input_stream_read_all (istream, &data, &size, cancellable, error))
			return image;
		handle.istream = g_memory_input_stream_new_from_data (data, size, g_free);
		handle.size = size;
	}


	TIFFSetErrorHandler (tiff_error_handler);
	TIFFSetWarningHandler (tiff_error_handler);

	tif = TIFFClientOpen ("gth-tiff-reader", "r",
			      &handle,
	                      tiff_read,
	                      tiff_write,
	                      tiff_seek,
	                      tiff_close,
	                      tiff_size,
	                      NULL,
	                      NULL);

	if (tif == NULL) {
		g_object_unref (handle.istream);
		g_set_error_literal (error,
				     GDK_PIXBUF_ERROR,
				     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
				     "Couldn't allocate memory for writing TIFF file");
		return image;
	}

	/* find the best image to load */

	first_directory = TRUE;
	best_directory = -1;
	max_width = -1;
	max_height = -1;
	min_diff = 0;
	do {
		int width;
		int height;

		if (TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &width) != 1)
			continue;
		if (TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &height) != 1)
			continue;

		if (! TIFFRGBAImageOK (tif, emsg))
			continue;

		if (width > max_width) {
			max_width = width;
			max_height = height;
			if (requested_size <= 0)
				best_directory = TIFFCurrentDirectory (tif);
		}

		if (requested_size > 0) {
			int diff = abs (requested_size - width);

			if (first_directory) {
				min_diff = diff;
				best_directory = TIFFCurrentDirectory (tif);
			}
			else if (diff < min_diff) {
				min_diff = diff;
				best_directory = TIFFCurrentDirectory (tif);
			}
		}

		first_directory = FALSE;
	}
	while (TIFFReadDirectory (tif));

	if (best_directory == -1) {
		TIFFClose (tif);
		g_object_unref (handle.istream);
		g_set_error_literal (error,
				     G_IO_ERROR,
				     G_IO_ERROR_INVALID_DATA,
				     "Invalid TIFF format");
		return image;
	}

	/* read the image */

	TIFFSetDirectory (tif, best_directory);
	TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &image_width);
	TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &image_height);
	TIFFGetField (tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
	TIFFGetFieldDefaulted (tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo);
	if (TIFFGetFieldDefaulted (tif, TIFFTAG_ORIENTATION, &orientation) != 1)
		orientation = ORIENTATION_TOPLEFT;

	if (original_width_p)
		*original_width_p = max_width;
	if (original_height_p)
		*original_height_p = max_height;
	if (loaded_original_p)
		*loaded_original_p = (max_width == image_width);

	surface = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32, image_width, image_height);
	if (surface == NULL) {
		TIFFClose (tif);
		g_object_unref (handle.istream);
		g_set_error_literal (error,
				     GDK_PIXBUF_ERROR,
				     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
				     "Couldn't allocate memory for writing TIFF file");
		return image;
	}

	metadata = _cairo_image_surface_get_metadata (surface);
	_cairo_metadata_set_has_alpha (metadata, (extrasamples == 1) || (spp == 4));
	_cairo_metadata_set_original_size (metadata, max_width, max_height);

	raster = (uint32*) _TIFFmalloc (image_width * image_height * sizeof (uint32));
	if (raster == NULL) {
		cairo_surface_destroy (surface);
		TIFFClose (tif);
		g_object_unref (handle.istream);
		g_set_error_literal (error,
				     GDK_PIXBUF_ERROR,
				     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
				     "Couldn't allocate memory for writing TIFF file");
		return image;
	}

	if (TIFFReadRGBAImageOriented (tif, image_width, image_height, raster, orientation, 0)) {
		guchar *surface_row;
		int     line_step;
		int     x, y, temp;
		guchar  r, g, b, a;
		uint32 *src_pixel;

		surface_row = _cairo_image_surface_flush_and_get_data (surface);
		line_step = cairo_image_surface_get_stride (surface);
		src_pixel = raster;
		for (y = 0; y < image_height; y++) {
			guchar *dest_pixel = surface_row;

			if (g_cancellable_is_cancelled (cancellable))
				goto stop_loading;

			for (x = 0; x < image_width; x++) {
				r = TIFFGetR (*src_pixel);
				g = TIFFGetG (*src_pixel);
				b = TIFFGetB (*src_pixel);
				a = TIFFGetA (*src_pixel);
				CAIRO_SET_RGBA (dest_pixel, r, g, b, a);

				dest_pixel += 4;
				src_pixel += 1;
			}

			surface_row += line_step;
		}
	}

stop_loading:

	cairo_surface_mark_dirty (surface);
	if (! g_cancellable_is_cancelled (cancellable))
		gth_image_set_cairo_surface (image, surface);

	_TIFFfree (raster);
	cairo_surface_destroy (surface);
	TIFFClose (tif);
	g_object_unref (handle.istream);

	return image;
}
コード例 #15
0
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;
}
コード例 #16
0
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;
}
コード例 #17
0
GthImage *
_cairo_image_surface_create_from_webp (GInputStream  *istream,
		       	       	       GthFileData   *file_data,
				       int            requested_size,
				       int           *original_width,
				       int           *original_height,
				       gboolean      *loaded_original,
				       gpointer       user_data,
				       GCancellable  *cancellable,
				       GError       **error)
{
	GthImage                  *image;
	WebPDecoderConfig          config;
	guchar                    *buffer;
	gssize                     bytes_read;
	int                        width, height;
	cairo_surface_t           *surface;
	cairo_surface_metadata_t  *metadata;
	WebPIDecoder              *idec;

	image = gth_image_new ();

	if (! WebPInitDecoderConfig (&config))
		return image;

	buffer = g_new (guchar, BUFFER_SIZE);
	bytes_read = g_input_stream_read (istream,
					  buffer,
					  BUFFER_SIZE,
					  cancellable,
					  error);

	if (WebPGetFeatures (buffer, bytes_read, &config.input) != VP8_STATUS_OK) {
		g_free (buffer);
		return image;
	}

	width = config.input.width;
	height = config.input.height;

	if (original_width != NULL)
		*original_width = width;
	if (original_height != NULL)
		*original_height = height;

#if SCALING_WORKS
	if (requested_size > 0)
		scale_keeping_ratio (&width, &height, requested_size, requested_size, FALSE);
#endif

	surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
	metadata = _cairo_image_surface_get_metadata (surface);
	_cairo_metadata_set_has_alpha (metadata, config.input.has_alpha);

	config.options.no_fancy_upsampling = 1;

#if SCALING_WORKS
	if (requested_size > 0) {
		config.options.use_scaling = 1;
		config.options.scaled_width = width;
		config.options.scaled_height = height;
	}
#endif

#if G_BYTE_ORDER == G_LITTLE_ENDIAN
	config.output.colorspace = MODE_BGRA;
#elif G_BYTE_ORDER == G_BIG_ENDIAN
	config.output.colorspace = MODE_ARGB;
#endif
	config.output.u.RGBA.rgba = (uint8_t *) _cairo_image_surface_flush_and_get_data (surface);
	config.output.u.RGBA.stride = cairo_image_surface_get_stride (surface);
	config.output.u.RGBA.size = cairo_image_surface_get_stride (surface) * height;
	config.output.is_external_memory = 1;

	idec = WebPINewDecoder (&config.output);
	if (idec == NULL) {
		g_free (buffer);
		return image;
	}

	do {
		VP8StatusCode status = WebPIAppend (idec, buffer, bytes_read);
		if ((status != VP8_STATUS_OK) && (status != VP8_STATUS_SUSPENDED))
			break;
	}
	while ((bytes_read = g_input_stream_read (istream,
						  buffer,
						  BUFFER_SIZE,
						  cancellable,
						  error)) > 0);

	cairo_surface_mark_dirty (surface);
	if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS)
		gth_image_set_cairo_surface (image, surface);

	WebPIDelete (idec);
	WebPFreeDecBuffer (&config.output);

	g_free (buffer);

	return image;
}
コード例 #18
0
ファイル: cairo-scale.c プロジェクト: cristiklein/gthumb
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;
}
コード例 #19
0
ファイル: gth-image-saver-tga.c プロジェクト: KapTmaN/gthumb
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;
}
コード例 #20
0
ファイル: gth-image-saver-jpeg.c プロジェクト: KapTmaN/gthumb
static gboolean
_cairo_surface_write_as_jpeg (cairo_surface_t  *image,
			      char            **buffer,
			      gsize            *buffer_size,
			      char            **keys,
			      char            **values,
			      GError          **error)
{
	struct jpeg_compress_struct cinfo;
	struct error_handler_data jerr;
	guchar            *buf = NULL;
	guchar            *pixels = NULL;
	volatile int       quality = 85; /* default; must be between 0 and 100 */
	volatile int       smoothing = 0;
	volatile gboolean  optimize = FALSE;
#ifdef HAVE_PROGRESSIVE_JPEG
	volatile gboolean  progressive = FALSE;
#endif
	int                w, h = 0;
	int                rowstride = 0;

	if (keys && *keys) {
		char **kiter = keys;
		char **viter = values;

		while (*kiter) {
			if (strcmp (*kiter, "quality") == 0) {
				char *endptr = NULL;
				quality = strtol (*viter, &endptr, 10);

				if (endptr == *viter) {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "JPEG quality must be a value between 0 and 100; value '%s' could not be parsed.",
						     *viter);

					return FALSE;
				}

				if (quality < 0 || quality > 100) {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "JPEG quality must be a value between 0 and 100; value '%d' is not allowed.",
						     quality);

					return FALSE;
				}
			}
			else if (strcmp (*kiter, "smooth") == 0) {
				char *endptr = NULL;
				smoothing = strtol (*viter, &endptr, 10);

				if (endptr == *viter) {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "JPEG smoothing must be a value between 0 and 100; value '%s' could not be parsed.",
						     *viter);

					return FALSE;
				}

				if (smoothing < 0 || smoothing > 100) {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "JPEG smoothing must be a value between 0 and 100; value '%d' is not allowed.",
						     smoothing);

					return FALSE;
				}
			}
			else if (strcmp (*kiter, "optimize") == 0) {
				if (strcmp (*viter, "yes") == 0)
					optimize = TRUE;
				else if (strcmp (*viter, "no") == 0)
					optimize = FALSE;
				else {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "JPEG optimize option must be 'yes' or 'no', value is: %s", *viter);

					return FALSE;
				}
			}
#ifdef HAVE_PROGRESSIVE_JPEG
			else if (strcmp (*kiter, "progressive") == 0) {
				if (strcmp (*viter, "yes") == 0)
					progressive = TRUE;
				else if (strcmp (*viter, "no") == 0)
					progressive = FALSE;
				else {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "JPEG progressive option must be 'yes' or 'no', value is: %s", *viter);

					return FALSE;
				}
			}
#endif
			else {
				g_warning ("Bad option name '%s' passed to JPEG saver", *kiter);
				return FALSE;
			}

			++kiter;
			++viter;
		}
	}

	rowstride = cairo_image_surface_get_stride (image);
	w = cairo_image_surface_get_width (image);
	h = cairo_image_surface_get_height (image);
	pixels = _cairo_image_surface_flush_and_get_data (image);
	g_return_val_if_fail (pixels != NULL, FALSE);

	/* allocate a small buffer to convert image data */

	buf = g_try_malloc (w * 3 * sizeof (guchar));
	if (! buf) {
		g_set_error (error,
			     GDK_PIXBUF_ERROR,
			     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
			     "Couldn't allocate memory for loading JPEG file");
		return FALSE;
	}

	/* set up error handling */

	cinfo.err = jpeg_std_error (&(jerr.pub));
	jerr.pub.error_exit = fatal_error_handler;
	jerr.pub.output_message = output_message_handler;
	jerr.error = error;
	if (sigsetjmp (jerr.setjmp_buffer, 1)) {
		jpeg_destroy_compress (&cinfo);
		g_free (buf);
		return FALSE;
	}

	/* setup compress params */

	jpeg_create_compress (&cinfo);
	_jpeg_memory_dest (&cinfo, (void **)buffer, buffer_size);

	cinfo.image_width      = w;
	cinfo.image_height     = h;
	cinfo.input_components = 3;
	cinfo.in_color_space   = JCS_RGB;

	/* set up jepg compression parameters */

	jpeg_set_defaults (&cinfo);
	jpeg_set_quality (&cinfo, quality, TRUE);
	cinfo.smoothing_factor = smoothing;
	cinfo.optimize_coding = optimize;

#ifdef HAVE_PROGRESSIVE_JPEG
	if (progressive)
		jpeg_simple_progression (&cinfo);
#endif /* HAVE_PROGRESSIVE_JPEG */

	jpeg_start_compress (&cinfo, TRUE);

	/* go one scanline at a time... and save */
	while (cinfo.next_scanline < cinfo.image_height) {
		JSAMPROW *jbuf;

		/* convert scanline from RGBA to RGB packed */

		_cairo_copy_line_as_rgba_big_endian (buf, pixels, w, FALSE);

		/* write scanline */
		jbuf = (JSAMPROW *)(&buf);
		jpeg_write_scanlines (&cinfo, jbuf, 1);

		pixels += rowstride;
	}

	/* finish off */

	jpeg_finish_compress (&cinfo);
	jpeg_destroy_compress (&cinfo);
	g_free (buf);

	return TRUE;
}
コード例 #21
0
ファイル: cairo-scale.c プロジェクト: cristiklein/gthumb
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);
}
コード例 #22
0
ファイル: cairo-scale.c プロジェクト: cristiklein/gthumb
cairo_surface_t *
_cairo_image_surface_scale_nearest (cairo_surface_t *image,
				    int              new_width,
				    int              new_height)
{
#if 0
	cairo_surface_t *scaled;
	int              src_width;
	int              src_height;
	guchar          *p_src;
	guchar          *p_dest;
	int              src_rowstride;
	int              dest_rowstride;
	gfixed           step_x, step_y;
	guchar          *p_src_row;
	guchar          *p_src_col;
	guchar          *p_dest_row;
	guchar          *p_dest_col;
	gfixed           max_row, max_col;
	gfixed           x_src, y_src;
	int              x, y;

	g_return_val_if_fail (cairo_image_surface_get_format (image) == CAIRO_FORMAT_ARGB32, NULL);

	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 = GDOUBLE_TO_FIXED ((double) src_width / new_width);
	step_y = GDOUBLE_TO_FIXED ((double) src_height / new_height);

	p_dest_row = p_dest;
	p_src_row = p_src;
	max_row = GINT_TO_FIXED (src_height - 1);
	max_col = GINT_TO_FIXED (src_width - 1);
	/* pick the pixel in the middle to avoid the shift effect. */
	y_src = gfixed_div (step_y, GFIXED_2);
	for (y = 0; y < new_height; y++) {
		p_dest_col = p_dest_row;
		p_src_col = p_src_row;

		x_src = gfixed_div (step_x, GFIXED_2);
		for (x = 0; x < new_width; x++) {
			p_src_col = p_src_row + (GFIXED_TO_INT (MIN (x_src, max_col)) << 2); /* p_src_col = p_src_row + x_src * 4 */
			memcpy (p_dest_col, p_src_col, 4);

			p_dest_col += 4;
			x_src += step_x;
		}

		p_dest_row += dest_rowstride;
		y_src += step_y;
		p_src_row = p_src + (GFIXED_TO_INT (MIN (y_src, max_row)) * src_rowstride);
	}

	cairo_surface_mark_dirty (scaled);

	return scaled;
#else

	cairo_surface_t *output;
	cairo_t         *cr;

	output = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
					     new_width,
					     new_height);
	cr = cairo_create (output);
	cairo_scale (cr,
		     (double) new_width / cairo_image_surface_get_width (image),
		     (double) new_height / cairo_image_surface_get_height (image));
	cairo_set_source_surface (cr, image, 0.0, 0.0);
	cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
	cairo_rectangle (cr, 0.0, 0.0, cairo_image_surface_get_width (image), cairo_image_surface_get_height (image));
	cairo_fill (cr);
	cairo_surface_flush (output);

	cairo_destroy (cr);

	return output;

#endif
}
コード例 #23
0
ファイル: gth-image-saver-png.c プロジェクト: KapTmaN/gthumb
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;
}
コード例 #24
0
ファイル: cairo-rotate.c プロジェクト: GNOME/gthumb
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;
}